From ecaa96418bfff378a229ebf79d14f9e3c312cf78 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 1 Nov 2019 23:24:07 +0300 Subject: `Span` cannot represent `span.hi < span.lo` So we can remove the corresponding checks from various code --- src/libsyntax/parse/lexer/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index e6dc9a4c134..5ac60b017d3 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -68,7 +68,7 @@ impl<'a> StringReader<'a> { let end = sess.source_map().lookup_byte_offset(span.hi()); // Make the range zero-length if the span is invalid. - if span.lo() > span.hi() || begin.sf.start_pos != end.sf.start_pos { + if begin.sf.start_pos != end.sf.start_pos { span = span.shrink_to_lo(); } -- cgit 1.4.1-3-g733a5 From b9cef6984b606705f42adf9587f4f1c3babf4d4d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 22 Oct 2019 11:04:25 +1100 Subject: Simplify various `Symbol` use points. Including removing a bunch of unnecessary `.as_str()` calls, and a bunch of unnecessary sigils. --- src/librustc/hir/lowering.rs | 2 +- src/librustc/mir/mono.rs | 2 +- src/librustc/traits/error_reporting.rs | 2 +- src/librustc_codegen_llvm/attributes.rs | 2 +- src/librustc_codegen_llvm/debuginfo/namespace.rs | 6 +++--- src/librustc_codegen_ssa/back/symbol_export.rs | 6 +++--- src/librustc_codegen_utils/symbol_names/legacy.rs | 5 +++-- src/librustc_incremental/assert_module_sources.rs | 2 +- src/librustc_incremental/persist/dirty_clean.rs | 4 ++-- src/librustc_lint/builtin.rs | 6 ++---- src/librustc_metadata/creader.rs | 2 +- src/librustc_metadata/native_libs.rs | 2 +- src/librustc_mir/borrow_check/conflict_errors.rs | 2 +- src/librustc_mir/interpret/intrinsics.rs | 2 +- src/librustc_mir/transform/check_unsafety.rs | 12 ++++++------ src/librustc_mir/transform/qualify_consts.rs | 4 ++-- src/librustc_mir/transform/qualify_min_const_fn.rs | 2 +- src/librustc_resolve/late.rs | 2 +- src/librustc_typeck/check/demand.rs | 6 +++--- src/librustc_typeck/check/method/suggest.rs | 4 ++-- src/librustc_typeck/check/pat.rs | 2 +- src/librustc_typeck/collect.rs | 2 +- src/librustdoc/clean/cfg.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/html/render.rs | 2 +- src/libsyntax/ast.rs | 2 +- src/libsyntax/feature_gate/check.rs | 2 +- src/libsyntax/parse/literal.rs | 4 ++-- src/libsyntax/parse/parser/module.rs | 2 +- src/libsyntax_ext/env.rs | 2 +- src/libsyntax_ext/format.rs | 2 +- 31 files changed, 49 insertions(+), 50 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 9ff52727187..3cc5c001300 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3423,7 +3423,7 @@ pub fn is_range_literal(sess: &Session, expr: &hir::Expr) -> bool { ExprKind::Call(ref func, _) => { if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.kind { if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.kind { - let new_call = segment.ident.as_str() == "new"; + let new_call = segment.ident.name == sym::new; return is_range_path(&path) && is_lit(sess, &expr.span) && new_call; } } diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs index 58f99667cb3..a54635c3d51 100644 --- a/src/librustc/mir/mono.rs +++ b/src/librustc/mir/mono.rs @@ -486,7 +486,7 @@ impl CodegenUnitNameBuilder<'tcx> { if self.tcx.sess.opts.debugging_opts.human_readable_cgu_names { cgu_name } else { - let cgu_name = &cgu_name.as_str()[..]; + let cgu_name = &cgu_name.as_str(); Symbol::intern(&CodegenUnit::mangle_name(cgu_name)) } } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 1f7bce1c644..184bbe0842b 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1130,7 +1130,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let restrict_msg = "consider further restricting this bound"; let param_name = self_ty.to_string(); for param in generics.params.iter().filter(|p| { - ¶m_name == std::convert::AsRef::::as_ref(&p.name.ident().as_str()) + p.name.ident().as_str() == param_name }) { if param_name.starts_with("impl ") { // `impl Trait` in argument: diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index 6a36a4a50cb..6f4e7d0f0ca 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -314,7 +314,7 @@ pub fn from_fn_attrs( codegen_fn_attrs.target_features .iter() .map(|f| { - let feature = &*f.as_str(); + let feature = &f.as_str(); format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature)) }) ) diff --git a/src/librustc_codegen_llvm/debuginfo/namespace.rs b/src/librustc_codegen_llvm/debuginfo/namespace.rs index 628d1372b57..482bcf2aa58 100644 --- a/src/librustc_codegen_llvm/debuginfo/namespace.rs +++ b/src/librustc_codegen_llvm/debuginfo/namespace.rs @@ -34,11 +34,11 @@ pub fn item_namespace(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope { }); let namespace_name = match def_key.disambiguated_data.data { - DefPathData::CrateRoot => cx.tcx.crate_name(def_id.krate).as_str(), - data => data.as_symbol().as_str() + DefPathData::CrateRoot => cx.tcx.crate_name(def_id.krate), + data => data.as_symbol() }; - let namespace_name = SmallCStr::new(&namespace_name); + let namespace_name = SmallCStr::new(&namespace_name.as_str()); let scope = unsafe { llvm::LLVMRustDIBuilderCreateNameSpace( diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs index 85a90459f5e..35b62603b07 100644 --- a/src/librustc_codegen_ssa/back/symbol_export.rs +++ b/src/librustc_codegen_ssa/back/symbol_export.rs @@ -129,9 +129,9 @@ fn reachable_non_generics_provider( // // In general though we won't link right if these // symbols are stripped, and LTO currently strips them. - if &*name == "rust_eh_personality" || - &*name == "rust_eh_register_frames" || - &*name == "rust_eh_unregister_frames" { + if name == "rust_eh_personality" || + name == "rust_eh_register_frames" || + name == "rust_eh_unregister_frames" { SymbolExportLevel::C } else { SymbolExportLevel::Rust diff --git a/src/librustc_codegen_utils/symbol_names/legacy.rs b/src/librustc_codegen_utils/symbol_names/legacy.rs index 601a33a66bb..66e1b6d949e 100644 --- a/src/librustc_codegen_utils/symbol_names/legacy.rs +++ b/src/librustc_codegen_utils/symbol_names/legacy.rs @@ -121,9 +121,10 @@ fn get_symbol_hash<'tcx>( substs.hash_stable(&mut hcx, &mut hasher); if let Some(instantiating_crate) = instantiating_crate { - (&tcx.original_crate_name(instantiating_crate).as_str()[..]) + tcx.original_crate_name(instantiating_crate).as_str() + .hash_stable(&mut hcx, &mut hasher); + tcx.crate_disambiguator(instantiating_crate) .hash_stable(&mut hcx, &mut hasher); - (&tcx.crate_disambiguator(instantiating_crate)).hash_stable(&mut hcx, &mut hasher); } // We want to avoid accidental collision between different types of instances. diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs index f740d1a9bfa..483b515f2ba 100644 --- a/src/librustc_incremental/assert_module_sources.rs +++ b/src/librustc_incremental/assert_module_sources.rs @@ -67,7 +67,7 @@ impl AssertModuleSource<'tcx> { } else if attr.check_name(ATTR_PARTITION_CODEGENED) { (CguReuse::No, ComparisonKind::Exact) } else if attr.check_name(ATTR_EXPECTED_CGU_REUSE) { - match &self.field(attr, sym::kind).as_str()[..] { + match &*self.field(attr, sym::kind).as_str() { "no" => (CguReuse::No, ComparisonKind::Exact), "pre-lto" => (CguReuse::PreLto, ComparisonKind::Exact), "post-lto" => (CguReuse::PostLto, ComparisonKind::Exact), diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index abe0ffb0e02..ea156a94ea1 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -303,7 +303,7 @@ impl DirtyCleanVisitor<'tcx> { for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.check_name(LABEL) { let value = expect_associated_value(self.tcx, &item); - return Some(self.resolve_labels(&item, value.as_str().as_ref())); + return Some(self.resolve_labels(&item, &value.as_str())); } } None @@ -314,7 +314,7 @@ impl DirtyCleanVisitor<'tcx> { for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.check_name(EXCEPT) { let value = expect_associated_value(self.tcx, &item); - return self.resolve_labels(&item, value.as_str().as_ref()); + return self.resolve_labels(&item, &value.as_str()); } } // if no `label` or `except` is given, only the node's group are asserted diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index e3c3966c2f5..30d68fd0bfc 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1476,14 +1476,12 @@ impl KeywordIdents { let mut lint = cx.struct_span_lint( KEYWORD_IDENTS, ident.span, - &format!("`{}` is a keyword in the {} edition", - ident.as_str(), - next_edition), + &format!("`{}` is a keyword in the {} edition", ident, next_edition), ); lint.span_suggestion( ident.span, "you can use a raw identifier to stay compatible", - format!("r#{}", ident.as_str()), + format!("r#{}", ident), Applicability::MachineApplicable, ); lint.emit() diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 07c49d91797..483b1a40e44 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -121,7 +121,7 @@ impl<'a> CrateLoader<'a> { // `source` stores paths which are normalized which may be different // from the strings on the command line. let source = &self.cstore.get_crate_data(cnum).source; - if let Some(entry) = self.sess.opts.externs.get(&*name.as_str()) { + if let Some(entry) = self.sess.opts.externs.get(&name.as_str()) { // Only use `--extern crate_name=path` here, not `--extern crate_name`. let found = entry.locations.iter().filter_map(|l| l.as_ref()).any(|l| { let l = fs::canonicalize(l).ok(); diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index a58db6a903b..c9de66a5c87 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/src/librustc_metadata/native_libs.rs @@ -68,7 +68,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> { Some(name) => name, None => continue, // skip like historical compilers }; - lib.kind = match &kind.as_str()[..] { + lib.kind = match &*kind.as_str() { "static" => cstore::NativeStatic, "static-nobundle" => cstore::NativeStaticNobundle, "dylib" => cstore::NativeUnknown, diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs index 36db68a3372..0913d743328 100644 --- a/src/librustc_mir/borrow_check/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/conflict_errors.rs @@ -974,7 +974,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut err = self.cannot_borrow_across_destructor(borrow_span); let what_was_dropped = match self.describe_place(place.as_ref()) { - Some(name) => format!("`{}`", name.as_str()), + Some(name) => format!("`{}`", name), None => String::from("temporary value"), }; diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 519f4f03222..f8aec4a369d 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -95,7 +95,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) -> InterpResult<'tcx, bool> { let substs = instance.substs; - let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; + let intrinsic_name = &*self.tcx.item_name(instance.def_id()).as_str(); match intrinsic_name { "caller_location" => { let caller = self.tcx.sess.source_map().lookup_char_pos(span.lo()); diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index d9b983ab790..7d550716858 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -642,8 +642,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { struct_span_err!( tcx.sess, source_info.span, E0133, "{} is unsafe and requires unsafe function or block", description) - .span_label(source_info.span, &description.as_str()[..]) - .note(&details.as_str()[..]) + .span_label(source_info.span, &*description.as_str()) + .note(&details.as_str()) .emit(); } UnsafetyViolationKind::ExternStatic(lint_hir_id) => { @@ -651,8 +651,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { lint_hir_id, source_info.span, &format!("{} is unsafe and requires unsafe function or block \ - (error E0133)", &description.as_str()[..]), - &details.as_str()[..]); + (error E0133)", description), + &details.as_str()); } UnsafetyViolationKind::BorrowPacked(lint_hir_id) => { if let Some(impl_def_id) = builtin_derive_def_id(tcx, def_id) { @@ -662,8 +662,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: DefId) { lint_hir_id, source_info.span, &format!("{} is unsafe and requires unsafe function or block \ - (error E0133)", &description.as_str()[..]), - &details.as_str()[..]); + (error E0133)", description), + &details.as_str()); } } } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index f488b457334..518f23e23fe 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -537,7 +537,7 @@ impl Qualif for IsNotPromotable { Abi::RustIntrinsic | Abi::PlatformIntrinsic => { assert!(!cx.tcx.is_const_fn(def_id)); - match &cx.tcx.item_name(def_id).as_str()[..] { + match &*cx.tcx.item_name(def_id).as_str() { | "size_of" | "min_align_of" | "needs_drop" @@ -1476,7 +1476,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { Abi::RustIntrinsic | Abi::PlatformIntrinsic => { assert!(!self.tcx.is_const_fn(def_id)); - match &self.tcx.item_name(def_id).as_str()[..] { + match &*self.tcx.item_name(def_id).as_str() { // special intrinsic that can be called diretly without an intrinsic // feature gate needs a language feature gate "transmute" => { diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index c4e44091bc9..da1fba2518a 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -402,7 +402,7 @@ fn check_terminator( /// /// Adding more intrinsics requires sign-off from @rust-lang/lang. fn is_intrinsic_whitelisted(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { - match &tcx.item_name(def_id).as_str()[..] { + match &*tcx.item_name(def_id).as_str() { | "size_of" | "min_align_of" | "needs_drop" diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 02f4345ac10..038de870174 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -1876,7 +1876,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { None } }); - find_best_match_for_name(names, &*ident.as_str(), None) + find_best_match_for_name(names, &ident.as_str(), None) }); self.r.record_partial_res(expr.id, PartialRes::new(Res::Err)); self.r.report_error( diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index b4e07e4a0df..2961d80e776 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -308,7 +308,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) = parent { if let Ok(src) = cm.span_to_snippet(sp) { for field in fields { - if field.ident.as_str() == src.as_str() && field.is_shorthand { + if field.ident.as_str() == src && field.is_shorthand { return true; } } @@ -409,13 +409,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut sugg_sp = sp; if let hir::ExprKind::MethodCall(segment, _sp, args) = &expr.kind { let clone_trait = self.tcx.lang_items().clone_trait().unwrap(); - if let ([arg], Some(true), "clone") = ( + if let ([arg], Some(true), sym::clone) = ( &args[..], self.tables.borrow().type_dependent_def_id(expr.hir_id).map(|did| { let ai = self.tcx.associated_item(did); ai.container == ty::TraitContainer(clone_trait) }), - &segment.ident.as_str()[..], + segment.ident.name, ) { // If this expression had a clone call when suggesting borrowing // we want to suggest removing it because it'd now be unecessary. diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index d90ed2a790b..b7b7861ebef 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -835,11 +835,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp, &message(format!( "restrict type parameter `{}` with", - param.name.ident().as_str(), + param.name.ident(), )), candidates.iter().map(|t| format!( "{}{} {}{}", - param.name.ident().as_str(), + param.name.ident(), if impl_trait { " +" } else { ":" }, self.tcx.def_path_str(t.def_id), if has_bounds.is_some() { " + "} else { "" }, diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 950ae7c1d62..f3f4abf01eb 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -978,7 +978,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); // we don't want to throw `E0027` in case we have thrown `E0026` for them - unmentioned_fields.retain(|&x| x.as_str() != suggested_name.as_str()); + unmentioned_fields.retain(|&x| x.name != suggested_name); } } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 001d98aece2..b6c0b0d09fd 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2404,7 +2404,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( abi: abi::Abi, ) -> ty::PolyFnSig<'tcx> { let unsafety = if abi == abi::Abi::RustIntrinsic { - intrinsic_operation_unsafety(&*tcx.item_name(def_id).as_str()) + intrinsic_operation_unsafety(&tcx.item_name(def_id).as_str()) } else { hir::Unsafety::Unsafe }; diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 11f45c5f6d0..09f4873967e 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -404,7 +404,7 @@ impl<'a> fmt::Display for Html<'a> { if !human_readable.is_empty() { fmt.write_str(human_readable) } else if let Some(v) = value { - write!(fmt, "{}=\"{}\"", Escape(n), Escape(&*v.as_str())) + write!(fmt, "{}=\"{}\"", Escape(n), Escape(&v.as_str())) } else { write!(fmt, "{}", Escape(n)) } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index cc1d1503c43..e7f76155252 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -3704,7 +3704,7 @@ fn qpath_to_string(p: &hir::QPath) -> String { s.push_str("::"); } if seg.ident.name != kw::PathRoot { - s.push_str(&*seg.ident.as_str()); + s.push_str(&seg.ident.as_str()); } } s diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index c4ee84d33f3..29f0b99d8ee 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2964,7 +2964,7 @@ fn render_attribute(attr: &ast::MetaItem) -> Option { if attr.is_word() { Some(path) } else if let Some(v) = attr.value_str() { - Some(format!("{} = {:?}", path, v.as_str())) + Some(format!("{} = {:?}", path, v)) } else if let Some(values) = attr.meta_item_list() { let display: Vec<_> = values.iter().filter_map(|attr| { attr.meta_item().and_then(|mi| render_attribute(mi)) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 8b967048848..8af38507b48 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -90,7 +90,7 @@ impl fmt::Debug for Lifetime { impl fmt::Display for Lifetime { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.ident.name.as_str()) + write!(f, "{}", self.ident.name) } } diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 97b99b9392f..4389dae2770 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -730,7 +730,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], } if let Some(allowed) = allow_features.as_ref() { - if allowed.iter().find(|&f| f == &name.as_str() as &str).is_none() { + if allowed.iter().find(|&f| name.as_str() == *f).is_none() { span_err!(span_handler, mi.span(), E0725, "the feature `{}` is not in the list of allowed features", name); diff --git a/src/libsyntax/parse/literal.rs b/src/libsyntax/parse/literal.rs index 7952e293a53..c42f4aa25cc 100644 --- a/src/libsyntax/parse/literal.rs +++ b/src/libsyntax/parse/literal.rs @@ -134,9 +134,9 @@ impl LitKind { let (kind, symbol, suffix) = match *self { LitKind::Str(symbol, ast::StrStyle::Cooked) => { // Don't re-intern unless the escaped string is different. - let s: &str = &symbol.as_str(); + let s = symbol.as_str(); let escaped = s.escape_default().to_string(); - let symbol = if escaped == *s { symbol } else { Symbol::intern(&escaped) }; + let symbol = if s == escaped { symbol } else { Symbol::intern(&escaped) }; (token::Str, symbol, None) } LitKind::Str(symbol, ast::StrStyle::Raw(n)) => { diff --git a/src/libsyntax/parse/parser/module.rs b/src/libsyntax/parse/parser/module.rs index a0e4d2bbb7a..e80b1a7f607 100644 --- a/src/libsyntax/parse/parser/module.rs +++ b/src/libsyntax/parse/parser/module.rs @@ -229,7 +229,7 @@ impl<'a> Parser<'a> { // `./.rs` and `.//mod.rs`. let relative_prefix_string; let relative_prefix = if let Some(ident) = relative { - relative_prefix_string = format!("{}{}", ident.as_str(), path::MAIN_SEPARATOR); + relative_prefix_string = format!("{}{}", ident, path::MAIN_SEPARATOR); &relative_prefix_string } else { "" diff --git a/src/libsyntax_ext/env.rs b/src/libsyntax_ext/env.rs index 58fe56bd235..6fb48bf8173 100644 --- a/src/libsyntax_ext/env.rs +++ b/src/libsyntax_ext/env.rs @@ -21,7 +21,7 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt<'_>, }; let sp = cx.with_def_site_ctxt(sp); - let e = match env::var(&*var.as_str()) { + let e = match env::var(&var.as_str()) { Err(..) => { let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp)); cx.expr_path(cx.path_all(sp, diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 37310f46f7e..57b948858aa 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -992,7 +992,7 @@ pub fn expand_preparsed_format_args( vec![] }; - let fmt_str = &*fmt_str.as_str(); // for the suggestions below + let fmt_str = &fmt_str.as_str(); // for the suggestions below let mut parser = parse::Parser::new(fmt_str, str_style, skips, append_newline); let mut unverified_pieces = Vec::new(); -- cgit 1.4.1-3-g733a5 From d0db29003975d8c4b3a552ff8c3a68435173cdc7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 22 Oct 2019 11:21:37 +1100 Subject: Remove the `AsRef` impl for `SymbolStr`. Because it's highly magical, which goes against the goal of keeping `SymbolStr` simple. Plus it's only used in a handful of places that only require minor changes. --- src/librustc_codegen_ssa/back/command.rs | 2 +- src/libsyntax/parse/parser/module.rs | 8 ++++---- src/libsyntax_pos/symbol.rs | 10 ---------- 3 files changed, 5 insertions(+), 15 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/librustc_codegen_ssa/back/command.rs b/src/librustc_codegen_ssa/back/command.rs index 2d84d67e3c8..b8501f0e12a 100644 --- a/src/librustc_codegen_ssa/back/command.rs +++ b/src/librustc_codegen_ssa/back/command.rs @@ -53,7 +53,7 @@ impl Command { } pub fn sym_arg(&mut self, arg: Symbol) -> &mut Command { - self.arg(&arg.as_str()); + self.arg(&*arg.as_str()); self } diff --git a/src/libsyntax/parse/parser/module.rs b/src/libsyntax/parse/parser/module.rs index e80b1a7f607..242a17659a0 100644 --- a/src/libsyntax/parse/parser/module.rs +++ b/src/libsyntax/parse/parser/module.rs @@ -210,7 +210,7 @@ impl<'a> Parser<'a> { // `/` to `\`. #[cfg(windows)] let s = s.replace("/", "\\"); - Some(dir_path.join(s)) + Some(dir_path.join(&*s)) } else { None } @@ -314,7 +314,7 @@ impl<'a> Parser<'a> { fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) { if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) { - self.directory.path.to_mut().push(&path.as_str()); + self.directory.path.to_mut().push(&*path.as_str()); self.directory.ownership = DirectoryOwnership::Owned { relative: None }; } else { // We have to push on the current module name in the case of relative @@ -325,10 +325,10 @@ impl<'a> Parser<'a> { // directory path to `/x/y/z`, not `/x/z` with a relative offset of `y`. if let DirectoryOwnership::Owned { relative } = &mut self.directory.ownership { if let Some(ident) = relative.take() { // remove the relative offset - self.directory.path.to_mut().push(ident.as_str()); + self.directory.path.to_mut().push(&*ident.as_str()); } } - self.directory.path.to_mut().push(&id.as_str()); + self.directory.path.to_mut().push(&*id.as_str()); } } } diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 4ff558a22e1..3f7b3e5b3d8 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -1099,16 +1099,6 @@ pub struct SymbolStr { string: &'static str, } -impl std::convert::AsRef for SymbolStr -where - str: std::convert::AsRef -{ - #[inline] - fn as_ref(&self) -> &U { - self.string.as_ref() - } -} - // This impl allows a `SymbolStr` to be directly equated with a `String` or // `&str`. impl> std::cmp::PartialEq for SymbolStr { -- cgit 1.4.1-3-g733a5 From 90f891d8ae9073623769fac18f00c4f1031fcb59 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 3 Nov 2019 14:58:01 +0300 Subject: syntax: Avoid span arithmetics for delimiter tokens --- src/libsyntax/parse/parser.rs | 4 ++-- src/libsyntax/tokenstream.rs | 20 +++++------------- src/libsyntax_expand/mbe.rs | 24 +++++++--------------- src/libsyntax_expand/mbe/macro_rules.rs | 6 +++--- src/test/ui/imports/import-prefix-macro-1.stderr | 2 +- src/test/ui/issues/issue-39848.stderr | 2 +- src/test/ui/parser/issue-62973.stderr | 4 ++-- src/test/ui/parser/issue-63135.stderr | 8 ++++---- .../ui/parser/macro/macro-doc-comments-2.stderr | 2 +- src/test/ui/parser/missing_right_paren.rs | 3 +++ src/test/ui/parser/missing_right_paren.stderr | 17 +++++++++++++++ 11 files changed, 46 insertions(+), 46 deletions(-) create mode 100644 src/test/ui/parser/missing_right_paren.rs create mode 100644 src/test/ui/parser/missing_right_paren.stderr (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6ead1ce811d..bce36d259ac 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -210,12 +210,12 @@ impl TokenCursor { loop { let tree = if !self.frame.open_delim { self.frame.open_delim = true; - TokenTree::open_tt(self.frame.span.open, self.frame.delim) + TokenTree::open_tt(self.frame.span, self.frame.delim) } else if let Some(tree) = self.frame.tree_cursor.next() { tree } else if !self.frame.close_delim { self.frame.close_delim = true; - TokenTree::close_tt(self.frame.span.close, self.frame.delim) + TokenTree::close_tt(self.frame.span, self.frame.delim) } else if let Some(frame) = self.stack.pop() { self.frame = frame; continue diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 0559f224f1f..7e0582797c7 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -15,7 +15,7 @@ use crate::parse::token::{self, DelimToken, Token, TokenKind}; -use syntax_pos::{BytePos, Span, DUMMY_SP}; +use syntax_pos::{Span, DUMMY_SP}; #[cfg(target_arch = "x86_64")] use rustc_data_structures::static_assert_size; use rustc_data_structures::sync::Lrc; @@ -110,23 +110,13 @@ impl TokenTree { } /// Returns the opening delimiter as a token tree. - pub fn open_tt(span: Span, delim: DelimToken) -> TokenTree { - let open_span = if span.is_dummy() { - span - } else { - span.with_hi(span.lo() + BytePos(delim.len() as u32)) - }; - TokenTree::token(token::OpenDelim(delim), open_span) + pub fn open_tt(span: DelimSpan, delim: DelimToken) -> TokenTree { + TokenTree::token(token::OpenDelim(delim), span.open) } /// Returns the closing delimiter as a token tree. - pub fn close_tt(span: Span, delim: DelimToken) -> TokenTree { - let close_span = if span.is_dummy() { - span - } else { - span.with_lo(span.hi() - BytePos(delim.len() as u32)) - }; - TokenTree::token(token::CloseDelim(delim), close_span) + pub fn close_tt(span: DelimSpan, delim: DelimToken) -> TokenTree { + TokenTree::token(token::CloseDelim(delim), span.close) } } diff --git a/src/libsyntax_expand/mbe.rs b/src/libsyntax_expand/mbe.rs index d0f790638ef..06e0cde3ad8 100644 --- a/src/libsyntax_expand/mbe.rs +++ b/src/libsyntax_expand/mbe.rs @@ -13,7 +13,7 @@ use syntax::ast; use syntax::parse::token::{self, Token, TokenKind}; use syntax::tokenstream::{DelimSpan}; -use syntax_pos::{BytePos, Span}; +use syntax_pos::Span; use rustc_data_structures::sync::Lrc; @@ -27,23 +27,13 @@ struct Delimited { impl Delimited { /// Returns a `self::TokenTree` with a `Span` corresponding to the opening delimiter. - fn open_tt(&self, span: Span) -> TokenTree { - let open_span = if span.is_dummy() { - span - } else { - span.with_hi(span.lo() + BytePos(self.delim.len() as u32)) - }; - TokenTree::token(token::OpenDelim(self.delim), open_span) + fn open_tt(&self, span: DelimSpan) -> TokenTree { + TokenTree::token(token::OpenDelim(self.delim), span.open) } /// Returns a `self::TokenTree` with a `Span` corresponding to the closing delimiter. - fn close_tt(&self, span: Span) -> TokenTree { - let close_span = if span.is_dummy() { - span - } else { - span.with_lo(span.hi() - BytePos(self.delim.len() as u32)) - }; - TokenTree::token(token::CloseDelim(self.delim), close_span) + fn close_tt(&self, span: DelimSpan) -> TokenTree { + TokenTree::token(token::CloseDelim(self.delim), span.close) } } @@ -138,10 +128,10 @@ impl TokenTree { } (&TokenTree::Delimited(span, ref delimed), _) => { if index == 0 { - return delimed.open_tt(span.open); + return delimed.open_tt(span); } if index == delimed.tts.len() + 1 { - return delimed.close_tt(span.close); + return delimed.close_tt(span); } delimed.tts[index - 1].clone() } diff --git a/src/libsyntax_expand/mbe/macro_rules.rs b/src/libsyntax_expand/mbe/macro_rules.rs index 9a4130b2d8d..bfdc4c52b5a 100644 --- a/src/libsyntax_expand/mbe/macro_rules.rs +++ b/src/libsyntax_expand/mbe/macro_rules.rs @@ -566,7 +566,7 @@ impl FirstSets { } TokenTree::Delimited(span, ref delimited) => { build_recur(sets, &delimited.tts[..]); - first.replace_with(delimited.open_tt(span.open)); + first.replace_with(delimited.open_tt(span)); } TokenTree::Sequence(sp, ref seq_rep) => { let subfirst = build_recur(sets, &seq_rep.tts[..]); @@ -628,7 +628,7 @@ impl FirstSets { return first; } TokenTree::Delimited(span, ref delimited) => { - first.add_one(delimited.open_tt(span.open)); + first.add_one(delimited.open_tt(span)); return first; } TokenTree::Sequence(sp, ref seq_rep) => { @@ -826,7 +826,7 @@ fn check_matcher_core( } } TokenTree::Delimited(span, ref d) => { - let my_suffix = TokenSet::singleton(d.close_tt(span.close)); + let my_suffix = TokenSet::singleton(d.close_tt(span)); check_matcher_core(sess, features, attrs, first_sets, &d.tts, &my_suffix); // don't track non NT tokens last.replace_with_irrelevant(); diff --git a/src/test/ui/imports/import-prefix-macro-1.stderr b/src/test/ui/imports/import-prefix-macro-1.stderr index 577f1282471..862a31b4465 100644 --- a/src/test/ui/imports/import-prefix-macro-1.stderr +++ b/src/test/ui/imports/import-prefix-macro-1.stderr @@ -2,7 +2,7 @@ error: expected one of `::`, `;`, or `as`, found `{` --> $DIR/import-prefix-macro-1.rs:11:27 | LL | ($p: path) => (use $p {S, Z}); - | ^ expected one of `::`, `;`, or `as` here + | ^^^^^^ expected one of `::`, `;`, or `as` here ... LL | import! { a::b::c } | ------------------- in this macro invocation diff --git a/src/test/ui/issues/issue-39848.stderr b/src/test/ui/issues/issue-39848.stderr index fa87967432d..47aa8e17a30 100644 --- a/src/test/ui/issues/issue-39848.stderr +++ b/src/test/ui/issues/issue-39848.stderr @@ -2,7 +2,7 @@ error: expected `{`, found `foo` --> $DIR/issue-39848.rs:8:19 | LL | if $tgt.has_$field() {} - | -- - help: try placing this code inside a block: `{ ) }` + | -- -- help: try placing this code inside a block: `{ () }` | | | this `if` statement has a condition, but no block ... diff --git a/src/test/ui/parser/issue-62973.stderr b/src/test/ui/parser/issue-62973.stderr index e73776dc7b4..d22d78b72b9 100644 --- a/src/test/ui/parser/issue-62973.stderr +++ b/src/test/ui/parser/issue-62973.stderr @@ -34,13 +34,13 @@ LL | ) | error: expected one of `.`, `?`, `{`, or an operator, found `}` - --> $DIR/issue-62973.rs:8:1 + --> $DIR/issue-62973.rs:8:2 | LL | fn p() { match s { v, E { [) {) } | ----- while parsing this match expression LL | LL | - | ^ expected one of `.`, `?`, `{`, or an operator here + | ^ expected one of `.`, `?`, `{`, or an operator here error: incorrect close delimiter: `)` --> $DIR/issue-62973.rs:6:28 diff --git a/src/test/ui/parser/issue-63135.stderr b/src/test/ui/parser/issue-63135.stderr index a077ad454a9..8e8087978a3 100644 --- a/src/test/ui/parser/issue-63135.stderr +++ b/src/test/ui/parser/issue-63135.stderr @@ -23,16 +23,16 @@ LL | fn i(n{...,f # | `..` must be at the end and cannot have a trailing comma error: expected `[`, found `}` - --> $DIR/issue-63135.rs:3:15 + --> $DIR/issue-63135.rs:3:16 | LL | fn i(n{...,f # - | ^ expected `[` + | ^ expected `[` error: expected one of `:` or `|`, found `)` - --> $DIR/issue-63135.rs:3:15 + --> $DIR/issue-63135.rs:3:16 | LL | fn i(n{...,f # - | ^ expected one of `:` or `|` here + | ^ expected one of `:` or `|` here error: aborting due to 5 previous errors diff --git a/src/test/ui/parser/macro/macro-doc-comments-2.stderr b/src/test/ui/parser/macro/macro-doc-comments-2.stderr index 6abe95192be..023d1a3e039 100644 --- a/src/test/ui/parser/macro/macro-doc-comments-2.stderr +++ b/src/test/ui/parser/macro/macro-doc-comments-2.stderr @@ -5,7 +5,7 @@ LL | macro_rules! inner { | ------------------ when calling this macro ... LL | /// Outer - | ^ no rules expected this token in macro call + | ^^^^^^^^^ no rules expected this token in macro call error: aborting due to previous error diff --git a/src/test/ui/parser/missing_right_paren.rs b/src/test/ui/parser/missing_right_paren.rs new file mode 100644 index 00000000000..4f7c5eea1d1 --- /dev/null +++ b/src/test/ui/parser/missing_right_paren.rs @@ -0,0 +1,3 @@ +// ignore-tidy-trailing-newlines +// error-pattern: aborting due to 2 previous errors +fn main((ؼ \ No newline at end of file diff --git a/src/test/ui/parser/missing_right_paren.stderr b/src/test/ui/parser/missing_right_paren.stderr new file mode 100644 index 00000000000..fc75b031e76 --- /dev/null +++ b/src/test/ui/parser/missing_right_paren.stderr @@ -0,0 +1,17 @@ +error: this file contains an un-closed delimiter + --> $DIR/missing_right_paren.rs:3:11 + | +LL | fn main((ؼ + | -- ^ + | || + | |un-closed delimiter + | un-closed delimiter + +error: expected one of `:` or `|`, found `)` + --> $DIR/missing_right_paren.rs:3:11 + | +LL | fn main((ؼ + | ^ expected one of `:` or `|` here + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From 3bbfc7320ba0f23541f94a84cf5281a210a546cd Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Mon, 4 Nov 2019 16:19:55 -0800 Subject: Detect `::` -> `:` typo when involving turbofish --- src/libsyntax/parse/parser/diagnostics.rs | 3 ++- src/libsyntax/parse/parser/stmt.rs | 1 + .../ui/suggestions/type-ascription-instead-of-path-2.rs | 5 +++++ .../ui/suggestions/type-ascription-instead-of-path-2.stderr | 13 +++++++++++++ 4 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/suggestions/type-ascription-instead-of-path-2.rs create mode 100644 src/test/ui/suggestions/type-ascription-instead-of-path-2.stderr (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser/diagnostics.rs b/src/libsyntax/parse/parser/diagnostics.rs index ab2b4519cb7..ad479e6278b 100644 --- a/src/libsyntax/parse/parser/diagnostics.rs +++ b/src/libsyntax/parse/parser/diagnostics.rs @@ -354,7 +354,7 @@ impl<'a> Parser<'a> { } pub fn maybe_annotate_with_ascription( - &self, + &mut self, err: &mut DiagnosticBuilder<'_>, maybe_expected_semicolon: bool, ) { @@ -395,6 +395,7 @@ impl<'a> Parser<'a> { err.note("for more information, see \ https://github.com/rust-lang/rust/issues/23416"); } + self.last_type_ascription = None; } } diff --git a/src/libsyntax/parse/parser/stmt.rs b/src/libsyntax/parse/parser/stmt.rs index 4f51fefe66f..12c530f3cbb 100644 --- a/src/libsyntax/parse/parser/stmt.rs +++ b/src/libsyntax/parse/parser/stmt.rs @@ -397,6 +397,7 @@ impl<'a> Parser<'a> { } let stmt = match self.parse_full_stmt(false) { Err(mut err) => { + self.maybe_annotate_with_ascription(&mut err, false); err.emit(); self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore); Some(Stmt { diff --git a/src/test/ui/suggestions/type-ascription-instead-of-path-2.rs b/src/test/ui/suggestions/type-ascription-instead-of-path-2.rs new file mode 100644 index 00000000000..220fd1eebda --- /dev/null +++ b/src/test/ui/suggestions/type-ascription-instead-of-path-2.rs @@ -0,0 +1,5 @@ +fn main() -> Result<(), ()> { + vec![Ok(2)].into_iter().collect:,_>>()?; + //~^ ERROR expected `::`, found `(` + Ok(()) +} diff --git a/src/test/ui/suggestions/type-ascription-instead-of-path-2.stderr b/src/test/ui/suggestions/type-ascription-instead-of-path-2.stderr new file mode 100644 index 00000000000..191c4f631c4 --- /dev/null +++ b/src/test/ui/suggestions/type-ascription-instead-of-path-2.stderr @@ -0,0 +1,13 @@ +error: expected `::`, found `(` + --> $DIR/type-ascription-instead-of-path-2.rs:2:55 + | +LL | vec![Ok(2)].into_iter().collect:,_>>()?; + | - ^ expected `::` + | | + | tried to parse a type due to this type ascription + | + = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` + = note: for more information, see https://github.com/rust-lang/rust/issues/23416 + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From a8ccbf5f2fa75007ce0effe58caef4e342859a4f Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Tue, 5 Nov 2019 10:29:54 -0800 Subject: Account for typo in turbofish and suggest `::` --- src/libsyntax/parse/parser/diagnostics.rs | 14 ++++++++++---- .../suggestions/type-ascription-instead-of-path-2.stderr | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser/diagnostics.rs b/src/libsyntax/parse/parser/diagnostics.rs index ad479e6278b..fc2b10f2260 100644 --- a/src/libsyntax/parse/parser/diagnostics.rs +++ b/src/libsyntax/parse/parser/diagnostics.rs @@ -358,7 +358,7 @@ impl<'a> Parser<'a> { err: &mut DiagnosticBuilder<'_>, maybe_expected_semicolon: bool, ) { - if let Some((sp, likely_path)) = self.last_type_ascription { + if let Some((sp, likely_path)) = self.last_type_ascription.take() { let sm = self.sess.source_map(); let next_pos = sm.lookup_char_pos(self.token.span.lo()); let op_pos = sm.lookup_char_pos(sp.hi()); @@ -395,7 +395,6 @@ impl<'a> Parser<'a> { err.note("for more information, see \ https://github.com/rust-lang/rust/issues/23416"); } - self.last_type_ascription = None; } } @@ -1083,8 +1082,15 @@ impl<'a> Parser<'a> { } pub(super) fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool { - self.token.is_ident() && - if let ast::ExprKind::Path(..) = node { true } else { false } && + (self.token == token::Lt && // `foo: true, + _ => false, + } && !self.token.is_reserved_ident() && // v `foo:bar(baz)` self.look_ahead(1, |t| t == &token::OpenDelim(token::Paren)) || self.look_ahead(1, |t| t == &token::Lt) && // `foo:bar,_>>()?; | - ^ expected `::` | | - | tried to parse a type due to this type ascription + | help: maybe write a path separator here: `::` | = note: `#![feature(type_ascription)]` lets you annotate an expression with a type: `: ` = note: for more information, see https://github.com/rust-lang/rust/issues/23416 -- cgit 1.4.1-3-g733a5 From ad550b8ef32e336ad74a87669de041eba9f7d1c6 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Tue, 5 Nov 2019 15:10:24 -0500 Subject: use American spelling for `pluralize!` --- src/librustc/lint/builtin.rs | 4 ++-- src/librustc/middle/resolve_lifetime.rs | 4 ++-- src/librustc/traits/error_reporting.rs | 4 ++-- src/librustc/ty/error.rs | 14 +++++++------- src/librustc_errors/emitter.rs | 4 ++-- src/librustc_errors/lib.rs | 2 +- src/librustc_lint/unused.rs | 4 ++-- src/librustc_mir/hair/pattern/check_match.rs | 2 +- src/librustc_resolve/check_unused.rs | 4 ++-- src/librustc_resolve/resolve_imports.rs | 4 ++-- src/librustc_typeck/astconv.rs | 6 +++--- src/librustc_typeck/check/compare_method.rs | 10 +++++----- src/librustc_typeck/check/expr.rs | 4 ++-- src/librustc_typeck/check/method/suggest.rs | 4 ++-- src/librustc_typeck/check/mod.rs | 4 ++-- src/librustc_typeck/check/pat.rs | 14 +++++++------- src/libsyntax/parse/parser/diagnostics.rs | 6 +++--- src/libsyntax/parse/parser/path.rs | 6 +++--- src/libsyntax/parse/parser/ty.rs | 4 ++-- src/libsyntax_expand/mbe/transcribe.rs | 6 +++--- src/libsyntax_ext/format.rs | 4 ++-- 21 files changed, 57 insertions(+), 57 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 5c871bb6b69..65777fe78db 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -7,7 +7,7 @@ use crate::lint::{LintPass, LateLintPass, LintArray, FutureIncompatibleInfo}; use crate::middle::stability; use crate::session::Session; -use errors::{Applicability, DiagnosticBuilder, pluralise}; +use errors::{Applicability, DiagnosticBuilder, pluralize}; use syntax::ast; use syntax::edition::Edition; use syntax::source_map::Span; @@ -651,7 +651,7 @@ pub(crate) fn add_elided_lifetime_in_path_suggestion( }; db.span_suggestion( replace_span, - &format!("indicate the anonymous lifetime{}", pluralise!(n)), + &format!("indicate the anonymous lifetime{}", pluralize!(n)), suggestion, Applicability::MachineApplicable ); diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index a122d84a5aa..488d6332f7e 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -17,7 +17,7 @@ use crate::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt}; use crate::rustc::lint; use crate::session::Session; use crate::util::nodemap::{DefIdMap, FxHashMap, FxHashSet, HirIdMap, HirIdSet}; -use errors::{Applicability, DiagnosticBuilder, pluralise}; +use errors::{Applicability, DiagnosticBuilder, pluralize}; use rustc_macros::HashStable; use std::borrow::Cow; use std::cell::Cell; @@ -3044,7 +3044,7 @@ pub fn report_missing_lifetime_specifiers( span, E0106, "missing lifetime specifier{}", - pluralise!(count) + pluralize!(count) ) } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 1f7bce1c644..080ca8dfa73 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -33,7 +33,7 @@ use crate::ty::subst::Subst; use crate::ty::SubtypePredicate; use crate::util::nodemap::{FxHashMap, FxHashSet}; -use errors::{Applicability, DiagnosticBuilder, pluralise}; +use errors::{Applicability, DiagnosticBuilder, pluralize}; use std::fmt; use syntax::ast; use syntax::symbol::{sym, kw}; @@ -1553,7 +1553,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => format!("{} {}argument{}", arg_length, if distinct && arg_length > 1 { "distinct " } else { "" }, - pluralise!(arg_length)) + pluralize!(arg_length)) } }; diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 77613b548cf..6af265f4901 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -4,7 +4,7 @@ use std::borrow::Cow; use std::fmt; use rustc_target::spec::abi; use syntax::ast; -use syntax::errors::pluralise; +use syntax::errors::pluralize; use errors::{Applicability, DiagnosticBuilder}; use syntax_pos::Span; @@ -100,17 +100,17 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { write!(f, "expected a tuple with {} element{}, \ found one with {} element{}", values.expected, - pluralise!(values.expected), + pluralize!(values.expected), values.found, - pluralise!(values.found)) + pluralize!(values.found)) } FixedArraySize(values) => { write!(f, "expected an array with a fixed size of {} element{}, \ found one with {} element{}", values.expected, - pluralise!(values.expected), + pluralize!(values.expected), values.found, - pluralise!(values.found)) + pluralize!(values.found)) } ArgCount => { write!(f, "incorrect number of function parameters") @@ -165,7 +165,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { ProjectionBoundsLength(ref values) => { write!(f, "expected {} associated type binding{}, found {}", values.expected, - pluralise!(values.expected), + pluralize!(values.expected), values.found) }, ExistentialMismatch(ref values) => { @@ -196,7 +196,7 @@ impl<'tcx> ty::TyS<'tcx> { let n = tcx.lift(&n).unwrap(); match n.try_eval_usize(tcx, ty::ParamEnv::empty()) { Some(n) => { - format!("array of {} element{}", n, pluralise!(n)).into() + format!("array of {} element{}", n, pluralize!(n)).into() } None => "array".into(), } diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index b153f0f0e82..de00df2765a 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -12,7 +12,7 @@ use Destination::*; use syntax_pos::{SourceFile, Span, MultiSpan}; use crate::{ - Level, CodeSuggestion, Diagnostic, SubDiagnostic, pluralise, + Level, CodeSuggestion, Diagnostic, SubDiagnostic, pluralize, SuggestionStyle, SourceMapper, SourceMapperDyn, DiagnosticId, }; use crate::Level::Error; @@ -1573,7 +1573,7 @@ impl EmitterWriter { } if suggestions.len() > MAX_SUGGESTIONS { let others = suggestions.len() - MAX_SUGGESTIONS; - let msg = format!("and {} other candidate{}", others, pluralise!(others)); + let msg = format!("and {} other candidate{}", others, pluralize!(others)); buffer.puts(row_num, max_line_num_len + 3, &msg, Style::NoStyle); } else if notice_capitalization { let msg = "notice the capitalization difference"; diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 9743cf0d805..67c180a05e9 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -1027,7 +1027,7 @@ impl Level { } #[macro_export] -macro_rules! pluralise { +macro_rules! pluralize { ($x:expr) => { if $x != 1 { "s" } else { "" } }; diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 3f85e6d772e..642b8e3279d 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -10,7 +10,7 @@ use lint::{LintPass, EarlyLintPass, LateLintPass}; use syntax::ast; use syntax::attr; -use syntax::errors::{Applicability, pluralise}; +use syntax::errors::{Applicability, pluralize}; use syntax::feature_gate::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use syntax::print::pprust; use syntax::symbol::{kw, sym}; @@ -144,7 +144,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { return true; } - let plural_suffix = pluralise!(plural_len); + let plural_suffix = pluralize!(plural_len); match ty.kind { ty::Adt(..) if ty.is_box() => { diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 9d370554e86..29423536e65 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -548,7 +548,7 @@ fn joined_uncovered_patterns(witnesses: &[super::Pat<'_>]) -> String { } fn pattern_not_covered_label(witnesses: &[super::Pat<'_>], joined_patterns: &str) -> String { - format!("pattern{} {} not covered", rustc_errors::pluralise!(witnesses.len()), joined_patterns) + format!("pattern{} {} not covered", rustc_errors::pluralize!(witnesses.len()), joined_patterns) } /// Point at the definition of non-covered `enum` variants. diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs index 44b7a9fa047..0624b5eedfb 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/src/librustc_resolve/check_unused.rs @@ -26,7 +26,7 @@ use crate::Resolver; use crate::resolve_imports::ImportDirectiveSubclass; -use errors::pluralise; +use errors::pluralize; use rustc::util::nodemap::NodeMap; use rustc::{lint, ty}; @@ -297,7 +297,7 @@ impl Resolver<'_> { }).collect::>(); span_snippets.sort(); let msg = format!("unused import{}{}", - pluralise!(len), + pluralize!(len), if !span_snippets.is_empty() { format!(": {}", span_snippets.join(", ")) } else { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index c39f0c90f98..c06be18dc2c 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -11,7 +11,7 @@ use crate::{Resolver, ResolutionError, BindingKey, Segment, ModuleKind}; use crate::{names_to_string, module_to_string}; use crate::diagnostics::Suggestion; -use errors::{Applicability, pluralise}; +use errors::{Applicability, pluralize}; use rustc_data_structures::ptr_key::PtrKey; use rustc::ty; @@ -730,7 +730,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { let msg = format!( "unresolved import{} {}", - pluralise!(paths.len()), + pluralize!(paths.len()), paths.join(", "), ); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index b14121da79f..5c661513382 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -23,7 +23,7 @@ use rustc_target::spec::abi; use crate::require_c_abi_if_c_variadic; use smallvec::SmallVec; use syntax::ast; -use syntax::errors::pluralise; +use syntax::errors::pluralize; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::util::lev_distance::find_best_match_for_name; use syntax::symbol::sym; @@ -392,7 +392,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { quantifier, bound, kind, - pluralise!(bound), + pluralize!(bound), )) }; @@ -1360,7 +1360,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { span, E0191, "the value of the associated type{} {} must be specified", - pluralise!(associated_types.len()), + pluralize!(associated_types.len()), names, ); let (suggest, potential_assoc_types_spans) = diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 6818d5f521d..af0943db4cc 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -10,7 +10,7 @@ use rustc::util::common::ErrorReported; use errors::{Applicability, DiagnosticId}; use syntax_pos::Span; -use syntax::errors::pluralise; +use syntax::errors::pluralize; use super::{Inherited, FnCtxt, potentially_plural_count}; @@ -649,9 +649,9 @@ fn compare_number_of_generics<'tcx>( declaration has {} {kind} parameter{}", trait_.ident, impl_count, - pluralise!(impl_count), + pluralize!(impl_count), trait_count, - pluralise!(trait_count), + pluralize!(trait_count), kind = kind, ), DiagnosticId::Error("E0049".into()), @@ -666,7 +666,7 @@ fn compare_number_of_generics<'tcx>( "expected {} {} parameter{}", trait_count, kind, - pluralise!(trait_count), + pluralize!(trait_count), )); } for span in spans { @@ -681,7 +681,7 @@ fn compare_number_of_generics<'tcx>( "found {} {} parameter{}{}", impl_count, kind, - pluralise!(impl_count), + pluralize!(impl_count), suffix.unwrap_or_else(|| String::new()), )); } diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 8668dd99a8c..2428429c4dd 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -17,7 +17,7 @@ use crate::util::common::ErrorReported; use crate::util::nodemap::FxHashMap; use crate::astconv::AstConv as _; -use errors::{Applicability, DiagnosticBuilder, pluralise}; +use errors::{Applicability, DiagnosticBuilder, pluralize}; use syntax_pos::hygiene::DesugaringKind; use syntax::ast; use syntax::symbol::{Symbol, kw, sym}; @@ -1210,7 +1210,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { struct_span_err!(tcx.sess, span, E0063, "missing field{} {}{} in initializer of `{}`", - pluralise!(remaining_fields.len()), + pluralize!(remaining_fields.len()), remaining_fields_names, truncated_fields_error, adt_ty) diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index d90ed2a790b..9e22979b855 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -5,7 +5,7 @@ use crate::check::FnCtxt; use crate::middle::lang_items::FnOnceTraitLangItem; use crate::namespace::Namespace; use crate::util::nodemap::FxHashSet; -use errors::{Applicability, DiagnosticBuilder, pluralise}; +use errors::{Applicability, DiagnosticBuilder, pluralize}; use rustc::hir::{self, ExprKind, Node, QPath}; use rustc::hir::def::{Res, DefKind}; use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId}; @@ -601,7 +601,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "{an}other candidate{s} {were} found in the following trait{s}, perhaps \ add a `use` for {one_of_them}:", an = if candidates.len() == 1 {"an" } else { "" }, - s = pluralise!(candidates.len()), + s = pluralize!(candidates.len()), were = if candidates.len() == 1 { "was" } else { "were" }, one_of_them = if candidates.len() == 1 { "it" diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a2af29aef09..14d21fc217f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -88,7 +88,7 @@ pub mod intrinsic; mod op; use crate::astconv::{AstConv, PathSeg}; -use errors::{Applicability, DiagnosticBuilder, DiagnosticId, pluralise}; +use errors::{Applicability, DiagnosticBuilder, DiagnosticId, pluralize}; use rustc::hir::{self, ExprKind, GenericArg, ItemKind, Node, PatKind, QPath}; use rustc::hir::def::{CtorOf, Res, DefKind}; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; @@ -5167,5 +5167,5 @@ fn fatally_break_rust(sess: &Session) { } fn potentially_plural_count(count: usize, word: &str) -> String { - format!("{} {}{}", count, word, pluralise!(count)) + format!("{} {}{}", count, word, pluralize!(count)) } diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 950ae7c1d62..292e55e6608 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -1,6 +1,6 @@ use crate::check::FnCtxt; use crate::util::nodemap::FxHashMap; -use errors::{Applicability, DiagnosticBuilder, pluralise}; +use errors::{Applicability, DiagnosticBuilder, pluralize}; use rustc::hir::{self, PatKind, Pat, HirId}; use rustc::hir::def::{Res, DefKind, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; @@ -703,8 +703,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: &[ty::FieldDef], expected: Ty<'tcx> ) { - let subpats_ending = pluralise!(subpats.len()); - let fields_ending = pluralise!(fields.len()); + let subpats_ending = pluralize!(subpats.len()); + let fields_ending = pluralize!(fields.len()); let res_span = self.tcx.def_span(res.def_id()); let mut err = struct_span_err!( self.tcx.sess, @@ -1174,10 +1174,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { E0527, "pattern requires {} element{} but array has {}", min_len, - pluralise!(min_len), + pluralize!(min_len), size, ) - .span_label(span, format!("expected {} element{}", size, pluralise!(size))) + .span_label(span, format!("expected {} element{}", size, pluralize!(size))) .emit(); } @@ -1188,14 +1188,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { E0528, "pattern requires at least {} element{} but array has {}", min_len, - pluralise!(min_len), + pluralize!(min_len), size, ).span_label( span, format!( "pattern cannot match array of {} element{}", size, - pluralise!(size), + pluralize!(size), ), ).emit(); } diff --git a/src/libsyntax/parse/parser/diagnostics.rs b/src/libsyntax/parse/parser/diagnostics.rs index fcf3b4c0aa8..376916c371f 100644 --- a/src/libsyntax/parse/parser/diagnostics.rs +++ b/src/libsyntax/parse/parser/diagnostics.rs @@ -12,7 +12,7 @@ use crate::ptr::P; use crate::symbol::{kw, sym}; use crate::ThinVec; use crate::util::parser::AssocOp; -use errors::{Applicability, DiagnosticBuilder, DiagnosticId, pluralise}; +use errors::{Applicability, DiagnosticBuilder, DiagnosticId, pluralize}; use rustc_data_structures::fx::FxHashSet; use syntax_pos::{Span, DUMMY_SP, MultiSpan, SpanSnippetError}; use log::{debug, trace}; @@ -515,11 +515,11 @@ impl<'a> Parser<'a> { self.diagnostic() .struct_span_err( span, - &format!("unmatched angle bracket{}", pluralise!(total_num_of_gt)), + &format!("unmatched angle bracket{}", pluralize!(total_num_of_gt)), ) .span_suggestion( span, - &format!("remove extra angle bracket{}", pluralise!(total_num_of_gt)), + &format!("remove extra angle bracket{}", pluralize!(total_num_of_gt)), String::new(), Applicability::MachineApplicable, ) diff --git a/src/libsyntax/parse/parser/path.rs b/src/libsyntax/parse/parser/path.rs index 38a28224dab..f9944e36e2f 100644 --- a/src/libsyntax/parse/parser/path.rs +++ b/src/libsyntax/parse/parser/path.rs @@ -9,7 +9,7 @@ use crate::symbol::kw; use std::mem; use log::debug; -use errors::{Applicability, pluralise}; +use errors::{Applicability, pluralize}; /// Specifies how to parse a path. #[derive(Copy, Clone, PartialEq)] @@ -368,14 +368,14 @@ impl<'a> Parser<'a> { span, &format!( "unmatched angle bracket{}", - pluralise!(snapshot.unmatched_angle_bracket_count) + pluralize!(snapshot.unmatched_angle_bracket_count) ), ) .span_suggestion( span, &format!( "remove extra angle bracket{}", - pluralise!(snapshot.unmatched_angle_bracket_count) + pluralize!(snapshot.unmatched_angle_bracket_count) ), String::new(), Applicability::MachineApplicable, diff --git a/src/libsyntax/parse/parser/ty.rs b/src/libsyntax/parse/parser/ty.rs index e8f718a2483..b770b90705c 100644 --- a/src/libsyntax/parse/parser/ty.rs +++ b/src/libsyntax/parse/parser/ty.rs @@ -10,7 +10,7 @@ use crate::parse::token::{self, Token}; use crate::source_map::Span; use crate::symbol::{kw}; -use errors::{Applicability, pluralise}; +use errors::{Applicability, pluralize}; /// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT`, /// `IDENT<::AssocTy>`. @@ -412,7 +412,7 @@ impl<'a> Parser<'a> { } err.span_suggestion_hidden( bound_list, - &format!("remove the trait bound{}", pluralise!(negative_bounds_len)), + &format!("remove the trait bound{}", pluralize!(negative_bounds_len)), new_bound_list, Applicability::MachineApplicable, ); diff --git a/src/libsyntax_expand/mbe/transcribe.rs b/src/libsyntax_expand/mbe/transcribe.rs index 94523bbf91b..6f060103ef4 100644 --- a/src/libsyntax_expand/mbe/transcribe.rs +++ b/src/libsyntax_expand/mbe/transcribe.rs @@ -9,7 +9,7 @@ use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; use smallvec::{smallvec, SmallVec}; -use errors::pluralise; +use errors::pluralize; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use syntax_pos::hygiene::{ExpnId, Transparency}; @@ -350,10 +350,10 @@ impl LockstepIterSize { "meta-variable `{}` repeats {} time{}, but `{}` repeats {} time{}", l_id, l_len, - pluralise!(l_len), + pluralize!(l_len), r_id, r_len, - pluralise!(r_len), + pluralize!(r_len), ); LockstepIterSize::Contradiction(msg) } diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 37310f46f7e..bdc8b959191 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -5,7 +5,7 @@ use fmt_macros as parse; use errors::DiagnosticBuilder; use errors::Applicability; -use errors::pluralise; +use errors::pluralize; use syntax::ast; use syntax_expand::base::{self, *}; @@ -300,7 +300,7 @@ impl<'a, 'b> Context<'a, 'b> { &format!( "{} positional argument{} in format string, but {}", count, - pluralise!(count), + pluralize!(count), self.describe_num_args(), ), ); -- cgit 1.4.1-3-g733a5 From 79b35e90f1cbfa21b6a39354cf7d8e8acfa8b0e1 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sat, 3 Aug 2019 17:42:17 +0200 Subject: legacy_directory_ownership -> error --- src/doc/rustc/src/lints/listing/deny-by-default.md | 12 ---------- src/librustc/lint/builtin.rs | 12 ---------- src/librustc_lint/lib.rs | 2 ++ src/librustc_passes/ast_validation.rs | 5 ----- src/libsyntax/parse/mod.rs | 2 +- src/libsyntax/parse/parser/module.rs | 26 +++++----------------- src/libsyntax_expand/expand.rs | 2 +- src/libsyntax_pos/symbol.rs | 1 - 8 files changed, 9 insertions(+), 53 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/doc/rustc/src/lints/listing/deny-by-default.md b/src/doc/rustc/src/lints/listing/deny-by-default.md index 540543f98f3..f175a881fef 100644 --- a/src/doc/rustc/src/lints/listing/deny-by-default.md +++ b/src/doc/rustc/src/lints/listing/deny-by-default.md @@ -45,18 +45,6 @@ error: defaults for type parameters are only allowed in `struct`, `enum`, `type` = note: for more information, see issue #36887 ``` -## legacy-directory-ownership - -The legacy_directory_ownership warning is issued when - -* There is a non-inline module with a `#[path]` attribute (e.g. `#[path = "foo.rs"] mod bar;`), -* The module's file ("foo.rs" in the above example) is not named "mod.rs", and -* The module's file contains a non-inline child module without a `#[path]` attribute. - -The warning can be fixed by renaming the parent module to "mod.rs" and moving -it into its own directory if appropriate. - - ## missing-fragment-specifier The missing_fragment_specifier warning is issued when an unused pattern in a diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 4dd45f27aca..9301dac32cd 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -207,17 +207,6 @@ declare_lint! { }; } -declare_lint! { - pub LEGACY_DIRECTORY_OWNERSHIP, - Deny, - "non-inline, non-`#[path]` modules (e.g., `mod foo;`) were erroneously allowed in some files \ - not named `mod.rs`", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #37872 ", - edition: None, - }; -} - declare_lint! { pub MISSING_FRAGMENT_SPECIFIER, Deny, @@ -549,7 +538,6 @@ declare_lint_pass! { SAFE_EXTERN_STATICS, SAFE_PACKED_BORROWS, PATTERNS_IN_FNS_WITHOUT_BODY, - LEGACY_DIRECTORY_OWNERSHIP, MISSING_FRAGMENT_SPECIFIER, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, LATE_BOUND_LIFETIME_ARGUMENTS, diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 4636a3d65b7..1dcd61896c3 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -336,6 +336,8 @@ fn register_builtins(store: &mut lint::LintStore, no_interleave_lints: bool) { "converted into hard error, see https://github.com/rust-lang/rust/issues/46205"); store.register_removed("legacy_constructor_visibility", "converted into hard error, see https://github.com/rust-lang/rust/issues/39207"); + store.register_removed("legacy_disrectory_ownership", + "converted into hard error, see https://github.com/rust-lang/rust/issues/37872"); } fn register_internals(store: &mut lint::LintStore) { diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index e625334040e..e046f6c2a07 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -654,11 +654,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { ItemKind::Mod(_) => { // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). attr::first_attr_value_str_by_name(&item.attrs, sym::path); - if attr::contains_name(&item.attrs, sym::warn_directory_ownership) { - let lint = lint::builtin::LEGACY_DIRECTORY_OWNERSHIP; - let msg = "cannot declare a new module at this location"; - self.lint_buffer.buffer_lint(lint, item.id, item.span, msg); - } } ItemKind::Union(ref vdata, _) => { if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata { diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 6d8ecdf805b..59f4a4d22d6 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -51,7 +51,7 @@ pub enum DirectoryOwnership { relative: Option, }, UnownedViaBlock, - UnownedViaMod(bool /* legacy warnings? */), + UnownedViaMod, } // A bunch of utility functions of the form `parse__from_` diff --git a/src/libsyntax/parse/parser/module.rs b/src/libsyntax/parse/parser/module.rs index 242a17659a0..958cdae9492 100644 --- a/src/libsyntax/parse/parser/module.rs +++ b/src/libsyntax/parse/parser/module.rs @@ -21,7 +21,6 @@ pub(super) struct ModulePath { pub(super) struct ModulePathSuccess { pub path: PathBuf, pub directory_ownership: DirectoryOwnership, - warn: bool, } impl<'a> Parser<'a> { @@ -55,17 +54,10 @@ impl<'a> Parser<'a> { if self.eat(&token::Semi) { if in_cfg && self.recurse_into_file_modules { // This mod is in an external file. Let's go get it! - let ModulePathSuccess { path, directory_ownership, warn } = + let ModulePathSuccess { path, directory_ownership } = self.submod_path(id, &outer_attrs, id_span)?; - let (module, mut attrs) = + let (module, attrs) = self.eval_src_mod(path, directory_ownership, id.to_string(), id_span)?; - // Record that we fetched the mod from an external file. - if warn { - let attr = attr::mk_attr_outer( - attr::mk_word_item(Ident::with_dummy_span(sym::warn_directory_ownership))); - attr::mark_known(&attr); - attrs.push(attr); - } Ok((id, ItemKind::Mod(module), Some(attrs))) } else { let placeholder = ast::Mod { @@ -136,17 +128,16 @@ impl<'a> Parser<'a> { // `#[path]` included and contains a `mod foo;` declaration. // If you encounter this, it's your own darn fault :P Some(_) => DirectoryOwnership::Owned { relative: None }, - _ => DirectoryOwnership::UnownedViaMod(true), + _ => DirectoryOwnership::UnownedViaMod, }, path, - warn: false, }); } let relative = match self.directory.ownership { DirectoryOwnership::Owned { relative } => relative, DirectoryOwnership::UnownedViaBlock | - DirectoryOwnership::UnownedViaMod(_) => None, + DirectoryOwnership::UnownedViaMod => None, }; let paths = Parser::default_submod_path( id, relative, &self.directory.path, self.sess.source_map()); @@ -167,12 +158,7 @@ impl<'a> Parser<'a> { } Err(err) } - DirectoryOwnership::UnownedViaMod(warn) => { - if warn { - if let Ok(result) = paths.result { - return Ok(ModulePathSuccess { warn: true, ..result }); - } - } + DirectoryOwnership::UnownedViaMod => { let mut err = self.diagnostic().struct_span_err(id_sp, "cannot declare a new module at this location"); if !id_sp.is_dummy() { @@ -250,14 +236,12 @@ impl<'a> Parser<'a> { directory_ownership: DirectoryOwnership::Owned { relative: Some(id), }, - warn: false, }), (false, true) => Ok(ModulePathSuccess { path: secondary_path, directory_ownership: DirectoryOwnership::Owned { relative: None, }, - warn: false, }), (false, false) => Err(Error::FileNotFoundForModule { mod_name: mod_name.clone(), diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs index da70fdbb0f3..8c82e59e528 100644 --- a/src/libsyntax_expand/expand.rs +++ b/src/libsyntax_expand/expand.rs @@ -1300,7 +1300,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { Some(_) => DirectoryOwnership::Owned { relative: Some(item.ident), }, - None => DirectoryOwnership::UnownedViaMod(false), + None => DirectoryOwnership::UnownedViaMod, }; path.pop(); module.directory = path; diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 3f7b3e5b3d8..d834a59b486 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -734,7 +734,6 @@ symbols! { visible_private_types, volatile, warn, - warn_directory_ownership, wasm_import_module, wasm_target_feature, while_let, -- cgit 1.4.1-3-g733a5 From fe95cd2f4b3a722e023dc7bba8ff65136be441ca Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Wed, 30 Oct 2019 16:38:16 +0100 Subject: revamp pre-expansion gating infra --- src/libsyntax/feature_gate/check.rs | 10 ++--- src/libsyntax/parse/parser.rs | 2 +- src/libsyntax/parse/parser/expr.rs | 19 +++++----- src/libsyntax/parse/parser/generics.rs | 5 ++- src/libsyntax/parse/parser/item.rs | 8 ++-- src/libsyntax/parse/parser/pat.rs | 16 +++----- src/libsyntax/parse/parser/path.rs | 4 +- src/libsyntax/sess.rs | 69 ++++++++++++++++++---------------- 8 files changed, 65 insertions(+), 68 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index d9cc5f6c169..ea9946a8b7a 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -862,18 +862,17 @@ pub fn check_crate(krate: &ast::Crate, maybe_stage_features(&parse_sess.span_diagnostic, krate, unstable); let mut visitor = PostExpansionVisitor { parse_sess, features }; + let spans = parse_sess.gated_spans.spans.borrow(); macro_rules! gate_all { - ($gate:ident, $msg:literal) => { gate_all!($gate, $gate, $msg); }; - ($spans:ident, $gate:ident, $msg:literal) => { - for span in &*parse_sess.gated_spans.$spans.borrow() { + ($gate:ident, $msg:literal) => { + for span in spans.get(&sym::$gate).unwrap_or(&vec![]) { gate_feature!(&visitor, $gate, *span, $msg); } } } - gate_all!(let_chains, "`let` expressions in this position are experimental"); gate_all!(async_closure, "async closures are unstable"); - gate_all!(yields, generators, "yield syntax is experimental"); + 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"); @@ -901,7 +900,6 @@ pub fn check_crate(krate: &ast::Crate, gate_all!(try_blocks, "`try` blocks are unstable"); gate_all!(label_break_value, "labels on blocks are unstable"); gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead"); - // To avoid noise about type ascription in common syntax errors, // only emit if it is the *only* error. (Also check it last.) if parse_sess.span_diagnostic.err_count() == 0 { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 7652c730e51..efd716e7c4a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1121,7 +1121,7 @@ impl<'a> Parser<'a> { self.expected_tokens.push(TokenType::Keyword(kw::Crate)); if self.is_crate_vis() { self.bump(); // `crate` - self.sess.gated_spans.crate_visibility_modifier.borrow_mut().push(self.prev_span); + self.sess.gated_spans.gate(sym::crate_visibility_modifier, self.prev_span); return Ok(respan(self.prev_span, VisibilityKind::Crate(CrateSugar::JustCrate))); } diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 97b1092452a..79be67528b9 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -16,10 +16,10 @@ use crate::parse::token::{self, Token, TokenKind}; use crate::print::pprust; use crate::ptr::P; use crate::source_map::{self, Span}; -use crate::symbol::{kw, sym}; use crate::util::parser::{AssocOp, Fixity, prec_let_scrutinee_needs_par}; use errors::Applicability; +use syntax_pos::symbol::{kw, sym}; use syntax_pos::Symbol; use std::mem; use rustc_data_structures::thin_vec::ThinVec; @@ -252,7 +252,7 @@ impl<'a> Parser<'a> { self.last_type_ascription = Some((self.prev_span, maybe_path)); lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Type)?; - self.sess.gated_spans.type_ascription.borrow_mut().push(lhs.span); + self.sess.gated_spans.gate(sym::type_ascription, lhs.span); continue } else if op == AssocOp::DotDot || op == AssocOp::DotDotEq { // If we didn’t have to handle `x..`/`x..=`, it would be pretty easy to @@ -455,7 +455,7 @@ impl<'a> Parser<'a> { let e = self.parse_prefix_expr(None); let (span, e) = self.interpolated_or_expr_span(e)?; let span = lo.to(span); - self.sess.gated_spans.box_syntax.borrow_mut().push(span); + self.sess.gated_spans.gate(sym::box_syntax, span); (span, ExprKind::Box(e)) } token::Ident(..) if self.token.is_ident_named(sym::not) => { @@ -1045,7 +1045,7 @@ impl<'a> Parser<'a> { } let span = lo.to(hi); - self.sess.gated_spans.yields.borrow_mut().push(span); + self.sess.gated_spans.gate(sym::generators, span); } else if self.eat_keyword(kw::Let) { return self.parse_let_expr(attrs); } else if is_span_rust_2018 && self.eat_keyword(kw::Await) { @@ -1264,7 +1264,7 @@ impl<'a> Parser<'a> { outer_attrs: ThinVec, ) -> PResult<'a, P> { if let Some(label) = opt_label { - self.sess.gated_spans.label_break_value.borrow_mut().push(label.ident.span); + self.sess.gated_spans.gate(sym::label_break_value, label.ident.span); } self.expect(&token::OpenDelim(token::Brace))?; @@ -1293,7 +1293,7 @@ impl<'a> Parser<'a> { }; if asyncness.is_async() { // Feature-gate `async ||` closures. - self.sess.gated_spans.async_closure.borrow_mut().push(self.prev_span); + self.sess.gated_spans.gate(sym::async_closure, self.prev_span); } let capture_clause = self.parse_capture_clause(); @@ -1415,8 +1415,7 @@ impl<'a> Parser<'a> { if let ExprKind::Let(..) = cond.kind { // Remove the last feature gating of a `let` expression since it's stable. - let last = self.sess.gated_spans.let_chains.borrow_mut().pop(); - debug_assert_eq!(cond.span, last.unwrap()); + self.sess.gated_spans.ungate_last(sym::let_chains, cond.span); } Ok(cond) @@ -1433,7 +1432,7 @@ impl<'a> Parser<'a> { |this| this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into()) )?; let span = lo.to(expr.span); - self.sess.gated_spans.let_chains.borrow_mut().push(span); + self.sess.gated_spans.gate(sym::let_chains, span); Ok(self.mk_expr(span, ExprKind::Let(pat, expr), attrs)) } @@ -1654,7 +1653,7 @@ impl<'a> Parser<'a> { Err(error) } else { let span = span_lo.to(body.span); - self.sess.gated_spans.try_blocks.borrow_mut().push(span); + self.sess.gated_spans.gate(sym::try_blocks, span); Ok(self.mk_expr(span, ExprKind::TryBlock(body), attrs)) } } diff --git a/src/libsyntax/parse/parser/generics.rs b/src/libsyntax/parse/parser/generics.rs index 51caae69c86..3c094750b4d 100644 --- a/src/libsyntax/parse/parser/generics.rs +++ b/src/libsyntax/parse/parser/generics.rs @@ -3,7 +3,8 @@ use super::{Parser, PResult}; use crate::ast::{self, WhereClause, GenericParam, GenericParamKind, GenericBounds, Attribute}; use crate::parse::token; use crate::source_map::DUMMY_SP; -use crate::symbol::kw; + +use syntax_pos::symbol::{kw, sym}; impl<'a> Parser<'a> { /// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. @@ -62,7 +63,7 @@ impl<'a> Parser<'a> { self.expect(&token::Colon)?; let ty = self.parse_ty()?; - self.sess.gated_spans.const_generics.borrow_mut().push(lo.to(self.prev_span)); + self.sess.gated_spans.gate(sym::const_generics, lo.to(self.prev_span)); Ok(GenericParam { ident, diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 5b60e7e6dba..51e96b55c72 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -147,9 +147,7 @@ impl<'a> Parser<'a> { let unsafety = self.parse_unsafety(); if self.check_keyword(kw::Extern) { - self.sess.gated_spans.const_extern_fn.borrow_mut().push( - lo.to(self.token.span) - ); + self.sess.gated_spans.gate(sym::const_extern_fn, lo.to(self.token.span)); } let abi = self.parse_extern_abi()?; self.bump(); // `fn` @@ -830,7 +828,7 @@ impl<'a> Parser<'a> { .emit(); } - self.sess.gated_spans.trait_alias.borrow_mut().push(whole_span); + self.sess.gated_spans.gate(sym::trait_alias, whole_span); Ok((ident, ItemKind::TraitAlias(tps, bounds), None)) } else { @@ -1712,7 +1710,7 @@ impl<'a> Parser<'a> { let span = lo.to(self.prev_span); if !def.legacy { - self.sess.gated_spans.decl_macro.borrow_mut().push(span); + self.sess.gated_spans.gate(sym::decl_macro, span); } Ok(Some(self.mk_item(span, ident, ItemKind::MacroDef(def), vis.clone(), attrs.to_vec()))) diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index 969d5dd8374..cc8738edff7 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -8,9 +8,8 @@ use crate::mut_visit::{noop_visit_pat, noop_visit_mac, MutVisitor}; use crate::parse::token::{self}; use crate::print::pprust; use crate::source_map::{respan, Span, Spanned}; -use crate::symbol::kw; use crate::ThinVec; - +use syntax_pos::symbol::{kw, sym}; use errors::{Applicability, DiagnosticBuilder}; type Expected = Option<&'static str>; @@ -52,11 +51,8 @@ impl<'a> Parser<'a> { // and no other gated or-pattern has been parsed thus far, // then we should really gate the leading `|`. // This complicated procedure is done purely for diagnostics UX. - if gated_leading_vert { - let mut or_pattern_spans = self.sess.gated_spans.or_patterns.borrow_mut(); - if or_pattern_spans.is_empty() { - or_pattern_spans.push(leading_vert_span); - } + if gated_leading_vert && self.sess.gated_spans.is_ungated(sym::or_patterns) { + self.sess.gated_spans.gate(sym::or_patterns, leading_vert_span); } Ok(pat) @@ -117,7 +113,7 @@ impl<'a> Parser<'a> { // Feature gate the or-pattern if instructed: if gate_or == GateOr::Yes { - self.sess.gated_spans.or_patterns.borrow_mut().push(or_pattern_span); + self.sess.gated_spans.gate(sym::or_patterns, or_pattern_span); } Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats))) @@ -325,7 +321,7 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(kw::Box) { // Parse `box pat` let pat = self.parse_pat_with_range_pat(false, None)?; - self.sess.gated_spans.box_patterns.borrow_mut().push(lo.to(self.prev_span)); + self.sess.gated_spans.gate(sym::box_patterns, lo.to(self.prev_span)); PatKind::Box(pat) } else if self.can_be_ident_pat() { // Parse `ident @ pat` @@ -612,7 +608,7 @@ impl<'a> Parser<'a> { } fn excluded_range_end(&self, span: Span) -> RangeEnd { - self.sess.gated_spans.exclusive_range_pattern.borrow_mut().push(span); + self.sess.gated_spans.gate(sym::exclusive_range_pattern, span); RangeEnd::Excluded } diff --git a/src/libsyntax/parse/parser/path.rs b/src/libsyntax/parse/parser/path.rs index f9944e36e2f..4438d61d9ee 100644 --- a/src/libsyntax/parse/parser/path.rs +++ b/src/libsyntax/parse/parser/path.rs @@ -5,7 +5,7 @@ use crate::ast::{self, QSelf, Path, PathSegment, Ident, ParenthesizedArgs, Angle use crate::ast::{AnonConst, GenericArg, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode}; use crate::parse::token::{self, Token}; use crate::source_map::{Span, BytePos}; -use crate::symbol::kw; +use syntax_pos::symbol::{kw, sym}; use std::mem; use log::debug; @@ -426,7 +426,7 @@ impl<'a> Parser<'a> { // Gate associated type bounds, e.g., `Iterator`. if let AssocTyConstraintKind::Bound { .. } = kind { - self.sess.gated_spans.associated_type_bounds.borrow_mut().push(span); + self.sess.gated_spans.gate(sym::associated_type_bounds, span); } constraints.push(AssocTyConstraint { diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs index 30f8c56a056..f677d544bc3 100644 --- a/src/libsyntax/sess.rs +++ b/src/libsyntax/sess.rs @@ -20,38 +20,43 @@ use std::str; /// used and should be feature gated accordingly in `check_crate`. #[derive(Default)] crate struct GatedSpans { - /// Spans collected for gating `let_chains`, e.g. `if a && let b = c {}`. - crate let_chains: Lock>, - /// Spans collected for gating `async_closure`, e.g. `async || ..`. - crate async_closure: Lock>, - /// Spans collected for gating `yield e?` expressions (`generators` gate). - crate yields: Lock>, - /// Spans collected for gating `or_patterns`, e.g. `Some(Foo | Bar)`. - crate or_patterns: Lock>, - /// Spans collected for gating `const_extern_fn`, e.g. `const extern fn foo`. - crate const_extern_fn: Lock>, - /// Spans collected for gating `trait_alias`, e.g. `trait Foo = Ord + Eq;`. - pub trait_alias: Lock>, - /// Spans collected for gating `associated_type_bounds`, e.g. `Iterator`. - pub associated_type_bounds: Lock>, - /// Spans collected for gating `crate_visibility_modifier`, e.g. `crate fn`. - pub crate_visibility_modifier: Lock>, - /// Spans collected for gating `const_generics`, e.g. `const N: usize`. - pub const_generics: Lock>, - /// Spans collected for gating `decl_macro`, e.g. `macro m() {}`. - pub decl_macro: Lock>, - /// Spans collected for gating `box_patterns`, e.g. `box 0`. - pub box_patterns: Lock>, - /// Spans collected for gating `exclusive_range_pattern`, e.g. `0..2`. - pub exclusive_range_pattern: Lock>, - /// Spans collected for gating `try_blocks`, e.g. `try { a? + b? }`. - pub try_blocks: Lock>, - /// Spans collected for gating `label_break_value`, e.g. `'label: { ... }`. - pub label_break_value: Lock>, - /// Spans collected for gating `box_syntax`, e.g. `box $expr`. - pub box_syntax: Lock>, - /// Spans collected for gating `type_ascription`, e.g. `42: usize`. - pub type_ascription: Lock>, + crate spans: Lock>>, +} + +impl GatedSpans { + /// Feature gate the given `span` under the given `feature` + /// which is same `Symbol` used in `active.rs`. + pub fn gate(&self, feature: Symbol, span: Span) { + self.spans + .borrow_mut() + .entry(feature) + .or_default() + .push(span); + } + + /// Ungate the last span under the given `feature`. + /// Panics if the given `span` wasn't the last one. + /// + /// Using this is discouraged unless you have a really good reason to. + pub fn ungate_last(&self, feature: Symbol, span: Span) { + let removed_span = self.spans + .borrow_mut() + .entry(feature) + .or_default() + .pop() + .unwrap(); + debug_assert_eq!(span, removed_span); + } + + /// Is the provided `feature` gate ungated currently? + /// + /// Using this is discouraged unless you have a really good reason to. + pub fn is_ungated(&self, feature: Symbol) -> bool { + self.spans + .borrow() + .get(&feature) + .map_or(true, |spans| spans.is_empty()) + } } /// Info about a parsing session. -- cgit 1.4.1-3-g733a5 From 69bc4aba785e071740d2d46f109623b9951aae5d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 24 Oct 2019 06:40:35 +1100 Subject: Remove unnecessary `Deref` impl for `Attribute`. This kind of thing just makes the code harder to read. --- src/librustc/hir/lowering.rs | 4 ++-- src/librustc_lint/builtin.rs | 2 +- src/librustc_metadata/link_args.rs | 2 +- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_resolve/macros.rs | 5 ++++- src/librustc_save_analysis/lib.rs | 2 +- src/librustc_typeck/collect.rs | 4 ++-- src/libsyntax/ast.rs | 6 ------ src/libsyntax/attr/builtin.rs | 8 ++++---- src/libsyntax/attr/mod.rs | 10 +++++----- src/libsyntax/config.rs | 4 ++-- src/libsyntax/feature_gate/check.rs | 2 +- src/libsyntax/parse/mod.rs | 8 ++++---- src/libsyntax/visit.rs | 2 +- src/libsyntax_expand/expand.rs | 8 ++++---- src/libsyntax_expand/proc_macro.rs | 4 ++-- src/libsyntax_ext/proc_macro_harness.rs | 12 ++++++------ 17 files changed, 41 insertions(+), 44 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index c8bb35202f5..067fefd3210 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -999,8 +999,8 @@ impl<'a> LoweringContext<'a> { // the `HirId`s. We don't actually need HIR version of attributes anyway. Attribute { item: AttrItem { - path: attr.path.clone(), - tokens: self.lower_token_stream(attr.tokens.clone()), + path: attr.item.path.clone(), + tokens: self.lower_token_stream(attr.item.tokens.clone()), }, id: attr.id, style: attr.style, diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 30d68fd0bfc..5bc8a0e16a2 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -706,7 +706,7 @@ impl EarlyLintPass for DeprecatedAttr { } } if attr.check_name(sym::no_start) || attr.check_name(sym::crate_id) { - let path_str = pprust::path_to_string(&attr.path); + let path_str = pprust::path_to_string(&attr.item.path); let msg = format!("use of deprecated attribute `{}`: no longer used.", path_str); lint_deprecated_attr(cx, attr, &msg, None); } diff --git a/src/librustc_metadata/link_args.rs b/src/librustc_metadata/link_args.rs index 4291f3a4ae3..1b10cff5689 100644 --- a/src/librustc_metadata/link_args.rs +++ b/src/librustc_metadata/link_args.rs @@ -11,7 +11,7 @@ crate fn collect(tcx: TyCtxt<'_>) -> Vec { tcx.hir().krate().visit_all_item_likes(&mut collector); for attr in tcx.hir().krate().attrs.iter() { - if attr.path == sym::link_args { + if attr.item.path == sym::link_args { if let Some(linkarg) = attr.value_str() { collector.add_link_args(&linkarg.as_str()); } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 648c5104b1a..4849ec25560 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -1230,7 +1230,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { fn visit_attribute(&mut self, attr: &'b ast::Attribute) { if !attr.is_sugared_doc && is_builtin_attr(attr) { - self.r.builtin_attrs.push((attr.path.segments[0].ident, self.parent_scope)); + self.r.builtin_attrs.push((attr.item.path.segments[0].ident, self.parent_scope)); } visit::walk_attribute(self, attr); } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 0fbd6b0e5d3..f4338d24629 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -179,7 +179,10 @@ impl<'a> base::Resolver for Resolver<'a> { let (path, kind, derives, after_derive) = match invoc.kind { InvocationKind::Attr { ref attr, ref derives, after_derive, .. } => - (&attr.path, MacroKind::Attr, self.arenas.alloc_ast_paths(derives), after_derive), + (&attr.item.path, + MacroKind::Attr, + self.arenas.alloc_ast_paths(derives), + after_derive), InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang, &[][..], false), InvocationKind::Derive { ref path, .. } => diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 1cfb84bb511..7592df57fc6 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -1195,7 +1195,7 @@ fn null_id() -> rls_data::Id { fn lower_attributes(attrs: Vec, scx: &SaveContext<'_, '_>) -> Vec { attrs.into_iter() // Only retain real attributes. Doc comments are lowered separately. - .filter(|attr| attr.path != sym::doc) + .filter(|attr| attr.item.path != sym::doc) .map(|mut attr| { // Remove the surrounding '#[..]' or '#![..]' of the pretty printed // attribute. First normalize all inner attribute (#![..]) to outer diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index ffe034759a8..09e372ac830 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2706,7 +2706,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| { - if attr.path != sym::inline { + if attr.item.path != sym::inline { return ia; } match attr.meta().map(|i| i.kind) { @@ -2746,7 +2746,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { }); codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| { - if attr.path != sym::optimize { + if attr.item.path != sym::optimize { return ia; } let err = |sp, s| span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 8af38507b48..df1fb5d97d7 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2202,12 +2202,6 @@ pub struct Attribute { pub span: Span, } -// Compatibility impl to avoid churn, consider removing. -impl std::ops::Deref for Attribute { - type Target = AttrItem; - fn deref(&self) -> &Self::Target { &self.item } -} - /// `TraitRef`s appear in impls. /// /// Resolution maps each `TraitRef`'s `ref_id` to its defining trait; that's all diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index 84c86c9651f..e77d9ef326a 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -228,7 +228,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, sym::stable, sym::rustc_promotable, sym::rustc_allow_const_fn_ptr, - ].iter().any(|&s| attr.path == s) { + ].iter().any(|&s| attr.item.path == s) { continue // not a stability level } @@ -236,10 +236,10 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, let meta = attr.meta(); - if attr.path == sym::rustc_promotable { + if attr.item.path == sym::rustc_promotable { promotable = true; } - if attr.path == sym::rustc_allow_const_fn_ptr { + if attr.item.path == sym::rustc_allow_const_fn_ptr { allow_const_fn_ptr = true; } // attributes with data @@ -778,7 +778,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec { let mut acc = Vec::new(); let diagnostic = &sess.span_diagnostic; - if attr.path == sym::repr { + if attr.item.path == sym::repr { if let Some(items) = attr.meta_item_list() { mark_used(attr); for item in items { diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 3e240a855e2..0c46c501be9 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -150,7 +150,7 @@ impl Attribute { /// /// To check the attribute name without marking it used, use the `path` field directly. pub fn check_name(&self, name: Symbol) -> bool { - let matches = self.path == name; + let matches = self.item.path == name; if matches { mark_used(self); } @@ -159,8 +159,8 @@ impl Attribute { /// For a single-segment attribute, returns its name; otherwise, returns `None`. pub fn ident(&self) -> Option { - if self.path.segments.len() == 1 { - Some(self.path.segments[0].ident) + if self.item.path.segments.len() == 1 { + Some(self.item.path.segments[0].ident) } else { None } @@ -181,7 +181,7 @@ impl Attribute { } pub fn is_word(&self) -> bool { - self.tokens.is_empty() + self.item.tokens.is_empty() } pub fn is_meta_item_list(&self) -> bool { @@ -282,7 +282,7 @@ impl Attribute { pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> { Ok(MetaItem { - path: self.path.clone(), + path: self.item.path.clone(), kind: parse::parse_in_attr(sess, self, |p| p.parse_meta_item_kind())?, span: self.span, }) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 6003fd1d286..682c8f71dc8 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -93,10 +93,10 @@ impl<'a> StripUnconfigured<'a> { /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec { - if attr.path != sym::cfg_attr { + if attr.item.path != sym::cfg_attr { return vec![attr]; } - if attr.tokens.is_empty() { + if attr.item.tokens.is_empty() { self.sess.span_diagnostic .struct_span_err( attr.span, diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index d9cc5f6c169..c19ed774507 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -329,7 +329,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. Some((name, _, template, _)) if name != sym::rustc_dummy => check_builtin_attribute(self.parse_sess, attr, name, template), - _ => if let Some(TokenTree::Token(token)) = attr.tokens.trees().next() { + _ => if let Some(TokenTree::Token(token)) = attr.item.tokens.trees().next() { if token == token::Eq { // All key-value attributes are restricted to meta-item syntax. attr.parse_meta(self.parse_sess).map_err(|mut err| err.emit()).ok(); diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 6d8ecdf805b..6cfa0dfad82 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -287,7 +287,7 @@ pub fn parse_in_attr<'a, T>( ) -> PResult<'a, T> { let mut parser = Parser::new( sess, - attr.tokens.clone(), + attr.item.tokens.clone(), None, false, false, @@ -403,8 +403,8 @@ fn prepend_attrs( let mut brackets = tokenstream::TokenStreamBuilder::new(); // For simple paths, push the identifier directly - if attr.path.segments.len() == 1 && attr.path.segments[0].args.is_none() { - let ident = attr.path.segments[0].ident; + if attr.item.path.segments.len() == 1 && attr.item.path.segments[0].args.is_none() { + let ident = attr.item.path.segments[0].ident; let token = token::Ident(ident.name, ident.as_str().starts_with("r#")); brackets.push(tokenstream::TokenTree::token(token, ident.span)); @@ -415,7 +415,7 @@ fn prepend_attrs( brackets.push(stream); } - brackets.push(attr.tokens.clone()); + brackets.push(attr.item.tokens.clone()); // The span we list here for `#` and for `[ ... ]` are both wrong in // that it encompasses more than each token, but it hopefully is "good diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index a36783e2b64..64393a295de 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -846,7 +846,7 @@ pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) { } pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) { - visitor.visit_tts(attr.tokens.clone()); + visitor.visit_tts(attr.item.tokens.clone()); } pub fn walk_tt<'a, V: Visitor<'a>>(visitor: &mut V, tt: TokenTree) { diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs index da70fdbb0f3..392563587ba 100644 --- a/src/libsyntax_expand/expand.rs +++ b/src/libsyntax_expand/expand.rs @@ -419,7 +419,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } let mut item = self.fully_configure(item); - item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive)); + item.visit_attrs(|attrs| attrs.retain(|a| a.item.path != sym::derive)); let mut helper_attrs = Vec::new(); let mut has_copy = false; for ext in exts { @@ -974,7 +974,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { -> Option { let attr = attrs.iter() .position(|a| { - if a.path == sym::derive { + if a.item.path == sym::derive { *after_derive = true; } !attr::is_known(a) && !is_builtin_attr(a) @@ -982,7 +982,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { .map(|i| attrs.remove(i)); if let Some(attr) = &attr { if !self.cx.ecfg.custom_inner_attributes() && - attr.style == ast::AttrStyle::Inner && attr.path != sym::test { + attr.style == ast::AttrStyle::Inner && attr.item.path != sym::test { emit_feature_err(&self.cx.parse_sess, sym::custom_inner_attributes, attr.span, GateIssue::Language, "non-builtin inner attributes are unstable"); @@ -1032,7 +1032,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { feature_gate::check_attribute(attr, self.cx.parse_sess, features); // macros are expanded before any lint passes so this warning has to be hardcoded - if attr.path == sym::derive { + if attr.item.path == sym::derive { self.cx.struct_span_warn(attr.span, "`#[derive]` does nothing on macro invocations") .note("this may become a hard error in a future release") .emit(); diff --git a/src/libsyntax_expand/proc_macro.rs b/src/libsyntax_expand/proc_macro.rs index bda9478ce96..53cd4d3519f 100644 --- a/src/libsyntax_expand/proc_macro.rs +++ b/src/libsyntax_expand/proc_macro.rs @@ -181,7 +181,7 @@ impl<'a> Visitor<'a> for MarkAttrs<'a> { crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) -> Vec { let mut result = Vec::new(); attrs.retain(|attr| { - if attr.path != sym::derive { + if attr.item.path != sym::derive { return true; } if !attr.is_meta_item_list() { @@ -196,7 +196,7 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) } let parse_derive_paths = |attr: &ast::Attribute| { - if attr.tokens.is_empty() { + if attr.item.tokens.is_empty() { return Ok(Vec::new()); } parse::parse_in_attr(cx.parse_sess, attr, |p| p.parse_derive_paths()) diff --git a/src/libsyntax_ext/proc_macro_harness.rs b/src/libsyntax_ext/proc_macro_harness.rs index fc4a7a0a0fe..bef91399927 100644 --- a/src/libsyntax_ext/proc_macro_harness.rs +++ b/src/libsyntax_ext/proc_macro_harness.rs @@ -249,9 +249,9 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { for attr in &item.attrs { if is_proc_macro_attr(&attr) { if let Some(prev_attr) = found_attr { - let path_str = pprust::path_to_string(&attr.path); - let msg = if attr.path.segments[0].ident.name == - prev_attr.path.segments[0].ident.name { + let path_str = pprust::path_to_string(&attr.item.path); + let msg = if attr.item.path.segments[0].ident.name == + prev_attr.item.path.segments[0].ident.name { format!( "only one `#[{}]` attribute is allowed on any given function", path_str, @@ -261,7 +261,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { "`#[{}]` and `#[{}]` attributes cannot both be applied to the same function", path_str, - pprust::path_to_string(&prev_attr.path), + pprust::path_to_string(&prev_attr.item.path), ) }; @@ -290,7 +290,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { if !is_fn { let msg = format!( "the `#[{}]` attribute may only be used on bare functions", - pprust::path_to_string(&attr.path), + pprust::path_to_string(&attr.item.path), ); self.handler.span_err(attr.span, &msg); @@ -304,7 +304,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { if !self.is_proc_macro_crate { let msg = format!( "the `#[{}]` attribute is only usable with crates of the `proc-macro` crate type", - pprust::path_to_string(&attr.path), + pprust::path_to_string(&attr.item.path), ); self.handler.span_err(attr.span, &msg); -- cgit 1.4.1-3-g733a5 From eea6f23a0ed67fd8c6b8e1b02cda3628fee56b2f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 24 Oct 2019 06:33:12 +1100 Subject: Make doc comments cheaper with `AttrKind`. `AttrKind` is a new type with two variants, `Normal` and `DocComment`. It's a big performance win (over 10% in some cases) because `DocComment` lets doc comments (which are common) be represented very cheaply. `Attribute` gets some new helper methods to ease the transition: - `has_name()`: check if the attribute name matches a single `Symbol`; for `DocComment` variants it succeeds if the symbol is `sym::doc`. - `is_doc_comment()`: check if it has a `DocComment` kind. - `{get,unwrap}_normal_item()`: extract the item from a `Normal` variant; panic otherwise. Fixes #60935. --- src/librustc/hir/lowering.rs | 16 ++-- src/librustc/ich/impls_syntax.rs | 25 +++---- src/librustc_lint/builtin.rs | 6 +- src/librustc_metadata/link_args.rs | 2 +- src/librustc_passes/ast_validation.rs | 2 +- src/librustc_resolve/build_reduced_graph.rs | 6 +- src/librustc_resolve/macros.rs | 2 +- src/librustc_save_analysis/lib.rs | 4 +- src/librustc_typeck/collect.rs | 4 +- src/librustdoc/clean/mod.rs | 47 ++++++------ src/libsyntax/ast.rs | 19 ++++- src/libsyntax/attr/builtin.rs | 8 +- src/libsyntax/attr/mod.rs | 110 ++++++++++++++++++++-------- src/libsyntax/config.rs | 9 +-- src/libsyntax/feature_gate/check.rs | 3 +- src/libsyntax/mut_visit.rs | 12 ++- src/libsyntax/parse/mod.rs | 22 +++--- src/libsyntax/parse/parser/attr.rs | 7 +- src/libsyntax/parse/parser/item.rs | 12 +-- src/libsyntax/parse/tests.rs | 2 +- src/libsyntax/print/pprust.rs | 21 +++--- src/libsyntax/visit.rs | 5 +- src/libsyntax_expand/expand.rs | 18 +++-- src/libsyntax_expand/proc_macro.rs | 4 +- src/libsyntax_ext/proc_macro_harness.rs | 14 ++-- 25 files changed, 233 insertions(+), 147 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 067fefd3210..230fbb16b87 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -997,14 +997,20 @@ impl<'a> LoweringContext<'a> { // Note that we explicitly do not walk the path. Since we don't really // lower attributes (we use the AST version) there is nowhere to keep // the `HirId`s. We don't actually need HIR version of attributes anyway. + let kind = match attr.kind { + AttrKind::Normal(ref item) => { + AttrKind::Normal(AttrItem { + path: item.path.clone(), + tokens: self.lower_token_stream(item.tokens.clone()), + }) + } + AttrKind::DocComment(comment) => AttrKind::DocComment(comment) + }; + Attribute { - item: AttrItem { - path: attr.item.path.clone(), - tokens: self.lower_token_stream(attr.item.tokens.clone()), - }, + kind, id: attr.id, style: attr.style, - is_sugared_doc: attr.is_sugared_doc, span: attr.span, } } diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 304735fb1c7..aa147462e3d 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -177,7 +177,7 @@ impl<'a> HashStable> for [ast::Attribute] { let filtered: SmallVec<[&ast::Attribute; 8]> = self .iter() .filter(|attr| { - !attr.is_sugared_doc && + !attr.is_doc_comment() && !attr.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name)) }) .collect(); @@ -207,19 +207,16 @@ impl<'a> HashStable> for ast::Attribute { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { // Make sure that these have been filtered out. debug_assert!(!self.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name))); - debug_assert!(!self.is_sugared_doc); - - let ast::Attribute { - ref item, - id: _, - style, - is_sugared_doc: _, - span, - } = *self; - - item.hash_stable(hcx, hasher); - style.hash_stable(hcx, hasher); - span.hash_stable(hcx, hasher); + debug_assert!(!self.is_doc_comment()); + + let ast::Attribute { kind, id: _, style, span } = self; + if let ast::AttrKind::Normal(item) = kind { + item.hash_stable(hcx, hasher); + style.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + } else { + unreachable!(); + } } } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 5bc8a0e16a2..d40af615eb1 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -706,7 +706,7 @@ impl EarlyLintPass for DeprecatedAttr { } } if attr.check_name(sym::no_start) || attr.check_name(sym::crate_id) { - let path_str = pprust::path_to_string(&attr.item.path); + let path_str = pprust::path_to_string(&attr.get_normal_item().path); let msg = format!("use of deprecated attribute `{}`: no longer used.", path_str); lint_deprecated_attr(cx, attr, &msg, None); } @@ -736,7 +736,7 @@ impl UnusedDocComment { let mut sugared_span: Option = None; while let Some(attr) = attrs.next() { - if attr.is_sugared_doc { + if attr.is_doc_comment() { sugared_span = Some( sugared_span.map_or_else( || attr.span, @@ -745,7 +745,7 @@ impl UnusedDocComment { ); } - if attrs.peek().map(|next_attr| next_attr.is_sugared_doc).unwrap_or_default() { + if attrs.peek().map(|next_attr| next_attr.is_doc_comment()).unwrap_or_default() { continue; } diff --git a/src/librustc_metadata/link_args.rs b/src/librustc_metadata/link_args.rs index 1b10cff5689..b40d58a6819 100644 --- a/src/librustc_metadata/link_args.rs +++ b/src/librustc_metadata/link_args.rs @@ -11,7 +11,7 @@ crate fn collect(tcx: TyCtxt<'_>) -> Vec { tcx.hir().krate().visit_all_item_likes(&mut collector); for attr in tcx.hir().krate().attrs.iter() { - if attr.item.path == sym::link_args { + if attr.has_name(sym::link_args) { if let Some(linkarg) = attr.value_str() { collector.add_link_args(&linkarg.as_str()); } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index e625334040e..d1a801b3006 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -328,7 +328,7 @@ impl<'a> AstValidator<'a> { let arr = [sym::allow, sym::cfg, sym::cfg_attr, sym::deny, sym::forbid, sym::warn]; !arr.contains(&attr.name_or_empty()) && is_builtin_attr(attr) }) - .for_each(|attr| if attr.is_sugared_doc { + .for_each(|attr| if attr.is_doc_comment() { let mut err = self.err_handler().struct_span_err( attr.span, "documentation comments cannot be applied to function parameters" diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 4849ec25560..55f054d0be3 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -1229,8 +1229,10 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { } fn visit_attribute(&mut self, attr: &'b ast::Attribute) { - if !attr.is_sugared_doc && is_builtin_attr(attr) { - self.r.builtin_attrs.push((attr.item.path.segments[0].ident, self.parent_scope)); + if !attr.is_doc_comment() && is_builtin_attr(attr) { + self.r.builtin_attrs.push( + (attr.get_normal_item().path.segments[0].ident, self.parent_scope) + ); } visit::walk_attribute(self, attr); } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index f4338d24629..3d5a7f26eda 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -179,7 +179,7 @@ impl<'a> base::Resolver for Resolver<'a> { let (path, kind, derives, after_derive) = match invoc.kind { InvocationKind::Attr { ref attr, ref derives, after_derive, .. } => - (&attr.item.path, + (&attr.get_normal_item().path, MacroKind::Attr, self.arenas.alloc_ast_paths(derives), after_derive), diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 7592df57fc6..9408bbe557a 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -885,7 +885,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { for attr in attrs { if attr.check_name(sym::doc) { if let Some(val) = attr.value_str() { - if attr.is_sugared_doc { + if attr.is_doc_comment() { result.push_str(&strip_doc_comment_decoration(&val.as_str())); } else { result.push_str(&val.as_str()); @@ -1195,7 +1195,7 @@ fn null_id() -> rls_data::Id { fn lower_attributes(attrs: Vec, scx: &SaveContext<'_, '_>) -> Vec { attrs.into_iter() // Only retain real attributes. Doc comments are lowered separately. - .filter(|attr| attr.item.path != sym::doc) + .filter(|attr| !attr.has_name(sym::doc)) .map(|mut attr| { // Remove the surrounding '#[..]' or '#![..]' of the pretty printed // attribute. First normalize all inner attribute (#![..]) to outer diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 09e372ac830..71a7b52a27b 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2706,7 +2706,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| { - if attr.item.path != sym::inline { + if !attr.has_name(sym::inline) { return ia; } match attr.meta().map(|i| i.kind) { @@ -2746,7 +2746,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { }); codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| { - if attr.item.path != sym::optimize { + if !attr.has_name(sym::optimize) { return ia; } let err = |sp, s| span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e7f76155252..32c8ca234a0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -26,7 +26,7 @@ use rustc::ty::{self, DefIdTree, TyCtxt, Region, RegionVid, Ty, AdtKind}; use rustc::ty::fold::TypeFolder; use rustc::ty::layout::VariantIdx; use rustc::util::nodemap::{FxHashMap, FxHashSet}; -use syntax::ast::{self, Attribute, AttrStyle, AttrItem, Ident}; +use syntax::ast::{self, Attribute, AttrStyle, AttrKind, Ident}; use syntax::attr; use syntax::parse::lexer::comments; use syntax::source_map::DUMMY_SP; @@ -859,31 +859,32 @@ impl Attributes { let mut cfg = Cfg::True; let mut doc_line = 0; - /// Converts `attr` to a normal `#[doc="foo"]` comment, if it is a - /// comment like `///` or `/** */`. (Returns `attr` unchanged for - /// non-sugared doc attributes.) - pub fn with_desugared_doc(attr: &Attribute, f: impl FnOnce(&Attribute) -> T) -> T { - if attr.is_sugared_doc { - let comment = attr.value_str().unwrap(); - let meta = attr::mk_name_value_item_str( - Ident::with_dummy_span(sym::doc), - Symbol::intern(&comments::strip_doc_comment_decoration(&comment.as_str())), - DUMMY_SP, - ); - f(&Attribute { - item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) }, - id: attr.id, - style: attr.style, - is_sugared_doc: true, - span: attr.span, - }) - } else { - f(attr) + /// If `attr` is a doc comment, strips the leading and (if present) + /// trailing comments symbols, e.g. `///`, `/**`, and `*/`. Otherwise, + /// returns `attr` unchanged. + pub fn with_doc_comment_markers_stripped( + attr: &Attribute, + f: impl FnOnce(&Attribute) -> T + ) -> T { + match attr.kind { + AttrKind::Normal(_) => { + f(attr) + } + AttrKind::DocComment(comment) => { + let comment = + Symbol::intern(&comments::strip_doc_comment_decoration(&comment.as_str())); + f(&Attribute { + kind: AttrKind::DocComment(comment), + id: attr.id, + style: attr.style, + span: attr.span, + }) + } } } let other_attrs = attrs.iter().filter_map(|attr| { - with_desugared_doc(attr, |attr| { + with_doc_comment_markers_stripped(attr, |attr| { if attr.check_name(sym::doc) { if let Some(mi) = attr.meta() { if let Some(value) = mi.value_str() { @@ -892,7 +893,7 @@ impl Attributes { let line = doc_line; doc_line += value.lines().count(); - if attr.is_sugared_doc { + if attr.is_doc_comment() { doc_strings.push(DocFragment::SugaredDoc(line, attr.span, value)); } else { doc_strings.push(DocFragment::RawDoc(line, attr.span, value)); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index df1fb5d97d7..2392b809150 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2190,18 +2190,31 @@ pub struct AttrItem { } /// Metadata associated with an item. -/// Doc-comments are promoted to attributes that have `is_sugared_doc = true`. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Attribute { - pub item: AttrItem, + pub kind: AttrKind, pub id: AttrId, /// Denotes if the attribute decorates the following construct (outer) /// or the construct this attribute is contained within (inner). pub style: AttrStyle, - pub is_sugared_doc: bool, pub span: Span, } +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub enum AttrKind { + /// A normal attribute. + Normal(AttrItem), + + /// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`). + /// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal` + /// variant (which is much less compact and thus more expensive). + /// + /// Note: `self.has_name(sym::doc)` and `self.check_name(sym::doc)` succeed + /// for this variant, but this may change in the future. + /// ``` + DocComment(Symbol), +} + /// `TraitRef`s appear in impls. /// /// Resolution maps each `TraitRef`'s `ref_id` to its defining trait; that's all diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index e77d9ef326a..787d69f5e99 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -228,7 +228,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, sym::stable, sym::rustc_promotable, sym::rustc_allow_const_fn_ptr, - ].iter().any(|&s| attr.item.path == s) { + ].iter().any(|&s| attr.has_name(s)) { continue // not a stability level } @@ -236,10 +236,10 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, let meta = attr.meta(); - if attr.item.path == sym::rustc_promotable { + if attr.has_name(sym::rustc_promotable) { promotable = true; } - if attr.item.path == sym::rustc_allow_const_fn_ptr { + if attr.has_name(sym::rustc_allow_const_fn_ptr) { allow_const_fn_ptr = true; } // attributes with data @@ -778,7 +778,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec { let mut acc = Vec::new(); let diagnostic = &sess.span_diagnostic; - if attr.item.path == sym::repr { + if attr.has_name(sym::repr) { if let Some(items) = attr.meta_item_list() { mark_used(attr); for item in items { diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 0c46c501be9..c663995eb8f 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -9,7 +9,7 @@ pub use StabilityLevel::*; pub use crate::ast::Attribute; use crate::ast; -use crate::ast::{AttrItem, AttrId, AttrStyle, Name, Ident, Path, PathSegment}; +use crate::ast::{AttrItem, AttrId, AttrKind, AttrStyle, Name, Ident, Path, PathSegment}; use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem}; use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam}; use crate::mut_visit::visit_clobber; @@ -145,12 +145,17 @@ impl NestedMetaItem { } impl Attribute { + pub fn has_name(&self, name: Symbol) -> bool { + match self.kind { + AttrKind::Normal(ref item) => item.path == name, + AttrKind::DocComment(_) => name == sym::doc, + } + } + /// Returns `true` if the attribute's path matches the argument. If it matches, then the /// attribute is marked as used. - /// - /// To check the attribute name without marking it used, use the `path` field directly. pub fn check_name(&self, name: Symbol) -> bool { - let matches = self.item.path == name; + let matches = self.has_name(name); if matches { mark_used(self); } @@ -159,10 +164,15 @@ impl Attribute { /// For a single-segment attribute, returns its name; otherwise, returns `None`. pub fn ident(&self) -> Option { - if self.item.path.segments.len() == 1 { - Some(self.item.path.segments[0].ident) - } else { - None + match self.kind { + AttrKind::Normal(ref item) => { + if item.path.segments.len() == 1 { + Some(item.path.segments[0].ident) + } else { + None + } + } + AttrKind::DocComment(_) => Some(Ident::new(sym::doc, self.span)), } } pub fn name_or_empty(&self) -> Symbol { @@ -170,18 +180,32 @@ impl Attribute { } pub fn value_str(&self) -> Option { - self.meta().and_then(|meta| meta.value_str()) + match self.kind { + AttrKind::Normal(ref item) => { + item.meta(self.span).and_then(|meta| meta.value_str()) + } + AttrKind::DocComment(comment) => Some(comment), + } } pub fn meta_item_list(&self) -> Option> { - match self.meta() { - Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list), - _ => None + match self.kind { + AttrKind::Normal(ref item) => { + match item.meta(self.span) { + Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list), + _ => None + } + } + AttrKind::DocComment(_) => None, } } pub fn is_word(&self) -> bool { - self.item.tokens.is_empty() + if let AttrKind::Normal(item) = &self.kind { + item.tokens.is_empty() + } else { + false + } } pub fn is_meta_item_list(&self) -> bool { @@ -275,17 +299,49 @@ impl AttrItem { } impl Attribute { + pub fn is_doc_comment(&self) -> bool { + match self.kind { + AttrKind::Normal(_) => false, + AttrKind::DocComment(_) => true, + } + } + + pub fn get_normal_item(&self) -> &AttrItem { + match self.kind { + AttrKind::Normal(ref item) => item, + AttrKind::DocComment(_) => panic!("unexpected sugared doc"), + } + } + + pub fn unwrap_normal_item(self) -> AttrItem { + match self.kind { + AttrKind::Normal(item) => item, + AttrKind::DocComment(_) => panic!("unexpected sugared doc"), + } + } + /// Extracts the MetaItem from inside this Attribute. pub fn meta(&self) -> Option { - self.item.meta(self.span) + match self.kind { + AttrKind::Normal(ref item) => item.meta(self.span), + AttrKind::DocComment(comment) => + Some(mk_name_value_item_str(Ident::new(sym::doc, self.span), comment, self.span)), + } } pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> { - Ok(MetaItem { - path: self.item.path.clone(), - kind: parse::parse_in_attr(sess, self, |p| p.parse_meta_item_kind())?, - span: self.span, - }) + match self.kind { + AttrKind::Normal(ref item) => { + Ok(MetaItem { + path: item.path.clone(), + kind: parse::parse_in_attr(sess, self, |parser| parser.parse_meta_item_kind())?, + span: self.span, + }) + } + AttrKind::DocComment(comment) => { + Ok(mk_name_value_item_str(Ident::new(sym::doc, self.span), comment, self.span)) + } + } } } @@ -327,10 +383,9 @@ crate fn mk_attr_id() -> AttrId { pub fn mk_attr(style: AttrStyle, path: Path, tokens: TokenStream, span: Span) -> Attribute { Attribute { - item: AttrItem { path, tokens }, + kind: AttrKind::Normal(AttrItem { path, tokens }), id: mk_attr_id(), style, - is_sugared_doc: false, span, } } @@ -345,18 +400,11 @@ pub fn mk_attr_outer(item: MetaItem) -> Attribute { mk_attr(AttrStyle::Outer, item.path, item.kind.tokens(item.span), item.span) } -pub fn mk_sugared_doc_attr(text: Symbol, span: Span) -> Attribute { - let style = doc_comment_style(&text.as_str()); - let lit_kind = LitKind::Str(text, ast::StrStyle::Cooked); - let lit = Lit::from_lit_kind(lit_kind, span); +pub fn mk_doc_comment(comment: Symbol, span: Span) -> Attribute { Attribute { - item: AttrItem { - path: Path::from_ident(Ident::with_dummy_span(sym::doc).with_span_pos(span)), - tokens: MetaItemKind::NameValue(lit).tokens(span), - }, + kind: AttrKind::DocComment(comment), id: mk_attr_id(), - style, - is_sugared_doc: true, + style: doc_comment_style(&comment.as_str()), span, } } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 682c8f71dc8..5f89ed36e2a 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -93,10 +93,10 @@ impl<'a> StripUnconfigured<'a> { /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec { - if attr.item.path != sym::cfg_attr { + if !attr.has_name(sym::cfg_attr) { return vec![attr]; } - if attr.item.tokens.is_empty() { + if attr.get_normal_item().tokens.is_empty() { self.sess.span_diagnostic .struct_span_err( attr.span, @@ -136,10 +136,9 @@ impl<'a> StripUnconfigured<'a> { // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. expanded_attrs.into_iter() .flat_map(|(item, span)| self.process_cfg_attr(ast::Attribute { - item, + kind: ast::AttrKind::Normal(item), id: attr::mk_attr_id(), style: attr.style, - is_sugared_doc: false, span, })) .collect() @@ -212,7 +211,7 @@ impl<'a> StripUnconfigured<'a> { GateIssue::Language, EXPLAIN_STMT_ATTR_SYNTAX); - if attr.is_sugared_doc { + if attr.is_doc_comment() { err.help("`///` is for documentation comments. For a plain comment, use `//`."); } diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index c19ed774507..b7e75ff3a7e 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -329,7 +329,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. Some((name, _, template, _)) if name != sym::rustc_dummy => check_builtin_attribute(self.parse_sess, attr, name, template), - _ => if let Some(TokenTree::Token(token)) = attr.item.tokens.trees().next() { + _ => if let Some(TokenTree::Token(token)) = + attr.get_normal_item().tokens.trees().next() { if token == token::Eq { // All key-value attributes are restricted to meta-item syntax. attr.parse_meta(self.parse_sess).map_err(|mut err| err.emit()).ok(); diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 60ee17d09b7..7261601e144 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -550,10 +550,14 @@ pub fn noop_visit_local(local: &mut P, vis: &mut T) { } pub fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { - let Attribute { item: AttrItem { path, tokens }, id: _, style: _, is_sugared_doc: _, span } - = attr; - vis.visit_path(path); - vis.visit_tts(tokens); + let Attribute { kind, id: _, style: _, span } = attr; + match kind { + AttrKind::Normal(AttrItem { path, tokens }) => { + vis.visit_path(path); + vis.visit_tts(tokens); + } + AttrKind::DocComment(_) => {} + } vis.visit_span(span); } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 6cfa0dfad82..b688dce87c1 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -287,7 +287,7 @@ pub fn parse_in_attr<'a, T>( ) -> PResult<'a, T> { let mut parser = Parser::new( sess, - attr.item.tokens.clone(), + attr.get_normal_item().tokens.clone(), None, false, false, @@ -393,18 +393,22 @@ fn prepend_attrs( let source = pprust::attribute_to_string(attr); let macro_filename = FileName::macro_expansion_source_code(&source); - if attr.is_sugared_doc { - let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span)); - builder.push(stream); - continue - } + + let item = match attr.kind { + ast::AttrKind::Normal(ref item) => item, + ast::AttrKind::DocComment(_) => { + let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span)); + builder.push(stream); + continue + } + }; // synthesize # [ $path $tokens ] manually here let mut brackets = tokenstream::TokenStreamBuilder::new(); // For simple paths, push the identifier directly - if attr.item.path.segments.len() == 1 && attr.item.path.segments[0].args.is_none() { - let ident = attr.item.path.segments[0].ident; + if item.path.segments.len() == 1 && item.path.segments[0].args.is_none() { + let ident = item.path.segments[0].ident; let token = token::Ident(ident.name, ident.as_str().starts_with("r#")); brackets.push(tokenstream::TokenTree::token(token, ident.span)); @@ -415,7 +419,7 @@ fn prepend_attrs( brackets.push(stream); } - brackets.push(attr.item.tokens.clone()); + brackets.push(item.tokens.clone()); // The span we list here for `#` and for `[ ... ]` are both wrong in // that it encompasses more than each token, but it hopefully is "good diff --git a/src/libsyntax/parse/parser/attr.rs b/src/libsyntax/parse/parser/attr.rs index 188a144cac9..1c292661f24 100644 --- a/src/libsyntax/parse/parser/attr.rs +++ b/src/libsyntax/parse/parser/attr.rs @@ -43,7 +43,7 @@ impl<'a> Parser<'a> { just_parsed_doc_comment = false; } token::DocComment(s) => { - let attr = attr::mk_sugared_doc_attr(s, self.token.span); + let attr = attr::mk_doc_comment(s, self.token.span); if attr.style != ast::AttrStyle::Outer { let mut err = self.fatal("expected outer doc comment"); err.note("inner doc comments like this (starting with \ @@ -150,10 +150,9 @@ impl<'a> Parser<'a> { }; Ok(ast::Attribute { - item, + kind: ast::AttrKind::Normal(item), id: attr::mk_attr_id(), style, - is_sugared_doc: false, span, }) } @@ -229,7 +228,7 @@ impl<'a> Parser<'a> { } token::DocComment(s) => { // We need to get the position of this token before we bump. - let attr = attr::mk_sugared_doc_attr(s, self.token.span); + let attr = attr::mk_doc_comment(s, self.token.span); if attr.style == ast::AttrStyle::Inner { attrs.push(attr); self.bump(); diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 5b60e7e6dba..cc6235c6fc7 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -3,8 +3,8 @@ use super::diagnostics::{Error, dummy_arg, ConsumeClosingDelim}; use crate::maybe_whole; use crate::ptr::P; -use crate::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrStyle, AnonConst, Item, ItemKind}; -use crate::ast::{ImplItem, ImplItemKind, TraitItem, TraitItemKind, UseTree, UseTreeKind}; +use crate::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrKind, AttrStyle, AnonConst, Item}; +use crate::ast::{ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind, UseTree, UseTreeKind}; use crate::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness}; use crate::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind}; use crate::ast::{Ty, TyKind, Generics, GenericBounds, TraitRef, EnumDef, VariantData, StructField}; @@ -483,12 +483,14 @@ impl<'a> Parser<'a> { /// Emits an expected-item-after-attributes error. fn expected_item_err(&mut self, attrs: &[Attribute]) -> PResult<'a, ()> { let message = match attrs.last() { - Some(&Attribute { is_sugared_doc: true, .. }) => "expected item after doc comment", - _ => "expected item after attributes", + Some(&Attribute { kind: AttrKind::DocComment(_), .. }) => + "expected item after doc comment", + _ => + "expected item after attributes", }; let mut err = self.diagnostic().struct_span_err(self.prev_span, message); - if attrs.last().unwrap().is_sugared_doc { + if attrs.last().unwrap().is_doc_comment() { err.span_label(self.prev_span, "this doc comment doesn't document anything"); } Err(err) diff --git a/src/libsyntax/parse/tests.rs b/src/libsyntax/parse/tests.rs index 3bdb9227b4e..169eb954efa 100644 --- a/src/libsyntax/parse/tests.rs +++ b/src/libsyntax/parse/tests.rs @@ -246,7 +246,7 @@ let mut fflags: c_int = wb(); let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name_2, source, &sess) .unwrap().unwrap(); - let docs = item.attrs.iter().filter(|a| a.path == sym::doc) + let docs = item.attrs.iter().filter(|a| a.has_name(sym::doc)) .map(|a| a.value_str().unwrap().to_string()).collect::>(); let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()]; assert_eq!(&docs[..], b); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 74ab5c79019..c8afe8a1ff4 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -622,16 +622,19 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.hardbreak_if_not_bol(); } self.maybe_print_comment(attr.span.lo()); - if attr.is_sugared_doc { - self.word(attr.value_str().unwrap().to_string()); - self.hardbreak() - } else { - match attr.style { - ast::AttrStyle::Inner => self.word("#!["), - ast::AttrStyle::Outer => self.word("#["), + match attr.kind { + ast::AttrKind::Normal(ref item) => { + match attr.style { + ast::AttrStyle::Inner => self.word("#!["), + ast::AttrStyle::Outer => self.word("#["), + } + self.print_attr_item(&item, attr.span); + self.word("]"); + } + ast::AttrKind::DocComment(comment) => { + self.word(comment.to_string()); + self.hardbreak() } - self.print_attr_item(&attr.item, attr.span); - self.word("]"); } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 64393a295de..117787d08c7 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -846,7 +846,10 @@ pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) { } pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) { - visitor.visit_tts(attr.item.tokens.clone()); + match attr.kind { + AttrKind::Normal(ref item) => visitor.visit_tts(item.tokens.clone()), + AttrKind::DocComment(_) => {} + } } pub fn walk_tt<'a, V: Visitor<'a>>(visitor: &mut V, tt: TokenTree) { diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs index 392563587ba..7dbc7787010 100644 --- a/src/libsyntax_expand/expand.rs +++ b/src/libsyntax_expand/expand.rs @@ -419,7 +419,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } let mut item = self.fully_configure(item); - item.visit_attrs(|attrs| attrs.retain(|a| a.item.path != sym::derive)); + item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive))); let mut helper_attrs = Vec::new(); let mut has_copy = false; for ext in exts { @@ -634,9 +634,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { | Annotatable::Variant(..) => panic!("unexpected annotatable"), })), DUMMY_SP).into(); - let input = self.extract_proc_macro_attr_input(attr.item.tokens, span); + let item = attr.unwrap_normal_item(); + let input = self.extract_proc_macro_attr_input(item.tokens, span); let tok_result = expander.expand(self.cx, span, input, item_tok); - self.parse_ast_fragment(tok_result, fragment_kind, &attr.item.path, span) + self.parse_ast_fragment(tok_result, fragment_kind, &item.path, span) } SyntaxExtensionKind::LegacyAttr(expander) => { match attr.parse_meta(self.cx.parse_sess) { @@ -974,7 +975,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { -> Option { let attr = attrs.iter() .position(|a| { - if a.item.path == sym::derive { + if a.has_name(sym::derive) { *after_derive = true; } !attr::is_known(a) && !is_builtin_attr(a) @@ -982,7 +983,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { .map(|i| attrs.remove(i)); if let Some(attr) = &attr { if !self.cx.ecfg.custom_inner_attributes() && - attr.style == ast::AttrStyle::Inner && attr.item.path != sym::test { + attr.style == ast::AttrStyle::Inner && !attr.has_name(sym::test) { emit_feature_err(&self.cx.parse_sess, sym::custom_inner_attributes, attr.span, GateIssue::Language, "non-builtin inner attributes are unstable"); @@ -1032,7 +1033,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { feature_gate::check_attribute(attr, self.cx.parse_sess, features); // macros are expanded before any lint passes so this warning has to be hardcoded - if attr.item.path == sym::derive { + if attr.has_name(sym::derive) { self.cx.struct_span_warn(attr.span, "`#[derive]` does nothing on macro invocations") .note("this may become a hard error in a future release") .emit(); @@ -1547,11 +1548,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { let meta = attr::mk_list_item(Ident::with_dummy_span(sym::doc), items); *at = attr::Attribute { - item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) }, + kind: ast::AttrKind::Normal( + AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) }, + ), span: at.span, id: at.id, style: at.style, - is_sugared_doc: false, }; } else { noop_visit_attribute(at, self) diff --git a/src/libsyntax_expand/proc_macro.rs b/src/libsyntax_expand/proc_macro.rs index 53cd4d3519f..1f4c481e3ea 100644 --- a/src/libsyntax_expand/proc_macro.rs +++ b/src/libsyntax_expand/proc_macro.rs @@ -181,7 +181,7 @@ impl<'a> Visitor<'a> for MarkAttrs<'a> { crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) -> Vec { let mut result = Vec::new(); attrs.retain(|attr| { - if attr.item.path != sym::derive { + if !attr.has_name(sym::derive) { return true; } if !attr.is_meta_item_list() { @@ -196,7 +196,7 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) } let parse_derive_paths = |attr: &ast::Attribute| { - if attr.item.tokens.is_empty() { + if attr.get_normal_item().tokens.is_empty() { return Ok(Vec::new()); } parse::parse_in_attr(cx.parse_sess, attr, |p| p.parse_derive_paths()) diff --git a/src/libsyntax_ext/proc_macro_harness.rs b/src/libsyntax_ext/proc_macro_harness.rs index bef91399927..792c97d8508 100644 --- a/src/libsyntax_ext/proc_macro_harness.rs +++ b/src/libsyntax_ext/proc_macro_harness.rs @@ -249,9 +249,11 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { for attr in &item.attrs { if is_proc_macro_attr(&attr) { if let Some(prev_attr) = found_attr { - let path_str = pprust::path_to_string(&attr.item.path); - let msg = if attr.item.path.segments[0].ident.name == - prev_attr.item.path.segments[0].ident.name { + let prev_item = prev_attr.get_normal_item(); + let item = attr.get_normal_item(); + let path_str = pprust::path_to_string(&item.path); + let msg = if item.path.segments[0].ident.name == + prev_item.path.segments[0].ident.name { format!( "only one `#[{}]` attribute is allowed on any given function", path_str, @@ -261,7 +263,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { "`#[{}]` and `#[{}]` attributes cannot both be applied to the same function", path_str, - pprust::path_to_string(&prev_attr.item.path), + pprust::path_to_string(&prev_item.path), ) }; @@ -290,7 +292,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { if !is_fn { let msg = format!( "the `#[{}]` attribute may only be used on bare functions", - pprust::path_to_string(&attr.item.path), + pprust::path_to_string(&attr.get_normal_item().path), ); self.handler.span_err(attr.span, &msg); @@ -304,7 +306,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { if !self.is_proc_macro_crate { let msg = format!( "the `#[{}]` attribute is only usable with crates of the `proc-macro` crate type", - pprust::path_to_string(&attr.item.path), + pprust::path_to_string(&attr.get_normal_item().path), ); self.handler.span_err(attr.span, &msg); -- cgit 1.4.1-3-g733a5 From 52e8ec14322e1f0c2cba5fc3c54e876e58a5ddee Mon Sep 17 00:00:00 2001 From: Esteban Küber Date: Mon, 28 Oct 2019 11:08:53 -0700 Subject: Remove "here" from "expected one of X here" --- src/libsyntax/parse/parser/diagnostics.rs | 2 +- src/test/ui/anon-params-denied-2018.stderr | 8 ++++---- .../await-keyword/incorrect-syntax-suggestions.stderr | 2 +- src/test/ui/async-await/no-async-const.stderr | 2 +- src/test/ui/async-await/no-unsafe-async.stderr | 4 ++-- src/test/ui/can-begin-expr-check.stderr | 2 +- src/test/ui/codemap_tests/bad-format-args.stderr | 2 +- src/test/ui/const-generics/const-expression-parameter.stderr | 2 +- src/test/ui/did_you_mean/issue-40006.stderr | 2 +- .../issue-54109-and_instead_of_ampersands.stderr | 8 ++++---- .../ui/editions/edition-keywords-2018-2015-parsing.stderr | 2 +- .../ui/editions/edition-keywords-2018-2018-parsing.stderr | 2 +- src/test/ui/feature-gates/feature-gate-extern_prelude.stderr | 2 +- src/test/ui/imports/import-prefix-macro-1.stderr | 2 +- src/test/ui/invalid/invalid-variadic-function.stderr | 2 +- src/test/ui/issues/issue-20616-1.stderr | 2 +- src/test/ui/issues/issue-20616-2.stderr | 2 +- src/test/ui/issues/issue-20616-3.stderr | 2 +- src/test/ui/issues/issue-20616-4.stderr | 2 +- src/test/ui/issues/issue-20616-5.stderr | 2 +- src/test/ui/issues/issue-20616-6.stderr | 2 +- src/test/ui/issues/issue-20616-7.stderr | 2 +- src/test/ui/issues/issue-20616-8.stderr | 2 +- src/test/ui/issues/issue-20616-9.stderr | 2 +- src/test/ui/issues/issue-21146.stderr | 2 +- src/test/ui/issues/issue-34334.stderr | 2 +- src/test/ui/issues/issue-39616.stderr | 2 +- src/test/ui/issues/issue-44021.stderr | 2 +- src/test/ui/issues/issue-52496.stderr | 2 +- src/test/ui/issues/issue-58856-2.stderr | 2 +- src/test/ui/issues/issue-60075.stderr | 2 +- src/test/ui/label/label_break_value_illegal_uses.stderr | 4 ++-- src/test/ui/macro_backtrace/main.stderr | 6 +++--- src/test/ui/macros/assert-trailing-junk.stderr | 4 ++-- src/test/ui/macros/issue-54441.stderr | 2 +- src/test/ui/malformed/malformed-derive-entry.stderr | 4 ++-- src/test/ui/mismatched_types/recovered-block.stderr | 2 +- src/test/ui/missing/missing-comma-in-match.fixed | 2 +- src/test/ui/missing/missing-comma-in-match.rs | 2 +- src/test/ui/missing/missing-comma-in-match.stderr | 2 +- .../ui/on-unimplemented/expected-comma-found-token.stderr | 2 +- src/test/ui/parser/assoc-oddities-1.stderr | 2 +- src/test/ui/parser/assoc-oddities-2.stderr | 2 +- .../associated-types-project-from-hrtb-explicit.stderr | 2 +- src/test/ui/parser/attr-bad-meta.stderr | 2 +- src/test/ui/parser/bad-match.stderr | 2 +- src/test/ui/parser/bad-name.stderr | 2 +- src/test/ui/parser/better-expected.stderr | 2 +- src/test/ui/parser/bounds-lifetime-1.stderr | 2 +- src/test/ui/parser/bounds-lifetime-2.stderr | 2 +- src/test/ui/parser/bounds-lifetime-where.stderr | 2 +- src/test/ui/parser/bounds-lifetime.stderr | 2 +- src/test/ui/parser/bounds-type-where.stderr | 2 +- src/test/ui/parser/class-implements-bad-trait.stderr | 2 +- src/test/ui/parser/closure-return-syntax.stderr | 2 +- src/test/ui/parser/default.stderr | 2 +- src/test/ui/parser/duplicate-visibility.stderr | 2 +- src/test/ui/parser/empty-impl-semicolon.stderr | 2 +- src/test/ui/parser/extern-crate-unexpected-token.stderr | 2 +- src/test/ui/parser/extern-expected-fn-or-brace.stderr | 2 +- src/test/ui/parser/extern-foreign-crate.stderr | 2 +- src/test/ui/parser/inverted-parameters.stderr | 12 ++++++------ src/test/ui/parser/issue-15980.rs | 2 +- src/test/ui/parser/issue-15980.stderr | 2 +- src/test/ui/parser/issue-17904.stderr | 2 +- src/test/ui/parser/issue-19096.stderr | 4 ++-- src/test/ui/parser/issue-20711-2.stderr | 2 +- src/test/ui/parser/issue-20711.stderr | 2 +- src/test/ui/parser/issue-22647.stderr | 2 +- src/test/ui/parser/issue-22712.stderr | 2 +- src/test/ui/parser/issue-24197.stderr | 2 +- src/test/ui/parser/issue-24375.stderr | 2 +- src/test/ui/parser/issue-24780.stderr | 2 +- src/test/ui/parser/issue-32446.stderr | 2 +- src/test/ui/parser/issue-33455.stderr | 2 +- src/test/ui/parser/issue-41155.stderr | 2 +- src/test/ui/parser/issue-62660.stderr | 2 +- src/test/ui/parser/issue-62973.stderr | 4 ++-- src/test/ui/parser/issue-63135.stderr | 2 +- src/test/ui/parser/lifetime-semicolon.stderr | 2 +- src/test/ui/parser/macro/issue-37234.stderr | 2 +- src/test/ui/parser/macro/macro-incomplete-parse.stderr | 2 +- src/test/ui/parser/macro/trait-non-item-macros.stderr | 2 +- src/test/ui/parser/macros-no-semicolon.stderr | 2 +- src/test/ui/parser/match-refactor-to-expr.rs | 2 +- src/test/ui/parser/match-refactor-to-expr.stderr | 2 +- .../missing-close-brace-in-impl-trait.stderr | 2 +- .../mismatched-braces/missing-close-brace-in-trait.stderr | 2 +- src/test/ui/parser/missing_right_paren.stderr | 2 +- src/test/ui/parser/multitrait.stderr | 2 +- src/test/ui/parser/not-a-pred.stderr | 2 +- src/test/ui/parser/omitted-arg-in-item-fn.stderr | 2 +- src/test/ui/parser/pat-lt-bracket-1.stderr | 2 +- src/test/ui/parser/pat-lt-bracket-2.stderr | 2 +- src/test/ui/parser/pat-lt-bracket-3.stderr | 2 +- src/test/ui/parser/pat-lt-bracket-4.stderr | 2 +- src/test/ui/parser/pat-lt-bracket-5.stderr | 2 +- src/test/ui/parser/pat-lt-bracket-6.stderr | 2 +- src/test/ui/parser/pat-lt-bracket-7.stderr | 2 +- src/test/ui/parser/pat-ranges-1.stderr | 2 +- src/test/ui/parser/pat-ranges-2.stderr | 2 +- src/test/ui/parser/pat-ranges-3.stderr | 2 +- src/test/ui/parser/pat-ranges-4.stderr | 2 +- src/test/ui/parser/range-3.stderr | 2 +- src/test/ui/parser/range-4.stderr | 2 +- src/test/ui/parser/raw-str-unbalanced.stderr | 2 +- src/test/ui/parser/raw/raw-literal-keywords.stderr | 6 +++--- src/test/ui/parser/recover-enum2.stderr | 2 +- .../ui/parser/recover-for-loop-parens-around-head.stderr | 2 +- src/test/ui/parser/removed-syntax-closure-lifetime.stderr | 2 +- src/test/ui/parser/removed-syntax-enum-newtype.stderr | 2 +- src/test/ui/parser/removed-syntax-fixed-vec.stderr | 2 +- src/test/ui/parser/removed-syntax-ptr-lifetime.stderr | 2 +- src/test/ui/parser/removed-syntax-static-fn.stderr | 2 +- src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr | 2 +- src/test/ui/parser/removed-syntax-with-1.stderr | 2 +- src/test/ui/parser/removed-syntax-with-2.stderr | 2 +- src/test/ui/parser/underscore_item_not_const.stderr | 2 +- src/test/ui/parser/use-as-where-use-ends-with-mod-sep.stderr | 2 +- src/test/ui/resolve/token-error-correct-3.stderr | 2 +- .../ui/rfc-2497-if-let-chains/disallowed-positions.stderr | 2 +- src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr | 2 +- .../rfc1598-generic-associated-types/empty_generics.stderr | 2 +- src/test/ui/similar-tokens.stderr | 2 +- src/test/ui/span/issue-34264.stderr | 6 +++--- src/test/ui/suggestions/issue-64252-self-type.stderr | 4 ++-- src/test/ui/tuple/tuple-struct-fields/test.stderr | 2 +- src/test/ui/tuple/tuple-struct-fields/test2.stderr | 2 +- src/test/ui/tuple/tuple-struct-fields/test3.stderr | 2 +- src/test/ui/type/ascription/issue-54516.stderr | 2 +- src/test/ui/type/ascription/issue-60933.stderr | 2 +- src/test/ui/unsafe/unsafe-block-without-braces.stderr | 2 +- 132 files changed, 156 insertions(+), 156 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser/diagnostics.rs b/src/libsyntax/parse/parser/diagnostics.rs index 49a517a5c44..c4d60ec098d 100644 --- a/src/libsyntax/parse/parser/diagnostics.rs +++ b/src/libsyntax/parse/parser/diagnostics.rs @@ -289,7 +289,7 @@ impl<'a> Parser<'a> { }; (format!("expected one of {}, found {}", expect, actual), (self.sess.source_map().next_point(self.prev_span), - format!("expected one of {} here", short_expect))) + format!("expected one of {}", short_expect))) } else if expected.is_empty() { (format!("unexpected token: {}", actual), (self.prev_span, "unexpected token after this".to_string())) diff --git a/src/test/ui/anon-params-denied-2018.stderr b/src/test/ui/anon-params-denied-2018.stderr index 3fcf41a9a60..e7a806a8468 100644 --- a/src/test/ui/anon-params-denied-2018.stderr +++ b/src/test/ui/anon-params-denied-2018.stderr @@ -2,7 +2,7 @@ error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/anon-params-denied-2018.rs:6:15 | LL | fn foo(i32); - | ^ expected one of `:`, `@`, or `|` here + | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this is a `self` type, give it a parameter name @@ -22,7 +22,7 @@ error: expected one of `:`, `@`, or `|`, found `,` --> $DIR/anon-params-denied-2018.rs:8:36 | LL | fn bar_with_default_impl(String, String) {} - | ^ expected one of `:`, `@`, or `|` here + | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this is a `self` type, give it a parameter name @@ -42,7 +42,7 @@ error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/anon-params-denied-2018.rs:8:44 | LL | fn bar_with_default_impl(String, String) {} - | ^ expected one of `:`, `@`, or `|` here + | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type @@ -58,7 +58,7 @@ error: expected one of `:`, `@`, or `|`, found `,` --> $DIR/anon-params-denied-2018.rs:13:22 | LL | fn baz(a:usize, b, c: usize) -> usize { - | ^ expected one of `:`, `@`, or `|` here + | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr index 4b5e2d59e38..92cef80c193 100644 --- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr +++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -130,7 +130,7 @@ error: expected one of `.`, `?`, `{`, or an operator, found `}` --> $DIR/incorrect-syntax-suggestions.rs:134:1 | LL | match await { await => () } - | ----- - expected one of `.`, `?`, `{`, or an operator here + | ----- - expected one of `.`, `?`, `{`, or an operator | | | while parsing this match expression ... diff --git a/src/test/ui/async-await/no-async-const.stderr b/src/test/ui/async-await/no-async-const.stderr index f89d1810ba4..05cdbff0bf0 100644 --- a/src/test/ui/async-await/no-async-const.stderr +++ b/src/test/ui/async-await/no-async-const.stderr @@ -2,7 +2,7 @@ error: expected one of `fn` or `unsafe`, found keyword `const` --> $DIR/no-async-const.rs:5:11 | LL | pub async const fn x() {} - | ^^^^^ expected one of `fn` or `unsafe` here + | ^^^^^ expected one of `fn` or `unsafe` error: aborting due to previous error diff --git a/src/test/ui/async-await/no-unsafe-async.stderr b/src/test/ui/async-await/no-unsafe-async.stderr index 79d9f1befd6..bbeb3427849 100644 --- a/src/test/ui/async-await/no-unsafe-async.stderr +++ b/src/test/ui/async-await/no-unsafe-async.stderr @@ -2,13 +2,13 @@ error: expected one of `extern` or `fn`, found keyword `async` --> $DIR/no-unsafe-async.rs:7:12 | LL | unsafe async fn g() {} - | ^^^^^ expected one of `extern` or `fn` here + | ^^^^^ expected one of `extern` or `fn` error: expected one of `extern`, `fn`, or `{`, found keyword `async` --> $DIR/no-unsafe-async.rs:11:8 | LL | unsafe async fn f() {} - | ^^^^^ expected one of `extern`, `fn`, or `{` here + | ^^^^^ expected one of `extern`, `fn`, or `{` error: aborting due to 2 previous errors diff --git a/src/test/ui/can-begin-expr-check.stderr b/src/test/ui/can-begin-expr-check.stderr index 0e03e9915fc..d674fc36bc2 100644 --- a/src/test/ui/can-begin-expr-check.stderr +++ b/src/test/ui/can-begin-expr-check.stderr @@ -2,7 +2,7 @@ error: expected one of `.`, `;`, `?`, `}`, or an operator, found keyword `enum` --> $DIR/can-begin-expr-check.rs:19:12 | LL | return enum; - | ^^^^ expected one of `.`, `;`, `?`, `}`, or an operator here + | ^^^^ expected one of `.`, `;`, `?`, `}`, or an operator error: aborting due to previous error diff --git a/src/test/ui/codemap_tests/bad-format-args.stderr b/src/test/ui/codemap_tests/bad-format-args.stderr index 3372ef6dea1..17d4df2a223 100644 --- a/src/test/ui/codemap_tests/bad-format-args.stderr +++ b/src/test/ui/codemap_tests/bad-format-args.stderr @@ -16,7 +16,7 @@ error: expected one of `,`, `.`, `?`, or an operator, found `1` --> $DIR/bad-format-args.rs:4:19 | LL | format!("", 1 1); - | ^ expected one of `,`, `.`, `?`, or an operator here + | ^ expected one of `,`, `.`, `?`, or an operator error: aborting due to 3 previous errors diff --git a/src/test/ui/const-generics/const-expression-parameter.stderr b/src/test/ui/const-generics/const-expression-parameter.stderr index 7311e27c289..28bea4ec94f 100644 --- a/src/test/ui/const-generics/const-expression-parameter.stderr +++ b/src/test/ui/const-generics/const-expression-parameter.stderr @@ -2,7 +2,7 @@ error: expected one of `,` or `>`, found `+` --> $DIR/const-expression-parameter.rs:13:22 | LL | i32_identity::<1 + 2>(); - | ^ expected one of `,` or `>` here + | ^ expected one of `,` or `>` warning: the feature `const_generics` is incomplete and may cause the compiler to crash --> $DIR/const-expression-parameter.rs:1:12 diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr index f0baa175d63..30ae6ed4c6d 100644 --- a/src/test/ui/did_you_mean/issue-40006.stderr +++ b/src/test/ui/did_you_mean/issue-40006.stderr @@ -48,7 +48,7 @@ error: expected one of `!` or `::`, found `(` --> $DIR/issue-40006.rs:28:9 | LL | ::Y (); - | ^ expected one of `!` or `::` here + | ^ expected one of `!` or `::` error: missing `fn`, `type`, or `const` for impl-item declaration --> $DIR/issue-40006.rs:32:8 diff --git a/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr b/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr index 35123b11133..f230395f7a5 100644 --- a/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr +++ b/src/test/ui/did_you_mean/issue-54109-and_instead_of_ampersands.stderr @@ -24,7 +24,7 @@ error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found LL | if (a and b) { | ^^^ | | - | expected one of 8 possible tokens here + | expected one of 8 possible tokens | help: use `&&` instead of `and` for the boolean operator error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `or` @@ -33,7 +33,7 @@ error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found LL | if (a or b) { | ^^ | | - | expected one of 8 possible tokens here + | expected one of 8 possible tokens | help: use `||` instead of `or` for the boolean operator error: expected one of `!`, `.`, `::`, `?`, `{`, or an operator, found `and` @@ -42,7 +42,7 @@ error: expected one of `!`, `.`, `::`, `?`, `{`, or an operator, found `and` LL | while a and b { | ^^^ | | - | expected one of `!`, `.`, `::`, `?`, `{`, or an operator here + | expected one of `!`, `.`, `::`, `?`, `{`, or an operator | help: use `&&` instead of `and` for the boolean operator error: expected one of `!`, `.`, `::`, `?`, `{`, or an operator, found `or` @@ -51,7 +51,7 @@ error: expected one of `!`, `.`, `::`, `?`, `{`, or an operator, found `or` LL | while a or b { | ^^ | | - | expected one of `!`, `.`, `::`, `?`, `{`, or an operator here + | expected one of `!`, `.`, `::`, `?`, `{`, or an operator | help: use `||` instead of `or` for the boolean operator error: aborting due to 6 previous errors diff --git a/src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr b/src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr index 77eb44c2065..22a7495ca23 100644 --- a/src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr +++ b/src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr @@ -36,7 +36,7 @@ error: macro expansion ends with an incomplete expression: expected one of `move --> <::edition_kw_macro_2015::passes_ident macros>:1:22 | LL | ($ i : ident) => ($ i) - | ^ expected one of `move`, `|`, or `||` here + | ^ expected one of `move`, `|`, or `||` | ::: $DIR/edition-keywords-2018-2015-parsing.rs:16:8 | diff --git a/src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr b/src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr index 01f9f00e91c..7488fcc2e58 100644 --- a/src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr +++ b/src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr @@ -36,7 +36,7 @@ error: macro expansion ends with an incomplete expression: expected one of `move --> <::edition_kw_macro_2018::passes_ident macros>:1:22 | LL | ($ i : ident) => ($ i) - | ^ expected one of `move`, `|`, or `||` here + | ^ expected one of `move`, `|`, or `||` | ::: $DIR/edition-keywords-2018-2018-parsing.rs:16:8 | diff --git a/src/test/ui/feature-gates/feature-gate-extern_prelude.stderr b/src/test/ui/feature-gates/feature-gate-extern_prelude.stderr index c15a8b33037..d72e47e9ed8 100644 --- a/src/test/ui/feature-gates/feature-gate-extern_prelude.stderr +++ b/src/test/ui/feature-gates/feature-gate-extern_prelude.stderr @@ -2,7 +2,7 @@ error: expected one of `!` or `::`, found `-` --> $DIR/feature-gate-extern_prelude.rs:1:4 | LL | can-only-test-this-in-run-make-fulldeps - | ^ expected one of `!` or `::` here + | ^ expected one of `!` or `::` error: aborting due to previous error diff --git a/src/test/ui/imports/import-prefix-macro-1.stderr b/src/test/ui/imports/import-prefix-macro-1.stderr index 862a31b4465..6c12a366b71 100644 --- a/src/test/ui/imports/import-prefix-macro-1.stderr +++ b/src/test/ui/imports/import-prefix-macro-1.stderr @@ -2,7 +2,7 @@ error: expected one of `::`, `;`, or `as`, found `{` --> $DIR/import-prefix-macro-1.rs:11:27 | LL | ($p: path) => (use $p {S, Z}); - | ^^^^^^ expected one of `::`, `;`, or `as` here + | ^^^^^^ expected one of `::`, `;`, or `as` ... LL | import! { a::b::c } | ------------------- in this macro invocation diff --git a/src/test/ui/invalid/invalid-variadic-function.stderr b/src/test/ui/invalid/invalid-variadic-function.stderr index fd20bd84edc..7e58b17e7db 100644 --- a/src/test/ui/invalid/invalid-variadic-function.stderr +++ b/src/test/ui/invalid/invalid-variadic-function.stderr @@ -8,7 +8,7 @@ error: expected one of `->`, `where`, or `{`, found `;` --> $DIR/invalid-variadic-function.rs:1:30 | LL | extern "C" fn foo(x: u8, ...); - | ^ expected one of `->`, `where`, or `{` here + | ^ expected one of `->`, `where`, or `{` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-20616-1.stderr b/src/test/ui/issues/issue-20616-1.stderr index 143486c8f5a..81604623785 100644 --- a/src/test/ui/issues/issue-20616-1.stderr +++ b/src/test/ui/issues/issue-20616-1.stderr @@ -2,7 +2,7 @@ error: expected one of `,`, `:`, or `>`, found `T` --> $DIR/issue-20616-1.rs:9:16 | LL | type Type_1<'a T> = &'a T; - | ^ expected one of `,`, `:`, or `>` here + | ^ expected one of `,`, `:`, or `>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-2.stderr b/src/test/ui/issues/issue-20616-2.stderr index 1152dec8bad..50ec7a304c5 100644 --- a/src/test/ui/issues/issue-20616-2.stderr +++ b/src/test/ui/issues/issue-20616-2.stderr @@ -2,7 +2,7 @@ error: expected one of `,` or `>`, found `(` --> $DIR/issue-20616-2.rs:12:31 | LL | type Type_2 = Type_1_<'static ()>; - | ^ expected one of `,` or `>` here + | ^ expected one of `,` or `>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-3.stderr b/src/test/ui/issues/issue-20616-3.stderr index f51fb949c74..cc4d79484e7 100644 --- a/src/test/ui/issues/issue-20616-3.stderr +++ b/src/test/ui/issues/issue-20616-3.stderr @@ -2,7 +2,7 @@ error: expected one of `>`, const, identifier, lifetime, or type, found `,` --> $DIR/issue-20616-3.rs:13:24 | LL | type Type_3 = Box; - | ^ expected one of `>`, const, identifier, lifetime, or type here + | ^ expected one of `>`, const, identifier, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-4.stderr b/src/test/ui/issues/issue-20616-4.stderr index 22a655465e8..254e4d6a34d 100644 --- a/src/test/ui/issues/issue-20616-4.stderr +++ b/src/test/ui/issues/issue-20616-4.stderr @@ -2,7 +2,7 @@ error: expected one of `>`, const, identifier, lifetime, or type, found `,` --> $DIR/issue-20616-4.rs:16:34 | LL | type Type_4 = Type_1_<'static,, T>; - | ^ expected one of `>`, const, identifier, lifetime, or type here + | ^ expected one of `>`, const, identifier, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-5.stderr b/src/test/ui/issues/issue-20616-5.stderr index d83fc41f43e..aee8bf01a43 100644 --- a/src/test/ui/issues/issue-20616-5.stderr +++ b/src/test/ui/issues/issue-20616-5.stderr @@ -2,7 +2,7 @@ error: expected one of `>`, const, identifier, lifetime, or type, found `,` --> $DIR/issue-20616-5.rs:22:34 | LL | type Type_5<'a> = Type_1_<'a, (),,>; - | ^ expected one of `>`, const, identifier, lifetime, or type here + | ^ expected one of `>`, const, identifier, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-6.stderr b/src/test/ui/issues/issue-20616-6.stderr index 0740df59523..7192a87bc18 100644 --- a/src/test/ui/issues/issue-20616-6.stderr +++ b/src/test/ui/issues/issue-20616-6.stderr @@ -2,7 +2,7 @@ error: expected one of `>`, const, identifier, lifetime, or type, found `,` --> $DIR/issue-20616-6.rs:25:26 | LL | type Type_6 = Type_5_<'a,,>; - | ^ expected one of `>`, const, identifier, lifetime, or type here + | ^ expected one of `>`, const, identifier, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-7.stderr b/src/test/ui/issues/issue-20616-7.stderr index c0e108375be..123dc1e2b7d 100644 --- a/src/test/ui/issues/issue-20616-7.stderr +++ b/src/test/ui/issues/issue-20616-7.stderr @@ -2,7 +2,7 @@ error: expected one of `>`, const, identifier, lifetime, or type, found `,` --> $DIR/issue-20616-7.rs:28:22 | LL | type Type_7 = Box<(),,>; - | ^ expected one of `>`, const, identifier, lifetime, or type here + | ^ expected one of `>`, const, identifier, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-8.stderr b/src/test/ui/issues/issue-20616-8.stderr index 0ef9192f1e7..479469634c5 100644 --- a/src/test/ui/issues/issue-20616-8.stderr +++ b/src/test/ui/issues/issue-20616-8.stderr @@ -2,7 +2,7 @@ error: expected one of `>`, `const`, identifier, or lifetime, found `,` --> $DIR/issue-20616-8.rs:31:16 | LL | type Type_8<'a,,> = &'a (); - | ^ expected one of `>`, `const`, identifier, or lifetime here + | ^ expected one of `>`, `const`, identifier, or lifetime error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20616-9.stderr b/src/test/ui/issues/issue-20616-9.stderr index 5fd1400a2e8..b7e3322b7aa 100644 --- a/src/test/ui/issues/issue-20616-9.stderr +++ b/src/test/ui/issues/issue-20616-9.stderr @@ -2,7 +2,7 @@ error: expected one of `>`, `const`, identifier, or lifetime, found `,` --> $DIR/issue-20616-9.rs:34:15 | LL | type Type_9 = Box; - | ^ expected one of `>`, `const`, identifier, or lifetime here + | ^ expected one of `>`, `const`, identifier, or lifetime error: aborting due to previous error diff --git a/src/test/ui/issues/issue-21146.stderr b/src/test/ui/issues/issue-21146.stderr index 2798196ea00..c71fda3d63f 100644 --- a/src/test/ui/issues/issue-21146.stderr +++ b/src/test/ui/issues/issue-21146.stderr @@ -2,7 +2,7 @@ error: expected one of `!` or `::`, found `` --> $DIR/auxiliary/issue-21146-inc.rs:3:1 | LL | parse_error - | ^^^^^^^^^^^ expected one of `!` or `::` here + | ^^^^^^^^^^^ expected one of `!` or `::` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-34334.stderr b/src/test/ui/issues/issue-34334.stderr index 8d52e08374a..a3749487ac9 100644 --- a/src/test/ui/issues/issue-34334.stderr +++ b/src/test/ui/issues/issue-34334.stderr @@ -14,7 +14,7 @@ error: expected one of `,` or `>`, found `=` --> $DIR/issue-34334.rs:2:29 | LL | let sr: Vec<(u32, _, _) = vec![]; - | --- ^ expected one of `,` or `>` here + | --- ^ expected one of `,` or `>` | | | | | help: use `=` if you meant to assign | while parsing the type for `sr` diff --git a/src/test/ui/issues/issue-39616.stderr b/src/test/ui/issues/issue-39616.stderr index 75eb55fa50b..74e94eda51f 100644 --- a/src/test/ui/issues/issue-39616.stderr +++ b/src/test/ui/issues/issue-39616.stderr @@ -8,7 +8,7 @@ error: expected one of `)`, `,`, `->`, `where`, or `{`, found `]` --> $DIR/issue-39616.rs:1:16 | LL | fn foo(a: [0; 1]) {} - | ^ expected one of `)`, `,`, `->`, `where`, or `{` here + | ^ expected one of `)`, `,`, `->`, `where`, or `{` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-44021.stderr b/src/test/ui/issues/issue-44021.stderr index 94500087e55..b888cd989a6 100644 --- a/src/test/ui/issues/issue-44021.stderr +++ b/src/test/ui/issues/issue-44021.stderr @@ -2,7 +2,7 @@ error: expected one of `:`, `@`, or `|`, found `}` --> $DIR/issue-44021.rs:3:18 | LL | fn f() {|x, y} - | ^ expected one of `:`, `@`, or `|` here + | ^ expected one of `:`, `@`, or `|` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-52496.stderr b/src/test/ui/issues/issue-52496.stderr index 43009a15bd4..10fcc46f344 100644 --- a/src/test/ui/issues/issue-52496.stderr +++ b/src/test/ui/issues/issue-52496.stderr @@ -8,7 +8,7 @@ error: expected one of `,` or `}`, found `.` --> $DIR/issue-52496.rs:8:22 | LL | let _ = Foo { bar.into(), bat: -1, . }; - | --- ^ expected one of `,` or `}` here + | --- ^ expected one of `,` or `}` | | | while parsing this struct diff --git a/src/test/ui/issues/issue-58856-2.stderr b/src/test/ui/issues/issue-58856-2.stderr index a83dd674a87..01d70d861e2 100644 --- a/src/test/ui/issues/issue-58856-2.stderr +++ b/src/test/ui/issues/issue-58856-2.stderr @@ -11,7 +11,7 @@ error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pu --> $DIR/issue-58856-2.rs:11:1 | LL | } - | - expected one of 10 possible tokens here + | - expected one of 10 possible tokens LL | } | ^ unexpected token diff --git a/src/test/ui/issues/issue-60075.stderr b/src/test/ui/issues/issue-60075.stderr index 961a546d8d6..39e3ad7b6b4 100644 --- a/src/test/ui/issues/issue-60075.stderr +++ b/src/test/ui/issues/issue-60075.stderr @@ -2,7 +2,7 @@ error: expected one of `.`, `;`, `?`, `else`, or an operator, found `}` --> $DIR/issue-60075.rs:6:10 | LL | }); - | ^ expected one of `.`, `;`, `?`, `else`, or an operator here + | ^ expected one of `.`, `;`, `?`, `else`, or an operator error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `}`, found `;` --> $DIR/issue-60075.rs:6:11 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 80b4329ad40..0036f0f1db0 100644 --- a/src/test/ui/label/label_break_value_illegal_uses.stderr +++ b/src/test/ui/label/label_break_value_illegal_uses.stderr @@ -2,7 +2,7 @@ error: expected one of `extern`, `fn`, or `{`, found `'b` --> $DIR/label_break_value_illegal_uses.rs:6:12 | LL | unsafe 'b: {} - | ^^ expected one of `extern`, `fn`, or `{` here + | ^^ expected one of `extern`, `fn`, or `{` error: expected `{`, found `'b` --> $DIR/label_break_value_illegal_uses.rs:10:13 @@ -27,7 +27,7 @@ error: expected one of `.`, `?`, `{`, or an operator, found `'b` --> $DIR/label_break_value_illegal_uses.rs:18:17 | LL | match false 'b: {} - | ----- ^^ expected one of `.`, `?`, `{`, or an operator here + | ----- ^^ expected one of `.`, `?`, `{`, or an operator | | | while parsing this match expression diff --git a/src/test/ui/macro_backtrace/main.stderr b/src/test/ui/macro_backtrace/main.stderr index e7bd141ccd5..c4950e0fdf5 100644 --- a/src/test/ui/macro_backtrace/main.stderr +++ b/src/test/ui/macro_backtrace/main.stderr @@ -3,7 +3,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found | LL | / macro_rules! pong { LL | | () => { syntax error }; - | | ^^^^^ expected one of 8 possible tokens here + | | ^^^^^ expected one of 8 possible tokens LL | | } | |_- in this expansion of `pong!` ... @@ -15,7 +15,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found | LL | / macro_rules! pong { LL | | () => { syntax error }; - | | ^^^^^ expected one of 8 possible tokens here + | | ^^^^^ expected one of 8 possible tokens LL | | } | |_- in this expansion of `pong!` ... @@ -35,7 +35,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found | LL | / macro_rules! pong { LL | | () => { syntax error }; - | | ^^^^^ expected one of 8 possible tokens here + | | ^^^^^ expected one of 8 possible tokens LL | | } | |_- in this expansion of `pong!` (#5) ... diff --git a/src/test/ui/macros/assert-trailing-junk.stderr b/src/test/ui/macros/assert-trailing-junk.stderr index 6fc0a278461..4d18a531a80 100644 --- a/src/test/ui/macros/assert-trailing-junk.stderr +++ b/src/test/ui/macros/assert-trailing-junk.stderr @@ -2,13 +2,13 @@ error: expected one of `,`, `.`, `?`, or an operator, found `some` --> $DIR/assert-trailing-junk.rs:6:18 | LL | assert!(true some extra junk, "whatever"); - | ^^^^ expected one of `,`, `.`, `?`, or an operator here + | ^^^^ expected one of `,`, `.`, `?`, or an operator error: expected one of `,`, `.`, `?`, or an operator, found `some` --> $DIR/assert-trailing-junk.rs:9:18 | LL | assert!(true some extra junk); - | ^^^^ expected one of `,`, `.`, `?`, or an operator here + | ^^^^ expected one of `,`, `.`, `?`, or an operator error: no rules expected the token `blah` --> $DIR/assert-trailing-junk.rs:12:30 diff --git a/src/test/ui/macros/issue-54441.stderr b/src/test/ui/macros/issue-54441.stderr index 287d579c76d..1139ef06a12 100644 --- a/src/test/ui/macros/issue-54441.stderr +++ b/src/test/ui/macros/issue-54441.stderr @@ -2,7 +2,7 @@ error: expected one of `crate`, `fn`, `pub`, `static`, or `type`, found keyword --> $DIR/issue-54441.rs:3:9 | LL | let - | ^^^ expected one of `crate`, `fn`, `pub`, `static`, or `type` here + | ^^^ expected one of `crate`, `fn`, `pub`, `static`, or `type` ... LL | m!(); | ----- in this macro invocation diff --git a/src/test/ui/malformed/malformed-derive-entry.stderr b/src/test/ui/malformed/malformed-derive-entry.stderr index f7500febe97..8d750b66838 100644 --- a/src/test/ui/malformed/malformed-derive-entry.stderr +++ b/src/test/ui/malformed/malformed-derive-entry.stderr @@ -2,13 +2,13 @@ error: expected one of `)`, `,`, or `::`, found `(` --> $DIR/malformed-derive-entry.rs:1:14 | LL | #[derive(Copy(Bad))] - | ^ expected one of `)`, `,`, or `::` here + | ^ expected one of `)`, `,`, or `::` error: expected one of `)`, `,`, or `::`, found `=` --> $DIR/malformed-derive-entry.rs:4:14 | LL | #[derive(Copy="bad")] - | ^ expected one of `)`, `,`, or `::` here + | ^ expected one of `)`, `,`, or `::` error: malformed `derive` attribute input --> $DIR/malformed-derive-entry.rs:7:1 diff --git a/src/test/ui/mismatched_types/recovered-block.stderr b/src/test/ui/mismatched_types/recovered-block.stderr index 207dc78a4b9..525d09b8fc1 100644 --- a/src/test/ui/mismatched_types/recovered-block.stderr +++ b/src/test/ui/mismatched_types/recovered-block.stderr @@ -13,7 +13,7 @@ error: expected one of `(` or `<`, found `{` --> $DIR/recovered-block.rs:19:9 | LL | Foo { text: "".to_string() } - | ^ expected one of `(` or `<` here + | ^ expected one of `(` or `<` error: aborting due to 2 previous errors diff --git a/src/test/ui/missing/missing-comma-in-match.fixed b/src/test/ui/missing/missing-comma-in-match.fixed index de1b9506af9..f091082f35f 100644 --- a/src/test/ui/missing/missing-comma-in-match.fixed +++ b/src/test/ui/missing/missing-comma-in-match.fixed @@ -5,7 +5,7 @@ fn main() { &None => 1, &Some(2) => { 3 } //~^ ERROR expected one of `,`, `.`, `?`, `}`, or an operator, found `=>` - //~| NOTE expected one of `,`, `.`, `?`, `}`, or an operator here + //~| NOTE expected one of `,`, `.`, `?`, `}`, or an operator _ => 2 }; } diff --git a/src/test/ui/missing/missing-comma-in-match.rs b/src/test/ui/missing/missing-comma-in-match.rs index d7d16155cf2..54dab4e9750 100644 --- a/src/test/ui/missing/missing-comma-in-match.rs +++ b/src/test/ui/missing/missing-comma-in-match.rs @@ -5,7 +5,7 @@ fn main() { &None => 1 &Some(2) => { 3 } //~^ ERROR expected one of `,`, `.`, `?`, `}`, or an operator, found `=>` - //~| NOTE expected one of `,`, `.`, `?`, `}`, or an operator here + //~| NOTE expected one of `,`, `.`, `?`, `}`, or an operator _ => 2 }; } diff --git a/src/test/ui/missing/missing-comma-in-match.stderr b/src/test/ui/missing/missing-comma-in-match.stderr index ae46516f8d1..fe210f697c4 100644 --- a/src/test/ui/missing/missing-comma-in-match.stderr +++ b/src/test/ui/missing/missing-comma-in-match.stderr @@ -4,7 +4,7 @@ error: expected one of `,`, `.`, `?`, `}`, or an operator, found `=>` LL | &None => 1 | - help: missing a comma here to end this `match` arm LL | &Some(2) => { 3 } - | ^^ expected one of `,`, `.`, `?`, `}`, or an operator here + | ^^ expected one of `,`, `.`, `?`, `}`, or an operator error: aborting due to previous error diff --git a/src/test/ui/on-unimplemented/expected-comma-found-token.stderr b/src/test/ui/on-unimplemented/expected-comma-found-token.stderr index 5bbdbe29416..738bf7c6c6b 100644 --- a/src/test/ui/on-unimplemented/expected-comma-found-token.stderr +++ b/src/test/ui/on-unimplemented/expected-comma-found-token.stderr @@ -2,7 +2,7 @@ error: expected one of `)` or `,`, found `label` --> $DIR/expected-comma-found-token.rs:9:5 | LL | message="the message" - | - expected one of `)` or `,` here + | - expected one of `)` or `,` LL | label="the label" | ^^^^^ unexpected token diff --git a/src/test/ui/parser/assoc-oddities-1.stderr b/src/test/ui/parser/assoc-oddities-1.stderr index 376ddf4d68b..acf71b4893a 100644 --- a/src/test/ui/parser/assoc-oddities-1.stderr +++ b/src/test/ui/parser/assoc-oddities-1.stderr @@ -2,7 +2,7 @@ error: expected one of `.`, `;`, `?`, or `}`, found `[` --> $DIR/assoc-oddities-1.rs:10:28 | LL | ..if c { a } else { b }[n]; - | ^ expected one of `.`, `;`, `?`, or `}` here + | ^ expected one of `.`, `;`, `?`, or `}` error: aborting due to previous error diff --git a/src/test/ui/parser/assoc-oddities-2.stderr b/src/test/ui/parser/assoc-oddities-2.stderr index 4b3893d2c17..d3b90c34c29 100644 --- a/src/test/ui/parser/assoc-oddities-2.stderr +++ b/src/test/ui/parser/assoc-oddities-2.stderr @@ -2,7 +2,7 @@ error: expected one of `.`, `;`, `?`, or `}`, found `[` --> $DIR/assoc-oddities-2.rs:5:29 | LL | x..if c { a } else { b }[n]; - | ^ expected one of `.`, `;`, `?`, or `}` here + | ^ expected one of `.`, `;`, `?`, or `}` error: aborting due to previous error diff --git a/src/test/ui/parser/associated-types-project-from-hrtb-explicit.stderr b/src/test/ui/parser/associated-types-project-from-hrtb-explicit.stderr index 7d0bb0965b6..17bd5b54738 100644 --- a/src/test/ui/parser/associated-types-project-from-hrtb-explicit.stderr +++ b/src/test/ui/parser/associated-types-project-from-hrtb-explicit.stderr @@ -13,7 +13,7 @@ error: expected one of `::` or `>`, found `Foo` --> $DIR/associated-types-project-from-hrtb-explicit.rs:10:29 | LL | fn foo2(x: Foo<&'x isize>>::A) - | ^^^ expected one of `::` or `>` here + | ^^^ expected one of `::` or `>` error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/attr-bad-meta.stderr b/src/test/ui/parser/attr-bad-meta.stderr index a452df5e90c..8d65c423c8d 100644 --- a/src/test/ui/parser/attr-bad-meta.stderr +++ b/src/test/ui/parser/attr-bad-meta.stderr @@ -2,7 +2,7 @@ error: expected one of `(`, `::`, `=`, `[`, `]`, or `{`, found `*` --> $DIR/attr-bad-meta.rs:1:7 | LL | #[path*] - | ^ expected one of `(`, `::`, `=`, `[`, `]`, or `{` here + | ^ expected one of `(`, `::`, `=`, `[`, `]`, or `{` error: aborting due to previous error diff --git a/src/test/ui/parser/bad-match.stderr b/src/test/ui/parser/bad-match.stderr index d5baaf5e93b..13784c409cd 100644 --- a/src/test/ui/parser/bad-match.stderr +++ b/src/test/ui/parser/bad-match.stderr @@ -2,7 +2,7 @@ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `x` --> $DIR/bad-match.rs:2:13 | LL | let isize x = 5; - | ^ expected one of `:`, `;`, `=`, `@`, or `|` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` error: aborting due to previous error diff --git a/src/test/ui/parser/bad-name.stderr b/src/test/ui/parser/bad-name.stderr index dce4dabedf5..a36b67794fa 100644 --- a/src/test/ui/parser/bad-name.stderr +++ b/src/test/ui/parser/bad-name.stderr @@ -2,7 +2,7 @@ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `.` --> $DIR/bad-name.rs:4:8 | LL | let x.y::.z foo; - | ^ expected one of `:`, `;`, `=`, `@`, or `|` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` error: aborting due to previous error diff --git a/src/test/ui/parser/better-expected.stderr b/src/test/ui/parser/better-expected.stderr index d100d01e78f..21bf8d19a72 100644 --- a/src/test/ui/parser/better-expected.stderr +++ b/src/test/ui/parser/better-expected.stderr @@ -2,7 +2,7 @@ error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `3` --> $DIR/better-expected.rs:2:19 | LL | let x: [isize 3]; - | - ^ expected one of 7 possible tokens here + | - ^ expected one of 7 possible tokens | | | while parsing the type for `x` diff --git a/src/test/ui/parser/bounds-lifetime-1.stderr b/src/test/ui/parser/bounds-lifetime-1.stderr index 17d65314d96..000e84f635b 100644 --- a/src/test/ui/parser/bounds-lifetime-1.stderr +++ b/src/test/ui/parser/bounds-lifetime-1.stderr @@ -2,7 +2,7 @@ error: expected one of `,`, `:`, or `>`, found `'b` --> $DIR/bounds-lifetime-1.rs:1:17 | LL | type A = for<'a 'b> fn(); - | ^^ expected one of `,`, `:`, or `>` here + | ^^ expected one of `,`, `:`, or `>` error: aborting due to previous error diff --git a/src/test/ui/parser/bounds-lifetime-2.stderr b/src/test/ui/parser/bounds-lifetime-2.stderr index 587e527f0a8..dd3e69c1139 100644 --- a/src/test/ui/parser/bounds-lifetime-2.stderr +++ b/src/test/ui/parser/bounds-lifetime-2.stderr @@ -2,7 +2,7 @@ error: expected one of `,`, `:`, or `>`, found `+` --> $DIR/bounds-lifetime-2.rs:1:17 | LL | type A = for<'a + 'b> fn(); - | ^ expected one of `,`, `:`, or `>` here + | ^ expected one of `,`, `:`, or `>` error: aborting due to previous error diff --git a/src/test/ui/parser/bounds-lifetime-where.stderr b/src/test/ui/parser/bounds-lifetime-where.stderr index 9507a459858..05cebd6d351 100644 --- a/src/test/ui/parser/bounds-lifetime-where.stderr +++ b/src/test/ui/parser/bounds-lifetime-where.stderr @@ -2,7 +2,7 @@ error: expected one of `=`, lifetime, or type, found `,` --> $DIR/bounds-lifetime-where.rs:8:14 | LL | type A where , = u8; - | ^ expected one of `=`, lifetime, or type here + | ^ expected one of `=`, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/parser/bounds-lifetime.stderr b/src/test/ui/parser/bounds-lifetime.stderr index facbd280070..12b9b61ebd1 100644 --- a/src/test/ui/parser/bounds-lifetime.stderr +++ b/src/test/ui/parser/bounds-lifetime.stderr @@ -2,7 +2,7 @@ error: expected one of `>`, `const`, identifier, or lifetime, found `,` --> $DIR/bounds-lifetime.rs:9:14 | LL | type A = for<,> fn(); - | ^ expected one of `>`, `const`, identifier, or lifetime here + | ^ expected one of `>`, `const`, identifier, or lifetime error: aborting due to previous error diff --git a/src/test/ui/parser/bounds-type-where.stderr b/src/test/ui/parser/bounds-type-where.stderr index 459d5c3b6ea..5636ee75c97 100644 --- a/src/test/ui/parser/bounds-type-where.stderr +++ b/src/test/ui/parser/bounds-type-where.stderr @@ -2,7 +2,7 @@ error: expected one of `!`, `(`, `+`, `::`, `:`, `<`, `==`, or `=`, found `,` --> $DIR/bounds-type-where.rs:8:15 | LL | type A where T, = u8; - | ^ expected one of 8 possible tokens here + | ^ expected one of 8 possible tokens error: aborting due to previous error diff --git a/src/test/ui/parser/class-implements-bad-trait.stderr b/src/test/ui/parser/class-implements-bad-trait.stderr index 45583466adc..3a4dea95d5d 100644 --- a/src/test/ui/parser/class-implements-bad-trait.stderr +++ b/src/test/ui/parser/class-implements-bad-trait.stderr @@ -2,7 +2,7 @@ error: expected one of `!` or `::`, found `cat` --> $DIR/class-implements-bad-trait.rs:2:7 | LL | class cat : nonexistent { - | ^^^ expected one of `!` or `::` here + | ^^^ expected one of `!` or `::` error: aborting due to previous error diff --git a/src/test/ui/parser/closure-return-syntax.stderr b/src/test/ui/parser/closure-return-syntax.stderr index dd7ebffd506..bfb7f98c5f5 100644 --- a/src/test/ui/parser/closure-return-syntax.stderr +++ b/src/test/ui/parser/closure-return-syntax.stderr @@ -2,7 +2,7 @@ error: expected one of `!`, `(`, `+`, `::`, `<`, or `{`, found `22` --> $DIR/closure-return-syntax.rs:5:23 | LL | let x = || -> i32 22; - | ^^ expected one of `!`, `(`, `+`, `::`, `<`, or `{` here + | ^^ expected one of `!`, `(`, `+`, `::`, `<`, or `{` error: aborting due to previous error diff --git a/src/test/ui/parser/default.stderr b/src/test/ui/parser/default.stderr index 8843fd303ec..dde36cf8dde 100644 --- a/src/test/ui/parser/default.stderr +++ b/src/test/ui/parser/default.stderr @@ -2,7 +2,7 @@ error: expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`, fo --> $DIR/default.rs:22:13 | LL | default pub fn foo() -> T { T::default() } - | ^^^ expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe` here + | ^^^ expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe` error[E0449]: unnecessary visibility qualifier --> $DIR/default.rs:16:5 diff --git a/src/test/ui/parser/duplicate-visibility.stderr b/src/test/ui/parser/duplicate-visibility.stderr index 675adb88d20..313e88e812b 100644 --- a/src/test/ui/parser/duplicate-visibility.stderr +++ b/src/test/ui/parser/duplicate-visibility.stderr @@ -2,7 +2,7 @@ error: expected one of `(`, `fn`, `static`, or `type`, found keyword `pub` --> $DIR/duplicate-visibility.rs:3:9 | LL | pub pub fn foo(); - | ^^^ expected one of `(`, `fn`, `static`, or `type` here + | ^^^ expected one of `(`, `fn`, `static`, or `type` error: aborting due to previous error diff --git a/src/test/ui/parser/empty-impl-semicolon.stderr b/src/test/ui/parser/empty-impl-semicolon.stderr index 46f2393cd83..398eb5c898c 100644 --- a/src/test/ui/parser/empty-impl-semicolon.stderr +++ b/src/test/ui/parser/empty-impl-semicolon.stderr @@ -2,7 +2,7 @@ error: expected one of `!`, `(`, `+`, `::`, `<`, `for`, `where`, or `{`, found ` --> $DIR/empty-impl-semicolon.rs:1:9 | LL | impl Foo; - | ^ expected one of 8 possible tokens here + | ^ expected one of 8 possible tokens error: aborting due to previous error diff --git a/src/test/ui/parser/extern-crate-unexpected-token.stderr b/src/test/ui/parser/extern-crate-unexpected-token.stderr index 04edd46936a..0e745dc582f 100644 --- a/src/test/ui/parser/extern-crate-unexpected-token.stderr +++ b/src/test/ui/parser/extern-crate-unexpected-token.stderr @@ -2,7 +2,7 @@ error: expected one of `crate`, `fn`, or `{`, found `crte` --> $DIR/extern-crate-unexpected-token.rs:1:8 | LL | extern crte foo; - | ^^^^ expected one of `crate`, `fn`, or `{` here + | ^^^^ expected one of `crate`, `fn`, or `{` error: aborting due to previous error 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 691f4cddff2..0ebe9a0d3ea 100644 --- a/src/test/ui/parser/extern-expected-fn-or-brace.stderr +++ b/src/test/ui/parser/extern-expected-fn-or-brace.stderr @@ -2,7 +2,7 @@ error: expected one of `fn` or `{`, found keyword `mod` --> $DIR/extern-expected-fn-or-brace.rs:4:12 | LL | extern "C" mod foo; - | ^^^ expected one of `fn` or `{` here + | ^^^ expected one of `fn` or `{` error: aborting due to previous error diff --git a/src/test/ui/parser/extern-foreign-crate.stderr b/src/test/ui/parser/extern-foreign-crate.stderr index de9f0c93232..eb75c0fc9c6 100644 --- a/src/test/ui/parser/extern-foreign-crate.stderr +++ b/src/test/ui/parser/extern-foreign-crate.stderr @@ -2,7 +2,7 @@ error: expected one of `;` or `as`, found `{` --> $DIR/extern-foreign-crate.rs:4:18 | LL | extern crate foo {} - | ^ expected one of `;` or `as` here + | ^ expected one of `;` or `as` error: aborting due to previous error diff --git a/src/test/ui/parser/inverted-parameters.stderr b/src/test/ui/parser/inverted-parameters.stderr index 2bda4460031..51e9087ffc1 100644 --- a/src/test/ui/parser/inverted-parameters.stderr +++ b/src/test/ui/parser/inverted-parameters.stderr @@ -4,7 +4,7 @@ error: expected one of `:`, `@`, or `|`, found `bar` LL | fn foo(&self, &str bar) {} | -----^^^ | | | - | | expected one of `:`, `@`, or `|` here + | | expected one of `:`, `@`, or `|` | help: declare the type after the parameter binding: `: ` error: expected one of `:`, `@`, or `|`, found `quux` @@ -13,26 +13,26 @@ error: expected one of `:`, `@`, or `|`, found `quux` LL | fn baz(S quux, xyzzy: i32) {} | --^^^^ | | | - | | expected one of `:`, `@`, or `|` here + | | expected one of `:`, `@`, or `|` | help: declare the type after the parameter binding: `: ` error: expected one of `:`, `@`, or `|`, found `a` --> $DIR/inverted-parameters.rs:15:12 | LL | fn one(i32 a b) {} - | ^ expected one of `:`, `@`, or `|` here + | ^ expected one of `:`, `@`, or `|` error: expected one of `:` or `|`, found `(` --> $DIR/inverted-parameters.rs:18:23 | LL | fn pattern((i32, i32) (a, b)) {} - | ^ expected one of `:` or `|` here + | ^ expected one of `:` or `|` error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/inverted-parameters.rs:21:12 | LL | fn fizz(i32) {} - | ^ expected one of `:`, `@`, or `|` here + | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type @@ -50,7 +50,7 @@ error: expected one of `:`, `@`, or `|`, found `S` LL | fn missing_colon(quux S) {} | -----^ | | | - | | expected one of `:`, `@`, or `|` here + | | expected one of `:`, `@`, or `|` | help: declare the type after the parameter binding: `: ` error: aborting due to 6 previous errors diff --git a/src/test/ui/parser/issue-15980.rs b/src/test/ui/parser/issue-15980.rs index beb94c8042d..87faa7d5ff1 100644 --- a/src/test/ui/parser/issue-15980.rs +++ b/src/test/ui/parser/issue-15980.rs @@ -9,7 +9,7 @@ fn main(){ //~^ ERROR expected identifier, found keyword `return` //~| NOTE expected identifier, found keyword } - //~^ NOTE expected one of `.`, `=>`, `?`, or an operator here + //~^ NOTE expected one of `.`, `=>`, `?`, or an operator _ => {} //~^ ERROR expected one of `.`, `=>`, `?`, or an operator, found reserved identifier `_` //~| NOTE unexpected token diff --git a/src/test/ui/parser/issue-15980.stderr b/src/test/ui/parser/issue-15980.stderr index 26f75d45fa2..5cefead2c74 100644 --- a/src/test/ui/parser/issue-15980.stderr +++ b/src/test/ui/parser/issue-15980.stderr @@ -16,7 +16,7 @@ error: expected one of `.`, `=>`, `?`, or an operator, found reserved identifier --> $DIR/issue-15980.rs:13:9 | LL | } - | - expected one of `.`, `=>`, `?`, or an operator here + | - expected one of `.`, `=>`, `?`, or an operator LL | LL | _ => {} | ^ unexpected token diff --git a/src/test/ui/parser/issue-17904.stderr b/src/test/ui/parser/issue-17904.stderr index 38f30099ed5..a3cac676189 100644 --- a/src/test/ui/parser/issue-17904.stderr +++ b/src/test/ui/parser/issue-17904.stderr @@ -2,7 +2,7 @@ error: expected one of `:`, `==`, or `=`, found `;` --> $DIR/issue-17904.rs:4:33 | LL | struct Foo where T: Copy, (T); - | ^ expected one of `:`, `==`, or `=` here + | ^ expected one of `:`, `==`, or `=` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-19096.stderr b/src/test/ui/parser/issue-19096.stderr index 957b40dbd5e..4df7f878b9e 100644 --- a/src/test/ui/parser/issue-19096.stderr +++ b/src/test/ui/parser/issue-19096.stderr @@ -2,13 +2,13 @@ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `::` --> $DIR/issue-19096.rs:3:8 | LL | t.0::; - | ^^ expected one of `.`, `;`, `?`, `}`, or an operator here + | ^^ expected one of `.`, `;`, `?`, `}`, or an operator error: expected one of `.`, `;`, `?`, `}`, or an operator, found `::` --> $DIR/issue-19096.rs:8:8 | LL | t.0::; - | ^^ expected one of `.`, `;`, `?`, `}`, or an operator here + | ^^ expected one of `.`, `;`, `?`, `}`, or an operator error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/issue-20711-2.stderr b/src/test/ui/parser/issue-20711-2.stderr index 56749c107d1..ee484890fad 100644 --- a/src/test/ui/parser/issue-20711-2.stderr +++ b/src/test/ui/parser/issue-20711-2.stderr @@ -2,7 +2,7 @@ error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pu --> $DIR/issue-20711-2.rs:7:1 | LL | #[stable(feature = "rust1", since = "1.0.0")] - | - expected one of 9 possible tokens here + | - expected one of 9 possible tokens LL | } | ^ unexpected token diff --git a/src/test/ui/parser/issue-20711.stderr b/src/test/ui/parser/issue-20711.stderr index f7b99a91b51..152c9f1c689 100644 --- a/src/test/ui/parser/issue-20711.stderr +++ b/src/test/ui/parser/issue-20711.stderr @@ -2,7 +2,7 @@ error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pu --> $DIR/issue-20711.rs:5:1 | LL | #[stable(feature = "rust1", since = "1.0.0")] - | - expected one of 9 possible tokens here + | - expected one of 9 possible tokens LL | } | ^ unexpected token diff --git a/src/test/ui/parser/issue-22647.stderr b/src/test/ui/parser/issue-22647.stderr index 4b1ef4f3dfc..89b454d1973 100644 --- a/src/test/ui/parser/issue-22647.stderr +++ b/src/test/ui/parser/issue-22647.stderr @@ -2,7 +2,7 @@ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `<` --> $DIR/issue-22647.rs:2:15 | LL | let caller = |f: F| - | ^ expected one of `:`, `;`, `=`, `@`, or `|` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-22712.stderr b/src/test/ui/parser/issue-22712.stderr index d9e83144b36..30fabac6564 100644 --- a/src/test/ui/parser/issue-22712.stderr +++ b/src/test/ui/parser/issue-22712.stderr @@ -2,7 +2,7 @@ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `<` --> $DIR/issue-22712.rs:6:12 | LL | let Foo> - | ^ expected one of `:`, `;`, `=`, `@`, or `|` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-24197.stderr b/src/test/ui/parser/issue-24197.stderr index 24818db622a..fd7015ccd39 100644 --- a/src/test/ui/parser/issue-24197.stderr +++ b/src/test/ui/parser/issue-24197.stderr @@ -2,7 +2,7 @@ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` --> $DIR/issue-24197.rs:2:12 | LL | let buf[0] = 0; - | ^ expected one of `:`, `;`, `=`, `@`, or `|` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-24375.stderr b/src/test/ui/parser/issue-24375.stderr index e45b08be9ab..7aed88768a0 100644 --- a/src/test/ui/parser/issue-24375.stderr +++ b/src/test/ui/parser/issue-24375.stderr @@ -2,7 +2,7 @@ error: expected one of `=>`, `@`, `if`, or `|`, found `[` --> $DIR/issue-24375.rs:6:12 | LL | tmp[0] => {} - | ^ expected one of `=>`, `@`, `if`, or `|` here + | ^ expected one of `=>`, `@`, `if`, or `|` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-24780.stderr b/src/test/ui/parser/issue-24780.stderr index 469c034795e..d9470191b25 100644 --- a/src/test/ui/parser/issue-24780.stderr +++ b/src/test/ui/parser/issue-24780.stderr @@ -2,7 +2,7 @@ error: expected one of `!`, `+`, `::`, `where`, or `{`, found `>` --> $DIR/issue-24780.rs:5:23 | LL | fn foo() -> Vec> { - | ^ expected one of `!`, `+`, `::`, `where`, or `{` here + | ^ expected one of `!`, `+`, `::`, `where`, or `{` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-32446.stderr b/src/test/ui/parser/issue-32446.stderr index b0c18f4ec5a..ab37dd7c39d 100644 --- a/src/test/ui/parser/issue-32446.stderr +++ b/src/test/ui/parser/issue-32446.stderr @@ -2,7 +2,7 @@ error: expected one of `async`, `const`, `extern`, `fn`, `type`, `unsafe`, or `} --> $DIR/issue-32446.rs:4:11 | LL | trait T { ... } - | ^^^ expected one of 7 possible tokens here + | ^^^ expected one of 7 possible tokens error: aborting due to previous error diff --git a/src/test/ui/parser/issue-33455.stderr b/src/test/ui/parser/issue-33455.stderr index 4516c388afc..c535ef23b22 100644 --- a/src/test/ui/parser/issue-33455.stderr +++ b/src/test/ui/parser/issue-33455.stderr @@ -2,7 +2,7 @@ error: expected one of `::`, `;`, or `as`, found `.` --> $DIR/issue-33455.rs:1:8 | LL | use foo.bar; - | ^ expected one of `::`, `;`, or `as` here + | ^ expected one of `::`, `;`, or `as` error: aborting due to previous error diff --git a/src/test/ui/parser/issue-41155.stderr b/src/test/ui/parser/issue-41155.stderr index 624d1a3d11e..0e191eb7e0a 100644 --- a/src/test/ui/parser/issue-41155.stderr +++ b/src/test/ui/parser/issue-41155.stderr @@ -2,7 +2,7 @@ error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `type`, --> $DIR/issue-41155.rs:5:1 | LL | pub - | - expected one of 8 possible tokens here + | - expected one of 8 possible tokens LL | } | ^ unexpected token diff --git a/src/test/ui/parser/issue-62660.stderr b/src/test/ui/parser/issue-62660.stderr index 3a8f6797b82..0844da1bd92 100644 --- a/src/test/ui/parser/issue-62660.stderr +++ b/src/test/ui/parser/issue-62660.stderr @@ -2,7 +2,7 @@ error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `)` --> $DIR/issue-62660.rs:7:38 | LL | pub fn foo(_: i32, self: Box $DIR/issue-62973.rs:6:25 | LL | fn p() { match s { v, E { [) {) } - | - - -^ expected one of `,` or `}` here + | - - -^ expected one of `,` or `}` | | | | | | | help: `}` may belong here | | while parsing this struct @@ -42,7 +42,7 @@ LL | fn p() { match s { v, E { [) {) } | ----- while parsing this match expression LL | LL | - | ^ expected one of `.`, `?`, `{`, or an operator here + | ^ expected one of `.`, `?`, `{`, or an operator error: incorrect close delimiter: `)` --> $DIR/issue-62973.rs:6:28 diff --git a/src/test/ui/parser/issue-63135.stderr b/src/test/ui/parser/issue-63135.stderr index 8e8087978a3..152601b3538 100644 --- a/src/test/ui/parser/issue-63135.stderr +++ b/src/test/ui/parser/issue-63135.stderr @@ -32,7 +32,7 @@ error: expected one of `:` or `|`, found `)` --> $DIR/issue-63135.rs:3:16 | LL | fn i(n{...,f # - | ^ expected one of `:` or `|` here + | ^ expected one of `:` or `|` error: aborting due to 5 previous errors diff --git a/src/test/ui/parser/lifetime-semicolon.stderr b/src/test/ui/parser/lifetime-semicolon.stderr index 71ed8200e9a..4641c286cb8 100644 --- a/src/test/ui/parser/lifetime-semicolon.stderr +++ b/src/test/ui/parser/lifetime-semicolon.stderr @@ -2,7 +2,7 @@ error: expected one of `,` or `>`, found `;` --> $DIR/lifetime-semicolon.rs:5:30 | LL | fn foo<'a, 'b>(x: &mut Foo<'a; 'b>) {} - | ^ expected one of `,` or `>` here + | ^ expected one of `,` or `>` error: aborting due to previous error diff --git a/src/test/ui/parser/macro/issue-37234.stderr b/src/test/ui/parser/macro/issue-37234.stderr index 004de9d905f..8cef5ae3758 100644 --- a/src/test/ui/parser/macro/issue-37234.stderr +++ b/src/test/ui/parser/macro/issue-37234.stderr @@ -2,7 +2,7 @@ error: expected one of `.`, `;`, `?`, or an operator, found `""` --> $DIR/issue-37234.rs:3:19 | LL | let x = 5 ""; - | ^^ expected one of `.`, `;`, `?`, or an operator here + | ^^ expected one of `.`, `;`, `?`, or an operator ... LL | failed!(); | ---------- in this macro invocation diff --git a/src/test/ui/parser/macro/macro-incomplete-parse.stderr b/src/test/ui/parser/macro/macro-incomplete-parse.stderr index e40919cda94..46cccba74c0 100644 --- a/src/test/ui/parser/macro/macro-incomplete-parse.stderr +++ b/src/test/ui/parser/macro/macro-incomplete-parse.stderr @@ -13,7 +13,7 @@ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,` --> $DIR/macro-incomplete-parse.rs:10:14 | LL | () => ( 1, - | ^ expected one of `.`, `;`, `?`, `}`, or an operator here + | ^ expected one of `.`, `;`, `?`, `}`, or an operator ... LL | ignored_expr!(); | ---------------- in this macro invocation diff --git a/src/test/ui/parser/macro/trait-non-item-macros.stderr b/src/test/ui/parser/macro/trait-non-item-macros.stderr index a953e23a710..dd97a3afa99 100644 --- a/src/test/ui/parser/macro/trait-non-item-macros.stderr +++ b/src/test/ui/parser/macro/trait-non-item-macros.stderr @@ -2,7 +2,7 @@ error: expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe`, fo --> $DIR/trait-non-item-macros.rs:2:19 | LL | ($a:expr) => ($a) - | ^^ expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe` here + | ^^ expected one of `async`, `const`, `extern`, `fn`, `type`, or `unsafe` ... LL | bah!(2); | -------- in this macro invocation diff --git a/src/test/ui/parser/macros-no-semicolon.stderr b/src/test/ui/parser/macros-no-semicolon.stderr index 09925eae51d..9492191b8df 100644 --- a/src/test/ui/parser/macros-no-semicolon.stderr +++ b/src/test/ui/parser/macros-no-semicolon.stderr @@ -2,7 +2,7 @@ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `assert_eq` --> $DIR/macros-no-semicolon.rs:3:5 | LL | assert_eq!(1, 2) - | - expected one of `.`, `;`, `?`, `}`, or an operator here + | - expected one of `.`, `;`, `?`, `}`, or an operator LL | assert_eq!(3, 4) | ^^^^^^^^^ unexpected token diff --git a/src/test/ui/parser/match-refactor-to-expr.rs b/src/test/ui/parser/match-refactor-to-expr.rs index 09ebb2e1d83..e10ebf2e2d6 100644 --- a/src/test/ui/parser/match-refactor-to-expr.rs +++ b/src/test/ui/parser/match-refactor-to-expr.rs @@ -2,7 +2,7 @@ fn main() { let foo = match //~ NOTE while parsing this match expression Some(4).unwrap_or_else(5) - //~^ NOTE expected one of `.`, `?`, `{`, or an operator here + //~^ NOTE expected one of `.`, `?`, `{`, or an operator ; //~ NOTE unexpected token //~^ ERROR expected one of `.`, `?`, `{`, or an operator, found `;` diff --git a/src/test/ui/parser/match-refactor-to-expr.stderr b/src/test/ui/parser/match-refactor-to-expr.stderr index bf20bc93500..5cbf0232bc3 100644 --- a/src/test/ui/parser/match-refactor-to-expr.stderr +++ b/src/test/ui/parser/match-refactor-to-expr.stderr @@ -7,7 +7,7 @@ LL | match | while parsing this match expression | help: try removing this `match` LL | Some(4).unwrap_or_else(5) - | - expected one of `.`, `?`, `{`, or an operator here + | - expected one of `.`, `?`, `{`, or an operator LL | LL | ; | ^ unexpected token diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr index 9bf54181a07..e1aed8a6b4e 100644 --- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-impl-trait.stderr @@ -16,7 +16,7 @@ LL | LL | fn foo(&self) {} | - | | - | expected one of 10 possible tokens here + | expected one of 10 possible tokens | help: `}` may belong here LL | LL | trait T { diff --git a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr index 4bfb4c1cb3a..1bd8e445fad 100644 --- a/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr +++ b/src/test/ui/parser/mismatched-braces/missing-close-brace-in-trait.stderr @@ -15,7 +15,7 @@ LL | trait T { LL | fn foo(&self); | - | | - | expected one of 7 possible tokens here + | expected one of 7 possible tokens | help: `}` may belong here LL | LL | pub(crate) struct Bar(); diff --git a/src/test/ui/parser/missing_right_paren.stderr b/src/test/ui/parser/missing_right_paren.stderr index fc75b031e76..ac16ebe6412 100644 --- a/src/test/ui/parser/missing_right_paren.stderr +++ b/src/test/ui/parser/missing_right_paren.stderr @@ -11,7 +11,7 @@ error: expected one of `:` or `|`, found `)` --> $DIR/missing_right_paren.rs:3:11 | LL | fn main((ؼ - | ^ expected one of `:` or `|` here + | ^ expected one of `:` or `|` error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/multitrait.stderr b/src/test/ui/parser/multitrait.stderr index 61dbc823848..5a8bb2f7a45 100644 --- a/src/test/ui/parser/multitrait.stderr +++ b/src/test/ui/parser/multitrait.stderr @@ -2,7 +2,7 @@ error: expected one of `!`, `(`, `+`, `::`, `<`, `for`, `where`, or `{`, found ` --> $DIR/multitrait.rs:5:9 | LL | impl Cmp, ToString for S { - | ^ expected one of 8 possible tokens here + | ^ expected one of 8 possible tokens error: aborting due to previous error diff --git a/src/test/ui/parser/not-a-pred.stderr b/src/test/ui/parser/not-a-pred.stderr index 46d6038e802..90246b92bf0 100644 --- a/src/test/ui/parser/not-a-pred.stderr +++ b/src/test/ui/parser/not-a-pred.stderr @@ -2,7 +2,7 @@ error: expected one of `->`, `where`, or `{`, found `:` --> $DIR/not-a-pred.rs:3:26 | LL | fn f(a: isize, b: isize) : lt(a, b) { } - | ^ expected one of `->`, `where`, or `{` here + | ^ expected one of `->`, `where`, or `{` error: aborting due to previous error diff --git a/src/test/ui/parser/omitted-arg-in-item-fn.stderr b/src/test/ui/parser/omitted-arg-in-item-fn.stderr index 7feb15592c5..c7c76a7f1d4 100644 --- a/src/test/ui/parser/omitted-arg-in-item-fn.stderr +++ b/src/test/ui/parser/omitted-arg-in-item-fn.stderr @@ -2,7 +2,7 @@ error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/omitted-arg-in-item-fn.rs:1:9 | LL | fn foo(x) { - | ^ expected one of `:`, `@`, or `|` here + | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type diff --git a/src/test/ui/parser/pat-lt-bracket-1.stderr b/src/test/ui/parser/pat-lt-bracket-1.stderr index 1bf27161513..e8ccbad668a 100644 --- a/src/test/ui/parser/pat-lt-bracket-1.stderr +++ b/src/test/ui/parser/pat-lt-bracket-1.stderr @@ -2,7 +2,7 @@ error: expected one of `=>`, `@`, `if`, or `|`, found `<` --> $DIR/pat-lt-bracket-1.rs:3:7 | LL | x < 7 => (), - | ^ expected one of `=>`, `@`, `if`, or `|` here + | ^ expected one of `=>`, `@`, `if`, or `|` error: aborting due to previous error diff --git a/src/test/ui/parser/pat-lt-bracket-2.stderr b/src/test/ui/parser/pat-lt-bracket-2.stderr index 2191e31ad1f..e51dd57f9c7 100644 --- a/src/test/ui/parser/pat-lt-bracket-2.stderr +++ b/src/test/ui/parser/pat-lt-bracket-2.stderr @@ -2,7 +2,7 @@ error: expected one of `:`, `@`, or `|`, found `<` --> $DIR/pat-lt-bracket-2.rs:1:7 | LL | fn a(B<) {} - | ^ expected one of `:`, `@`, or `|` here + | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this is a type, explicitly ignore the parameter name diff --git a/src/test/ui/parser/pat-lt-bracket-3.stderr b/src/test/ui/parser/pat-lt-bracket-3.stderr index 536d14e1b65..bacf868e3c4 100644 --- a/src/test/ui/parser/pat-lt-bracket-3.stderr +++ b/src/test/ui/parser/pat-lt-bracket-3.stderr @@ -2,7 +2,7 @@ error: expected one of `=>`, `@`, `if`, or `|`, found `<` --> $DIR/pat-lt-bracket-3.rs:6:16 | LL | Foo(x, y) => { - | ^ expected one of `=>`, `@`, `if`, or `|` here + | ^ expected one of `=>`, `@`, `if`, or `|` error: aborting due to previous error diff --git a/src/test/ui/parser/pat-lt-bracket-4.stderr b/src/test/ui/parser/pat-lt-bracket-4.stderr index d14702acee6..911c276b931 100644 --- a/src/test/ui/parser/pat-lt-bracket-4.stderr +++ b/src/test/ui/parser/pat-lt-bracket-4.stderr @@ -2,7 +2,7 @@ error: expected one of `=>`, `@`, `if`, or `|`, found `<` --> $DIR/pat-lt-bracket-4.rs:8:12 | LL | Foo::A(value) => value, - | ^ expected one of `=>`, `@`, `if`, or `|` here + | ^ expected one of `=>`, `@`, `if`, or `|` error: aborting due to previous error diff --git a/src/test/ui/parser/pat-lt-bracket-5.stderr b/src/test/ui/parser/pat-lt-bracket-5.stderr index 167314dde06..e23674bcec5 100644 --- a/src/test/ui/parser/pat-lt-bracket-5.stderr +++ b/src/test/ui/parser/pat-lt-bracket-5.stderr @@ -2,7 +2,7 @@ error: expected one of `:`, `;`, `=`, `@`, or `|`, found `[` --> $DIR/pat-lt-bracket-5.rs:2:10 | LL | let v[0] = v[1]; - | ^ expected one of `:`, `;`, `=`, `@`, or `|` here + | ^ expected one of `:`, `;`, `=`, `@`, or `|` error: aborting due to previous error diff --git a/src/test/ui/parser/pat-lt-bracket-6.stderr b/src/test/ui/parser/pat-lt-bracket-6.stderr index 6f08f0a9d95..234e0c37723 100644 --- a/src/test/ui/parser/pat-lt-bracket-6.stderr +++ b/src/test/ui/parser/pat-lt-bracket-6.stderr @@ -2,7 +2,7 @@ error: expected one of `)`, `,`, `@`, or `|`, found `[` --> $DIR/pat-lt-bracket-6.rs:5:19 | LL | let Test(&desc[..]) = x; - | ^ expected one of `)`, `,`, `@`, or `|` here + | ^ expected one of `)`, `,`, `@`, or `|` error[E0658]: subslice patterns are unstable --> $DIR/pat-lt-bracket-6.rs:5:20 diff --git a/src/test/ui/parser/pat-lt-bracket-7.stderr b/src/test/ui/parser/pat-lt-bracket-7.stderr index 196f1c0ae91..86693ac27bd 100644 --- a/src/test/ui/parser/pat-lt-bracket-7.stderr +++ b/src/test/ui/parser/pat-lt-bracket-7.stderr @@ -2,7 +2,7 @@ error: expected one of `)`, `,`, `@`, or `|`, found `[` --> $DIR/pat-lt-bracket-7.rs:5:16 | LL | for Thing(x[]) in foo {} - | ^ expected one of `)`, `,`, `@`, or `|` here + | ^ expected one of `)`, `,`, `@`, or `|` error[E0308]: mismatched types --> $DIR/pat-lt-bracket-7.rs:9:30 diff --git a/src/test/ui/parser/pat-ranges-1.stderr b/src/test/ui/parser/pat-ranges-1.stderr index 4e2c5d28381..b64a3ce5c08 100644 --- a/src/test/ui/parser/pat-ranges-1.stderr +++ b/src/test/ui/parser/pat-ranges-1.stderr @@ -2,7 +2,7 @@ error: expected one of `:`, `;`, `=`, or `|`, found `..=` --> $DIR/pat-ranges-1.rs:4:21 | LL | let macropus!() ..= 11 = 12; - | ^^^ expected one of `:`, `;`, `=`, or `|` here + | ^^^ expected one of `:`, `;`, `=`, or `|` error: aborting due to previous error diff --git a/src/test/ui/parser/pat-ranges-2.stderr b/src/test/ui/parser/pat-ranges-2.stderr index 64df56f5a61..1a9e33bebe9 100644 --- a/src/test/ui/parser/pat-ranges-2.stderr +++ b/src/test/ui/parser/pat-ranges-2.stderr @@ -2,7 +2,7 @@ error: expected one of `::`, `:`, `;`, `=`, or `|`, found `!` --> $DIR/pat-ranges-2.rs:4:26 | LL | let 10 ..= makropulos!() = 12; - | ^ expected one of `::`, `:`, `;`, `=`, or `|` here + | ^ expected one of `::`, `:`, `;`, `=`, or `|` error: aborting due to previous error diff --git a/src/test/ui/parser/pat-ranges-3.stderr b/src/test/ui/parser/pat-ranges-3.stderr index c32c18d98dc..c9787b789a8 100644 --- a/src/test/ui/parser/pat-ranges-3.stderr +++ b/src/test/ui/parser/pat-ranges-3.stderr @@ -2,7 +2,7 @@ error: expected one of `:`, `;`, `=`, or `|`, found `+` --> $DIR/pat-ranges-3.rs:4:19 | LL | let 10 ..= 10 + 3 = 12; - | ^ expected one of `:`, `;`, `=`, or `|` here + | ^ expected one of `:`, `;`, `=`, or `|` error: aborting due to previous error diff --git a/src/test/ui/parser/pat-ranges-4.stderr b/src/test/ui/parser/pat-ranges-4.stderr index 53e38bc670b..69084b5a414 100644 --- a/src/test/ui/parser/pat-ranges-4.stderr +++ b/src/test/ui/parser/pat-ranges-4.stderr @@ -2,7 +2,7 @@ error: expected one of `...`, `..=`, `..`, `:`, `;`, `=`, or `|`, found `-` --> $DIR/pat-ranges-4.rs:4:12 | LL | let 10 - 3 ..= 10 = 8; - | ^ expected one of 7 possible tokens here + | ^ expected one of 7 possible tokens error: aborting due to previous error diff --git a/src/test/ui/parser/range-3.stderr b/src/test/ui/parser/range-3.stderr index 92c33487ee4..f866ea59983 100644 --- a/src/test/ui/parser/range-3.stderr +++ b/src/test/ui/parser/range-3.stderr @@ -2,7 +2,7 @@ error: expected one of `.`, `;`, `?`, or an operator, found `..` --> $DIR/range-3.rs:4:17 | LL | let r = 1..2..3; - | ^^ expected one of `.`, `;`, `?`, or an operator here + | ^^ expected one of `.`, `;`, `?`, or an operator error: aborting due to previous error diff --git a/src/test/ui/parser/range-4.stderr b/src/test/ui/parser/range-4.stderr index 90ec46165e7..dcb85170c1d 100644 --- a/src/test/ui/parser/range-4.stderr +++ b/src/test/ui/parser/range-4.stderr @@ -2,7 +2,7 @@ error: expected one of `.`, `;`, `?`, or an operator, found `..` --> $DIR/range-4.rs:4:16 | LL | let r = ..1..2; - | ^^ expected one of `.`, `;`, `?`, or an operator here + | ^^ expected one of `.`, `;`, `?`, or an operator error: aborting due to previous error diff --git a/src/test/ui/parser/raw-str-unbalanced.stderr b/src/test/ui/parser/raw-str-unbalanced.stderr index 26910ff64f5..ddb75722bef 100644 --- a/src/test/ui/parser/raw-str-unbalanced.stderr +++ b/src/test/ui/parser/raw-str-unbalanced.stderr @@ -2,7 +2,7 @@ error: expected one of `.`, `;`, `?`, or an operator, found `#` --> $DIR/raw-str-unbalanced.rs:3:9 | LL | "## - | ^ expected one of `.`, `;`, `?`, or an operator here + | ^ expected one of `.`, `;`, `?`, or an operator error: aborting due to previous error diff --git a/src/test/ui/parser/raw/raw-literal-keywords.stderr b/src/test/ui/parser/raw/raw-literal-keywords.stderr index 4cea605be6f..fd8eda3770d 100644 --- a/src/test/ui/parser/raw/raw-literal-keywords.stderr +++ b/src/test/ui/parser/raw/raw-literal-keywords.stderr @@ -2,19 +2,19 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found --> $DIR/raw-literal-keywords.rs:2:10 | LL | r#if true { } - | ^^^^ expected one of 8 possible tokens here + | ^^^^ expected one of 8 possible tokens error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `Test` --> $DIR/raw-literal-keywords.rs:6:14 | LL | r#struct Test; - | ^^^^ expected one of 8 possible tokens here + | ^^^^ expected one of 8 possible tokens error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `Test` --> $DIR/raw-literal-keywords.rs:10:13 | LL | r#union Test; - | ^^^^ expected one of 8 possible tokens here + | ^^^^ expected one of 8 possible tokens error[E0425]: cannot find value `if` in this scope --> $DIR/raw-literal-keywords.rs:14:13 diff --git a/src/test/ui/parser/recover-enum2.stderr b/src/test/ui/parser/recover-enum2.stderr index 2311887a6fb..ee29f06638f 100644 --- a/src/test/ui/parser/recover-enum2.stderr +++ b/src/test/ui/parser/recover-enum2.stderr @@ -8,7 +8,7 @@ error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `{` --> $DIR/recover-enum2.rs:25:22 | LL | Nope(i32 {}) - | ^ expected one of 7 possible tokens here + | ^ expected one of 7 possible tokens error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/recover-for-loop-parens-around-head.stderr b/src/test/ui/parser/recover-for-loop-parens-around-head.stderr index 1a1f395ee21..ccabfbded8b 100644 --- a/src/test/ui/parser/recover-for-loop-parens-around-head.stderr +++ b/src/test/ui/parser/recover-for-loop-parens-around-head.stderr @@ -2,7 +2,7 @@ error: expected one of `)`, `,`, `@`, or `|`, found keyword `in` --> $DIR/recover-for-loop-parens-around-head.rs:10:16 | LL | for ( elem in vec ) { - | ^^ expected one of `)`, `,`, `@`, or `|` here + | ^^ expected one of `)`, `,`, `@`, or `|` error: unexpected closing `)` --> $DIR/recover-for-loop-parens-around-head.rs:10:23 diff --git a/src/test/ui/parser/removed-syntax-closure-lifetime.stderr b/src/test/ui/parser/removed-syntax-closure-lifetime.stderr index f52988cdb20..a100f689fb8 100644 --- a/src/test/ui/parser/removed-syntax-closure-lifetime.stderr +++ b/src/test/ui/parser/removed-syntax-closure-lifetime.stderr @@ -2,7 +2,7 @@ error: expected one of `!`, `(`, `+`, `,`, `::`, `<`, or `>`, found `/` --> $DIR/removed-syntax-closure-lifetime.rs:1:22 | LL | type closure = Box; - | ^ expected one of 7 possible tokens here + | ^ expected one of 7 possible tokens error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-enum-newtype.stderr b/src/test/ui/parser/removed-syntax-enum-newtype.stderr index a6d0ff4eaf2..2daa6249b4c 100644 --- a/src/test/ui/parser/removed-syntax-enum-newtype.stderr +++ b/src/test/ui/parser/removed-syntax-enum-newtype.stderr @@ -2,7 +2,7 @@ error: expected one of `<`, `where`, or `{`, found `=` --> $DIR/removed-syntax-enum-newtype.rs:1:8 | LL | enum e = isize; - | ^ expected one of `<`, `where`, or `{` here + | ^ expected one of `<`, `where`, or `{` error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-fixed-vec.stderr b/src/test/ui/parser/removed-syntax-fixed-vec.stderr index ca6969d1e87..a2b97544f9e 100644 --- a/src/test/ui/parser/removed-syntax-fixed-vec.stderr +++ b/src/test/ui/parser/removed-syntax-fixed-vec.stderr @@ -2,7 +2,7 @@ error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `]`, found `*` --> $DIR/removed-syntax-fixed-vec.rs:1:17 | LL | type v = [isize * 3]; - | ^ expected one of 7 possible tokens here + | ^ expected one of 7 possible tokens error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-ptr-lifetime.stderr b/src/test/ui/parser/removed-syntax-ptr-lifetime.stderr index 7beef9883bd..5b388ff4ce0 100644 --- a/src/test/ui/parser/removed-syntax-ptr-lifetime.stderr +++ b/src/test/ui/parser/removed-syntax-ptr-lifetime.stderr @@ -2,7 +2,7 @@ error: expected one of `!`, `(`, `::`, `;`, or `<`, found `/` --> $DIR/removed-syntax-ptr-lifetime.rs:1:22 | LL | type bptr = &lifetime/isize; - | ^ expected one of `!`, `(`, `::`, `;`, or `<` here + | ^ expected one of `!`, `(`, `::`, `;`, or `<` error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-static-fn.stderr b/src/test/ui/parser/removed-syntax-static-fn.stderr index af148e69711..dfadefee23c 100644 --- a/src/test/ui/parser/removed-syntax-static-fn.stderr +++ b/src/test/ui/parser/removed-syntax-static-fn.stderr @@ -2,7 +2,7 @@ error: expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pu --> $DIR/removed-syntax-static-fn.rs:4:5 | LL | impl S { - | - expected one of 10 possible tokens here + | - expected one of 10 possible tokens LL | static fn f() {} | ^^^^^^ unexpected token diff --git a/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr b/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr index 9c47e3db67d..0703caf5bed 100644 --- a/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr +++ b/src/test/ui/parser/removed-syntax-uniq-mut-ty.stderr @@ -2,7 +2,7 @@ error: expected one of `>`, const, lifetime, or type, found keyword `mut` --> $DIR/removed-syntax-uniq-mut-ty.rs:1:20 | LL | type mut_box = Box; - | ^^^ expected one of `>`, const, lifetime, or type here + | ^^^ expected one of `>`, const, lifetime, or type error: aborting due to previous error diff --git a/src/test/ui/parser/removed-syntax-with-1.stderr b/src/test/ui/parser/removed-syntax-with-1.stderr index a157873916a..193138d7460 100644 --- a/src/test/ui/parser/removed-syntax-with-1.stderr +++ b/src/test/ui/parser/removed-syntax-with-1.stderr @@ -2,7 +2,7 @@ error: expected one of `,`, `.`, `?`, `}`, or an operator, found `with` --> $DIR/removed-syntax-with-1.rs:8:25 | LL | let b = S { foo: () with a, bar: () }; - | - ^^^^ expected one of `,`, `.`, `?`, `}`, or an operator here + | - ^^^^ expected one of `,`, `.`, `?`, `}`, or an operator | | | while parsing this struct diff --git a/src/test/ui/parser/removed-syntax-with-2.stderr b/src/test/ui/parser/removed-syntax-with-2.stderr index 7717b49d3a2..024c97cc9c1 100644 --- a/src/test/ui/parser/removed-syntax-with-2.stderr +++ b/src/test/ui/parser/removed-syntax-with-2.stderr @@ -2,7 +2,7 @@ error: expected one of `,` or `}`, found `a` --> $DIR/removed-syntax-with-2.rs:8:31 | LL | let b = S { foo: (), with a }; - | - ^ expected one of `,` or `}` here + | - ^ expected one of `,` or `}` | | | while parsing this struct diff --git a/src/test/ui/parser/underscore_item_not_const.stderr b/src/test/ui/parser/underscore_item_not_const.stderr index 8814aa35271..ebf1ff9ff1e 100644 --- a/src/test/ui/parser/underscore_item_not_const.stderr +++ b/src/test/ui/parser/underscore_item_not_const.stderr @@ -86,7 +86,7 @@ error: expected one of `!` or `::`, found reserved identifier `_` --> $DIR/underscore_item_not_const.rs:28:7 | LL | union _ { f: u8 } - | ^ expected one of `!` or `::` here + | ^ expected one of `!` or `::` error: aborting due to 15 previous errors diff --git a/src/test/ui/parser/use-as-where-use-ends-with-mod-sep.stderr b/src/test/ui/parser/use-as-where-use-ends-with-mod-sep.stderr index c73e17d2fc9..7a461cf630c 100644 --- a/src/test/ui/parser/use-as-where-use-ends-with-mod-sep.stderr +++ b/src/test/ui/parser/use-as-where-use-ends-with-mod-sep.stderr @@ -13,7 +13,7 @@ error: expected one of `::`, `;`, or `as`, found `foo` --> $DIR/use-as-where-use-ends-with-mod-sep.rs:1:19 | LL | use std::any:: as foo; - | ^^^ expected one of `::`, `;`, or `as` here + | ^^^ expected one of `::`, `;`, or `as` error: aborting due to 2 previous errors diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr index 57dd7c9f034..dd0e2597850 100644 --- a/src/test/ui/resolve/token-error-correct-3.stderr +++ b/src/test/ui/resolve/token-error-correct-3.stderr @@ -10,7 +10,7 @@ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` --> $DIR/token-error-correct-3.rs:18:9 | LL | fs::create_dir_all(path.as_ref()).map(|()| true) - | - expected one of `.`, `;`, `?`, `}`, or an operator here + | - expected one of `.`, `;`, `?`, `}`, or an operator LL | } else { | ^ unexpected token diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index ad4686c1915..65de150b100 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -2,7 +2,7 @@ error: expected one of `,` or `>`, found `&&` --> $DIR/disallowed-positions.rs:242:14 | LL | true && let 1 = 1 - | ^^ expected one of `,` or `>` here + | ^^ expected one of `,` or `>` error: `let` expressions are not supported here --> $DIR/disallowed-positions.rs:32:9 diff --git a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr index e4248f3b974..1e51567a9b1 100644 --- a/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr +++ b/src/test/ui/rfc-2565-param-attrs/param-attrs-2018.stderr @@ -2,7 +2,7 @@ error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/param-attrs-2018.rs:3:41 | LL | trait Trait2015 { fn foo(#[allow(C)] i32); } - | ^ expected one of `:`, `@`, or `|` here + | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this is a `self` type, give it a parameter name diff --git a/src/test/ui/rfc1598-generic-associated-types/empty_generics.stderr b/src/test/ui/rfc1598-generic-associated-types/empty_generics.stderr index 749032dbcc2..9c8d3f192da 100644 --- a/src/test/ui/rfc1598-generic-associated-types/empty_generics.stderr +++ b/src/test/ui/rfc1598-generic-associated-types/empty_generics.stderr @@ -2,7 +2,7 @@ error: expected one of `>`, `const`, identifier, or lifetime, found `,` --> $DIR/empty_generics.rs:5:14 | LL | type Bar<,>; - | ^ expected one of `>`, `const`, identifier, or lifetime here + | ^ expected one of `>`, `const`, identifier, or lifetime warning: the feature `generic_associated_types` is incomplete and may cause the compiler to crash --> $DIR/empty_generics.rs:1:12 diff --git a/src/test/ui/similar-tokens.stderr b/src/test/ui/similar-tokens.stderr index 3113d4a872d..d3d5b4a6d1e 100644 --- a/src/test/ui/similar-tokens.stderr +++ b/src/test/ui/similar-tokens.stderr @@ -2,7 +2,7 @@ error: expected one of `,`, `::`, `as`, or `}`, found `.` --> $DIR/similar-tokens.rs:7:10 | LL | use x::{A. B}; - | ^ expected one of `,`, `::`, `as`, or `}` here + | ^ expected one of `,`, `::`, `as`, or `}` error: aborting due to previous error diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr index 8d4a66f142d..26d686f6f50 100644 --- a/src/test/ui/span/issue-34264.stderr +++ b/src/test/ui/span/issue-34264.stderr @@ -2,7 +2,7 @@ error: expected one of `:`, `@`, or `|`, found `<` --> $DIR/issue-34264.rs:1:14 | LL | fn foo(Option, String) {} - | ^ expected one of `:`, `@`, or `|` here + | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this is a type, explicitly ignore the parameter name @@ -14,7 +14,7 @@ error: expected one of `:`, `@`, or `|`, found `)` --> $DIR/issue-34264.rs:1:27 | LL | fn foo(Option, String) {} - | ^ expected one of `:`, `@`, or `|` here + | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type @@ -30,7 +30,7 @@ error: expected one of `:`, `@`, or `|`, found `,` --> $DIR/issue-34264.rs:3:9 | LL | fn bar(x, y: usize) {} - | ^ expected one of `:`, `@`, or `|` here + | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this was a parameter name, give it a type diff --git a/src/test/ui/suggestions/issue-64252-self-type.stderr b/src/test/ui/suggestions/issue-64252-self-type.stderr index fa28a0d684e..4abffb1ad79 100644 --- a/src/test/ui/suggestions/issue-64252-self-type.stderr +++ b/src/test/ui/suggestions/issue-64252-self-type.stderr @@ -2,7 +2,7 @@ error: expected one of `:`, `@`, or `|`, found `<` --> $DIR/issue-64252-self-type.rs:4:15 | LL | pub fn foo(Box) { } - | ^ expected one of `:`, `@`, or `|` here + | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this is a type, explicitly ignore the parameter name @@ -14,7 +14,7 @@ error: expected one of `:`, `@`, or `|`, found `<` --> $DIR/issue-64252-self-type.rs:10:15 | LL | fn bar(Box) { } - | ^ expected one of `:`, `@`, or `|` here + | ^ expected one of `:`, `@`, or `|` | = note: anonymous parameters are removed in the 2018 edition (see RFC 1685) help: if this is a `self` type, give it a parameter name diff --git a/src/test/ui/tuple/tuple-struct-fields/test.stderr b/src/test/ui/tuple/tuple-struct-fields/test.stderr index 295f0b146dd..94f39f3b9f1 100644 --- a/src/test/ui/tuple/tuple-struct-fields/test.stderr +++ b/src/test/ui/tuple/tuple-struct-fields/test.stderr @@ -2,7 +2,7 @@ error: expected one of `)` or `,`, found `(` --> $DIR/test.rs:4:26 | LL | struct S2(pub((foo)) ()); - | ^ expected one of `)` or `,` here + | ^ expected one of `)` or `,` error[E0412]: cannot find type `foo` in this scope --> $DIR/test.rs:4:20 diff --git a/src/test/ui/tuple/tuple-struct-fields/test2.stderr b/src/test/ui/tuple/tuple-struct-fields/test2.stderr index 78176c67ed2..9a64ed97ae1 100644 --- a/src/test/ui/tuple/tuple-struct-fields/test2.stderr +++ b/src/test/ui/tuple/tuple-struct-fields/test2.stderr @@ -2,7 +2,7 @@ error: expected one of `)` or `,`, found `(` --> $DIR/test2.rs:5:26 | LL | struct S3(pub $t ()); - | ^ expected one of `)` or `,` here + | ^ expected one of `)` or `,` ... LL | define_struct! { (foo) } | ------------------------ in this macro invocation diff --git a/src/test/ui/tuple/tuple-struct-fields/test3.stderr b/src/test/ui/tuple/tuple-struct-fields/test3.stderr index e105aad09e6..89ae784882d 100644 --- a/src/test/ui/tuple/tuple-struct-fields/test3.stderr +++ b/src/test/ui/tuple/tuple-struct-fields/test3.stderr @@ -2,7 +2,7 @@ error: expected one of `)` or `,`, found `(` --> $DIR/test3.rs:5:27 | LL | struct S3(pub($t) ()); - | ^ expected one of `)` or `,` here + | ^ expected one of `)` or `,` ... LL | define_struct! { foo } | ---------------------- in this macro invocation diff --git a/src/test/ui/type/ascription/issue-54516.stderr b/src/test/ui/type/ascription/issue-54516.stderr index 97942904a0f..47e3c78459d 100644 --- a/src/test/ui/type/ascription/issue-54516.stderr +++ b/src/test/ui/type/ascription/issue-54516.stderr @@ -2,7 +2,7 @@ error: expected one of `!`, `,`, or `::`, found `(` --> $DIR/issue-54516.rs:4:58 | LL | println!("{}", std::mem:size_of::>()); - | - ^ expected one of `!`, `,`, or `::` here + | - ^ expected one of `!`, `,`, or `::` | | | help: maybe write a path separator here: `::` | diff --git a/src/test/ui/type/ascription/issue-60933.stderr b/src/test/ui/type/ascription/issue-60933.stderr index c2fc7bbcfc8..c47042bbe59 100644 --- a/src/test/ui/type/ascription/issue-60933.stderr +++ b/src/test/ui/type/ascription/issue-60933.stderr @@ -2,7 +2,7 @@ error: expected one of `!`, `::`, or `;`, found `(` --> $DIR/issue-60933.rs:2:43 | LL | let u: usize = std::mem:size_of::(); - | - ^ expected one of `!`, `::`, or `;` here + | - ^ expected one of `!`, `::`, or `;` | | | help: maybe write a path separator here: `::` | diff --git a/src/test/ui/unsafe/unsafe-block-without-braces.stderr b/src/test/ui/unsafe/unsafe-block-without-braces.stderr index 34a90352e92..637fdeead36 100644 --- a/src/test/ui/unsafe/unsafe-block-without-braces.stderr +++ b/src/test/ui/unsafe/unsafe-block-without-braces.stderr @@ -2,7 +2,7 @@ error: expected one of `extern`, `fn`, or `{`, found `std` --> $DIR/unsafe-block-without-braces.rs:3:9 | LL | unsafe //{ - | - expected one of `extern`, `fn`, or `{` here + | - expected one of `extern`, `fn`, or `{` LL | std::mem::transmute::(1.0); | ^^^ unexpected token -- cgit 1.4.1-3-g733a5 From beddf67a4b1ce5f1e14a67690644690c4b1bcfaa Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 27 Oct 2019 23:14:35 +0100 Subject: parser: don't hardcode ABIs into grammar --- src/librustc/error_codes.rs | 1 + src/librustc/hir/lowering.rs | 2 +- src/librustc/hir/lowering/item.rs | 25 +- src/librustc_save_analysis/sig.rs | 26 +- src/libsyntax/ast.rs | 24 +- src/libsyntax/error_codes.rs | 1 - src/libsyntax/feature_gate/check.rs | 63 ++--- src/libsyntax/parse/parser.rs | 38 +-- src/libsyntax/parse/parser/item.rs | 21 +- src/libsyntax/print/pprust.rs | 13 +- src/libsyntax/print/pprust/tests.rs | 7 +- src/libsyntax_ext/deriving/generic/mod.rs | 31 +-- src/libsyntax_pos/symbol.rs | 1 + .../ui/feature-gated-feature-in-macro-arg.stderr | 8 +- .../feature-gate-abi-msp430-interrupt.stderr | 4 +- src/test/ui/feature-gates/feature-gate-abi.stderr | 272 ++++++++++----------- .../feature-gate-abi_unadjusted.stderr | 8 +- .../feature-gates/feature-gate-intrinsics.stderr | 12 +- ...ature-gate-unboxed-closures-manual-impls.stderr | 16 +- .../feature-gate-unboxed-closures.stderr | 8 +- 20 files changed, 296 insertions(+), 285 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs index f5ff92e69bc..cf892127a30 100644 --- a/src/librustc/error_codes.rs +++ b/src/librustc/error_codes.rs @@ -2336,6 +2336,7 @@ the future, [RFC 2091] prohibits their implementation without a follow-up RFC. E0657, // `impl Trait` can only capture lifetimes bound at the fn level E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders + E0703, // invalid ABI // E0707, // multiple elided lifetimes used in arguments of `async fn` E0708, // `async` non-`move` closures with parameters are not currently // supported diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 230fbb16b87..6344c7a233c 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1216,7 +1216,7 @@ impl<'a> LoweringContext<'a> { ImplTraitContext::disallowed(), ), unsafety: this.lower_unsafety(f.unsafety), - abi: f.abi, + abi: this.lower_abi(f.abi), 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/hir/lowering/item.rs b/src/librustc/hir/lowering/item.rs index f1b999cdd6f..5fe463d783f 100644 --- a/src/librustc/hir/lowering/item.rs +++ b/src/librustc/hir/lowering/item.rs @@ -12,6 +12,7 @@ use crate::hir::def::{Res, DefKind}; use crate::util::nodemap::NodeMap; use rustc_data_structures::thin_vec::ThinVec; +use rustc_target::spec::abi; use std::collections::BTreeSet; use smallvec::SmallVec; @@ -735,7 +736,7 @@ impl LoweringContext<'_> { fn lower_foreign_mod(&mut self, fm: &ForeignMod) -> hir::ForeignMod { hir::ForeignMod { - abi: fm.abi, + abi: self.lower_abi(fm.abi), items: fm.items .iter() .map(|x| self.lower_foreign_item(x)) @@ -1291,10 +1292,30 @@ impl LoweringContext<'_> { unsafety: self.lower_unsafety(h.unsafety), asyncness: self.lower_asyncness(h.asyncness.node), constness: self.lower_constness(h.constness), - abi: h.abi, + abi: self.lower_abi(h.abi), } } + pub(super) fn lower_abi(&mut self, abi: Abi) -> abi::Abi { + abi::lookup(&abi.symbol.as_str()).unwrap_or_else(|| { + self.error_on_invalid_abi(abi); + abi::Abi::Rust + }) + } + + fn error_on_invalid_abi(&self, abi: Abi) { + struct_span_err!( + self.sess, + abi.span, + E0703, + "invalid ABI: found `{}`", + abi.symbol + ) + .span_label(abi.span, "invalid ABI") + .help(&format!("valid ABIs: {}", abi::all_names().join(", "))) + .emit(); + } + pub(super) fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety { match u { Unsafety::Unsafe => hir::Unsafety::Unsafe, diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 203bd4d4167..019e92717b5 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -32,7 +32,7 @@ use rls_data::{SigElement, Signature}; use rustc::hir::def::{Res, DefKind}; use syntax::ast::{self, NodeId}; use syntax::print::pprust; - +use syntax_pos::sym; pub fn item_signature(item: &ast::Item, scx: &SaveContext<'_, '_>) -> Option { if !scx.config.signatures { @@ -157,6 +157,12 @@ fn text_sig(text: String) -> Signature { } } +fn push_abi(text: &mut String, abi: ast::Abi) { + if abi.symbol != sym::Rust { + text.push_str(&format!("extern \"{}\" ", abi.symbol)); + } +} + impl Sig for ast::Ty { fn make(&self, offset: usize, _parent_id: Option, scx: &SaveContext<'_, '_>) -> Result { let id = Some(self.id); @@ -231,11 +237,7 @@ impl Sig for ast::Ty { if f.unsafety == ast::Unsafety::Unsafe { text.push_str("unsafe "); } - if f.abi != rustc_target::spec::abi::Abi::Rust { - text.push_str("extern"); - text.push_str(&f.abi.to_string()); - text.push(' '); - } + push_abi(&mut text, f.abi); text.push_str("fn("); let mut defs = vec![]; @@ -385,11 +387,7 @@ impl Sig for ast::Item { if header.unsafety == ast::Unsafety::Unsafe { text.push_str("unsafe "); } - if header.abi != rustc_target::spec::abi::Abi::Rust { - text.push_str("extern"); - text.push_str(&header.abi.to_string()); - text.push(' '); - } + push_abi(&mut text, header.abi); text.push_str("fn "); let mut sig = name_and_generics(text, offset, generics, self.id, self.ident, scx)?; @@ -948,11 +946,7 @@ fn make_method_signature( if m.header.unsafety == ast::Unsafety::Unsafe { text.push_str("unsafe "); } - if m.header.abi != rustc_target::spec::abi::Abi::Rust { - text.push_str("extern"); - text.push_str(&m.header.abi.to_string()); - text.push(' '); - } + push_abi(&mut text, m.header.abi); text.push_str("fn "); let mut sig = name_and_generics(text, 0, generics, id, ident, scx)?; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 2392b809150..f761c35cd5c 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -38,7 +38,6 @@ use rustc_data_structures::sync::Lrc; use rustc_data_structures::thin_vec::ThinVec; use rustc_index::vec::Idx; use rustc_serialize::{self, Decoder, Encoder}; -use rustc_target::spec::abi::Abi; #[cfg(target_arch = "x86_64")] use rustc_data_structures::static_assert_size; @@ -2358,6 +2357,27 @@ impl Item { } } +/// A reference to an ABI. +/// +/// In AST our notion of an ABI is still syntactic unlike in `rustc_target::spec::abi::Abi`. +#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, PartialEq)] +pub struct Abi { + pub symbol: Symbol, + pub span: Span, +} + +impl Abi { + pub fn new(symbol: Symbol, span: Span) -> Self { + Self { symbol, span } + } +} + +impl Default for Abi { + fn default() -> Self { + Self::new(sym::Rust, DUMMY_SP) + } +} + /// A function header. /// /// All the information between the visibility and the name of the function is @@ -2376,7 +2396,7 @@ impl Default for FnHeader { unsafety: Unsafety::Normal, asyncness: dummy_spanned(IsAsync::NotAsync), constness: dummy_spanned(Constness::NotConst), - abi: Abi::Rust, + abi: Abi::default(), } } } diff --git a/src/libsyntax/error_codes.rs b/src/libsyntax/error_codes.rs index 941df5ea570..c23c8d65a7f 100644 --- a/src/libsyntax/error_codes.rs +++ b/src/libsyntax/error_codes.rs @@ -540,6 +540,5 @@ equivalent in Rust would be to use macros directly. E0630, E0693, // incorrect `repr(align)` attribute format // E0694, // an unknown tool name found in scoped attributes - E0703, // invalid ABI E0717, // rustc_promotable without stability attribute } diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index b7e75ff3a7e..213e9680524 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -18,7 +18,6 @@ use crate::tokenstream::TokenTree; use errors::{Applicability, DiagnosticBuilder, Handler}; use rustc_data_structures::fx::FxHashMap; -use rustc_target::spec::abi::Abi; use syntax_pos::{Span, DUMMY_SP, MultiSpan}; use log::debug; @@ -192,62 +191,70 @@ macro_rules! gate_feature_post { } impl<'a> PostExpansionVisitor<'a> { - fn check_abi(&self, abi: Abi, span: Span) { - match abi { - Abi::RustIntrinsic => { + fn check_abi(&self, abi: ast::Abi) { + let ast::Abi { symbol, span } = abi; + + match &*symbol.as_str() { + // Stable + "Rust" | + "C" | + "cdecl" | + "stdcall" | + "fastcall" | + "aapcs" | + "win64" | + "sysv64" | + "system" => {} + "rust-intrinsic" => { gate_feature_post!(&self, intrinsics, span, "intrinsics are subject to change"); }, - Abi::PlatformIntrinsic => { + "platform-intrinsic" => { gate_feature_post!(&self, platform_intrinsics, span, "platform intrinsics are experimental and possibly buggy"); }, - Abi::Vectorcall => { + "vectorcall" => { gate_feature_post!(&self, abi_vectorcall, span, "vectorcall is experimental and subject to change"); }, - Abi::Thiscall => { + "thiscall" => { gate_feature_post!(&self, abi_thiscall, span, "thiscall is experimental and subject to change"); }, - Abi::RustCall => { + "rust-call" => { gate_feature_post!(&self, unboxed_closures, span, "rust-call ABI is subject to change"); }, - Abi::PtxKernel => { + "ptx-kernel" => { gate_feature_post!(&self, abi_ptx, span, "PTX ABIs are experimental and subject to change"); }, - Abi::Unadjusted => { + "unadjusted" => { gate_feature_post!(&self, abi_unadjusted, span, "unadjusted ABI is an implementation detail and perma-unstable"); }, - Abi::Msp430Interrupt => { + "msp430-interrupt" => { gate_feature_post!(&self, abi_msp430_interrupt, span, "msp430-interrupt ABI is experimental and subject to change"); }, - Abi::X86Interrupt => { + "x86-interrupt" => { gate_feature_post!(&self, abi_x86_interrupt, span, "x86-interrupt ABI is experimental and subject to change"); }, - Abi::AmdGpuKernel => { + "amdgpu-kernel" => { gate_feature_post!(&self, abi_amdgpu_kernel, span, "amdgpu-kernel ABI is experimental and subject to change"); }, - Abi::EfiApi => { + "efiapi" => { gate_feature_post!(&self, abi_efiapi, span, "efiapi ABI is experimental and subject to change"); }, - // Stable - Abi::Cdecl | - Abi::Stdcall | - Abi::Fastcall | - Abi::Aapcs | - Abi::Win64 | - Abi::SysV64 | - Abi::Rust | - Abi::C | - Abi::System => {} + abi => { + self.parse_sess.span_diagnostic.delay_span_bug( + span, + &format!("unrecognized ABI not caught in lowering: {}", abi), + ) + } } } @@ -373,7 +380,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_item(&mut self, i: &'a ast::Item) { match i.kind { ast::ItemKind::ForeignMod(ref foreign_module) => { - self.check_abi(foreign_module.abi, i.span); + self.check_abi(foreign_module.abi); } ast::ItemKind::Fn(..) => { @@ -503,7 +510,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_ty(&mut self, ty: &'a ast::Ty) { match ty.kind { ast::TyKind::BareFn(ref bare_fn_ty) => { - self.check_abi(bare_fn_ty.abi, ty.span); + self.check_abi(bare_fn_ty.abi); } ast::TyKind::Never => { gate_feature_post!(&self, never_type, ty.span, @@ -597,7 +604,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { // Stability of const fn methods are covered in // `visit_trait_item` and `visit_impl_item` below; this is // because default methods don't pass through this point. - self.check_abi(header.abi, span); + self.check_abi(header.abi); } if fn_decl.c_variadic() { @@ -631,7 +638,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { match ti.kind { ast::TraitItemKind::Method(ref sig, ref block) => { if block.is_none() { - self.check_abi(sig.header.abi, ti.span); + self.check_abi(sig.header.abi); } if sig.decl.c_variadic() { gate_feature_post!(&self, c_variadic, ti.span, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 7652c730e51..382c1a517aa 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -12,7 +12,7 @@ mod diagnostics; use diagnostics::Error; use crate::ast::{ - self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident, + self, Abi, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident, IsAsync, MacDelimiter, Mutability, StrStyle, Visibility, VisibilityKind, Unsafety, }; use crate::parse::{PResult, Directory, DirectoryOwnership}; @@ -28,7 +28,6 @@ use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint}; use crate::ThinVec; use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError}; -use rustc_target::spec::abi::{self, Abi}; use syntax_pos::{Span, BytePos, DUMMY_SP, FileName}; use log::debug; @@ -1208,48 +1207,27 @@ impl<'a> Parser<'a> { /// Parses `extern` followed by an optional ABI string, or nothing. fn parse_extern_abi(&mut self) -> PResult<'a, Abi> { - if self.eat_keyword(kw::Extern) { - Ok(self.parse_opt_abi()?.unwrap_or(Abi::C)) + Ok(if self.eat_keyword(kw::Extern) { + let ext_sp = self.prev_span; + self.parse_opt_abi()?.unwrap_or_else(|| Abi::new(sym::C, ext_sp)) } else { - Ok(Abi::Rust) - } + Abi::default() + }) } - /// Parses a string as an ABI spec on an extern type or module. Consumes - /// the `extern` keyword, if one is found. + /// Parses a string as an ABI spec on an extern type or module. fn parse_opt_abi(&mut self) -> PResult<'a, Option> { match self.token.kind { token::Literal(token::Lit { kind: token::Str, symbol, suffix }) | token::Literal(token::Lit { kind: token::StrRaw(..), symbol, suffix }) => { self.expect_no_suffix(self.token.span, "an ABI spec", suffix); self.bump(); - match abi::lookup(&symbol.as_str()) { - Some(abi) => Ok(Some(abi)), - None => { - self.error_on_invalid_abi(symbol); - Ok(None) - } - } + Ok(Some(Abi::new(symbol, self.prev_span))) } _ => Ok(None), } } - /// Emit an error where `symbol` is an invalid ABI. - fn error_on_invalid_abi(&self, symbol: Symbol) { - let prev_span = self.prev_span; - struct_span_err!( - self.sess.span_diagnostic, - prev_span, - E0703, - "invalid ABI: found `{}`", - symbol - ) - .span_label(prev_span, "invalid ABI") - .help(&format!("valid ABIs: {}", abi::all_names().join(", "))) - .emit(); - } - /// 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() { diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index cc6235c6fc7..76411e7cf13 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -3,7 +3,7 @@ use super::diagnostics::{Error, dummy_arg, ConsumeClosingDelim}; use crate::maybe_whole; use crate::ptr::P; -use crate::ast::{self, DUMMY_NODE_ID, Ident, Attribute, AttrKind, AttrStyle, AnonConst, Item}; +use crate::ast::{self, Abi, DUMMY_NODE_ID, Ident, Attribute, AttrKind, AttrStyle, AnonConst, Item}; use crate::ast::{ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind, UseTree, UseTreeKind}; use crate::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness}; use crate::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind}; @@ -17,7 +17,6 @@ use crate::ThinVec; use log::debug; use std::mem; -use rustc_target::spec::abi::Abi; use errors::{Applicability, DiagnosticBuilder, DiagnosticId, StashKey}; use syntax_pos::BytePos; @@ -111,7 +110,7 @@ impl<'a> Parser<'a> { return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?)); } - let opt_abi = self.parse_opt_abi()?; + let abi = self.parse_opt_abi()?.unwrap_or_else(|| Abi::new(sym::C, extern_sp)); if self.eat_keyword(kw::Fn) { // EXTERN FUNCTION ITEM @@ -120,12 +119,12 @@ impl<'a> Parser<'a> { unsafety: Unsafety::Normal, asyncness: respan(fn_span, IsAsync::NotAsync), constness: respan(fn_span, Constness::NotConst), - abi: opt_abi.unwrap_or(Abi::C), + 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, opt_abi, vis, attrs, extern_sp)?, + self.parse_item_foreign_mod(lo, abi, vis, attrs, extern_sp)?, )); } @@ -201,7 +200,7 @@ impl<'a> Parser<'a> { unsafety, asyncness, constness: respan(fn_span, Constness::NotConst), - abi: Abi::Rust, + abi: Abi::new(sym::Rust, fn_span), }; return self.parse_item_fn(lo, vis, attrs, header); } @@ -238,7 +237,7 @@ impl<'a> Parser<'a> { unsafety: Unsafety::Normal, asyncness: respan(fn_span, IsAsync::NotAsync), constness: respan(fn_span, Constness::NotConst), - abi: Abi::Rust, + abi: Abi::new(sym::Rust, fn_span), }; return self.parse_item_fn(lo, vis, attrs, header); } @@ -1115,15 +1114,13 @@ impl<'a> Parser<'a> { fn parse_item_foreign_mod( &mut self, lo: Span, - opt_abi: Option, + abi: Abi, visibility: Visibility, mut attrs: Vec, extern_sp: Span, ) -> PResult<'a, P> { self.expect(&token::OpenDelim(token::Brace))?; - let abi = opt_abi.unwrap_or(Abi::C); - attrs.extend(self.parse_inner_attributes()?); let mut foreign_items = vec![]; @@ -1801,7 +1798,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, Option>> { let (ident, decl, generics) = self.parse_fn_sig(ParamCfg { is_self_allowed: false, - allow_c_variadic: header.abi == Abi::C && header.unsafety == Unsafety::Unsafe, + allow_c_variadic: header.abi.symbol == sym::C && header.unsafety == Unsafety::Unsafe, is_name_required: |_| true, })?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; @@ -1930,7 +1927,7 @@ impl<'a> Parser<'a> { let asyncness = respan(self.prev_span, asyncness); let unsafety = self.parse_unsafety(); let (constness, unsafety, abi) = if is_const_fn { - (respan(const_span, Constness::Const), unsafety, Abi::Rust) + (respan(const_span, Constness::Const), unsafety, Abi::default()) } else { let abi = self.parse_extern_abi()?; (respan(self.prev_span, Constness::NotConst), unsafety, abi) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index c8afe8a1ff4..1d59c13a9d0 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -14,7 +14,6 @@ use crate::sess::ParseSess; use crate::symbol::{kw, sym}; use crate::tokenstream::{self, TokenStream, TokenTree}; -use rustc_target::spec::abi::{self, Abi}; use syntax_pos::{self, BytePos}; use syntax_pos::{FileName, Span}; @@ -1230,7 +1229,7 @@ impl<'a> State<'a> { } ast::ItemKind::ForeignMod(ref nmod) => { self.head("extern"); - self.word_nbsp(nmod.abi.to_string()); + self.print_abi(nmod.abi); self.bopen(); self.print_foreign_mod(nmod, &item.attrs); self.bclose(item.span); @@ -2823,7 +2822,7 @@ impl<'a> State<'a> { } crate fn print_ty_fn(&mut self, - abi: abi::Abi, + abi: ast::Abi, unsafety: ast::Unsafety, decl: &ast::FnDecl, name: Option, @@ -2884,14 +2883,18 @@ impl<'a> State<'a> { self.print_asyncness(header.asyncness.node); self.print_unsafety(header.unsafety); - if header.abi != Abi::Rust { + if header.abi.symbol != sym::Rust { self.word_nbsp("extern"); - self.word_nbsp(header.abi.to_string()); + self.print_abi(header.abi); } self.s.word("fn") } + fn print_abi(&mut self, abi: ast::Abi) { + self.word_nbsp(format!("\"{}\"", abi.symbol)); + } + crate fn print_unsafety(&mut self, s: ast::Unsafety) { match s { ast::Unsafety::Normal => {}, diff --git a/src/libsyntax/print/pprust/tests.rs b/src/libsyntax/print/pprust/tests.rs index faa70edbfa2..2c6dd0fb1c6 100644 --- a/src/libsyntax/print/pprust/tests.rs +++ b/src/libsyntax/print/pprust/tests.rs @@ -34,12 +34,7 @@ fn test_fun_to_string() { assert_eq!( fun_to_string( &decl, - ast::FnHeader { - unsafety: ast::Unsafety::Normal, - constness: source_map::dummy_spanned(ast::Constness::NotConst), - asyncness: source_map::dummy_spanned(ast::IsAsync::NotAsync), - abi: Abi::Rust, - }, + ast::FnHeader::default(), abba_ident, &generics ), diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 2e5ae235893..b18fd50ae76 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -182,8 +182,7 @@ use std::iter; use std::vec; use rustc_data_structures::thin_vec::ThinVec; -use rustc_target::spec::abi::Abi; -use syntax::ast::{self, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind}; +use syntax::ast::{self, Abi, BinOpKind, EnumDef, Expr, Generics, Ident, PatKind}; use syntax::ast::{VariantData, GenericParamKind, GenericArg}; use syntax::attr; use syntax::source_map::respan; @@ -738,7 +737,7 @@ impl<'a> TraitDef<'a> { self, type_ident, generics, - Abi::Rust, + sym::Rust, explicit_self, tys, body) @@ -793,7 +792,7 @@ impl<'a> TraitDef<'a> { self, type_ident, generics, - Abi::Rust, + sym::Rust, explicit_self, tys, body) @@ -919,7 +918,7 @@ impl<'a> MethodDef<'a> { trait_: &TraitDef<'_>, type_ident: Ident, generics: &Generics, - abi: Abi, + abi: Symbol, explicit_self: Option, arg_types: Vec<(Ident, P)>, body: P) @@ -949,23 +948,27 @@ impl<'a> MethodDef<'a> { ast::Unsafety::Normal }; + let trait_lo_sp = trait_.span.shrink_to_lo(); + + let sig = ast::MethodSig { + header: ast::FnHeader { + unsafety, + abi: Abi::new(abi, trait_lo_sp), + ..ast::FnHeader::default() + }, + decl: fn_decl, + }; + // Create the method. ast::ImplItem { id: ast::DUMMY_NODE_ID, attrs: self.attributes.clone(), generics: fn_generics, span: trait_.span, - vis: respan(trait_.span.shrink_to_lo(), ast::VisibilityKind::Inherited), + vis: respan(trait_lo_sp, ast::VisibilityKind::Inherited), defaultness: ast::Defaultness::Final, ident: method_ident, - kind: ast::ImplItemKind::Method(ast::MethodSig { - header: ast::FnHeader { - unsafety, abi, - ..ast::FnHeader::default() - }, - decl: fn_decl, - }, - body_block), + kind: ast::ImplItemKind::Method(sig, body_block), tokens: None, } } diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 3f7b3e5b3d8..2bdd8eacd11 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -563,6 +563,7 @@ symbols! { rust_2018_preview, rust_begin_unwind, rustc, + Rust, RustcDecodable, RustcEncodable, rustc_allocator, diff --git a/src/test/ui/feature-gated-feature-in-macro-arg.stderr b/src/test/ui/feature-gated-feature-in-macro-arg.stderr index 5ee05154c3a..218e0292776 100644 --- a/src/test/ui/feature-gated-feature-in-macro-arg.stderr +++ b/src/test/ui/feature-gated-feature-in-macro-arg.stderr @@ -1,10 +1,8 @@ error[E0658]: intrinsics are subject to change - --> $DIR/feature-gated-feature-in-macro-arg.rs:8:9 + --> $DIR/feature-gated-feature-in-macro-arg.rs:8:16 | -LL | / extern "rust-intrinsic" { -LL | | fn atomic_fence(); -LL | | } - | |_________^ +LL | extern "rust-intrinsic" { + | ^^^^^^^^^^^^^^^^ | = help: add `#![feature(intrinsics)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr b/src/test/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr index 0d2e355535d..d58a2d91b2b 100644 --- a/src/test/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr +++ b/src/test/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr @@ -1,8 +1,8 @@ error[E0658]: msp430-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi-msp430-interrupt.rs:4:1 + --> $DIR/feature-gate-abi-msp430-interrupt.rs:4:8 | LL | extern "msp430-interrupt" fn foo() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-abi.stderr b/src/test/ui/feature-gates/feature-gate-abi.stderr index 0f2622f1065..6db6cb49cef 100644 --- a/src/test/ui/feature-gates/feature-gate-abi.stderr +++ b/src/test/ui/feature-gates/feature-gate-abi.stderr @@ -1,591 +1,591 @@ error[E0658]: intrinsics are subject to change - --> $DIR/feature-gate-abi.rs:13:1 + --> $DIR/feature-gate-abi.rs:13:8 | LL | extern "rust-intrinsic" fn f1() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = help: add `#![feature(intrinsics)]` to the crate attributes to enable error[E0658]: platform intrinsics are experimental and possibly buggy - --> $DIR/feature-gate-abi.rs:15:1 + --> $DIR/feature-gate-abi.rs:15:8 | LL | extern "platform-intrinsic" fn f2() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:17:1 + --> $DIR/feature-gate-abi.rs:17:8 | LL | extern "vectorcall" fn f3() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:18:1 + --> $DIR/feature-gate-abi.rs:18:8 | LL | extern "rust-call" fn f4() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: msp430-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:19:1 + --> $DIR/feature-gate-abi.rs:19:8 | LL | extern "msp430-interrupt" fn f5() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable error[E0658]: PTX ABIs are experimental and subject to change - --> $DIR/feature-gate-abi.rs:20:1 + --> $DIR/feature-gate-abi.rs:20:8 | LL | extern "ptx-kernel" fn f6() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add `#![feature(abi_ptx)]` to the crate attributes to enable error[E0658]: x86-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:21:1 + --> $DIR/feature-gate-abi.rs:21:8 | LL | extern "x86-interrupt" fn f7() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:22:1 + --> $DIR/feature-gate-abi.rs:22:8 | LL | extern "thiscall" fn f8() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ | = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:23:1 + --> $DIR/feature-gate-abi.rs:23:8 | LL | extern "amdgpu-kernel" fn f9() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable error[E0658]: efiapi ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:24:1 + --> $DIR/feature-gate-abi.rs:24:8 | LL | extern "efiapi" fn f10() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/65815 = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable error[E0658]: intrinsics are subject to change - --> $DIR/feature-gate-abi.rs:28:5 + --> $DIR/feature-gate-abi.rs:28:12 | LL | extern "rust-intrinsic" fn m1(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = help: add `#![feature(intrinsics)]` to the crate attributes to enable error[E0658]: platform intrinsics are experimental and possibly buggy - --> $DIR/feature-gate-abi.rs:30:5 + --> $DIR/feature-gate-abi.rs:30:12 | LL | extern "platform-intrinsic" fn m2(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:32:5 + --> $DIR/feature-gate-abi.rs:32:12 | LL | extern "vectorcall" fn m3(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:33:5 + --> $DIR/feature-gate-abi.rs:33:12 | LL | extern "rust-call" fn m4(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: msp430-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:34:5 + --> $DIR/feature-gate-abi.rs:34:12 | LL | extern "msp430-interrupt" fn m5(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable error[E0658]: PTX ABIs are experimental and subject to change - --> $DIR/feature-gate-abi.rs:35:5 + --> $DIR/feature-gate-abi.rs:35:12 | LL | extern "ptx-kernel" fn m6(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add `#![feature(abi_ptx)]` to the crate attributes to enable error[E0658]: x86-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:36:5 + --> $DIR/feature-gate-abi.rs:36:12 | LL | extern "x86-interrupt" fn m7(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:37:5 + --> $DIR/feature-gate-abi.rs:37:12 | LL | extern "thiscall" fn m8(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ | = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:38:5 + --> $DIR/feature-gate-abi.rs:38:12 | LL | extern "amdgpu-kernel" fn m9(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable error[E0658]: efiapi ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:39:5 + --> $DIR/feature-gate-abi.rs:39:12 | LL | extern "efiapi" fn m10(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/65815 = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:41:5 + --> $DIR/feature-gate-abi.rs:41:12 | LL | extern "vectorcall" fn dm3() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:42:5 + --> $DIR/feature-gate-abi.rs:42:12 | LL | extern "rust-call" fn dm4() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: msp430-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:43:5 + --> $DIR/feature-gate-abi.rs:43:12 | LL | extern "msp430-interrupt" fn dm5() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable error[E0658]: PTX ABIs are experimental and subject to change - --> $DIR/feature-gate-abi.rs:44:5 + --> $DIR/feature-gate-abi.rs:44:12 | LL | extern "ptx-kernel" fn dm6() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add `#![feature(abi_ptx)]` to the crate attributes to enable error[E0658]: x86-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:45:5 + --> $DIR/feature-gate-abi.rs:45:12 | LL | extern "x86-interrupt" fn dm7() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:46:5 + --> $DIR/feature-gate-abi.rs:46:12 | LL | extern "thiscall" fn dm8() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ | = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:47:5 + --> $DIR/feature-gate-abi.rs:47:12 | LL | extern "amdgpu-kernel" fn dm9() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable error[E0658]: efiapi ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:48:5 + --> $DIR/feature-gate-abi.rs:48:12 | LL | extern "efiapi" fn dm10() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/65815 = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable error[E0658]: intrinsics are subject to change - --> $DIR/feature-gate-abi.rs:55:5 + --> $DIR/feature-gate-abi.rs:55:12 | LL | extern "rust-intrinsic" fn m1() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = help: add `#![feature(intrinsics)]` to the crate attributes to enable error[E0658]: platform intrinsics are experimental and possibly buggy - --> $DIR/feature-gate-abi.rs:57:5 + --> $DIR/feature-gate-abi.rs:57:12 | LL | extern "platform-intrinsic" fn m2() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:59:5 + --> $DIR/feature-gate-abi.rs:59:12 | LL | extern "vectorcall" fn m3() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:60:5 + --> $DIR/feature-gate-abi.rs:60:12 | LL | extern "rust-call" fn m4() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: msp430-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:61:5 + --> $DIR/feature-gate-abi.rs:61:12 | LL | extern "msp430-interrupt" fn m5() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable error[E0658]: PTX ABIs are experimental and subject to change - --> $DIR/feature-gate-abi.rs:62:5 + --> $DIR/feature-gate-abi.rs:62:12 | LL | extern "ptx-kernel" fn m6() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add `#![feature(abi_ptx)]` to the crate attributes to enable error[E0658]: x86-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:63:5 + --> $DIR/feature-gate-abi.rs:63:12 | LL | extern "x86-interrupt" fn m7() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:64:5 + --> $DIR/feature-gate-abi.rs:64:12 | LL | extern "thiscall" fn m8() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ | = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:65:5 + --> $DIR/feature-gate-abi.rs:65:12 | LL | extern "amdgpu-kernel" fn m9() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable error[E0658]: efiapi ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:66:5 + --> $DIR/feature-gate-abi.rs:66:12 | LL | extern "efiapi" fn m10() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/65815 = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable error[E0658]: intrinsics are subject to change - --> $DIR/feature-gate-abi.rs:71:5 + --> $DIR/feature-gate-abi.rs:71:12 | LL | extern "rust-intrinsic" fn im1() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = help: add `#![feature(intrinsics)]` to the crate attributes to enable error[E0658]: platform intrinsics are experimental and possibly buggy - --> $DIR/feature-gate-abi.rs:73:5 + --> $DIR/feature-gate-abi.rs:73:12 | LL | extern "platform-intrinsic" fn im2() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:75:5 + --> $DIR/feature-gate-abi.rs:75:12 | LL | extern "vectorcall" fn im3() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:76:5 + --> $DIR/feature-gate-abi.rs:76:12 | LL | extern "rust-call" fn im4() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: msp430-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:77:5 + --> $DIR/feature-gate-abi.rs:77:12 | LL | extern "msp430-interrupt" fn im5() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable error[E0658]: PTX ABIs are experimental and subject to change - --> $DIR/feature-gate-abi.rs:78:5 + --> $DIR/feature-gate-abi.rs:78:12 | LL | extern "ptx-kernel" fn im6() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add `#![feature(abi_ptx)]` to the crate attributes to enable error[E0658]: x86-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:79:5 + --> $DIR/feature-gate-abi.rs:79:12 | LL | extern "x86-interrupt" fn im7() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:80:5 + --> $DIR/feature-gate-abi.rs:80:12 | LL | extern "thiscall" fn im8() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ | = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:81:5 + --> $DIR/feature-gate-abi.rs:81:12 | LL | extern "amdgpu-kernel" fn im9() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable error[E0658]: efiapi ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:82:5 + --> $DIR/feature-gate-abi.rs:82:12 | LL | extern "efiapi" fn im10() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/65815 = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable error[E0658]: intrinsics are subject to change - --> $DIR/feature-gate-abi.rs:86:11 + --> $DIR/feature-gate-abi.rs:86:18 | LL | type A1 = extern "rust-intrinsic" fn(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = help: add `#![feature(intrinsics)]` to the crate attributes to enable error[E0658]: platform intrinsics are experimental and possibly buggy - --> $DIR/feature-gate-abi.rs:87:11 + --> $DIR/feature-gate-abi.rs:87:18 | LL | type A2 = extern "platform-intrinsic" fn(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:88:11 + --> $DIR/feature-gate-abi.rs:88:18 | LL | type A3 = extern "vectorcall" fn(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:89:11 + --> $DIR/feature-gate-abi.rs:89:18 | LL | type A4 = extern "rust-call" fn(); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: msp430-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:90:11 + --> $DIR/feature-gate-abi.rs:90:18 | LL | type A5 = extern "msp430-interrupt" fn(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable error[E0658]: PTX ABIs are experimental and subject to change - --> $DIR/feature-gate-abi.rs:91:11 + --> $DIR/feature-gate-abi.rs:91:18 | LL | type A6 = extern "ptx-kernel" fn (); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add `#![feature(abi_ptx)]` to the crate attributes to enable error[E0658]: x86-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:92:11 + --> $DIR/feature-gate-abi.rs:92:18 | LL | type A7 = extern "x86-interrupt" fn(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:93:11 + --> $DIR/feature-gate-abi.rs:93:18 | LL | type A8 = extern "thiscall" fn(); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ | = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:94:11 + --> $DIR/feature-gate-abi.rs:94:18 | LL | type A9 = extern "amdgpu-kernel" fn(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable error[E0658]: efiapi ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:95:12 + --> $DIR/feature-gate-abi.rs:95:19 | LL | type A10 = extern "efiapi" fn(); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/65815 = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable error[E0658]: intrinsics are subject to change - --> $DIR/feature-gate-abi.rs:98:1 + --> $DIR/feature-gate-abi.rs:98:8 | LL | extern "rust-intrinsic" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = help: add `#![feature(intrinsics)]` to the crate attributes to enable error[E0658]: platform intrinsics are experimental and possibly buggy - --> $DIR/feature-gate-abi.rs:99:1 + --> $DIR/feature-gate-abi.rs:99:8 | LL | extern "platform-intrinsic" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:100:1 + --> $DIR/feature-gate-abi.rs:100:8 | LL | extern "vectorcall" {} - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-abi.rs:101:1 + --> $DIR/feature-gate-abi.rs:101:8 | LL | extern "rust-call" {} - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: msp430-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:102:1 + --> $DIR/feature-gate-abi.rs:102:8 | LL | extern "msp430-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add `#![feature(abi_msp430_interrupt)]` to the crate attributes to enable error[E0658]: PTX ABIs are experimental and subject to change - --> $DIR/feature-gate-abi.rs:103:1 + --> $DIR/feature-gate-abi.rs:103:8 | LL | extern "ptx-kernel" {} - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add `#![feature(abi_ptx)]` to the crate attributes to enable error[E0658]: x86-interrupt ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:104:1 + --> $DIR/feature-gate-abi.rs:104:8 | LL | extern "x86-interrupt" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add `#![feature(abi_x86_interrupt)]` to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change - --> $DIR/feature-gate-abi.rs:105:1 + --> $DIR/feature-gate-abi.rs:105:8 | LL | extern "thiscall" {} - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ | = help: add `#![feature(abi_thiscall)]` to the crate attributes to enable error[E0658]: amdgpu-kernel ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:106:1 + --> $DIR/feature-gate-abi.rs:106:8 | LL | extern "amdgpu-kernel" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add `#![feature(abi_amdgpu_kernel)]` to the crate attributes to enable error[E0658]: efiapi ABI is experimental and subject to change - --> $DIR/feature-gate-abi.rs:107:1 + --> $DIR/feature-gate-abi.rs:107:8 | LL | extern "efiapi" {} - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/65815 = help: add `#![feature(abi_efiapi)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-abi_unadjusted.stderr b/src/test/ui/feature-gates/feature-gate-abi_unadjusted.stderr index 4954a7d1f71..1757befec35 100644 --- a/src/test/ui/feature-gates/feature-gate-abi_unadjusted.stderr +++ b/src/test/ui/feature-gates/feature-gate-abi_unadjusted.stderr @@ -1,10 +1,8 @@ error[E0658]: unadjusted ABI is an implementation detail and perma-unstable - --> $DIR/feature-gate-abi_unadjusted.rs:1:1 + --> $DIR/feature-gate-abi_unadjusted.rs:1:8 | -LL | / extern "unadjusted" fn foo() { -LL | | -LL | | } - | |_^ +LL | extern "unadjusted" fn foo() { + | ^^^^^^^^^^^^ | = help: add `#![feature(abi_unadjusted)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-intrinsics.stderr b/src/test/ui/feature-gates/feature-gate-intrinsics.stderr index 101a10e8df7..8f943d357ce 100644 --- a/src/test/ui/feature-gates/feature-gate-intrinsics.stderr +++ b/src/test/ui/feature-gates/feature-gate-intrinsics.stderr @@ -1,18 +1,16 @@ error[E0658]: intrinsics are subject to change - --> $DIR/feature-gate-intrinsics.rs:1:1 + --> $DIR/feature-gate-intrinsics.rs:1:8 | -LL | / extern "rust-intrinsic" { -LL | | fn bar(); -LL | | } - | |_^ +LL | extern "rust-intrinsic" { + | ^^^^^^^^^^^^^^^^ | = help: add `#![feature(intrinsics)]` to the crate attributes to enable error[E0658]: intrinsics are subject to change - --> $DIR/feature-gate-intrinsics.rs:5:1 + --> $DIR/feature-gate-intrinsics.rs:5:8 | LL | extern "rust-intrinsic" fn baz() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = help: add `#![feature(intrinsics)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr index c05379c71ee..657bf13c873 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr @@ -1,35 +1,35 @@ error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:11:5 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:11:12 | LL | extern "rust-call" fn call(self, args: ()) -> () {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:17:5 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:17:12 | LL | extern "rust-call" fn call_once(self, args: ()) -> () {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:5 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:12 | LL | extern "rust-call" fn call_mut(&self, args: ()) -> () {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:29:5 + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:29:12 | LL | extern "rust-call" fn call_once(&self, args: ()) -> () {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr index 723c6619887..f343a42eb8f 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr @@ -1,10 +1,8 @@ error[E0658]: rust-call ABI is subject to change - --> $DIR/feature-gate-unboxed-closures.rs:9:5 + --> $DIR/feature-gate-unboxed-closures.rs:9:12 | -LL | / extern "rust-call" fn call_once(self, (a, b): (u32, u32)) -> u32 { -LL | | a + b -LL | | } - | |_____^ +LL | extern "rust-call" fn call_once(self, (a, b): (u32, u32)) -> u32 { + | ^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable -- cgit 1.4.1-3-g733a5 From 49def0769c51d182bf6c321eefdcda288e3ad218 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 27 Oct 2019 23:22:59 +0100 Subject: cleanup can_begin_const_arg --- src/libsyntax/parse/token.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 03e77b199cc..ea82aad0eae 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -381,9 +381,7 @@ impl Token { match self.kind { OpenDelim(Brace) => true, Interpolated(ref nt) => match **nt { - NtExpr(..) => true, - NtBlock(..) => true, - NtLiteral(..) => true, + NtExpr(..) | NtBlock(..) | NtLiteral(..) => true, _ => false, } _ => self.can_begin_literal_or_bool(), -- cgit 1.4.1-3-g733a5 From 1db4d607e7621a7d813743e83125859a47970f79 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 28 Oct 2019 00:29:23 +0100 Subject: parser: allow ABIs from literal macro fragments --- src/libsyntax/parse/parser.rs | 40 +++++++++++++++------- src/libsyntax/parse/parser/expr.rs | 6 +++- src/libsyntax/parse/parser/item.rs | 2 +- src/libsyntax/parse/token.rs | 7 ---- src/test/ui/parser/bad-lit-suffixes.rs | 4 +-- src/test/ui/parser/bad-lit-suffixes.stderr | 4 +-- .../ui/parser/extern-abi-from-mac-literal-frag.rs | 26 ++++++++++++++ 7 files changed, 63 insertions(+), 26 deletions(-) create mode 100644 src/test/ui/parser/extern-abi-from-mac-literal-frag.rs (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 382c1a517aa..0c358b1caaf 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1205,27 +1205,41 @@ impl<'a> Parser<'a> { Ok(()) } - /// Parses `extern` followed by an optional ABI string, or nothing. + /// Parses `extern string_literal?`. + /// If `extern` is not found, the Rust ABI is used. + /// If `extern` is found and a `string_literal` does not follow, the C ABI is used. fn parse_extern_abi(&mut self) -> PResult<'a, Abi> { Ok(if self.eat_keyword(kw::Extern) { - let ext_sp = self.prev_span; - self.parse_opt_abi()?.unwrap_or_else(|| Abi::new(sym::C, ext_sp)) + self.parse_opt_abi()? } else { Abi::default() }) } - /// Parses a string as an ABI spec on an extern type or module. - fn parse_opt_abi(&mut self) -> PResult<'a, Option> { - match self.token.kind { - token::Literal(token::Lit { kind: token::Str, symbol, suffix }) | - token::Literal(token::Lit { kind: token::StrRaw(..), symbol, suffix }) => { - self.expect_no_suffix(self.token.span, "an ABI spec", suffix); - self.bump(); - Ok(Some(Abi::new(symbol, self.prev_span))) + /// Parses a string literal as an ABI spec. + /// If one is not found, the "C" ABI is used. + fn parse_opt_abi(&mut self) -> PResult<'a, Abi> { + let span = if self.token.can_begin_literal_or_bool() { + let ast::Lit { span, kind, .. } = self.parse_lit()?; + match kind { + ast::LitKind::Str(symbol, _) => return Ok(Abi::new(symbol, span)), + ast::LitKind::Err(_) => {} + _ => { + self.struct_span_err(span, "non-string ABI literal") + .span_suggestion( + span, + "specify the ABI with a string literal", + "\"C\"".to_string(), + Applicability::MaybeIncorrect, + ) + .emit(); + } } - _ => Ok(None), - } + span + } else { + self.prev_span + }; + Ok(Abi::new(sym::C, span)) } /// We are parsing `async fn`. If we are on Rust 2015, emit an error. diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 97b1092452a..80ea8f380fb 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -1116,7 +1116,11 @@ impl<'a> Parser<'a> { Err(self.span_fatal(token.span, &msg)) } Err(err) => { - let (lit, span) = (token.expect_lit(), token.span); + let span = token.span; + let lit = match token.kind { + token::Literal(lit) => lit, + _ => unreachable!(), + }; self.bump(); self.error_literal_from_token(err, lit, span); // Pack possible quotes and prefixes from the original literal into diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 76411e7cf13..ebb1cf12996 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -110,7 +110,7 @@ impl<'a> Parser<'a> { return Ok(Some(self.parse_item_extern_crate(lo, vis, attrs)?)); } - let abi = self.parse_opt_abi()?.unwrap_or_else(|| Abi::new(sym::C, extern_sp)); + let abi = self.parse_opt_abi()?; if self.eat_keyword(kw::Fn) { // EXTERN FUNCTION ITEM diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index ea82aad0eae..6f3da344ccf 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -402,13 +402,6 @@ impl Token { } } - crate fn expect_lit(&self) -> Lit { - match self.kind { - Literal(lit) => lit, - _ => panic!("`expect_lit` called on non-literal"), - } - } - /// 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). pub fn can_begin_literal_or_bool(&self) -> bool { diff --git a/src/test/ui/parser/bad-lit-suffixes.rs b/src/test/ui/parser/bad-lit-suffixes.rs index 9f301db0995..7db83674efc 100644 --- a/src/test/ui/parser/bad-lit-suffixes.rs +++ b/src/test/ui/parser/bad-lit-suffixes.rs @@ -1,9 +1,9 @@ extern - "C"suffix //~ ERROR suffixes on an ABI spec are invalid + "C"suffix //~ ERROR suffixes on a string literal are invalid fn foo() {} extern - "C"suffix //~ ERROR suffixes on an ABI spec are invalid + "C"suffix //~ ERROR suffixes on a string literal are invalid {} fn main() { diff --git a/src/test/ui/parser/bad-lit-suffixes.stderr b/src/test/ui/parser/bad-lit-suffixes.stderr index 208fcf43d91..6b0049298ff 100644 --- a/src/test/ui/parser/bad-lit-suffixes.stderr +++ b/src/test/ui/parser/bad-lit-suffixes.stderr @@ -1,10 +1,10 @@ -error: suffixes on an ABI spec are invalid +error: suffixes on a string literal are invalid --> $DIR/bad-lit-suffixes.rs:2:5 | LL | "C"suffix | ^^^^^^^^^ invalid suffix `suffix` -error: suffixes on an ABI spec are invalid +error: suffixes on a string literal are invalid --> $DIR/bad-lit-suffixes.rs:6:5 | LL | "C"suffix diff --git a/src/test/ui/parser/extern-abi-from-mac-literal-frag.rs b/src/test/ui/parser/extern-abi-from-mac-literal-frag.rs new file mode 100644 index 00000000000..cb23f2c808c --- /dev/null +++ b/src/test/ui/parser/extern-abi-from-mac-literal-frag.rs @@ -0,0 +1,26 @@ +// check-pass + +// In this test we check that the parser accepts an ABI string when it +// comes from a macro `literal` fragment as opposed to a hardcoded string. + +fn main() {} + +macro_rules! abi_from_lit_frag { + ($abi:literal) => { + extern $abi { + fn _import(); + } + + extern $abi fn _export() {} + + type _PTR = extern $abi fn(); + } +} + +mod rust { + abi_from_lit_frag!("Rust"); +} + +mod c { + abi_from_lit_frag!("C"); +} -- cgit 1.4.1-3-g733a5 From 55f76cdb2f4d01cf87e47148c706c53a129fa45e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Mon, 28 Oct 2019 03:46:22 +0100 Subject: syntax: use distinct FloatTy from rustc_target. We also sever syntax's dependency on rustc_target as a result. This should slightly improve pipe-lining. Moreover, some cleanup is done in related code. --- Cargo.lock | 3 - src/librustc/ich/impls_syntax.rs | 10 ++- src/librustc/ty/layout.rs | 5 +- src/librustc/ty/print/obsolete.rs | 18 +---- src/librustc/ty/print/pretty.rs | 18 ++--- src/librustc_codegen_llvm/debuginfo/metadata.rs | 6 +- src/librustc_codegen_llvm/intrinsic.rs | 6 +- src/librustc_codegen_ssa/debuginfo/type_names.rs | 6 +- src/librustc_interface/Cargo.toml | 4 +- src/librustc_lint/types.rs | 36 +++++----- src/librustc_mir/hair/constant.rs | 5 +- src/librustc_save_analysis/Cargo.toml | 1 - src/librustc_target/abi/mod.rs | 40 +---------- src/librustc_typeck/check/mod.rs | 4 +- src/libsyntax/Cargo.toml | 1 - src/libsyntax/ast.rs | 91 +++++++++++++----------- src/libsyntax/parse/literal.rs | 23 +++--- src/libsyntax_expand/Cargo.toml | 1 - src/libsyntax_ext/concat.rs | 3 +- 19 files changed, 123 insertions(+), 158 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/Cargo.lock b/Cargo.lock index a6dca2048d4..0f770f3eadb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3762,7 +3762,6 @@ dependencies = [ "rustc", "rustc_codegen_utils", "rustc_data_structures", - "rustc_target", "serde_json", "syntax", "syntax_pos", @@ -4362,7 +4361,6 @@ dependencies = [ "rustc_errors", "rustc_index", "rustc_lexer", - "rustc_target", "scoped-tls", "serialize", "smallvec 1.0.0", @@ -4380,7 +4378,6 @@ dependencies = [ "rustc_errors", "rustc_index", "rustc_lexer", - "rustc_target", "scoped-tls", "serialize", "smallvec 1.0.0", diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index aa147462e3d..2201c4b0980 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -124,7 +124,6 @@ for ::syntax::attr::StabilityLevel { impl_stable_hash_for!(struct ::syntax::attr::RustcDeprecation { since, reason, suggestion }); - impl_stable_hash_for!(enum ::syntax::attr::IntType { SignedInt(int_ty), UnsignedInt(uint_ty) @@ -136,6 +135,11 @@ impl_stable_hash_for!(enum ::syntax::ast::LitIntType { Unsuffixed }); +impl_stable_hash_for!(enum ::syntax::ast::LitFloatType { + Suffixed(float_ty), + Unsuffixed +}); + impl_stable_hash_for!(struct ::syntax::ast::Lit { kind, token, @@ -148,8 +152,7 @@ impl_stable_hash_for!(enum ::syntax::ast::LitKind { Byte(value), Char(value), Int(value, lit_int_type), - Float(value, float_ty), - FloatUnsuffixed(value), + Float(value, lit_float_type), Bool(value), Err(value) }); @@ -159,6 +162,7 @@ impl_stable_hash_for_spanned!(::syntax::ast::LitKind); impl_stable_hash_for!(enum ::syntax::ast::IntTy { Isize, I8, I16, I32, I64, I128 }); impl_stable_hash_for!(enum ::syntax::ast::UintTy { Usize, U8, U16, U32, U64, U128 }); impl_stable_hash_for!(enum ::syntax::ast::FloatTy { F32, F64 }); +impl_stable_hash_for!(enum ::rustc_target::abi::FloatTy { F32, F64 }); impl_stable_hash_for!(enum ::syntax::ast::Unsafety { Unsafe, Normal }); impl_stable_hash_for!(enum ::syntax::ast::Constness { Const, NotConst }); impl_stable_hash_for!(enum ::syntax::ast::Defaultness { Default, Final }); diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 95040135eb7..60aab6b6aa9 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -538,7 +538,10 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { ty::Uint(ity) => { scalar(Int(Integer::from_attr(dl, attr::UnsignedInt(ity)), false)) } - ty::Float(fty) => scalar(Float(fty)), + ty::Float(fty) => scalar(Float(match fty { + ast::FloatTy::F32 => FloatTy::F32, + ast::FloatTy::F64 => FloatTy::F64, + })), ty::FnPtr(_) => { let mut ptr = scalar_unit(Pointer); ptr.valid_range = 1..=*ptr.valid_range.end(); diff --git a/src/librustc/ty/print/obsolete.rs b/src/librustc/ty/print/obsolete.rs index e72916de6a9..d25f302cf88 100644 --- a/src/librustc/ty/print/obsolete.rs +++ b/src/librustc/ty/print/obsolete.rs @@ -12,7 +12,6 @@ use rustc::ty::{self, Const, Instance, Ty, TyCtxt}; use rustc::{bug, hir}; use std::fmt::Write; use std::iter; -use syntax::ast; /// Same as `unique_type_name()` but with the result pushed onto the given /// `output` parameter. @@ -39,20 +38,9 @@ impl DefPathBasedNames<'tcx> { ty::Char => output.push_str("char"), ty::Str => output.push_str("str"), ty::Never => output.push_str("!"), - ty::Int(ast::IntTy::Isize) => output.push_str("isize"), - ty::Int(ast::IntTy::I8) => output.push_str("i8"), - ty::Int(ast::IntTy::I16) => output.push_str("i16"), - ty::Int(ast::IntTy::I32) => output.push_str("i32"), - ty::Int(ast::IntTy::I64) => output.push_str("i64"), - ty::Int(ast::IntTy::I128) => output.push_str("i128"), - ty::Uint(ast::UintTy::Usize) => output.push_str("usize"), - ty::Uint(ast::UintTy::U8) => output.push_str("u8"), - ty::Uint(ast::UintTy::U16) => output.push_str("u16"), - ty::Uint(ast::UintTy::U32) => output.push_str("u32"), - ty::Uint(ast::UintTy::U64) => output.push_str("u64"), - ty::Uint(ast::UintTy::U128) => output.push_str("u128"), - ty::Float(ast::FloatTy::F32) => output.push_str("f32"), - ty::Float(ast::FloatTy::F64) => output.push_str("f64"), + ty::Int(ty) => output.push_str(ty.name_str()), + ty::Uint(ty) => output.push_str(ty.name_str()), + ty::Float(ty) => output.push_str(ty.name_str()), ty::Adt(adt_def, substs) => { self.push_def_path(adt_def.did, output); self.push_generic_params(substs, iter::empty(), output, debug); diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 8a98a5d8361..4d1fece2cb9 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -466,9 +466,9 @@ pub trait PrettyPrinter<'tcx>: match ty.kind { ty::Bool => p!(write("bool")), ty::Char => p!(write("char")), - ty::Int(t) => p!(write("{}", t.ty_to_string())), - ty::Uint(t) => p!(write("{}", t.ty_to_string())), - ty::Float(t) => p!(write("{}", t.ty_to_string())), + ty::Int(t) => p!(write("{}", t.name_str())), + ty::Uint(t) => p!(write("{}", t.name_str())), + ty::Float(t) => p!(write("{}", t.name_str())), ty::RawPtr(ref tm) => { p!(write("*{} ", match tm.mutbl { hir::MutMutable => "mut", @@ -895,10 +895,11 @@ pub trait PrettyPrinter<'tcx>: let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size(); let max = truncate(u128::max_value(), bit_size); + let ui_str = ui.name_str(); if data == max { - p!(write("std::{}::MAX", ui)) + p!(write("std::{}::MAX", ui_str)) } else { - p!(write("{}{}", data, ui)) + p!(write("{}{}", data, ui_str)) }; }, (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Int(i)) => { @@ -911,10 +912,11 @@ pub trait PrettyPrinter<'tcx>: let size = self.tcx().layout_of(ty::ParamEnv::empty().and(ty)) .unwrap() .size; + let i_str = i.name_str(); match data { - d if d == min => p!(write("std::{}::MIN", i)), - d if d == max => p!(write("std::{}::MAX", i)), - _ => p!(write("{}{}", sign_extend(data, size) as i128, i)) + d if d == min => p!(write("std::{}::MIN", i_str)), + d if d == max => p!(write("std::{}::MAX", i_str)), + _ => p!(write("{}{}", sign_extend(data, size) as i128, i_str)) } }, (ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Char) => diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index f0148a21ae6..5f18bb1700c 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -843,13 +843,13 @@ fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { ty::Bool => ("bool", DW_ATE_boolean), ty::Char => ("char", DW_ATE_unsigned_char), ty::Int(int_ty) => { - (int_ty.ty_to_string(), DW_ATE_signed) + (int_ty.name_str(), DW_ATE_signed) }, ty::Uint(uint_ty) => { - (uint_ty.ty_to_string(), DW_ATE_unsigned) + (uint_ty.name_str(), DW_ATE_unsigned) }, ty::Float(float_ty) => { - (float_ty.ty_to_string(), DW_ATE_float) + (float_ty.name_str(), DW_ATE_float) }, _ => bug!("debuginfo::basic_type_metadata - t is invalid type") }; diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 1bce34abe55..a4c3b42f51e 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -18,8 +18,8 @@ use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, Primitive}; use rustc::mir::interpret::GlobalId; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc::hir; -use syntax::ast::{self, FloatTy}; -use rustc_target::abi::HasDataLayout; +use rustc_target::abi::{FloatTy, HasDataLayout}; +use syntax::ast; use rustc_codegen_ssa::common::span_invalid_monomorphization_error; use rustc_codegen_ssa::traits::*; @@ -1335,7 +1335,7 @@ fn generic_simd_intrinsic( }, ty::Float(f) => { return_error!("unsupported element type `{}` of floating-point vector `{}`", - f, in_ty); + f.name_str(), in_ty); }, _ => { return_error!("`{}` is not a floating-point type", in_ty); diff --git a/src/librustc_codegen_ssa/debuginfo/type_names.rs b/src/librustc_codegen_ssa/debuginfo/type_names.rs index 166a74fe487..372aefacb95 100644 --- a/src/librustc_codegen_ssa/debuginfo/type_names.rs +++ b/src/librustc_codegen_ssa/debuginfo/type_names.rs @@ -37,9 +37,9 @@ pub fn push_debuginfo_type_name<'tcx>( ty::Char => output.push_str("char"), ty::Str => output.push_str("str"), ty::Never => output.push_str("!"), - ty::Int(int_ty) => output.push_str(int_ty.ty_to_string()), - ty::Uint(uint_ty) => output.push_str(uint_ty.ty_to_string()), - ty::Float(float_ty) => output.push_str(float_ty.ty_to_string()), + ty::Int(int_ty) => output.push_str(int_ty.name_str()), + ty::Uint(uint_ty) => output.push_str(uint_ty.name_str()), + ty::Float(float_ty) => output.push_str(float_ty.name_str()), ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output), ty::Adt(def, substs) => { push_item_name(tcx, def.did, qualified, output); diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml index 98e4f974a9f..35b93db1d65 100644 --- a/src/librustc_interface/Cargo.toml +++ b/src/librustc_interface/Cargo.toml @@ -27,7 +27,6 @@ rustc_codegen_utils = { path = "../librustc_codegen_utils" } rustc_metadata = { path = "../librustc_metadata" } rustc_mir = { path = "../librustc_mir" } rustc_passes = { path = "../librustc_passes" } -rustc_target = { path = "../librustc_target" } rustc_typeck = { path = "../librustc_typeck" } rustc_lint = { path = "../librustc_lint" } rustc_errors = { path = "../librustc_errors" } @@ -36,3 +35,6 @@ rustc_privacy = { path = "../librustc_privacy" } rustc_resolve = { path = "../librustc_resolve" } tempfile = "3.0.5" once_cell = "1" + +[dev-dependencies] +rustc_target = { path = "../librustc_target" } diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index f2ad400d5dd..65e0940920b 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -68,7 +68,7 @@ fn lint_overflowing_range_endpoint<'a, 'tcx>( max: u128, expr: &'tcx hir::Expr, parent_expr: &'tcx hir::Expr, - ty: impl std::fmt::Debug, + ty: &str, ) -> bool { // We only want to handle exclusive (`..`) ranges, // which are represented as `ExprKind::Struct`. @@ -83,15 +83,15 @@ fn lint_overflowing_range_endpoint<'a, 'tcx>( let mut err = cx.struct_span_lint( OVERFLOWING_LITERALS, parent_expr.span, - &format!("range endpoint is out of range for `{:?}`", ty), + &format!("range endpoint is out of range for `{}`", ty), ); if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) { use ast::{LitKind, LitIntType}; // We need to preserve the literal's suffix, // as it may determine typing information. let suffix = match lit.node { - LitKind::Int(_, LitIntType::Signed(s)) => format!("{}", s), - LitKind::Int(_, LitIntType::Unsigned(s)) => format!("{}", s), + LitKind::Int(_, LitIntType::Signed(s)) => format!("{}", s.name_str()), + LitKind::Int(_, LitIntType::Unsigned(s)) => format!("{}", s.name_str()), LitKind::Int(_, LitIntType::Unsuffixed) => "".to_owned(), _ => bug!(), }; @@ -161,11 +161,11 @@ fn report_bin_hex_error( let (t, actually) = match ty { attr::IntType::SignedInt(t) => { let actually = sign_extend(val, size) as i128; - (format!("{:?}", t), actually.to_string()) + (t.name_str(), actually.to_string()) } attr::IntType::UnsignedInt(t) => { let actually = truncate(val, size); - (format!("{:?}", t), actually.to_string()) + (t.name_str(), actually.to_string()) } }; let mut err = cx.struct_span_lint( @@ -204,7 +204,7 @@ fn report_bin_hex_error( // - `uX` => `uY` // // No suggestion for: `isize`, `usize`. -fn get_type_suggestion(t: Ty<'_>, val: u128, negative: bool) -> Option { +fn get_type_suggestion(t: Ty<'_>, val: u128, negative: bool) -> Option<&'static str> { use syntax::ast::IntTy::*; use syntax::ast::UintTy::*; macro_rules! find_fit { @@ -215,10 +215,10 @@ fn get_type_suggestion(t: Ty<'_>, val: u128, negative: bool) -> Option { match $ty { $($type => { $(if !negative && val <= uint_ty_range($utypes).1 { - return Some(format!("{:?}", $utypes)) + return Some($utypes.name_str()) })* $(if val <= int_ty_range($itypes).1 as u128 + _neg { - return Some(format!("{:?}", $itypes)) + return Some($itypes.name_str()) })* None },)+ @@ -281,7 +281,7 @@ fn lint_int_literal<'a, 'tcx>( if let Node::Expr(par_e) = cx.tcx.hir().get(par_id) { if let hir::ExprKind::Struct(..) = par_e.kind { if is_range_literal(cx.sess(), par_e) - && lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t) + && lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t.name_str()) { // The overflowing literal lint was overridden. return; @@ -292,7 +292,7 @@ fn lint_int_literal<'a, 'tcx>( cx.span_lint( OVERFLOWING_LITERALS, e.span, - &format!("literal out of range for `{:?}`", t), + &format!("literal out of range for `{}`", t.name_str()), ); } } @@ -338,6 +338,7 @@ fn lint_uint_literal<'a, 'tcx>( } hir::ExprKind::Struct(..) if is_range_literal(cx.sess(), par_e) => { + let t = t.name_str(); if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, par_e, t) { // The overflowing literal lint was overridden. return; @@ -353,7 +354,7 @@ fn lint_uint_literal<'a, 'tcx>( cx.span_lint( OVERFLOWING_LITERALS, e.span, - &format!("literal out of range for `{:?}`", t), + &format!("literal out of range for `{}`", t.name_str()), ); } } @@ -379,8 +380,7 @@ fn lint_literal<'a, 'tcx>( } ty::Float(t) => { let is_infinite = match lit.node { - ast::LitKind::Float(v, _) | - ast::LitKind::FloatUnsuffixed(v) => { + ast::LitKind::Float(v, _) => { match t { ast::FloatTy::F32 => v.as_str().parse().map(f32::is_infinite), ast::FloatTy::F64 => v.as_str().parse().map(f64::is_infinite), @@ -389,9 +389,11 @@ fn lint_literal<'a, 'tcx>( _ => bug!(), }; if is_infinite == Ok(true) { - cx.span_lint(OVERFLOWING_LITERALS, - e.span, - &format!("literal out of range for `{:?}`", t)); + cx.span_lint( + OVERFLOWING_LITERALS, + e.span, + &format!("literal out of range for `{}`", t.name_str()), + ); } } _ => {} diff --git a/src/librustc_mir/hair/constant.rs b/src/librustc_mir/hair/constant.rs index 956716f8cea..b9e75a576ca 100644 --- a/src/librustc_mir/hair/constant.rs +++ b/src/librustc_mir/hair/constant.rs @@ -45,10 +45,7 @@ crate fn lit_to_const<'tcx>( trunc(n as u128)? }, LitKind::Int(n, _) => trunc(n)?, - LitKind::Float(n, fty) => { - parse_float(n, fty, neg).map_err(|_| LitToConstError::UnparseableFloat)? - } - LitKind::FloatUnsuffixed(n) => { + LitKind::Float(n, _) => { let fty = match ty.kind { ty::Float(fty) => fty, _ => bug!() diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index b89c83d630b..2d93585e50e 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -13,7 +13,6 @@ log = "0.4" rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_codegen_utils = { path = "../librustc_codegen_utils" } -rustc_target = { path = "../librustc_target" } serde_json = "1" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index fde5c5bed4d..e58caed0c99 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -3,11 +3,9 @@ pub use Primitive::*; use crate::spec::Target; -use std::fmt; use std::ops::{Add, Deref, Sub, Mul, AddAssign, Range, RangeInclusive}; use rustc_index::vec::{Idx, IndexVec}; -use syntax_pos::symbol::{sym, Symbol}; use syntax_pos::Span; pub mod call; @@ -534,49 +532,13 @@ impl Integer { } } - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy, - PartialOrd, Ord)] + PartialOrd, Ord, Debug)] pub enum FloatTy { F32, F64, } -impl fmt::Debug for FloatTy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -impl fmt::Display for FloatTy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.ty_to_string()) - } -} - -impl FloatTy { - pub fn ty_to_string(self) -> &'static str { - match self { - FloatTy::F32 => "f32", - FloatTy::F64 => "f64", - } - } - - pub fn to_symbol(self) -> Symbol { - match self { - FloatTy::F32 => sym::f32, - FloatTy::F64 => sym::f64, - } - } - - pub fn bit_width(self) -> usize { - match self { - FloatTy::F32 => 32, - FloatTy::F64 => 64, - } - } -} - /// Fundamental unit of memory access and layout. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum Primitive { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 26f04081046..a297a0b014f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3660,8 +3660,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); opt_ty.unwrap_or_else(|| self.next_int_var()) } - ast::LitKind::Float(_, t) => tcx.mk_mach_float(t), - ast::LitKind::FloatUnsuffixed(_) => { + ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => tcx.mk_mach_float(t), + ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => { let opt_ty = expected.to_option(self).and_then(|ty| { match ty.kind { ty::Float(_) => Some(ty), diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index b1839cc05cd..3e17e7949ea 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -20,5 +20,4 @@ errors = { path = "../librustc_errors", package = "rustc_errors" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_index = { path = "../librustc_index" } rustc_lexer = { path = "../librustc_lexer" } -rustc_target = { path = "../librustc_target" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f761c35cd5c..67d1acbccfb 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -22,7 +22,6 @@ pub use GenericArgs::*; pub use UnsafeSource::*; pub use crate::util::parser::ExprPrecedence; -pub use rustc_target::abi::FloatTy; pub use syntax_pos::symbol::{Ident, Symbol as Name}; use crate::parse::token::{self, DelimToken}; @@ -1400,7 +1399,7 @@ pub struct Lit { // Clippy uses Hash and PartialEq /// Type of the integer literal based on provided suffix. -#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, Hash, PartialEq)] +#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, Hash, PartialEq)] pub enum LitIntType { /// e.g. `42_i32`. Signed(IntTy), @@ -1410,6 +1409,15 @@ pub enum LitIntType { Unsuffixed, } +/// Type of the float literal based on provided suffix. +#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug, Hash, PartialEq)] +pub enum LitFloatType { + /// A float literal with a suffix (`1f32` or `1E10f32`). + Suffixed(FloatTy), + /// A float literal without a suffix (`1.0 or 1.0E10`). + Unsuffixed, +} + /// Literal kind. /// /// E.g., `"foo"`, `42`, `12.34`, or `bool`. @@ -1427,9 +1435,7 @@ pub enum LitKind { /// An integer literal (`1`). Int(u128, LitIntType), /// A float literal (`1f64` or `1E10f64`). - Float(Symbol, FloatTy), - /// A float literal without a suffix (`1.0 or 1.0E10`). - FloatUnsuffixed(Symbol), + Float(Symbol, LitFloatType), /// A boolean literal. Bool(bool), /// Placeholder for a literal that wasn't well-formed in some way. @@ -1456,7 +1462,7 @@ impl LitKind { /// Returns `true` if this is a numeric literal. pub fn is_numeric(&self) -> bool { match *self { - LitKind::Int(..) | LitKind::Float(..) | LitKind::FloatUnsuffixed(..) => true, + LitKind::Int(..) | LitKind::Float(..) => true, _ => false, } } @@ -1473,14 +1479,14 @@ impl LitKind { // suffixed variants LitKind::Int(_, LitIntType::Signed(..)) | LitKind::Int(_, LitIntType::Unsigned(..)) - | LitKind::Float(..) => true, + | LitKind::Float(_, LitFloatType::Suffixed(..)) => true, // unsuffixed variants LitKind::Str(..) | LitKind::ByteStr(..) | LitKind::Byte(..) | LitKind::Char(..) | LitKind::Int(_, LitIntType::Unsuffixed) - | LitKind::FloatUnsuffixed(..) + | LitKind::Float(_, LitFloatType::Unsuffixed) | LitKind::Bool(..) | LitKind::Err(..) => false, } @@ -1552,7 +1558,36 @@ pub enum ImplItemKind { Macro(Mac), } -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Copy)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug)] +pub enum FloatTy { + F32, + F64, +} + +impl FloatTy { + pub fn name_str(self) -> &'static str { + match self { + FloatTy::F32 => "f32", + FloatTy::F64 => "f64", + } + } + + pub fn name(self) -> Symbol { + match self { + FloatTy::F32 => sym::f32, + FloatTy::F64 => sym::f64, + } + } + + pub fn bit_width(self) -> usize { + match self { + FloatTy::F32 => 32, + FloatTy::F64 => 64, + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug)] pub enum IntTy { Isize, I8, @@ -1562,20 +1597,8 @@ pub enum IntTy { I128, } -impl fmt::Debug for IntTy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -impl fmt::Display for IntTy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.ty_to_string()) - } -} - impl IntTy { - pub fn ty_to_string(&self) -> &'static str { + pub fn name_str(&self) -> &'static str { match *self { IntTy::Isize => "isize", IntTy::I8 => "i8", @@ -1586,7 +1609,7 @@ impl IntTy { } } - pub fn to_symbol(&self) -> Symbol { + pub fn name(&self) -> Symbol { match *self { IntTy::Isize => sym::isize, IntTy::I8 => sym::i8, @@ -1601,7 +1624,7 @@ impl IntTy { // Cast to a `u128` so we can correctly print `INT128_MIN`. All integral types // are parsed as `u128`, so we wouldn't want to print an extra negative // sign. - format!("{}{}", val as u128, self.ty_to_string()) + format!("{}{}", val as u128, self.name_str()) } pub fn bit_width(&self) -> Option { @@ -1616,7 +1639,7 @@ impl IntTy { } } -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Copy)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Copy, Debug)] pub enum UintTy { Usize, U8, @@ -1627,7 +1650,7 @@ pub enum UintTy { } impl UintTy { - pub fn ty_to_string(&self) -> &'static str { + pub fn name_str(&self) -> &'static str { match *self { UintTy::Usize => "usize", UintTy::U8 => "u8", @@ -1638,7 +1661,7 @@ impl UintTy { } } - pub fn to_symbol(&self) -> Symbol { + pub fn name(&self) -> Symbol { match *self { UintTy::Usize => sym::usize, UintTy::U8 => sym::u8, @@ -1650,7 +1673,7 @@ impl UintTy { } pub fn val_to_string(&self, val: u128) -> String { - format!("{}{}", val, self.ty_to_string()) + format!("{}{}", val, self.name_str()) } pub fn bit_width(&self) -> Option { @@ -1665,18 +1688,6 @@ impl UintTy { } } -impl fmt::Debug for UintTy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -impl fmt::Display for UintTy { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.ty_to_string()) - } -} - /// A constraint on an associated type (e.g., `A = Bar` in `Foo` or /// `A: TraitA + TraitB` in `Foo`). #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] diff --git a/src/libsyntax/parse/literal.rs b/src/libsyntax/parse/literal.rs index c42f4aa25cc..a8eeac59954 100644 --- a/src/libsyntax/parse/literal.rs +++ b/src/libsyntax/parse/literal.rs @@ -157,17 +157,18 @@ impl LitKind { } LitKind::Int(n, ty) => { let suffix = match ty { - ast::LitIntType::Unsigned(ty) => Some(ty.to_symbol()), - ast::LitIntType::Signed(ty) => Some(ty.to_symbol()), + ast::LitIntType::Unsigned(ty) => Some(ty.name()), + ast::LitIntType::Signed(ty) => Some(ty.name()), ast::LitIntType::Unsuffixed => None, }; (token::Integer, sym::integer(n), suffix) } LitKind::Float(symbol, ty) => { - (token::Float, symbol, Some(ty.to_symbol())) - } - LitKind::FloatUnsuffixed(symbol) => { - (token::Float, symbol, None) + let suffix = match ty { + ast::LitFloatType::Suffixed(ty) => Some(ty.name()), + ast::LitFloatType::Unsuffixed => None, + }; + (token::Float, symbol, suffix) } LitKind::Bool(value) => { let symbol = if value { kw::True } else { kw::False }; @@ -244,12 +245,12 @@ fn filtered_float_lit(symbol: Symbol, suffix: Option, base: u32) return Err(LitError::NonDecimalFloat(base)); } Ok(match suffix { - Some(suf) => match suf { - sym::f32 => LitKind::Float(symbol, ast::FloatTy::F32), - sym::f64 => LitKind::Float(symbol, ast::FloatTy::F64), + Some(suf) => LitKind::Float(symbol, ast::LitFloatType::Suffixed(match suf { + sym::f32 => ast::FloatTy::F32, + sym::f64 => ast::FloatTy::F64, _ => return Err(LitError::InvalidFloatSuffix), - } - None => LitKind::FloatUnsuffixed(symbol) + })), + None => LitKind::Float(symbol, ast::LitFloatType::Unsuffixed) }) } diff --git a/src/libsyntax_expand/Cargo.toml b/src/libsyntax_expand/Cargo.toml index d98b9457a62..02c711bc387 100644 --- a/src/libsyntax_expand/Cargo.toml +++ b/src/libsyntax_expand/Cargo.toml @@ -21,6 +21,5 @@ errors = { path = "../librustc_errors", package = "rustc_errors" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_index = { path = "../librustc_index" } rustc_lexer = { path = "../librustc_lexer" } -rustc_target = { path = "../librustc_target" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } syntax = { path = "../libsyntax" } diff --git a/src/libsyntax_ext/concat.rs b/src/libsyntax_ext/concat.rs index 47bade698a8..4bf13f37711 100644 --- a/src/libsyntax_ext/concat.rs +++ b/src/libsyntax_ext/concat.rs @@ -21,8 +21,7 @@ pub fn expand_concat( match e.kind { ast::ExprKind::Lit(ref lit) => match lit.kind { ast::LitKind::Str(ref s, _) - | ast::LitKind::Float(ref s, _) - | ast::LitKind::FloatUnsuffixed(ref s) => { + | ast::LitKind::Float(ref s, _) => { accumulator.push_str(&s.as_str()); } ast::LitKind::Char(c) => { -- cgit 1.4.1-3-g733a5 From da116223c709392db3741d966cb49ea0407de19e Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 25 Oct 2019 04:57:40 +0200 Subject: move parse/parser.rs -> parse/parser/mod.rs --- src/libsyntax/parse/parser.rs | 1391 ------------------------------------- src/libsyntax/parse/parser/mod.rs | 1391 +++++++++++++++++++++++++++++++++++++ 2 files changed, 1391 insertions(+), 1391 deletions(-) delete mode 100644 src/libsyntax/parse/parser.rs create mode 100644 src/libsyntax/parse/parser/mod.rs (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs deleted file mode 100644 index 1284e89f195..00000000000 --- a/src/libsyntax/parse/parser.rs +++ /dev/null @@ -1,1391 +0,0 @@ -pub mod attr; -mod expr; -mod pat; -mod item; -mod module; -mod ty; -mod path; -pub use path::PathStyle; -mod stmt; -mod generics; -mod diagnostics; -use diagnostics::Error; - -use crate::ast::{ - self, Abi, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident, - IsAsync, MacDelimiter, Mutability, StrStyle, Visibility, VisibilityKind, Unsafety, -}; -use crate::parse::{PResult, Directory, DirectoryOwnership}; -use crate::parse::lexer::UnmatchedBrace; -use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; -use crate::parse::token::{self, Token, TokenKind, DelimToken}; -use crate::print::pprust; -use crate::ptr::P; -use crate::sess::ParseSess; -use crate::source_map::respan; -use crate::symbol::{kw, sym, Symbol}; -use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint}; -use crate::ThinVec; - -use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError}; -use syntax_pos::{Span, BytePos, DUMMY_SP, FileName}; -use log::debug; - -use std::borrow::Cow; -use std::{cmp, mem, slice}; -use std::path::PathBuf; - -bitflags::bitflags! { - struct Restrictions: u8 { - const STMT_EXPR = 1 << 0; - const NO_STRUCT_LITERAL = 1 << 1; - } -} - -#[derive(Clone, Copy, PartialEq, Debug)] -enum SemiColonMode { - Break, - Ignore, - Comma, -} - -#[derive(Clone, Copy, PartialEq, Debug)] -enum BlockMode { - Break, - Ignore, -} - -/// Like `maybe_whole_expr`, but for things other than expressions. -#[macro_export] -macro_rules! maybe_whole { - ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { - if let token::Interpolated(nt) = &$p.token.kind { - if let token::$constructor(x) = &**nt { - let $x = x.clone(); - $p.bump(); - return Ok($e); - } - } - }; -} - -/// If the next tokens are ill-formed `$ty::` recover them as `<$ty>::`. -#[macro_export] -macro_rules! maybe_recover_from_interpolated_ty_qpath { - ($self: expr, $allow_qpath_recovery: expr) => { - if $allow_qpath_recovery && $self.look_ahead(1, |t| t == &token::ModSep) { - if let token::Interpolated(nt) = &$self.token.kind { - if let token::NtTy(ty) = &**nt { - let ty = ty.clone(); - $self.bump(); - return $self.maybe_recover_from_bad_qpath_stage_2($self.prev_span, ty); - } - } - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq)] -enum PrevTokenKind { - DocComment, - Comma, - Plus, - Interpolated, - Eof, - Ident, - BitOr, - Other, -} - -// NOTE: `Ident`s are handled by `common.rs`. - -#[derive(Clone)] -pub struct Parser<'a> { - pub sess: &'a ParseSess, - /// The current normalized token. - /// "Normalized" means that some interpolated tokens - /// (`$i: ident` and `$l: lifetime` meta-variables) are replaced - /// with non-interpolated identifier and lifetime tokens they refer to. - /// Perhaps the normalized / non-normalized setup can be simplified somehow. - pub token: Token, - /// The span of the current non-normalized token. - meta_var_span: Option, - /// The span of the previous non-normalized token. - pub prev_span: Span, - /// The kind of the previous normalized token (in simplified form). - prev_token_kind: PrevTokenKind, - restrictions: Restrictions, - /// Used to determine the path to externally loaded source files. - pub(super) directory: Directory<'a>, - /// `true` to parse sub-modules in other files. - pub(super) recurse_into_file_modules: bool, - /// Name of the root module this parser originated from. If `None`, then the - /// name is not known. This does not change while the parser is descending - /// into modules, and sub-parsers have new values for this name. - pub root_module_name: Option, - expected_tokens: Vec, - token_cursor: TokenCursor, - desugar_doc_comments: bool, - /// `true` we should configure out of line modules as we parse. - cfg_mods: bool, - /// This field is used to keep track of how many left angle brackets we have seen. This is - /// required in order to detect extra leading left angle brackets (`<` characters) and error - /// appropriately. - /// - /// See the comments in the `parse_path_segment` function for more details. - unmatched_angle_bracket_count: u32, - max_angle_bracket_count: u32, - /// A list of all unclosed delimiters found by the lexer. If an entry is used for error recovery - /// it gets removed from here. Every entry left at the end gets emitted as an independent - /// error. - pub(super) unclosed_delims: Vec, - last_unexpected_token_span: Option, - pub last_type_ascription: Option<(Span, bool /* likely path typo */)>, - /// If present, this `Parser` is not parsing Rust code but rather a macro call. - subparser_name: Option<&'static str>, -} - -impl<'a> Drop for Parser<'a> { - fn drop(&mut self) { - emit_unclosed_delims(&mut self.unclosed_delims, &self.sess); - } -} - -#[derive(Clone)] -struct TokenCursor { - frame: TokenCursorFrame, - stack: Vec, -} - -#[derive(Clone)] -struct TokenCursorFrame { - delim: token::DelimToken, - span: DelimSpan, - open_delim: bool, - tree_cursor: tokenstream::Cursor, - close_delim: bool, - last_token: LastToken, -} - -/// This is used in `TokenCursorFrame` above to track tokens that are consumed -/// by the parser, and then that's transitively used to record the tokens that -/// each parse AST item is created with. -/// -/// Right now this has two states, either collecting tokens or not collecting -/// tokens. If we're collecting tokens we just save everything off into a local -/// `Vec`. This should eventually though likely save tokens from the original -/// token stream and just use slicing of token streams to avoid creation of a -/// whole new vector. -/// -/// The second state is where we're passively not recording tokens, but the last -/// token is still tracked for when we want to start recording tokens. This -/// "last token" means that when we start recording tokens we'll want to ensure -/// that this, the first token, is included in the output. -/// -/// You can find some more example usage of this in the `collect_tokens` method -/// on the parser. -#[derive(Clone)] -enum LastToken { - Collecting(Vec), - Was(Option), -} - -impl TokenCursorFrame { - fn new(span: DelimSpan, delim: DelimToken, tts: &TokenStream) -> Self { - TokenCursorFrame { - delim, - span, - open_delim: delim == token::NoDelim, - tree_cursor: tts.clone().into_trees(), - close_delim: delim == token::NoDelim, - last_token: LastToken::Was(None), - } - } -} - -impl TokenCursor { - fn next(&mut self) -> Token { - loop { - let tree = if !self.frame.open_delim { - self.frame.open_delim = true; - TokenTree::open_tt(self.frame.span, self.frame.delim) - } else if let Some(tree) = self.frame.tree_cursor.next() { - tree - } else if !self.frame.close_delim { - self.frame.close_delim = true; - TokenTree::close_tt(self.frame.span, self.frame.delim) - } else if let Some(frame) = self.stack.pop() { - self.frame = frame; - continue - } else { - return Token::new(token::Eof, DUMMY_SP); - }; - - match self.frame.last_token { - LastToken::Collecting(ref mut v) => v.push(tree.clone().into()), - LastToken::Was(ref mut t) => *t = Some(tree.clone().into()), - } - - match tree { - TokenTree::Token(token) => return token, - TokenTree::Delimited(sp, delim, tts) => { - let frame = TokenCursorFrame::new(sp, delim, &tts); - self.stack.push(mem::replace(&mut self.frame, frame)); - } - } - } - } - - fn next_desugared(&mut self) -> Token { - let (name, sp) = match self.next() { - Token { kind: token::DocComment(name), span } => (name, span), - tok => return tok, - }; - - let stripped = strip_doc_comment_decoration(&name.as_str()); - - // Searches for the occurrences of `"#*` and returns the minimum number of `#`s - // required to wrap the text. - let mut num_of_hashes = 0; - let mut count = 0; - for ch in stripped.chars() { - count = match ch { - '"' => 1, - '#' if count > 0 => count + 1, - _ => 0, - }; - num_of_hashes = cmp::max(num_of_hashes, count); - } - - let delim_span = DelimSpan::from_single(sp); - let body = TokenTree::Delimited( - delim_span, - token::Bracket, - [ - TokenTree::token(token::Ident(sym::doc, false), sp), - TokenTree::token(token::Eq, sp), - TokenTree::token(TokenKind::lit( - token::StrRaw(num_of_hashes), Symbol::intern(&stripped), None - ), sp), - ] - .iter().cloned().collect::().into(), - ); - - self.stack.push(mem::replace(&mut self.frame, TokenCursorFrame::new( - delim_span, - token::NoDelim, - &if doc_comment_style(&name.as_str()) == AttrStyle::Inner { - [TokenTree::token(token::Pound, sp), TokenTree::token(token::Not, sp), body] - .iter().cloned().collect::() - } else { - [TokenTree::token(token::Pound, sp), body] - .iter().cloned().collect::() - }, - ))); - - self.next() - } -} - -#[derive(Clone, PartialEq)] -enum TokenType { - Token(TokenKind), - Keyword(Symbol), - Operator, - Lifetime, - Ident, - Path, - Type, - Const, -} - -impl TokenType { - fn to_string(&self) -> String { - match *self { - TokenType::Token(ref t) => format!("`{}`", pprust::token_kind_to_string(t)), - TokenType::Keyword(kw) => format!("`{}`", kw), - TokenType::Operator => "an operator".to_string(), - TokenType::Lifetime => "lifetime".to_string(), - TokenType::Ident => "identifier".to_string(), - TokenType::Path => "path".to_string(), - TokenType::Type => "type".to_string(), - TokenType::Const => "const".to_string(), - } - } -} - -#[derive(Copy, Clone, Debug)] -enum TokenExpectType { - Expect, - NoExpect, -} - -/// A sequence separator. -struct SeqSep { - /// The separator token. - sep: Option, - /// `true` if a trailing separator is allowed. - trailing_sep_allowed: bool, -} - -impl SeqSep { - fn trailing_allowed(t: TokenKind) -> SeqSep { - SeqSep { - sep: Some(t), - trailing_sep_allowed: true, - } - } - - fn none() -> SeqSep { - SeqSep { - sep: None, - trailing_sep_allowed: false, - } - } -} - -impl<'a> Parser<'a> { - pub fn new( - sess: &'a ParseSess, - tokens: TokenStream, - directory: Option>, - recurse_into_file_modules: bool, - desugar_doc_comments: bool, - subparser_name: Option<&'static str>, - ) -> Self { - let mut parser = Parser { - sess, - token: Token::dummy(), - prev_span: DUMMY_SP, - meta_var_span: None, - prev_token_kind: PrevTokenKind::Other, - restrictions: Restrictions::empty(), - recurse_into_file_modules, - directory: Directory { - path: Cow::from(PathBuf::new()), - ownership: DirectoryOwnership::Owned { relative: None } - }, - root_module_name: None, - expected_tokens: Vec::new(), - token_cursor: TokenCursor { - frame: TokenCursorFrame::new( - DelimSpan::dummy(), - token::NoDelim, - &tokens.into(), - ), - stack: Vec::new(), - }, - desugar_doc_comments, - cfg_mods: true, - unmatched_angle_bracket_count: 0, - max_angle_bracket_count: 0, - unclosed_delims: Vec::new(), - last_unexpected_token_span: None, - last_type_ascription: None, - subparser_name, - }; - - parser.token = parser.next_tok(); - - if let Some(directory) = directory { - parser.directory = directory; - } else if !parser.token.span.is_dummy() { - if let Some(FileName::Real(path)) = - &sess.source_map().lookup_char_pos(parser.token.span.lo()).file.unmapped_path { - if let Some(directory_path) = path.parent() { - parser.directory.path = Cow::from(directory_path.to_path_buf()); - } - } - } - - parser.process_potential_macro_variable(); - parser - } - - fn next_tok(&mut self) -> Token { - let mut next = if self.desugar_doc_comments { - self.token_cursor.next_desugared() - } else { - self.token_cursor.next() - }; - if next.span.is_dummy() { - // Tweak the location for better diagnostics, but keep syntactic context intact. - next.span = self.prev_span.with_ctxt(next.span.ctxt()); - } - next - } - - /// Converts the current token to a string using `self`'s reader. - pub fn this_token_to_string(&self) -> String { - pprust::token_to_string(&self.token) - } - - fn token_descr(&self) -> Option<&'static str> { - Some(match &self.token.kind { - _ if self.token.is_special_ident() => "reserved identifier", - _ if self.token.is_used_keyword() => "keyword", - _ if self.token.is_unused_keyword() => "reserved keyword", - token::DocComment(..) => "doc comment", - _ => return None, - }) - } - - pub(super) fn this_token_descr(&self) -> String { - if let Some(prefix) = self.token_descr() { - format!("{} `{}`", prefix, self.this_token_to_string()) - } else { - format!("`{}`", self.this_token_to_string()) - } - } - - crate fn unexpected(&mut self) -> PResult<'a, T> { - match self.expect_one_of(&[], &[]) { - Err(e) => Err(e), - Ok(_) => unreachable!(), - } - } - - /// Expects and consumes the token `t`. Signals an error if the next token is not `t`. - pub fn expect(&mut self, t: &TokenKind) -> PResult<'a, bool /* recovered */> { - if self.expected_tokens.is_empty() { - if self.token == *t { - self.bump(); - Ok(false) - } else { - self.unexpected_try_recover(t) - } - } else { - self.expect_one_of(slice::from_ref(t), &[]) - } - } - - /// Expect next token to be edible or inedible token. If edible, - /// then consume it; if inedible, then return without consuming - /// anything. Signal a fatal error if next token is unexpected. - pub fn expect_one_of( - &mut self, - edible: &[TokenKind], - inedible: &[TokenKind], - ) -> PResult<'a, bool /* recovered */> { - if edible.contains(&self.token.kind) { - self.bump(); - Ok(false) - } else if inedible.contains(&self.token.kind) { - // leave it in the input - Ok(false) - } else if self.last_unexpected_token_span == Some(self.token.span) { - FatalError.raise(); - } else { - self.expected_one_of_not_found(edible, inedible) - } - } - - fn parse_ident(&mut self) -> PResult<'a, ast::Ident> { - self.parse_ident_common(true) - } - - fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, ast::Ident> { - match self.token.kind { - token::Ident(name, _) => { - if self.token.is_reserved_ident() { - let mut err = self.expected_ident_found(); - if recover { - err.emit(); - } else { - return Err(err); - } - } - let span = self.token.span; - self.bump(); - Ok(Ident::new(name, span)) - } - _ => { - Err(if self.prev_token_kind == PrevTokenKind::DocComment { - self.span_fatal_err(self.prev_span, Error::UselessDocComment) - } else { - self.expected_ident_found() - }) - } - } - } - - /// Checks if the next token is `tok`, and returns `true` if so. - /// - /// This method will automatically add `tok` to `expected_tokens` if `tok` is not - /// encountered. - fn check(&mut self, tok: &TokenKind) -> bool { - let is_present = self.token == *tok; - if !is_present { self.expected_tokens.push(TokenType::Token(tok.clone())); } - is_present - } - - /// Consumes a token 'tok' if it exists. Returns whether the given token was present. - pub fn eat(&mut self, tok: &TokenKind) -> bool { - let is_present = self.check(tok); - if is_present { self.bump() } - is_present - } - - /// If the next token is the given keyword, returns `true` without eating it. - /// An expectation is also added for diagnostics purposes. - fn check_keyword(&mut self, kw: Symbol) -> bool { - self.expected_tokens.push(TokenType::Keyword(kw)); - self.token.is_keyword(kw) - } - - /// If the next token is the given keyword, eats it and returns `true`. - /// Otherwise, returns `false`. An expectation is also added for diagnostics purposes. - fn eat_keyword(&mut self, kw: Symbol) -> bool { - if self.check_keyword(kw) { - self.bump(); - true - } else { - false - } - } - - fn eat_keyword_noexpect(&mut self, kw: Symbol) -> bool { - if self.token.is_keyword(kw) { - self.bump(); - true - } else { - false - } - } - - /// If the given word is not a keyword, signals an error. - /// If the next token is not the given word, signals an error. - /// Otherwise, eats it. - fn expect_keyword(&mut self, kw: Symbol) -> PResult<'a, ()> { - if !self.eat_keyword(kw) { - self.unexpected() - } else { - Ok(()) - } - } - - fn check_or_expected(&mut self, ok: bool, typ: TokenType) -> bool { - if ok { - true - } else { - self.expected_tokens.push(typ); - false - } - } - - fn check_ident(&mut self) -> bool { - self.check_or_expected(self.token.is_ident(), TokenType::Ident) - } - - fn check_path(&mut self) -> bool { - self.check_or_expected(self.token.is_path_start(), TokenType::Path) - } - - fn check_type(&mut self) -> bool { - self.check_or_expected(self.token.can_begin_type(), TokenType::Type) - } - - fn check_const_arg(&mut self) -> bool { - self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const) - } - - /// Checks to see if the next token is either `+` or `+=`. - /// Otherwise returns `false`. - fn check_plus(&mut self) -> bool { - self.check_or_expected( - self.token.is_like_plus(), - TokenType::Token(token::BinOp(token::Plus)), - ) - } - - /// Expects and consumes a `+`. if `+=` is seen, replaces it with a `=` - /// and continues. If a `+` is not seen, returns `false`. - /// - /// This is used when token-splitting `+=` into `+`. - /// See issue #47856 for an example of when this may occur. - fn eat_plus(&mut self) -> bool { - self.expected_tokens.push(TokenType::Token(token::BinOp(token::Plus))); - match self.token.kind { - token::BinOp(token::Plus) => { - self.bump(); - true - } - token::BinOpEq(token::Plus) => { - let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); - self.bump_with(token::Eq, span); - true - } - _ => false, - } - } - - /// Expects and consumes an `&`. If `&&` is seen, replaces it with a single - /// `&` and continues. If an `&` is not seen, signals an error. - fn expect_and(&mut self) -> PResult<'a, ()> { - self.expected_tokens.push(TokenType::Token(token::BinOp(token::And))); - match self.token.kind { - token::BinOp(token::And) => { - self.bump(); - Ok(()) - } - token::AndAnd => { - let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); - Ok(self.bump_with(token::BinOp(token::And), span)) - } - _ => self.unexpected() - } - } - - /// Expects and consumes an `|`. If `||` is seen, replaces it with a single - /// `|` and continues. If an `|` is not seen, signals an error. - fn expect_or(&mut self) -> PResult<'a, ()> { - self.expected_tokens.push(TokenType::Token(token::BinOp(token::Or))); - match self.token.kind { - token::BinOp(token::Or) => { - self.bump(); - Ok(()) - } - token::OrOr => { - let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); - Ok(self.bump_with(token::BinOp(token::Or), span)) - } - _ => self.unexpected() - } - } - - /// Attempts to consume a `<`. If `<<` is seen, replaces it with a single - /// `<` and continue. If `<-` is seen, replaces it with a single `<` - /// and continue. If a `<` is not seen, returns false. - /// - /// This is meant to be used when parsing generics on a path to get the - /// starting token. - fn eat_lt(&mut self) -> bool { - self.expected_tokens.push(TokenType::Token(token::Lt)); - let ate = match self.token.kind { - token::Lt => { - self.bump(); - true - } - token::BinOp(token::Shl) => { - let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); - self.bump_with(token::Lt, span); - true - } - token::LArrow => { - let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); - self.bump_with(token::BinOp(token::Minus), span); - true - } - _ => false, - }; - - if ate { - // See doc comment for `unmatched_angle_bracket_count`. - self.unmatched_angle_bracket_count += 1; - self.max_angle_bracket_count += 1; - debug!("eat_lt: (increment) count={:?}", self.unmatched_angle_bracket_count); - } - - ate - } - - fn expect_lt(&mut self) -> PResult<'a, ()> { - if !self.eat_lt() { - self.unexpected() - } else { - Ok(()) - } - } - - /// Expects and consumes a single `>` token. if a `>>` is seen, replaces it - /// with a single `>` and continues. If a `>` is not seen, signals an error. - fn expect_gt(&mut self) -> PResult<'a, ()> { - self.expected_tokens.push(TokenType::Token(token::Gt)); - let ate = match self.token.kind { - token::Gt => { - self.bump(); - Some(()) - } - token::BinOp(token::Shr) => { - let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); - Some(self.bump_with(token::Gt, span)) - } - token::BinOpEq(token::Shr) => { - let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); - Some(self.bump_with(token::Ge, span)) - } - token::Ge => { - let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); - Some(self.bump_with(token::Eq, span)) - } - _ => None, - }; - - match ate { - Some(_) => { - // See doc comment for `unmatched_angle_bracket_count`. - if self.unmatched_angle_bracket_count > 0 { - self.unmatched_angle_bracket_count -= 1; - debug!("expect_gt: (decrement) count={:?}", self.unmatched_angle_bracket_count); - } - - Ok(()) - }, - None => self.unexpected(), - } - } - - /// Parses a sequence, including the closing delimiter. The function - /// `f` must consume tokens until reaching the next separator or - /// closing bracket. - fn parse_seq_to_end( - &mut self, - ket: &TokenKind, - sep: SeqSep, - f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, - ) -> PResult<'a, Vec> { - let (val, _, recovered) = self.parse_seq_to_before_end(ket, sep, f)?; - if !recovered { - self.bump(); - } - Ok(val) - } - - /// Parses a sequence, not including the closing delimiter. The function - /// `f` must consume tokens until reaching the next separator or - /// closing bracket. - fn parse_seq_to_before_end( - &mut self, - ket: &TokenKind, - sep: SeqSep, - f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, - ) -> PResult<'a, (Vec, bool, bool)> { - self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f) - } - - fn expect_any_with_type(&mut self, kets: &[&TokenKind], expect: TokenExpectType) -> bool { - kets.iter().any(|k| { - match expect { - TokenExpectType::Expect => self.check(k), - TokenExpectType::NoExpect => self.token == **k, - } - }) - } - - fn parse_seq_to_before_tokens( - &mut self, - kets: &[&TokenKind], - sep: SeqSep, - expect: TokenExpectType, - mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, - ) -> PResult<'a, (Vec, bool /* trailing */, bool /* recovered */)> { - let mut first = true; - let mut recovered = false; - let mut trailing = false; - let mut v = vec![]; - while !self.expect_any_with_type(kets, expect) { - if let token::CloseDelim(..) | token::Eof = self.token.kind { - break - } - if let Some(ref t) = sep.sep { - if first { - first = false; - } else { - match self.expect(t) { - Ok(false) => {} - Ok(true) => { - recovered = true; - break; - } - Err(mut e) => { - // Attempt to keep parsing if it was a similar separator. - if let Some(ref tokens) = t.similar_tokens() { - if tokens.contains(&self.token.kind) { - self.bump(); - } - } - e.emit(); - // Attempt to keep parsing if it was an omitted separator. - match f(self) { - Ok(t) => { - v.push(t); - continue; - }, - Err(mut e) => { - e.cancel(); - break; - } - } - } - } - } - } - if sep.trailing_sep_allowed && self.expect_any_with_type(kets, expect) { - trailing = true; - break; - } - - let t = f(self)?; - v.push(t); - } - - Ok((v, trailing, recovered)) - } - - /// Parses a sequence, including the closing delimiter. The function - /// `f` must consume tokens until reaching the next separator or - /// closing bracket. - fn parse_unspanned_seq( - &mut self, - bra: &TokenKind, - ket: &TokenKind, - sep: SeqSep, - f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, - ) -> PResult<'a, (Vec, bool)> { - self.expect(bra)?; - let (result, trailing, recovered) = self.parse_seq_to_before_end(ket, sep, f)?; - if !recovered { - self.eat(ket); - } - Ok((result, trailing)) - } - - fn parse_delim_comma_seq( - &mut self, - delim: DelimToken, - f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, - ) -> PResult<'a, (Vec, bool)> { - self.parse_unspanned_seq( - &token::OpenDelim(delim), - &token::CloseDelim(delim), - SeqSep::trailing_allowed(token::Comma), - f, - ) - } - - fn parse_paren_comma_seq( - &mut self, - f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, - ) -> PResult<'a, (Vec, bool)> { - self.parse_delim_comma_seq(token::Paren, f) - } - - /// Advance the parser by one token. - pub fn bump(&mut self) { - if self.prev_token_kind == PrevTokenKind::Eof { - // Bumping after EOF is a bad sign, usually an infinite loop. - self.bug("attempted to bump the parser past EOF (may be stuck in a loop)"); - } - - self.prev_span = self.meta_var_span.take().unwrap_or(self.token.span); - - // Record last token kind for possible error recovery. - self.prev_token_kind = match self.token.kind { - token::DocComment(..) => PrevTokenKind::DocComment, - token::Comma => PrevTokenKind::Comma, - token::BinOp(token::Plus) => PrevTokenKind::Plus, - token::BinOp(token::Or) => PrevTokenKind::BitOr, - token::Interpolated(..) => PrevTokenKind::Interpolated, - token::Eof => PrevTokenKind::Eof, - token::Ident(..) => PrevTokenKind::Ident, - _ => PrevTokenKind::Other, - }; - - self.token = self.next_tok(); - self.expected_tokens.clear(); - // Check after each token. - self.process_potential_macro_variable(); - } - - /// Advances the parser using provided token as a next one. Use this when - /// consuming a part of a token. For example a single `<` from `<<`. - fn bump_with(&mut self, next: TokenKind, span: Span) { - self.prev_span = self.token.span.with_hi(span.lo()); - // It would be incorrect to record the kind of the current token, but - // fortunately for tokens currently using `bump_with`, the - // `prev_token_kind` will be of no use anyway. - self.prev_token_kind = PrevTokenKind::Other; - self.token = Token::new(next, span); - self.expected_tokens.clear(); - } - - /// Look-ahead `dist` tokens of `self.token` and get access to that token there. - /// When `dist == 0` then the current token is looked at. - pub fn look_ahead(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R { - if dist == 0 { - return looker(&self.token); - } - - let frame = &self.token_cursor.frame; - looker(&match frame.tree_cursor.look_ahead(dist - 1) { - Some(tree) => match tree { - TokenTree::Token(token) => token, - TokenTree::Delimited(dspan, delim, _) => - Token::new(token::OpenDelim(delim), dspan.open), - } - None => Token::new(token::CloseDelim(frame.delim), frame.span.close) - }) - } - - /// Returns whether any of the given keywords are `dist` tokens ahead of the current one. - fn is_keyword_ahead(&self, dist: usize, kws: &[Symbol]) -> bool { - self.look_ahead(dist, |t| kws.iter().any(|&kw| t.is_keyword(kw))) - } - - /// Parses asyncness: `async` or nothing. - fn parse_asyncness(&mut self) -> IsAsync { - if self.eat_keyword(kw::Async) { - IsAsync::Async { - closure_id: DUMMY_NODE_ID, - return_impl_trait_id: DUMMY_NODE_ID, - } - } else { - IsAsync::NotAsync - } - } - - /// Parses unsafety: `unsafe` or nothing. - fn parse_unsafety(&mut self) -> Unsafety { - if self.eat_keyword(kw::Unsafe) { - Unsafety::Unsafe - } else { - Unsafety::Normal - } - } - - /// Parses mutability (`mut` or nothing). - fn parse_mutability(&mut self) -> Mutability { - if self.eat_keyword(kw::Mut) { - Mutability::Mutable - } else { - Mutability::Immutable - } - } - - /// Possibly parses mutability (`const` or `mut`). - fn parse_const_or_mut(&mut self) -> Option { - if self.eat_keyword(kw::Mut) { - Some(Mutability::Mutable) - } else if self.eat_keyword(kw::Const) { - Some(Mutability::Immutable) - } else { - None - } - } - - fn parse_field_name(&mut self) -> PResult<'a, Ident> { - if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = - self.token.kind { - self.expect_no_suffix(self.token.span, "a tuple index", suffix); - self.bump(); - Ok(Ident::new(symbol, self.prev_span)) - } else { - self.parse_ident_common(false) - } - } - - fn expect_delimited_token_tree(&mut self) -> PResult<'a, (MacDelimiter, TokenStream)> { - let delim = match self.token.kind { - token::OpenDelim(delim) => delim, - _ => { - let msg = "expected open delimiter"; - let mut err = self.fatal(msg); - err.span_label(self.token.span, msg); - return Err(err) - } - }; - let tts = match self.parse_token_tree() { - TokenTree::Delimited(_, _, tts) => tts, - _ => unreachable!(), - }; - let delim = match delim { - token::Paren => MacDelimiter::Parenthesis, - token::Bracket => MacDelimiter::Bracket, - token::Brace => MacDelimiter::Brace, - token::NoDelim => self.bug("unexpected no delimiter"), - }; - Ok((delim, tts.into())) - } - - fn parse_or_use_outer_attributes( - &mut self, - already_parsed_attrs: Option>, - ) -> PResult<'a, ThinVec> { - if let Some(attrs) = already_parsed_attrs { - Ok(attrs) - } else { - self.parse_outer_attributes().map(|a| a.into()) - } - } - - pub fn process_potential_macro_variable(&mut self) { - self.token = match self.token.kind { - token::Dollar if self.token.span.from_expansion() && - self.look_ahead(1, |t| t.is_ident()) => { - self.bump(); - let name = match self.token.kind { - token::Ident(name, _) => name, - _ => unreachable!() - }; - let span = self.prev_span.to(self.token.span); - self.diagnostic() - .struct_span_fatal(span, &format!("unknown macro variable `{}`", name)) - .span_label(span, "unknown macro variable") - .emit(); - self.bump(); - return - } - token::Interpolated(ref nt) => { - self.meta_var_span = Some(self.token.span); - // Interpolated identifier and lifetime tokens are replaced with usual identifier - // and lifetime tokens, so the former are never encountered during normal parsing. - match **nt { - token::NtIdent(ident, is_raw) => - Token::new(token::Ident(ident.name, is_raw), ident.span), - token::NtLifetime(ident) => - Token::new(token::Lifetime(ident.name), ident.span), - _ => return, - } - } - _ => return, - }; - } - - /// Parses a single token tree from the input. - pub fn parse_token_tree(&mut self) -> TokenTree { - match self.token.kind { - token::OpenDelim(..) => { - let frame = mem::replace(&mut self.token_cursor.frame, - self.token_cursor.stack.pop().unwrap()); - self.token.span = frame.span.entire(); - self.bump(); - TokenTree::Delimited( - frame.span, - frame.delim, - frame.tree_cursor.stream.into(), - ) - }, - token::CloseDelim(_) | token::Eof => unreachable!(), - _ => { - let token = self.token.take(); - self.bump(); - TokenTree::Token(token) - } - } - } - - /// Parses a stream of tokens into a list of `TokenTree`s, up to EOF. - pub fn parse_all_token_trees(&mut self) -> PResult<'a, Vec> { - let mut tts = Vec::new(); - while self.token != token::Eof { - tts.push(self.parse_token_tree()); - } - Ok(tts) - } - - pub fn parse_tokens(&mut self) -> TokenStream { - let mut result = Vec::new(); - loop { - match self.token.kind { - token::Eof | token::CloseDelim(..) => break, - _ => result.push(self.parse_token_tree().into()), - } - } - TokenStream::new(result) - } - - /// Evaluates the closure with restrictions in place. - /// - /// Afters the closure is evaluated, restrictions are reset. - fn with_res(&mut self, res: Restrictions, f: impl FnOnce(&mut Self) -> T) -> T { - let old = self.restrictions; - self.restrictions = res; - let res = f(self); - self.restrictions = old; - res - } - - fn is_crate_vis(&self) -> bool { - self.token.is_keyword(kw::Crate) && self.look_ahead(1, |t| t != &token::ModSep) - } - - /// Parses `pub`, `pub(crate)` and `pub(in path)` plus shortcuts `crate` for `pub(crate)`, - /// `pub(self)` for `pub(in self)` and `pub(super)` for `pub(in super)`. - /// If the following element can't be a tuple (i.e., it's a function definition), then - /// it's not a tuple struct field), and the contents within the parentheses isn't valid, - /// so emit a proper diagnostic. - pub fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> { - maybe_whole!(self, NtVis, |x| x); - - self.expected_tokens.push(TokenType::Keyword(kw::Crate)); - if self.is_crate_vis() { - self.bump(); // `crate` - self.sess.gated_spans.gate(sym::crate_visibility_modifier, self.prev_span); - return Ok(respan(self.prev_span, VisibilityKind::Crate(CrateSugar::JustCrate))); - } - - if !self.eat_keyword(kw::Pub) { - // We need a span for our `Spanned`, but there's inherently no - // keyword to grab a span from for inherited visibility; an empty span at the - // beginning of the current token would seem to be the "Schelling span". - return Ok(respan(self.token.span.shrink_to_lo(), VisibilityKind::Inherited)) - } - let lo = self.prev_span; - - if self.check(&token::OpenDelim(token::Paren)) { - // We don't `self.bump()` the `(` yet because this might be a struct definition where - // `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`. - // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so - // by the following tokens. - if self.is_keyword_ahead(1, &[kw::Crate]) - && self.look_ahead(2, |t| t != &token::ModSep) // account for `pub(crate::foo)` - { - // Parse `pub(crate)`. - self.bump(); // `(` - self.bump(); // `crate` - self.expect(&token::CloseDelim(token::Paren))?; // `)` - let vis = VisibilityKind::Crate(CrateSugar::PubCrate); - return Ok(respan(lo.to(self.prev_span), vis)); - } else if self.is_keyword_ahead(1, &[kw::In]) { - // Parse `pub(in path)`. - self.bump(); // `(` - self.bump(); // `in` - let path = self.parse_path(PathStyle::Mod)?; // `path` - self.expect(&token::CloseDelim(token::Paren))?; // `)` - let vis = VisibilityKind::Restricted { - path: P(path), - id: ast::DUMMY_NODE_ID, - }; - return Ok(respan(lo.to(self.prev_span), vis)); - } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) - && self.is_keyword_ahead(1, &[kw::Super, kw::SelfLower]) - { - // Parse `pub(self)` or `pub(super)`. - self.bump(); // `(` - let path = self.parse_path(PathStyle::Mod)?; // `super`/`self` - self.expect(&token::CloseDelim(token::Paren))?; // `)` - let vis = VisibilityKind::Restricted { - path: P(path), - id: ast::DUMMY_NODE_ID, - }; - return Ok(respan(lo.to(self.prev_span), vis)); - } else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct. - self.recover_incorrect_vis_restriction()?; - // Emit diagnostic, but continue with public visibility. - } - } - - Ok(respan(lo, VisibilityKind::Public)) - } - - /// Recovery for e.g. `pub(something) fn ...` or `struct X { pub(something) y: Z }` - fn recover_incorrect_vis_restriction(&mut self) -> PResult<'a, ()> { - self.bump(); // `(` - let path = self.parse_path(PathStyle::Mod)?; - self.expect(&token::CloseDelim(token::Paren))?; // `)` - - let msg = "incorrect visibility restriction"; - let suggestion = r##"some possible visibility restrictions are: -`pub(crate)`: visible only on the current crate -`pub(super)`: visible only in the current module's parent -`pub(in path::to::module)`: visible only on the specified path"##; - - let path_str = pprust::path_to_string(&path); - - struct_span_err!(self.sess.span_diagnostic, path.span, E0704, "{}", msg) - .help(suggestion) - .span_suggestion( - path.span, - &format!("make this visible only to module `{}` with `in`", path_str), - format!("in {}", path_str), - Applicability::MachineApplicable, - ) - .emit(); - - Ok(()) - } - - /// Parses `extern string_literal?`. - /// If `extern` is not found, the Rust ABI is used. - /// If `extern` is found and a `string_literal` does not follow, the C ABI is used. - fn parse_extern_abi(&mut self) -> PResult<'a, Abi> { - Ok(if self.eat_keyword(kw::Extern) { - self.parse_opt_abi()? - } else { - Abi::default() - }) - } - - /// Parses a string literal as an ABI spec. - /// If one is not found, the "C" ABI is used. - fn parse_opt_abi(&mut self) -> PResult<'a, Abi> { - let span = if self.token.can_begin_literal_or_bool() { - let ast::Lit { span, kind, .. } = self.parse_lit()?; - match kind { - ast::LitKind::Str(symbol, _) => return Ok(Abi::new(symbol, span)), - ast::LitKind::Err(_) => {} - _ => { - self.struct_span_err(span, "non-string ABI literal") - .span_suggestion( - span, - "specify the ABI with a string literal", - "\"C\"".to_string(), - Applicability::MaybeIncorrect, - ) - .emit(); - } - } - span - } else { - self.prev_span - }; - Ok(Abi::new(sym::C, span)) - } - - /// 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() { - self.diagnostic() - .struct_span_err_with_code( - async_span, - "`async fn` is not permitted in the 2015 edition", - DiagnosticId::Error("E0670".into()) - ) - .emit(); - } - } - - fn collect_tokens( - &mut self, - f: impl FnOnce(&mut Self) -> PResult<'a, R>, - ) -> PResult<'a, (R, TokenStream)> { - // Record all tokens we parse when parsing this item. - let mut tokens = Vec::new(); - let prev_collecting = match self.token_cursor.frame.last_token { - LastToken::Collecting(ref mut list) => { - Some(mem::take(list)) - } - LastToken::Was(ref mut last) => { - tokens.extend(last.take()); - None - } - }; - self.token_cursor.frame.last_token = LastToken::Collecting(tokens); - let prev = self.token_cursor.stack.len(); - let ret = f(self); - let last_token = if self.token_cursor.stack.len() == prev { - &mut self.token_cursor.frame.last_token - } else if self.token_cursor.stack.get(prev).is_none() { - // This can happen due to a bad interaction of two unrelated recovery mechanisms with - // mismatched delimiters *and* recovery lookahead on the likely typo `pub ident(` - // (#62881). - return Ok((ret?, TokenStream::default())); - } else { - &mut self.token_cursor.stack[prev].last_token - }; - - // Pull out the tokens that we've collected from the call to `f` above. - let mut collected_tokens = match *last_token { - LastToken::Collecting(ref mut v) => mem::take(v), - LastToken::Was(ref was) => { - let msg = format!("our vector went away? - found Was({:?})", was); - debug!("collect_tokens: {}", msg); - self.sess.span_diagnostic.delay_span_bug(self.token.span, &msg); - // This can happen due to a bad interaction of two unrelated recovery mechanisms - // with mismatched delimiters *and* recovery lookahead on the likely typo - // `pub ident(` (#62895, different but similar to the case above). - return Ok((ret?, TokenStream::default())); - } - }; - - // If we're not at EOF our current token wasn't actually consumed by - // `f`, but it'll still be in our list that we pulled out. In that case - // put it back. - let extra_token = if self.token != token::Eof { - collected_tokens.pop() - } else { - None - }; - - // If we were previously collecting tokens, then this was a recursive - // call. In that case we need to record all the tokens we collected in - // our parent list as well. To do that we push a clone of our stream - // onto the previous list. - match prev_collecting { - Some(mut list) => { - list.extend(collected_tokens.iter().cloned()); - list.extend(extra_token); - *last_token = LastToken::Collecting(list); - } - None => { - *last_token = LastToken::Was(extra_token); - } - } - - Ok((ret?, TokenStream::new(collected_tokens))) - } - - /// `::{` or `::*` - fn is_import_coupler(&mut self) -> bool { - self.check(&token::ModSep) && - self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace) || - *t == token::BinOp(token::Star)) - } - - fn parse_optional_str(&mut self) -> Option<(Symbol, ast::StrStyle, Option)> { - let ret = match self.token.kind { - token::Literal(token::Lit { kind: token::Str, symbol, suffix }) => - (symbol, ast::StrStyle::Cooked, suffix), - token::Literal(token::Lit { kind: token::StrRaw(n), symbol, suffix }) => - (symbol, ast::StrStyle::Raw(n), suffix), - _ => return None - }; - self.bump(); - Some(ret) - } - - pub fn parse_str(&mut self) -> PResult<'a, (Symbol, StrStyle)> { - match self.parse_optional_str() { - Some((s, style, suf)) => { - let sp = self.prev_span; - self.expect_no_suffix(sp, "a string literal", suf); - Ok((s, style)) - } - _ => { - let msg = "expected string literal"; - let mut err = self.fatal(msg); - err.span_label(self.token.span, msg); - Err(err) - } - } - } -} - -crate fn make_unclosed_delims_error( - unmatched: UnmatchedBrace, - sess: &ParseSess, -) -> Option> { - // `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to - // `unmatched_braces` only for error recovery in the `Parser`. - let found_delim = unmatched.found_delim?; - let mut err = sess.span_diagnostic.struct_span_err(unmatched.found_span, &format!( - "incorrect close delimiter: `{}`", - pprust::token_kind_to_string(&token::CloseDelim(found_delim)), - )); - err.span_label(unmatched.found_span, "incorrect close delimiter"); - if let Some(sp) = unmatched.candidate_span { - err.span_label(sp, "close delimiter possibly meant for this"); - } - if let Some(sp) = unmatched.unclosed_span { - err.span_label(sp, "un-closed delimiter"); - } - Some(err) -} - -pub fn emit_unclosed_delims(unclosed_delims: &mut Vec, sess: &ParseSess) { - *sess.reached_eof.borrow_mut() |= unclosed_delims.iter() - .any(|unmatched_delim| unmatched_delim.found_delim.is_none()); - for unmatched in unclosed_delims.drain(..) { - make_unclosed_delims_error(unmatched, sess).map(|mut e| e.emit()); - } -} diff --git a/src/libsyntax/parse/parser/mod.rs b/src/libsyntax/parse/parser/mod.rs new file mode 100644 index 00000000000..1284e89f195 --- /dev/null +++ b/src/libsyntax/parse/parser/mod.rs @@ -0,0 +1,1391 @@ +pub mod attr; +mod expr; +mod pat; +mod item; +mod module; +mod ty; +mod path; +pub use path::PathStyle; +mod stmt; +mod generics; +mod diagnostics; +use diagnostics::Error; + +use crate::ast::{ + self, Abi, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident, + IsAsync, MacDelimiter, Mutability, StrStyle, Visibility, VisibilityKind, Unsafety, +}; +use crate::parse::{PResult, Directory, DirectoryOwnership}; +use crate::parse::lexer::UnmatchedBrace; +use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; +use crate::parse::token::{self, Token, TokenKind, DelimToken}; +use crate::print::pprust; +use crate::ptr::P; +use crate::sess::ParseSess; +use crate::source_map::respan; +use crate::symbol::{kw, sym, Symbol}; +use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint}; +use crate::ThinVec; + +use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError}; +use syntax_pos::{Span, BytePos, DUMMY_SP, FileName}; +use log::debug; + +use std::borrow::Cow; +use std::{cmp, mem, slice}; +use std::path::PathBuf; + +bitflags::bitflags! { + struct Restrictions: u8 { + const STMT_EXPR = 1 << 0; + const NO_STRUCT_LITERAL = 1 << 1; + } +} + +#[derive(Clone, Copy, PartialEq, Debug)] +enum SemiColonMode { + Break, + Ignore, + Comma, +} + +#[derive(Clone, Copy, PartialEq, Debug)] +enum BlockMode { + Break, + Ignore, +} + +/// Like `maybe_whole_expr`, but for things other than expressions. +#[macro_export] +macro_rules! maybe_whole { + ($p:expr, $constructor:ident, |$x:ident| $e:expr) => { + if let token::Interpolated(nt) = &$p.token.kind { + if let token::$constructor(x) = &**nt { + let $x = x.clone(); + $p.bump(); + return Ok($e); + } + } + }; +} + +/// If the next tokens are ill-formed `$ty::` recover them as `<$ty>::`. +#[macro_export] +macro_rules! maybe_recover_from_interpolated_ty_qpath { + ($self: expr, $allow_qpath_recovery: expr) => { + if $allow_qpath_recovery && $self.look_ahead(1, |t| t == &token::ModSep) { + if let token::Interpolated(nt) = &$self.token.kind { + if let token::NtTy(ty) = &**nt { + let ty = ty.clone(); + $self.bump(); + return $self.maybe_recover_from_bad_qpath_stage_2($self.prev_span, ty); + } + } + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq)] +enum PrevTokenKind { + DocComment, + Comma, + Plus, + Interpolated, + Eof, + Ident, + BitOr, + Other, +} + +// NOTE: `Ident`s are handled by `common.rs`. + +#[derive(Clone)] +pub struct Parser<'a> { + pub sess: &'a ParseSess, + /// The current normalized token. + /// "Normalized" means that some interpolated tokens + /// (`$i: ident` and `$l: lifetime` meta-variables) are replaced + /// with non-interpolated identifier and lifetime tokens they refer to. + /// Perhaps the normalized / non-normalized setup can be simplified somehow. + pub token: Token, + /// The span of the current non-normalized token. + meta_var_span: Option, + /// The span of the previous non-normalized token. + pub prev_span: Span, + /// The kind of the previous normalized token (in simplified form). + prev_token_kind: PrevTokenKind, + restrictions: Restrictions, + /// Used to determine the path to externally loaded source files. + pub(super) directory: Directory<'a>, + /// `true` to parse sub-modules in other files. + pub(super) recurse_into_file_modules: bool, + /// Name of the root module this parser originated from. If `None`, then the + /// name is not known. This does not change while the parser is descending + /// into modules, and sub-parsers have new values for this name. + pub root_module_name: Option, + expected_tokens: Vec, + token_cursor: TokenCursor, + desugar_doc_comments: bool, + /// `true` we should configure out of line modules as we parse. + cfg_mods: bool, + /// This field is used to keep track of how many left angle brackets we have seen. This is + /// required in order to detect extra leading left angle brackets (`<` characters) and error + /// appropriately. + /// + /// See the comments in the `parse_path_segment` function for more details. + unmatched_angle_bracket_count: u32, + max_angle_bracket_count: u32, + /// A list of all unclosed delimiters found by the lexer. If an entry is used for error recovery + /// it gets removed from here. Every entry left at the end gets emitted as an independent + /// error. + pub(super) unclosed_delims: Vec, + last_unexpected_token_span: Option, + pub last_type_ascription: Option<(Span, bool /* likely path typo */)>, + /// If present, this `Parser` is not parsing Rust code but rather a macro call. + subparser_name: Option<&'static str>, +} + +impl<'a> Drop for Parser<'a> { + fn drop(&mut self) { + emit_unclosed_delims(&mut self.unclosed_delims, &self.sess); + } +} + +#[derive(Clone)] +struct TokenCursor { + frame: TokenCursorFrame, + stack: Vec, +} + +#[derive(Clone)] +struct TokenCursorFrame { + delim: token::DelimToken, + span: DelimSpan, + open_delim: bool, + tree_cursor: tokenstream::Cursor, + close_delim: bool, + last_token: LastToken, +} + +/// This is used in `TokenCursorFrame` above to track tokens that are consumed +/// by the parser, and then that's transitively used to record the tokens that +/// each parse AST item is created with. +/// +/// Right now this has two states, either collecting tokens or not collecting +/// tokens. If we're collecting tokens we just save everything off into a local +/// `Vec`. This should eventually though likely save tokens from the original +/// token stream and just use slicing of token streams to avoid creation of a +/// whole new vector. +/// +/// The second state is where we're passively not recording tokens, but the last +/// token is still tracked for when we want to start recording tokens. This +/// "last token" means that when we start recording tokens we'll want to ensure +/// that this, the first token, is included in the output. +/// +/// You can find some more example usage of this in the `collect_tokens` method +/// on the parser. +#[derive(Clone)] +enum LastToken { + Collecting(Vec), + Was(Option), +} + +impl TokenCursorFrame { + fn new(span: DelimSpan, delim: DelimToken, tts: &TokenStream) -> Self { + TokenCursorFrame { + delim, + span, + open_delim: delim == token::NoDelim, + tree_cursor: tts.clone().into_trees(), + close_delim: delim == token::NoDelim, + last_token: LastToken::Was(None), + } + } +} + +impl TokenCursor { + fn next(&mut self) -> Token { + loop { + let tree = if !self.frame.open_delim { + self.frame.open_delim = true; + TokenTree::open_tt(self.frame.span, self.frame.delim) + } else if let Some(tree) = self.frame.tree_cursor.next() { + tree + } else if !self.frame.close_delim { + self.frame.close_delim = true; + TokenTree::close_tt(self.frame.span, self.frame.delim) + } else if let Some(frame) = self.stack.pop() { + self.frame = frame; + continue + } else { + return Token::new(token::Eof, DUMMY_SP); + }; + + match self.frame.last_token { + LastToken::Collecting(ref mut v) => v.push(tree.clone().into()), + LastToken::Was(ref mut t) => *t = Some(tree.clone().into()), + } + + match tree { + TokenTree::Token(token) => return token, + TokenTree::Delimited(sp, delim, tts) => { + let frame = TokenCursorFrame::new(sp, delim, &tts); + self.stack.push(mem::replace(&mut self.frame, frame)); + } + } + } + } + + fn next_desugared(&mut self) -> Token { + let (name, sp) = match self.next() { + Token { kind: token::DocComment(name), span } => (name, span), + tok => return tok, + }; + + let stripped = strip_doc_comment_decoration(&name.as_str()); + + // Searches for the occurrences of `"#*` and returns the minimum number of `#`s + // required to wrap the text. + let mut num_of_hashes = 0; + let mut count = 0; + for ch in stripped.chars() { + count = match ch { + '"' => 1, + '#' if count > 0 => count + 1, + _ => 0, + }; + num_of_hashes = cmp::max(num_of_hashes, count); + } + + let delim_span = DelimSpan::from_single(sp); + let body = TokenTree::Delimited( + delim_span, + token::Bracket, + [ + TokenTree::token(token::Ident(sym::doc, false), sp), + TokenTree::token(token::Eq, sp), + TokenTree::token(TokenKind::lit( + token::StrRaw(num_of_hashes), Symbol::intern(&stripped), None + ), sp), + ] + .iter().cloned().collect::().into(), + ); + + self.stack.push(mem::replace(&mut self.frame, TokenCursorFrame::new( + delim_span, + token::NoDelim, + &if doc_comment_style(&name.as_str()) == AttrStyle::Inner { + [TokenTree::token(token::Pound, sp), TokenTree::token(token::Not, sp), body] + .iter().cloned().collect::() + } else { + [TokenTree::token(token::Pound, sp), body] + .iter().cloned().collect::() + }, + ))); + + self.next() + } +} + +#[derive(Clone, PartialEq)] +enum TokenType { + Token(TokenKind), + Keyword(Symbol), + Operator, + Lifetime, + Ident, + Path, + Type, + Const, +} + +impl TokenType { + fn to_string(&self) -> String { + match *self { + TokenType::Token(ref t) => format!("`{}`", pprust::token_kind_to_string(t)), + TokenType::Keyword(kw) => format!("`{}`", kw), + TokenType::Operator => "an operator".to_string(), + TokenType::Lifetime => "lifetime".to_string(), + TokenType::Ident => "identifier".to_string(), + TokenType::Path => "path".to_string(), + TokenType::Type => "type".to_string(), + TokenType::Const => "const".to_string(), + } + } +} + +#[derive(Copy, Clone, Debug)] +enum TokenExpectType { + Expect, + NoExpect, +} + +/// A sequence separator. +struct SeqSep { + /// The separator token. + sep: Option, + /// `true` if a trailing separator is allowed. + trailing_sep_allowed: bool, +} + +impl SeqSep { + fn trailing_allowed(t: TokenKind) -> SeqSep { + SeqSep { + sep: Some(t), + trailing_sep_allowed: true, + } + } + + fn none() -> SeqSep { + SeqSep { + sep: None, + trailing_sep_allowed: false, + } + } +} + +impl<'a> Parser<'a> { + pub fn new( + sess: &'a ParseSess, + tokens: TokenStream, + directory: Option>, + recurse_into_file_modules: bool, + desugar_doc_comments: bool, + subparser_name: Option<&'static str>, + ) -> Self { + let mut parser = Parser { + sess, + token: Token::dummy(), + prev_span: DUMMY_SP, + meta_var_span: None, + prev_token_kind: PrevTokenKind::Other, + restrictions: Restrictions::empty(), + recurse_into_file_modules, + directory: Directory { + path: Cow::from(PathBuf::new()), + ownership: DirectoryOwnership::Owned { relative: None } + }, + root_module_name: None, + expected_tokens: Vec::new(), + token_cursor: TokenCursor { + frame: TokenCursorFrame::new( + DelimSpan::dummy(), + token::NoDelim, + &tokens.into(), + ), + stack: Vec::new(), + }, + desugar_doc_comments, + cfg_mods: true, + unmatched_angle_bracket_count: 0, + max_angle_bracket_count: 0, + unclosed_delims: Vec::new(), + last_unexpected_token_span: None, + last_type_ascription: None, + subparser_name, + }; + + parser.token = parser.next_tok(); + + if let Some(directory) = directory { + parser.directory = directory; + } else if !parser.token.span.is_dummy() { + if let Some(FileName::Real(path)) = + &sess.source_map().lookup_char_pos(parser.token.span.lo()).file.unmapped_path { + if let Some(directory_path) = path.parent() { + parser.directory.path = Cow::from(directory_path.to_path_buf()); + } + } + } + + parser.process_potential_macro_variable(); + parser + } + + fn next_tok(&mut self) -> Token { + let mut next = if self.desugar_doc_comments { + self.token_cursor.next_desugared() + } else { + self.token_cursor.next() + }; + if next.span.is_dummy() { + // Tweak the location for better diagnostics, but keep syntactic context intact. + next.span = self.prev_span.with_ctxt(next.span.ctxt()); + } + next + } + + /// Converts the current token to a string using `self`'s reader. + pub fn this_token_to_string(&self) -> String { + pprust::token_to_string(&self.token) + } + + fn token_descr(&self) -> Option<&'static str> { + Some(match &self.token.kind { + _ if self.token.is_special_ident() => "reserved identifier", + _ if self.token.is_used_keyword() => "keyword", + _ if self.token.is_unused_keyword() => "reserved keyword", + token::DocComment(..) => "doc comment", + _ => return None, + }) + } + + pub(super) fn this_token_descr(&self) -> String { + if let Some(prefix) = self.token_descr() { + format!("{} `{}`", prefix, self.this_token_to_string()) + } else { + format!("`{}`", self.this_token_to_string()) + } + } + + crate fn unexpected(&mut self) -> PResult<'a, T> { + match self.expect_one_of(&[], &[]) { + Err(e) => Err(e), + Ok(_) => unreachable!(), + } + } + + /// Expects and consumes the token `t`. Signals an error if the next token is not `t`. + pub fn expect(&mut self, t: &TokenKind) -> PResult<'a, bool /* recovered */> { + if self.expected_tokens.is_empty() { + if self.token == *t { + self.bump(); + Ok(false) + } else { + self.unexpected_try_recover(t) + } + } else { + self.expect_one_of(slice::from_ref(t), &[]) + } + } + + /// Expect next token to be edible or inedible token. If edible, + /// then consume it; if inedible, then return without consuming + /// anything. Signal a fatal error if next token is unexpected. + pub fn expect_one_of( + &mut self, + edible: &[TokenKind], + inedible: &[TokenKind], + ) -> PResult<'a, bool /* recovered */> { + if edible.contains(&self.token.kind) { + self.bump(); + Ok(false) + } else if inedible.contains(&self.token.kind) { + // leave it in the input + Ok(false) + } else if self.last_unexpected_token_span == Some(self.token.span) { + FatalError.raise(); + } else { + self.expected_one_of_not_found(edible, inedible) + } + } + + fn parse_ident(&mut self) -> PResult<'a, ast::Ident> { + self.parse_ident_common(true) + } + + fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, ast::Ident> { + match self.token.kind { + token::Ident(name, _) => { + if self.token.is_reserved_ident() { + let mut err = self.expected_ident_found(); + if recover { + err.emit(); + } else { + return Err(err); + } + } + let span = self.token.span; + self.bump(); + Ok(Ident::new(name, span)) + } + _ => { + Err(if self.prev_token_kind == PrevTokenKind::DocComment { + self.span_fatal_err(self.prev_span, Error::UselessDocComment) + } else { + self.expected_ident_found() + }) + } + } + } + + /// Checks if the next token is `tok`, and returns `true` if so. + /// + /// This method will automatically add `tok` to `expected_tokens` if `tok` is not + /// encountered. + fn check(&mut self, tok: &TokenKind) -> bool { + let is_present = self.token == *tok; + if !is_present { self.expected_tokens.push(TokenType::Token(tok.clone())); } + is_present + } + + /// Consumes a token 'tok' if it exists. Returns whether the given token was present. + pub fn eat(&mut self, tok: &TokenKind) -> bool { + let is_present = self.check(tok); + if is_present { self.bump() } + is_present + } + + /// If the next token is the given keyword, returns `true` without eating it. + /// An expectation is also added for diagnostics purposes. + fn check_keyword(&mut self, kw: Symbol) -> bool { + self.expected_tokens.push(TokenType::Keyword(kw)); + self.token.is_keyword(kw) + } + + /// If the next token is the given keyword, eats it and returns `true`. + /// Otherwise, returns `false`. An expectation is also added for diagnostics purposes. + fn eat_keyword(&mut self, kw: Symbol) -> bool { + if self.check_keyword(kw) { + self.bump(); + true + } else { + false + } + } + + fn eat_keyword_noexpect(&mut self, kw: Symbol) -> bool { + if self.token.is_keyword(kw) { + self.bump(); + true + } else { + false + } + } + + /// If the given word is not a keyword, signals an error. + /// If the next token is not the given word, signals an error. + /// Otherwise, eats it. + fn expect_keyword(&mut self, kw: Symbol) -> PResult<'a, ()> { + if !self.eat_keyword(kw) { + self.unexpected() + } else { + Ok(()) + } + } + + fn check_or_expected(&mut self, ok: bool, typ: TokenType) -> bool { + if ok { + true + } else { + self.expected_tokens.push(typ); + false + } + } + + fn check_ident(&mut self) -> bool { + self.check_or_expected(self.token.is_ident(), TokenType::Ident) + } + + fn check_path(&mut self) -> bool { + self.check_or_expected(self.token.is_path_start(), TokenType::Path) + } + + fn check_type(&mut self) -> bool { + self.check_or_expected(self.token.can_begin_type(), TokenType::Type) + } + + fn check_const_arg(&mut self) -> bool { + self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const) + } + + /// Checks to see if the next token is either `+` or `+=`. + /// Otherwise returns `false`. + fn check_plus(&mut self) -> bool { + self.check_or_expected( + self.token.is_like_plus(), + TokenType::Token(token::BinOp(token::Plus)), + ) + } + + /// Expects and consumes a `+`. if `+=` is seen, replaces it with a `=` + /// and continues. If a `+` is not seen, returns `false`. + /// + /// This is used when token-splitting `+=` into `+`. + /// See issue #47856 for an example of when this may occur. + fn eat_plus(&mut self) -> bool { + self.expected_tokens.push(TokenType::Token(token::BinOp(token::Plus))); + match self.token.kind { + token::BinOp(token::Plus) => { + self.bump(); + true + } + token::BinOpEq(token::Plus) => { + let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); + self.bump_with(token::Eq, span); + true + } + _ => false, + } + } + + /// Expects and consumes an `&`. If `&&` is seen, replaces it with a single + /// `&` and continues. If an `&` is not seen, signals an error. + fn expect_and(&mut self) -> PResult<'a, ()> { + self.expected_tokens.push(TokenType::Token(token::BinOp(token::And))); + match self.token.kind { + token::BinOp(token::And) => { + self.bump(); + Ok(()) + } + token::AndAnd => { + let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); + Ok(self.bump_with(token::BinOp(token::And), span)) + } + _ => self.unexpected() + } + } + + /// Expects and consumes an `|`. If `||` is seen, replaces it with a single + /// `|` and continues. If an `|` is not seen, signals an error. + fn expect_or(&mut self) -> PResult<'a, ()> { + self.expected_tokens.push(TokenType::Token(token::BinOp(token::Or))); + match self.token.kind { + token::BinOp(token::Or) => { + self.bump(); + Ok(()) + } + token::OrOr => { + let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); + Ok(self.bump_with(token::BinOp(token::Or), span)) + } + _ => self.unexpected() + } + } + + /// Attempts to consume a `<`. If `<<` is seen, replaces it with a single + /// `<` and continue. If `<-` is seen, replaces it with a single `<` + /// and continue. If a `<` is not seen, returns false. + /// + /// This is meant to be used when parsing generics on a path to get the + /// starting token. + fn eat_lt(&mut self) -> bool { + self.expected_tokens.push(TokenType::Token(token::Lt)); + let ate = match self.token.kind { + token::Lt => { + self.bump(); + true + } + token::BinOp(token::Shl) => { + let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); + self.bump_with(token::Lt, span); + true + } + token::LArrow => { + let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); + self.bump_with(token::BinOp(token::Minus), span); + true + } + _ => false, + }; + + if ate { + // See doc comment for `unmatched_angle_bracket_count`. + self.unmatched_angle_bracket_count += 1; + self.max_angle_bracket_count += 1; + debug!("eat_lt: (increment) count={:?}", self.unmatched_angle_bracket_count); + } + + ate + } + + fn expect_lt(&mut self) -> PResult<'a, ()> { + if !self.eat_lt() { + self.unexpected() + } else { + Ok(()) + } + } + + /// Expects and consumes a single `>` token. if a `>>` is seen, replaces it + /// with a single `>` and continues. If a `>` is not seen, signals an error. + fn expect_gt(&mut self) -> PResult<'a, ()> { + self.expected_tokens.push(TokenType::Token(token::Gt)); + let ate = match self.token.kind { + token::Gt => { + self.bump(); + Some(()) + } + token::BinOp(token::Shr) => { + let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); + Some(self.bump_with(token::Gt, span)) + } + token::BinOpEq(token::Shr) => { + let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); + Some(self.bump_with(token::Ge, span)) + } + token::Ge => { + let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1)); + Some(self.bump_with(token::Eq, span)) + } + _ => None, + }; + + match ate { + Some(_) => { + // See doc comment for `unmatched_angle_bracket_count`. + if self.unmatched_angle_bracket_count > 0 { + self.unmatched_angle_bracket_count -= 1; + debug!("expect_gt: (decrement) count={:?}", self.unmatched_angle_bracket_count); + } + + Ok(()) + }, + None => self.unexpected(), + } + } + + /// Parses a sequence, including the closing delimiter. The function + /// `f` must consume tokens until reaching the next separator or + /// closing bracket. + fn parse_seq_to_end( + &mut self, + ket: &TokenKind, + sep: SeqSep, + f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> PResult<'a, Vec> { + let (val, _, recovered) = self.parse_seq_to_before_end(ket, sep, f)?; + if !recovered { + self.bump(); + } + Ok(val) + } + + /// Parses a sequence, not including the closing delimiter. The function + /// `f` must consume tokens until reaching the next separator or + /// closing bracket. + fn parse_seq_to_before_end( + &mut self, + ket: &TokenKind, + sep: SeqSep, + f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> PResult<'a, (Vec, bool, bool)> { + self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f) + } + + fn expect_any_with_type(&mut self, kets: &[&TokenKind], expect: TokenExpectType) -> bool { + kets.iter().any(|k| { + match expect { + TokenExpectType::Expect => self.check(k), + TokenExpectType::NoExpect => self.token == **k, + } + }) + } + + fn parse_seq_to_before_tokens( + &mut self, + kets: &[&TokenKind], + sep: SeqSep, + expect: TokenExpectType, + mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> PResult<'a, (Vec, bool /* trailing */, bool /* recovered */)> { + let mut first = true; + let mut recovered = false; + let mut trailing = false; + let mut v = vec![]; + while !self.expect_any_with_type(kets, expect) { + if let token::CloseDelim(..) | token::Eof = self.token.kind { + break + } + if let Some(ref t) = sep.sep { + if first { + first = false; + } else { + match self.expect(t) { + Ok(false) => {} + Ok(true) => { + recovered = true; + break; + } + Err(mut e) => { + // Attempt to keep parsing if it was a similar separator. + if let Some(ref tokens) = t.similar_tokens() { + if tokens.contains(&self.token.kind) { + self.bump(); + } + } + e.emit(); + // Attempt to keep parsing if it was an omitted separator. + match f(self) { + Ok(t) => { + v.push(t); + continue; + }, + Err(mut e) => { + e.cancel(); + break; + } + } + } + } + } + } + if sep.trailing_sep_allowed && self.expect_any_with_type(kets, expect) { + trailing = true; + break; + } + + let t = f(self)?; + v.push(t); + } + + Ok((v, trailing, recovered)) + } + + /// Parses a sequence, including the closing delimiter. The function + /// `f` must consume tokens until reaching the next separator or + /// closing bracket. + fn parse_unspanned_seq( + &mut self, + bra: &TokenKind, + ket: &TokenKind, + sep: SeqSep, + f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> PResult<'a, (Vec, bool)> { + self.expect(bra)?; + let (result, trailing, recovered) = self.parse_seq_to_before_end(ket, sep, f)?; + if !recovered { + self.eat(ket); + } + Ok((result, trailing)) + } + + fn parse_delim_comma_seq( + &mut self, + delim: DelimToken, + f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> PResult<'a, (Vec, bool)> { + self.parse_unspanned_seq( + &token::OpenDelim(delim), + &token::CloseDelim(delim), + SeqSep::trailing_allowed(token::Comma), + f, + ) + } + + fn parse_paren_comma_seq( + &mut self, + f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, + ) -> PResult<'a, (Vec, bool)> { + self.parse_delim_comma_seq(token::Paren, f) + } + + /// Advance the parser by one token. + pub fn bump(&mut self) { + if self.prev_token_kind == PrevTokenKind::Eof { + // Bumping after EOF is a bad sign, usually an infinite loop. + self.bug("attempted to bump the parser past EOF (may be stuck in a loop)"); + } + + self.prev_span = self.meta_var_span.take().unwrap_or(self.token.span); + + // Record last token kind for possible error recovery. + self.prev_token_kind = match self.token.kind { + token::DocComment(..) => PrevTokenKind::DocComment, + token::Comma => PrevTokenKind::Comma, + token::BinOp(token::Plus) => PrevTokenKind::Plus, + token::BinOp(token::Or) => PrevTokenKind::BitOr, + token::Interpolated(..) => PrevTokenKind::Interpolated, + token::Eof => PrevTokenKind::Eof, + token::Ident(..) => PrevTokenKind::Ident, + _ => PrevTokenKind::Other, + }; + + self.token = self.next_tok(); + self.expected_tokens.clear(); + // Check after each token. + self.process_potential_macro_variable(); + } + + /// Advances the parser using provided token as a next one. Use this when + /// consuming a part of a token. For example a single `<` from `<<`. + fn bump_with(&mut self, next: TokenKind, span: Span) { + self.prev_span = self.token.span.with_hi(span.lo()); + // It would be incorrect to record the kind of the current token, but + // fortunately for tokens currently using `bump_with`, the + // `prev_token_kind` will be of no use anyway. + self.prev_token_kind = PrevTokenKind::Other; + self.token = Token::new(next, span); + self.expected_tokens.clear(); + } + + /// Look-ahead `dist` tokens of `self.token` and get access to that token there. + /// When `dist == 0` then the current token is looked at. + pub fn look_ahead(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R { + if dist == 0 { + return looker(&self.token); + } + + let frame = &self.token_cursor.frame; + looker(&match frame.tree_cursor.look_ahead(dist - 1) { + Some(tree) => match tree { + TokenTree::Token(token) => token, + TokenTree::Delimited(dspan, delim, _) => + Token::new(token::OpenDelim(delim), dspan.open), + } + None => Token::new(token::CloseDelim(frame.delim), frame.span.close) + }) + } + + /// Returns whether any of the given keywords are `dist` tokens ahead of the current one. + fn is_keyword_ahead(&self, dist: usize, kws: &[Symbol]) -> bool { + self.look_ahead(dist, |t| kws.iter().any(|&kw| t.is_keyword(kw))) + } + + /// Parses asyncness: `async` or nothing. + fn parse_asyncness(&mut self) -> IsAsync { + if self.eat_keyword(kw::Async) { + IsAsync::Async { + closure_id: DUMMY_NODE_ID, + return_impl_trait_id: DUMMY_NODE_ID, + } + } else { + IsAsync::NotAsync + } + } + + /// Parses unsafety: `unsafe` or nothing. + fn parse_unsafety(&mut self) -> Unsafety { + if self.eat_keyword(kw::Unsafe) { + Unsafety::Unsafe + } else { + Unsafety::Normal + } + } + + /// Parses mutability (`mut` or nothing). + fn parse_mutability(&mut self) -> Mutability { + if self.eat_keyword(kw::Mut) { + Mutability::Mutable + } else { + Mutability::Immutable + } + } + + /// Possibly parses mutability (`const` or `mut`). + fn parse_const_or_mut(&mut self) -> Option { + if self.eat_keyword(kw::Mut) { + Some(Mutability::Mutable) + } else if self.eat_keyword(kw::Const) { + Some(Mutability::Immutable) + } else { + None + } + } + + fn parse_field_name(&mut self) -> PResult<'a, Ident> { + if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = + self.token.kind { + self.expect_no_suffix(self.token.span, "a tuple index", suffix); + self.bump(); + Ok(Ident::new(symbol, self.prev_span)) + } else { + self.parse_ident_common(false) + } + } + + fn expect_delimited_token_tree(&mut self) -> PResult<'a, (MacDelimiter, TokenStream)> { + let delim = match self.token.kind { + token::OpenDelim(delim) => delim, + _ => { + let msg = "expected open delimiter"; + let mut err = self.fatal(msg); + err.span_label(self.token.span, msg); + return Err(err) + } + }; + let tts = match self.parse_token_tree() { + TokenTree::Delimited(_, _, tts) => tts, + _ => unreachable!(), + }; + let delim = match delim { + token::Paren => MacDelimiter::Parenthesis, + token::Bracket => MacDelimiter::Bracket, + token::Brace => MacDelimiter::Brace, + token::NoDelim => self.bug("unexpected no delimiter"), + }; + Ok((delim, tts.into())) + } + + fn parse_or_use_outer_attributes( + &mut self, + already_parsed_attrs: Option>, + ) -> PResult<'a, ThinVec> { + if let Some(attrs) = already_parsed_attrs { + Ok(attrs) + } else { + self.parse_outer_attributes().map(|a| a.into()) + } + } + + pub fn process_potential_macro_variable(&mut self) { + self.token = match self.token.kind { + token::Dollar if self.token.span.from_expansion() && + self.look_ahead(1, |t| t.is_ident()) => { + self.bump(); + let name = match self.token.kind { + token::Ident(name, _) => name, + _ => unreachable!() + }; + let span = self.prev_span.to(self.token.span); + self.diagnostic() + .struct_span_fatal(span, &format!("unknown macro variable `{}`", name)) + .span_label(span, "unknown macro variable") + .emit(); + self.bump(); + return + } + token::Interpolated(ref nt) => { + self.meta_var_span = Some(self.token.span); + // Interpolated identifier and lifetime tokens are replaced with usual identifier + // and lifetime tokens, so the former are never encountered during normal parsing. + match **nt { + token::NtIdent(ident, is_raw) => + Token::new(token::Ident(ident.name, is_raw), ident.span), + token::NtLifetime(ident) => + Token::new(token::Lifetime(ident.name), ident.span), + _ => return, + } + } + _ => return, + }; + } + + /// Parses a single token tree from the input. + pub fn parse_token_tree(&mut self) -> TokenTree { + match self.token.kind { + token::OpenDelim(..) => { + let frame = mem::replace(&mut self.token_cursor.frame, + self.token_cursor.stack.pop().unwrap()); + self.token.span = frame.span.entire(); + self.bump(); + TokenTree::Delimited( + frame.span, + frame.delim, + frame.tree_cursor.stream.into(), + ) + }, + token::CloseDelim(_) | token::Eof => unreachable!(), + _ => { + let token = self.token.take(); + self.bump(); + TokenTree::Token(token) + } + } + } + + /// Parses a stream of tokens into a list of `TokenTree`s, up to EOF. + pub fn parse_all_token_trees(&mut self) -> PResult<'a, Vec> { + let mut tts = Vec::new(); + while self.token != token::Eof { + tts.push(self.parse_token_tree()); + } + Ok(tts) + } + + pub fn parse_tokens(&mut self) -> TokenStream { + let mut result = Vec::new(); + loop { + match self.token.kind { + token::Eof | token::CloseDelim(..) => break, + _ => result.push(self.parse_token_tree().into()), + } + } + TokenStream::new(result) + } + + /// Evaluates the closure with restrictions in place. + /// + /// Afters the closure is evaluated, restrictions are reset. + fn with_res(&mut self, res: Restrictions, f: impl FnOnce(&mut Self) -> T) -> T { + let old = self.restrictions; + self.restrictions = res; + let res = f(self); + self.restrictions = old; + res + } + + fn is_crate_vis(&self) -> bool { + self.token.is_keyword(kw::Crate) && self.look_ahead(1, |t| t != &token::ModSep) + } + + /// Parses `pub`, `pub(crate)` and `pub(in path)` plus shortcuts `crate` for `pub(crate)`, + /// `pub(self)` for `pub(in self)` and `pub(super)` for `pub(in super)`. + /// If the following element can't be a tuple (i.e., it's a function definition), then + /// it's not a tuple struct field), and the contents within the parentheses isn't valid, + /// so emit a proper diagnostic. + pub fn parse_visibility(&mut self, can_take_tuple: bool) -> PResult<'a, Visibility> { + maybe_whole!(self, NtVis, |x| x); + + self.expected_tokens.push(TokenType::Keyword(kw::Crate)); + if self.is_crate_vis() { + self.bump(); // `crate` + self.sess.gated_spans.gate(sym::crate_visibility_modifier, self.prev_span); + return Ok(respan(self.prev_span, VisibilityKind::Crate(CrateSugar::JustCrate))); + } + + if !self.eat_keyword(kw::Pub) { + // We need a span for our `Spanned`, but there's inherently no + // keyword to grab a span from for inherited visibility; an empty span at the + // beginning of the current token would seem to be the "Schelling span". + return Ok(respan(self.token.span.shrink_to_lo(), VisibilityKind::Inherited)) + } + let lo = self.prev_span; + + if self.check(&token::OpenDelim(token::Paren)) { + // We don't `self.bump()` the `(` yet because this might be a struct definition where + // `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`. + // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so + // by the following tokens. + if self.is_keyword_ahead(1, &[kw::Crate]) + && self.look_ahead(2, |t| t != &token::ModSep) // account for `pub(crate::foo)` + { + // Parse `pub(crate)`. + self.bump(); // `(` + self.bump(); // `crate` + self.expect(&token::CloseDelim(token::Paren))?; // `)` + let vis = VisibilityKind::Crate(CrateSugar::PubCrate); + return Ok(respan(lo.to(self.prev_span), vis)); + } else if self.is_keyword_ahead(1, &[kw::In]) { + // Parse `pub(in path)`. + self.bump(); // `(` + self.bump(); // `in` + let path = self.parse_path(PathStyle::Mod)?; // `path` + self.expect(&token::CloseDelim(token::Paren))?; // `)` + let vis = VisibilityKind::Restricted { + path: P(path), + id: ast::DUMMY_NODE_ID, + }; + return Ok(respan(lo.to(self.prev_span), vis)); + } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) + && self.is_keyword_ahead(1, &[kw::Super, kw::SelfLower]) + { + // Parse `pub(self)` or `pub(super)`. + self.bump(); // `(` + let path = self.parse_path(PathStyle::Mod)?; // `super`/`self` + self.expect(&token::CloseDelim(token::Paren))?; // `)` + let vis = VisibilityKind::Restricted { + path: P(path), + id: ast::DUMMY_NODE_ID, + }; + return Ok(respan(lo.to(self.prev_span), vis)); + } else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct. + self.recover_incorrect_vis_restriction()?; + // Emit diagnostic, but continue with public visibility. + } + } + + Ok(respan(lo, VisibilityKind::Public)) + } + + /// Recovery for e.g. `pub(something) fn ...` or `struct X { pub(something) y: Z }` + fn recover_incorrect_vis_restriction(&mut self) -> PResult<'a, ()> { + self.bump(); // `(` + let path = self.parse_path(PathStyle::Mod)?; + self.expect(&token::CloseDelim(token::Paren))?; // `)` + + let msg = "incorrect visibility restriction"; + let suggestion = r##"some possible visibility restrictions are: +`pub(crate)`: visible only on the current crate +`pub(super)`: visible only in the current module's parent +`pub(in path::to::module)`: visible only on the specified path"##; + + let path_str = pprust::path_to_string(&path); + + struct_span_err!(self.sess.span_diagnostic, path.span, E0704, "{}", msg) + .help(suggestion) + .span_suggestion( + path.span, + &format!("make this visible only to module `{}` with `in`", path_str), + format!("in {}", path_str), + Applicability::MachineApplicable, + ) + .emit(); + + Ok(()) + } + + /// Parses `extern string_literal?`. + /// If `extern` is not found, the Rust ABI is used. + /// If `extern` is found and a `string_literal` does not follow, the C ABI is used. + fn parse_extern_abi(&mut self) -> PResult<'a, Abi> { + Ok(if self.eat_keyword(kw::Extern) { + self.parse_opt_abi()? + } else { + Abi::default() + }) + } + + /// Parses a string literal as an ABI spec. + /// If one is not found, the "C" ABI is used. + fn parse_opt_abi(&mut self) -> PResult<'a, Abi> { + let span = if self.token.can_begin_literal_or_bool() { + let ast::Lit { span, kind, .. } = self.parse_lit()?; + match kind { + ast::LitKind::Str(symbol, _) => return Ok(Abi::new(symbol, span)), + ast::LitKind::Err(_) => {} + _ => { + self.struct_span_err(span, "non-string ABI literal") + .span_suggestion( + span, + "specify the ABI with a string literal", + "\"C\"".to_string(), + Applicability::MaybeIncorrect, + ) + .emit(); + } + } + span + } else { + self.prev_span + }; + Ok(Abi::new(sym::C, span)) + } + + /// 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() { + self.diagnostic() + .struct_span_err_with_code( + async_span, + "`async fn` is not permitted in the 2015 edition", + DiagnosticId::Error("E0670".into()) + ) + .emit(); + } + } + + fn collect_tokens( + &mut self, + f: impl FnOnce(&mut Self) -> PResult<'a, R>, + ) -> PResult<'a, (R, TokenStream)> { + // Record all tokens we parse when parsing this item. + let mut tokens = Vec::new(); + let prev_collecting = match self.token_cursor.frame.last_token { + LastToken::Collecting(ref mut list) => { + Some(mem::take(list)) + } + LastToken::Was(ref mut last) => { + tokens.extend(last.take()); + None + } + }; + self.token_cursor.frame.last_token = LastToken::Collecting(tokens); + let prev = self.token_cursor.stack.len(); + let ret = f(self); + let last_token = if self.token_cursor.stack.len() == prev { + &mut self.token_cursor.frame.last_token + } else if self.token_cursor.stack.get(prev).is_none() { + // This can happen due to a bad interaction of two unrelated recovery mechanisms with + // mismatched delimiters *and* recovery lookahead on the likely typo `pub ident(` + // (#62881). + return Ok((ret?, TokenStream::default())); + } else { + &mut self.token_cursor.stack[prev].last_token + }; + + // Pull out the tokens that we've collected from the call to `f` above. + let mut collected_tokens = match *last_token { + LastToken::Collecting(ref mut v) => mem::take(v), + LastToken::Was(ref was) => { + let msg = format!("our vector went away? - found Was({:?})", was); + debug!("collect_tokens: {}", msg); + self.sess.span_diagnostic.delay_span_bug(self.token.span, &msg); + // This can happen due to a bad interaction of two unrelated recovery mechanisms + // with mismatched delimiters *and* recovery lookahead on the likely typo + // `pub ident(` (#62895, different but similar to the case above). + return Ok((ret?, TokenStream::default())); + } + }; + + // If we're not at EOF our current token wasn't actually consumed by + // `f`, but it'll still be in our list that we pulled out. In that case + // put it back. + let extra_token = if self.token != token::Eof { + collected_tokens.pop() + } else { + None + }; + + // If we were previously collecting tokens, then this was a recursive + // call. In that case we need to record all the tokens we collected in + // our parent list as well. To do that we push a clone of our stream + // onto the previous list. + match prev_collecting { + Some(mut list) => { + list.extend(collected_tokens.iter().cloned()); + list.extend(extra_token); + *last_token = LastToken::Collecting(list); + } + None => { + *last_token = LastToken::Was(extra_token); + } + } + + Ok((ret?, TokenStream::new(collected_tokens))) + } + + /// `::{` or `::*` + fn is_import_coupler(&mut self) -> bool { + self.check(&token::ModSep) && + self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace) || + *t == token::BinOp(token::Star)) + } + + fn parse_optional_str(&mut self) -> Option<(Symbol, ast::StrStyle, Option)> { + let ret = match self.token.kind { + token::Literal(token::Lit { kind: token::Str, symbol, suffix }) => + (symbol, ast::StrStyle::Cooked, suffix), + token::Literal(token::Lit { kind: token::StrRaw(n), symbol, suffix }) => + (symbol, ast::StrStyle::Raw(n), suffix), + _ => return None + }; + self.bump(); + Some(ret) + } + + pub fn parse_str(&mut self) -> PResult<'a, (Symbol, StrStyle)> { + match self.parse_optional_str() { + Some((s, style, suf)) => { + let sp = self.prev_span; + self.expect_no_suffix(sp, "a string literal", suf); + Ok((s, style)) + } + _ => { + let msg = "expected string literal"; + let mut err = self.fatal(msg); + err.span_label(self.token.span, msg); + Err(err) + } + } + } +} + +crate fn make_unclosed_delims_error( + unmatched: UnmatchedBrace, + sess: &ParseSess, +) -> Option> { + // `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to + // `unmatched_braces` only for error recovery in the `Parser`. + let found_delim = unmatched.found_delim?; + let mut err = sess.span_diagnostic.struct_span_err(unmatched.found_span, &format!( + "incorrect close delimiter: `{}`", + pprust::token_kind_to_string(&token::CloseDelim(found_delim)), + )); + err.span_label(unmatched.found_span, "incorrect close delimiter"); + if let Some(sp) = unmatched.candidate_span { + err.span_label(sp, "close delimiter possibly meant for this"); + } + if let Some(sp) = unmatched.unclosed_span { + err.span_label(sp, "un-closed delimiter"); + } + Some(err) +} + +pub fn emit_unclosed_delims(unclosed_delims: &mut Vec, sess: &ParseSess) { + *sess.reached_eof.borrow_mut() |= unclosed_delims.iter() + .any(|unmatched_delim| unmatched_delim.found_delim.is_none()); + for unmatched in unclosed_delims.drain(..) { + make_unclosed_delims_error(unmatched, sess).map(|mut e| e.emit()); + } +} -- cgit 1.4.1-3-g733a5 From 8fa8e02c282f6dc4ebcd0f8403a881116a948443 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 11 Oct 2019 12:29:23 +0200 Subject: syntax: simplify imports --- src/libsyntax/parse/lexer/comments.rs | 5 +++-- src/libsyntax/parse/parser/pat.rs | 2 +- src/libsyntax/parse/tests.rs | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs index ac79ce323bf..33415bdcb62 100644 --- a/src/libsyntax/parse/lexer/comments.rs +++ b/src/libsyntax/parse/lexer/comments.rs @@ -1,9 +1,10 @@ pub use CommentStyle::*; +use super::is_block_doc_comment; + use crate::ast; use crate::source_map::SourceMap; -use crate::parse::lexer::is_block_doc_comment; -use crate::parse::lexer::ParseSess; +use crate::sess::ParseSess; use syntax_pos::{BytePos, CharPos, Pos, FileName}; diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index cc8738edff7..fcb7c4d1323 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -5,7 +5,7 @@ use crate::ptr::P; use crate::ast::{self, Attribute, Pat, PatKind, FieldPat, RangeEnd, RangeSyntax, Mac}; use crate::ast::{BindingMode, Ident, Mutability, Path, QSelf, Expr, ExprKind}; use crate::mut_visit::{noop_visit_pat, noop_visit_mac, MutVisitor}; -use crate::parse::token::{self}; +use crate::parse::token; use crate::print::pprust; use crate::source_map::{respan, Span, Spanned}; use crate::ThinVec; diff --git a/src/libsyntax/parse/tests.rs b/src/libsyntax/parse/tests.rs index 169eb954efa..201eaca947b 100644 --- a/src/libsyntax/parse/tests.rs +++ b/src/libsyntax/parse/tests.rs @@ -2,8 +2,8 @@ use super::*; use crate::ast::{self, Name, PatKind}; use crate::attr::first_attr_value_str_by_name; -use crate::parse::{ParseSess, PResult}; -use crate::parse::new_parser_from_source_str; +use crate::sess::ParseSess; +use crate::parse::{PResult, new_parser_from_source_str}; use crate::parse::token::Token; use crate::print::pprust::item_to_string; use crate::ptr::P; -- cgit 1.4.1-3-g733a5 From 53a50d4e4fdb0b242d637142d0b2d64e7054c35b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 11 Oct 2019 12:32:18 +0200 Subject: move unescape_error_reporting to lexer/ --- src/libsyntax/parse/lexer/mod.rs | 3 +- .../parse/lexer/unescape_error_reporting.rs | 215 +++++++++++++++++++++ src/libsyntax/parse/mod.rs | 1 - src/libsyntax/parse/unescape_error_reporting.rs | 215 --------------------- 4 files changed, 217 insertions(+), 217 deletions(-) create mode 100644 src/libsyntax/parse/lexer/unescape_error_reporting.rs delete mode 100644 src/libsyntax/parse/unescape_error_reporting.rs (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index e2a7ea28b9b..a6dfed542d6 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1,7 +1,6 @@ use crate::parse::token::{self, Token, TokenKind}; use crate::sess::ParseSess; use crate::symbol::{sym, Symbol}; -use crate::parse::unescape_error_reporting::{emit_unescape_error, push_escaped_char}; use errors::{FatalError, DiagnosticBuilder}; use syntax_pos::{BytePos, Pos, Span}; @@ -19,6 +18,8 @@ mod tests; pub mod comments; mod tokentrees; mod unicode_chars; +mod unescape_error_reporting; +use unescape_error_reporting::{emit_unescape_error, push_escaped_char}; #[derive(Clone, Debug)] pub struct UnmatchedBrace { diff --git a/src/libsyntax/parse/lexer/unescape_error_reporting.rs b/src/libsyntax/parse/lexer/unescape_error_reporting.rs new file mode 100644 index 00000000000..5565015179c --- /dev/null +++ b/src/libsyntax/parse/lexer/unescape_error_reporting.rs @@ -0,0 +1,215 @@ +//! Utilities for rendering escape sequence errors as diagnostics. + +use std::ops::Range; +use std::iter::once; + +use rustc_lexer::unescape::{EscapeError, Mode}; +use syntax_pos::{Span, BytePos}; + +use crate::errors::{Handler, Applicability}; + +pub(crate) fn emit_unescape_error( + handler: &Handler, + // interior part of the literal, without quotes + lit: &str, + // full span of the literal, including quotes + span_with_quotes: Span, + mode: Mode, + // range of the error inside `lit` + range: Range, + error: EscapeError, +) { + log::debug!("emit_unescape_error: {:?}, {:?}, {:?}, {:?}, {:?}", + lit, span_with_quotes, mode, range, error); + let span = { + let Range { start, end } = range; + let (start, end) = (start as u32, end as u32); + let lo = span_with_quotes.lo() + BytePos(start + 1); + let hi = lo + BytePos(end - start); + span_with_quotes + .with_lo(lo) + .with_hi(hi) + }; + let last_char = || { + let c = lit[range.clone()].chars().rev().next().unwrap(); + let span = span.with_lo(span.hi() - BytePos(c.len_utf8() as u32)); + (c, span) + }; + match error { + EscapeError::LoneSurrogateUnicodeEscape => { + handler.struct_span_err(span, "invalid unicode character escape") + .help("unicode escape must not be a surrogate") + .emit(); + } + EscapeError::OutOfRangeUnicodeEscape => { + handler.struct_span_err(span, "invalid unicode character escape") + .help("unicode escape must be at most 10FFFF") + .emit(); + } + EscapeError::MoreThanOneChar => { + let msg = if mode.is_bytes() { + "if you meant to write a byte string literal, use double quotes" + } else { + "if you meant to write a `str` literal, use double quotes" + }; + + handler + .struct_span_err( + span_with_quotes, + "character literal may only contain one codepoint", + ) + .span_suggestion( + span_with_quotes, + msg, + format!("\"{}\"", lit), + Applicability::MachineApplicable, + ).emit() + } + EscapeError::EscapeOnlyChar => { + let (c, _span) = last_char(); + + let mut msg = if mode.is_bytes() { + "byte constant must be escaped: " + } else { + "character constant must be escaped: " + }.to_string(); + push_escaped_char(&mut msg, c); + + handler.span_err(span, msg.as_str()) + } + EscapeError::BareCarriageReturn => { + let msg = if mode.in_double_quotes() { + "bare CR not allowed in string, use \\r instead" + } else { + "character constant must be escaped: \\r" + }; + handler.span_err(span, msg); + } + EscapeError::BareCarriageReturnInRawString => { + assert!(mode.in_double_quotes()); + let msg = "bare CR not allowed in raw string"; + handler.span_err(span, msg); + } + EscapeError::InvalidEscape => { + let (c, span) = last_char(); + + let label = if mode.is_bytes() { + "unknown byte escape" + } else { + "unknown character escape" + }; + let mut msg = label.to_string(); + msg.push_str(": "); + push_escaped_char(&mut msg, c); + + let mut diag = handler.struct_span_err(span, msg.as_str()); + diag.span_label(span, label); + if c == '{' || c == '}' && !mode.is_bytes() { + diag.help("if used in a formatting string, \ + curly braces are escaped with `{{` and `}}`"); + } else if c == '\r' { + diag.help("this is an isolated carriage return; \ + consider checking your editor and version control settings"); + } + diag.emit(); + } + EscapeError::TooShortHexEscape => { + handler.span_err(span, "numeric character escape is too short") + } + EscapeError::InvalidCharInHexEscape | EscapeError::InvalidCharInUnicodeEscape => { + let (c, span) = last_char(); + + let mut msg = if error == EscapeError::InvalidCharInHexEscape { + "invalid character in numeric character escape: " + } else { + "invalid character in unicode escape: " + }.to_string(); + push_escaped_char(&mut msg, c); + + handler.span_err(span, msg.as_str()) + } + EscapeError::NonAsciiCharInByte => { + assert!(mode.is_bytes()); + let (_c, span) = last_char(); + handler.span_err(span, "byte constant must be ASCII. \ + Use a \\xHH escape for a non-ASCII byte") + } + EscapeError::NonAsciiCharInByteString => { + assert!(mode.is_bytes()); + let (_c, span) = last_char(); + handler.span_err(span, "raw byte string must be ASCII") + } + EscapeError::OutOfRangeHexEscape => { + handler.span_err(span, "this form of character escape may only be used \ + with characters in the range [\\x00-\\x7f]") + } + EscapeError::LeadingUnderscoreUnicodeEscape => { + let (_c, span) = last_char(); + handler.span_err(span, "invalid start of unicode escape") + } + EscapeError::OverlongUnicodeEscape => { + handler.span_err(span, "overlong unicode escape (must have at most 6 hex digits)") + } + EscapeError::UnclosedUnicodeEscape => { + handler.span_err(span, "unterminated unicode escape (needed a `}`)") + } + EscapeError::NoBraceInUnicodeEscape => { + let msg = "incorrect unicode escape sequence"; + let mut diag = handler.struct_span_err(span, msg); + + let mut suggestion = "\\u{".to_owned(); + let mut suggestion_len = 0; + let (c, char_span) = last_char(); + let chars = once(c).chain(lit[range.end..].chars()); + for c in chars.take(6).take_while(|c| c.is_digit(16)) { + suggestion.push(c); + suggestion_len += c.len_utf8(); + } + + if suggestion_len > 0 { + suggestion.push('}'); + let lo = char_span.lo(); + let hi = lo + BytePos(suggestion_len as u32); + diag.span_suggestion( + span.with_lo(lo).with_hi(hi), + "format of unicode escape sequences uses braces", + suggestion, + Applicability::MaybeIncorrect, + ); + } else { + diag.span_label(span, msg); + diag.help( + "format of unicode escape sequences is `\\u{...}`", + ); + } + + diag.emit(); + } + EscapeError::UnicodeEscapeInByte => { + handler.span_err(span, "unicode escape sequences cannot be used \ + as a byte or in a byte string") + } + EscapeError::EmptyUnicodeEscape => { + handler.span_err(span, "empty unicode escape (must have at least 1 hex digit)") + } + EscapeError::ZeroChars => { + handler.span_err(span, "empty character literal") + } + EscapeError::LoneSlash => { + handler.span_err(span, "invalid trailing slash in literal") + } + } +} + +/// Pushes a character to a message string for error reporting +pub(crate) fn push_escaped_char(msg: &mut String, c: char) { + match c { + '\u{20}'..='\u{7e}' => { + // Don't escape \, ' or " for user-facing messages + msg.push(c); + } + _ => { + msg.extend(c.escape_default()); + } + } +} diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index b688dce87c1..5b020d3d288 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -29,7 +29,6 @@ pub mod token; crate mod classify; crate mod literal; -crate mod unescape_error_reporting; pub type PResult<'a, T> = Result>; diff --git a/src/libsyntax/parse/unescape_error_reporting.rs b/src/libsyntax/parse/unescape_error_reporting.rs deleted file mode 100644 index 5565015179c..00000000000 --- a/src/libsyntax/parse/unescape_error_reporting.rs +++ /dev/null @@ -1,215 +0,0 @@ -//! Utilities for rendering escape sequence errors as diagnostics. - -use std::ops::Range; -use std::iter::once; - -use rustc_lexer::unescape::{EscapeError, Mode}; -use syntax_pos::{Span, BytePos}; - -use crate::errors::{Handler, Applicability}; - -pub(crate) fn emit_unescape_error( - handler: &Handler, - // interior part of the literal, without quotes - lit: &str, - // full span of the literal, including quotes - span_with_quotes: Span, - mode: Mode, - // range of the error inside `lit` - range: Range, - error: EscapeError, -) { - log::debug!("emit_unescape_error: {:?}, {:?}, {:?}, {:?}, {:?}", - lit, span_with_quotes, mode, range, error); - let span = { - let Range { start, end } = range; - let (start, end) = (start as u32, end as u32); - let lo = span_with_quotes.lo() + BytePos(start + 1); - let hi = lo + BytePos(end - start); - span_with_quotes - .with_lo(lo) - .with_hi(hi) - }; - let last_char = || { - let c = lit[range.clone()].chars().rev().next().unwrap(); - let span = span.with_lo(span.hi() - BytePos(c.len_utf8() as u32)); - (c, span) - }; - match error { - EscapeError::LoneSurrogateUnicodeEscape => { - handler.struct_span_err(span, "invalid unicode character escape") - .help("unicode escape must not be a surrogate") - .emit(); - } - EscapeError::OutOfRangeUnicodeEscape => { - handler.struct_span_err(span, "invalid unicode character escape") - .help("unicode escape must be at most 10FFFF") - .emit(); - } - EscapeError::MoreThanOneChar => { - let msg = if mode.is_bytes() { - "if you meant to write a byte string literal, use double quotes" - } else { - "if you meant to write a `str` literal, use double quotes" - }; - - handler - .struct_span_err( - span_with_quotes, - "character literal may only contain one codepoint", - ) - .span_suggestion( - span_with_quotes, - msg, - format!("\"{}\"", lit), - Applicability::MachineApplicable, - ).emit() - } - EscapeError::EscapeOnlyChar => { - let (c, _span) = last_char(); - - let mut msg = if mode.is_bytes() { - "byte constant must be escaped: " - } else { - "character constant must be escaped: " - }.to_string(); - push_escaped_char(&mut msg, c); - - handler.span_err(span, msg.as_str()) - } - EscapeError::BareCarriageReturn => { - let msg = if mode.in_double_quotes() { - "bare CR not allowed in string, use \\r instead" - } else { - "character constant must be escaped: \\r" - }; - handler.span_err(span, msg); - } - EscapeError::BareCarriageReturnInRawString => { - assert!(mode.in_double_quotes()); - let msg = "bare CR not allowed in raw string"; - handler.span_err(span, msg); - } - EscapeError::InvalidEscape => { - let (c, span) = last_char(); - - let label = if mode.is_bytes() { - "unknown byte escape" - } else { - "unknown character escape" - }; - let mut msg = label.to_string(); - msg.push_str(": "); - push_escaped_char(&mut msg, c); - - let mut diag = handler.struct_span_err(span, msg.as_str()); - diag.span_label(span, label); - if c == '{' || c == '}' && !mode.is_bytes() { - diag.help("if used in a formatting string, \ - curly braces are escaped with `{{` and `}}`"); - } else if c == '\r' { - diag.help("this is an isolated carriage return; \ - consider checking your editor and version control settings"); - } - diag.emit(); - } - EscapeError::TooShortHexEscape => { - handler.span_err(span, "numeric character escape is too short") - } - EscapeError::InvalidCharInHexEscape | EscapeError::InvalidCharInUnicodeEscape => { - let (c, span) = last_char(); - - let mut msg = if error == EscapeError::InvalidCharInHexEscape { - "invalid character in numeric character escape: " - } else { - "invalid character in unicode escape: " - }.to_string(); - push_escaped_char(&mut msg, c); - - handler.span_err(span, msg.as_str()) - } - EscapeError::NonAsciiCharInByte => { - assert!(mode.is_bytes()); - let (_c, span) = last_char(); - handler.span_err(span, "byte constant must be ASCII. \ - Use a \\xHH escape for a non-ASCII byte") - } - EscapeError::NonAsciiCharInByteString => { - assert!(mode.is_bytes()); - let (_c, span) = last_char(); - handler.span_err(span, "raw byte string must be ASCII") - } - EscapeError::OutOfRangeHexEscape => { - handler.span_err(span, "this form of character escape may only be used \ - with characters in the range [\\x00-\\x7f]") - } - EscapeError::LeadingUnderscoreUnicodeEscape => { - let (_c, span) = last_char(); - handler.span_err(span, "invalid start of unicode escape") - } - EscapeError::OverlongUnicodeEscape => { - handler.span_err(span, "overlong unicode escape (must have at most 6 hex digits)") - } - EscapeError::UnclosedUnicodeEscape => { - handler.span_err(span, "unterminated unicode escape (needed a `}`)") - } - EscapeError::NoBraceInUnicodeEscape => { - let msg = "incorrect unicode escape sequence"; - let mut diag = handler.struct_span_err(span, msg); - - let mut suggestion = "\\u{".to_owned(); - let mut suggestion_len = 0; - let (c, char_span) = last_char(); - let chars = once(c).chain(lit[range.end..].chars()); - for c in chars.take(6).take_while(|c| c.is_digit(16)) { - suggestion.push(c); - suggestion_len += c.len_utf8(); - } - - if suggestion_len > 0 { - suggestion.push('}'); - let lo = char_span.lo(); - let hi = lo + BytePos(suggestion_len as u32); - diag.span_suggestion( - span.with_lo(lo).with_hi(hi), - "format of unicode escape sequences uses braces", - suggestion, - Applicability::MaybeIncorrect, - ); - } else { - diag.span_label(span, msg); - diag.help( - "format of unicode escape sequences is `\\u{...}`", - ); - } - - diag.emit(); - } - EscapeError::UnicodeEscapeInByte => { - handler.span_err(span, "unicode escape sequences cannot be used \ - as a byte or in a byte string") - } - EscapeError::EmptyUnicodeEscape => { - handler.span_err(span, "empty unicode escape (must have at least 1 hex digit)") - } - EscapeError::ZeroChars => { - handler.span_err(span, "empty character literal") - } - EscapeError::LoneSlash => { - handler.span_err(span, "invalid trailing slash in literal") - } - } -} - -/// Pushes a character to a message string for error reporting -pub(crate) fn push_escaped_char(msg: &mut String, c: char) { - match c { - '\u{20}'..='\u{7e}' => { - // Don't escape \, ' or " for user-facing messages - msg.push(c); - } - _ => { - msg.extend(c.escape_default()); - } - } -} -- cgit 1.4.1-3-g733a5 From 9d6768a478b8a6afa1e16dfebe9d79bd3f508cdf Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 11 Oct 2019 12:46:32 +0200 Subject: syntax::parser::token -> syntax::token --- src/librustc/hir/lowering.rs | 2 +- src/librustc/hir/map/def_collector.rs | 2 +- src/librustc/ich/impls_syntax.rs | 4 +- src/librustc_interface/interface.rs | 2 +- src/librustc_resolve/build_reduced_graph.rs | 2 +- src/librustc_save_analysis/dump_visitor.rs | 2 +- src/librustc_save_analysis/span_utils.rs | 2 +- src/librustdoc/html/highlight.rs | 2 +- src/librustdoc/passes/check_code_block_syntax.rs | 2 +- src/libsyntax/ast.rs | 2 +- src/libsyntax/attr/mod.rs | 2 +- src/libsyntax/feature_gate/check.rs | 2 +- src/libsyntax/lib.rs | 1 + src/libsyntax/mut_visit.rs | 2 +- src/libsyntax/parse/lexer/mod.rs | 2 +- src/libsyntax/parse/lexer/tests.rs | 2 +- src/libsyntax/parse/lexer/tokentrees.rs | 2 +- src/libsyntax/parse/lexer/unicode_chars.rs | 2 +- src/libsyntax/parse/literal.rs | 2 +- src/libsyntax/parse/mod.rs | 3 +- src/libsyntax/parse/parser/attr.rs | 2 +- src/libsyntax/parse/parser/diagnostics.rs | 2 +- src/libsyntax/parse/parser/expr.rs | 2 +- src/libsyntax/parse/parser/generics.rs | 2 +- src/libsyntax/parse/parser/mod.rs | 2 +- src/libsyntax/parse/parser/module.rs | 2 +- src/libsyntax/parse/parser/pat.rs | 2 +- src/libsyntax/parse/parser/path.rs | 2 +- src/libsyntax/parse/parser/stmt.rs | 2 +- src/libsyntax/parse/parser/ty.rs | 2 +- src/libsyntax/parse/tests.rs | 2 +- src/libsyntax/parse/token.rs | 728 ----------------------- src/libsyntax/print/pprust.rs | 2 +- src/libsyntax/token.rs | 728 +++++++++++++++++++++++ src/libsyntax/tokenstream.rs | 2 +- src/libsyntax/util/parser.rs | 2 +- src/libsyntax/visit.rs | 2 +- src/libsyntax_expand/base.rs | 2 +- src/libsyntax_expand/expand.rs | 2 +- src/libsyntax_expand/mbe.rs | 2 +- src/libsyntax_expand/mbe/macro_check.rs | 2 +- src/libsyntax_expand/mbe/macro_parser.rs | 2 +- src/libsyntax_expand/mbe/macro_rules.rs | 3 +- src/libsyntax_expand/mbe/quoted.rs | 2 +- src/libsyntax_expand/mbe/transcribe.rs | 2 +- src/libsyntax_expand/proc_macro.rs | 3 +- src/libsyntax_expand/proc_macro_server.rs | 7 +- src/libsyntax_ext/asm.rs | 2 +- src/libsyntax_ext/assert.rs | 2 +- src/libsyntax_ext/cfg.rs | 2 +- src/libsyntax_ext/cmdline_attrs.rs | 3 +- src/libsyntax_ext/concat_idents.rs | 2 +- src/libsyntax_ext/format.rs | 2 +- src/libsyntax_ext/global_asm.rs | 2 +- src/libsyntax_ext/plugin_macro_defs.rs | 4 +- src/libsyntax_ext/source_util.rs | 3 +- src/test/ui-fulldeps/ast_stmt_expr_attr.rs | 2 +- src/test/ui-fulldeps/auxiliary/roman-numerals.rs | 2 +- 58 files changed, 792 insertions(+), 789 deletions(-) delete mode 100644 src/libsyntax/parse/token.rs create mode 100644 src/libsyntax/token.rs (limited to 'src/libsyntax/parse') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 6344c7a233c..87ad4ace592 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -66,7 +66,7 @@ use syntax::ptr::P as AstP; use syntax::ast::*; use syntax::errors; use syntax::print::pprust; -use syntax::parse::token::{self, Nonterminal, Token}; +use syntax::token::{self, Nonterminal, Token}; use syntax::tokenstream::{TokenStream, TokenTree}; use syntax::sess::ParseSess; use syntax::source_map::{respan, ExpnData, ExpnKind, DesugaringKind, Spanned}; diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index e9970e30bf9..57c1421bde6 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -4,7 +4,7 @@ use crate::hir::def_id::DefIndex; use syntax::ast::*; use syntax::visit; use syntax::symbol::{kw, sym}; -use syntax::parse::token::{self, Token}; +use syntax::token::{self, Token}; use syntax_pos::hygiene::ExpnId; use syntax_pos::Span; diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 2201c4b0980..c401bd17dd4 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -8,9 +8,9 @@ use std::mem; use syntax::ast; use syntax::feature_gate; -use syntax::parse::token; -use syntax::symbol::SymbolStr; +use syntax::token; use syntax::tokenstream; +use syntax_pos::symbol::SymbolStr; use syntax_pos::SourceFile; use crate::hir::def_id::{DefId, CrateNum, CRATE_DEF_INDEX}; diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs index 4e4d6d982fb..034e861b212 100644 --- a/src/librustc_interface/interface.rs +++ b/src/librustc_interface/interface.rs @@ -16,7 +16,7 @@ use std::result; use std::sync::{Arc, Mutex}; use syntax::{self, parse}; use syntax::ast::{self, MetaItemKind}; -use syntax::parse::token; +use syntax::token; use syntax::source_map::{FileName, FileLoader, SourceMap}; use syntax::sess::ParseSess; use syntax_pos::edition; diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 55f054d0be3..4239518b879 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -33,7 +33,7 @@ use syntax::attr; use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId}; use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind}; use syntax::feature_gate::is_builtin_attr; -use syntax::parse::token::{self, Token}; +use syntax::token::{self, Token}; use syntax::print::pprust; use syntax::{span_err, struct_span_err}; use syntax::source_map::{respan, Spanned}; diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index a372106d379..5c5fbcc07de 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -24,7 +24,7 @@ use std::path::Path; use std::env; use syntax::ast::{self, Attribute, NodeId, PatKind}; -use syntax::parse::token; +use syntax::token; use syntax::visit::{self, Visitor}; use syntax::print::pprust::{ bounds_to_string, diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index fb9919d777d..4d0780cf94d 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -3,7 +3,7 @@ use rustc::session::Session; use crate::generated_code; use syntax::parse::lexer::{self, StringReader}; -use syntax::parse::token::{self, TokenKind}; +use syntax::token::{self, TokenKind}; use syntax_pos::*; #[derive(Clone)] diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 88ba13f2796..4bd72f7e61c 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -13,7 +13,7 @@ use std::io::prelude::*; use syntax::source_map::SourceMap; use syntax::parse::lexer; -use syntax::parse::token::{self, Token}; +use syntax::token::{self, Token}; use syntax::sess::ParseSess; use syntax::symbol::{kw, sym}; use syntax_pos::{Span, FileName}; diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index 10e15ab8881..4603e77b0fd 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -1,6 +1,6 @@ use errors::Applicability; use syntax::parse::lexer::{StringReader as Lexer}; -use syntax::parse::token; +use syntax::token; use syntax::sess::ParseSess; use syntax::source_map::FilePathMapping; use syntax_pos::{InnerSpan, FileName}; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 67d1acbccfb..18151a1586c 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -24,9 +24,9 @@ pub use crate::util::parser::ExprPrecedence; pub use syntax_pos::symbol::{Ident, Symbol as Name}; -use crate::parse::token::{self, DelimToken}; use crate::ptr::P; use crate::source_map::{dummy_spanned, respan, Spanned}; +use crate::token::{self, DelimToken}; use crate::tokenstream::TokenStream; use syntax_pos::symbol::{kw, sym, Symbol}; diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index c663995eb8f..1534d2723c8 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -17,7 +17,7 @@ use crate::source_map::{BytePos, Spanned}; use crate::parse::lexer::comments::doc_comment_style; use crate::parse; use crate::parse::PResult; -use crate::parse::token::{self, Token}; +use crate::token::{self, Token}; use crate::ptr::P; use crate::sess::ParseSess; use crate::symbol::{sym, Symbol}; diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index 5b1493ebc9b..ecff89ad59b 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -11,7 +11,7 @@ use crate::attr::{self, check_builtin_attribute}; use crate::source_map::Spanned; use crate::edition::{ALL_EDITIONS, Edition}; use crate::visit::{self, FnKind, Visitor}; -use crate::parse::token; +use crate::token; use crate::sess::ParseSess; use crate::symbol::{Symbol, sym}; use crate::tokenstream::TokenTree; diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 7be6e6c7e18..4c134430f30 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -107,6 +107,7 @@ pub mod show_span; pub use syntax_pos::edition; pub use syntax_pos::symbol; pub mod sess; +pub mod token; pub mod tokenstream; pub mod visit; diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 7261601e144..0c90652526d 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -9,7 +9,7 @@ use crate::ast::*; use crate::source_map::{Spanned, respan}; -use crate::parse::token::{self, Token}; +use crate::token::{self, Token}; use crate::ptr::P; use crate::ThinVec; use crate::tokenstream::*; diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index a6dfed542d6..5499a3cae5f 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1,4 +1,4 @@ -use crate::parse::token::{self, Token, TokenKind}; +use crate::token::{self, Token, TokenKind}; use crate::sess::ParseSess; use crate::symbol::{sym, Symbol}; diff --git a/src/libsyntax/parse/lexer/tests.rs b/src/libsyntax/parse/lexer/tests.rs index de301b1fc49..b9b82b2bcef 100644 --- a/src/libsyntax/parse/lexer/tests.rs +++ b/src/libsyntax/parse/lexer/tests.rs @@ -2,7 +2,7 @@ use super::*; use crate::symbol::Symbol; use crate::source_map::{SourceMap, FilePathMapping}; -use crate::parse::token; +use crate::token; use crate::with_default_globals; use errors::{Handler, emitter::EmitterWriter}; diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index de8ac2c71e8..3c15a5e1dae 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -4,8 +4,8 @@ use syntax_pos::Span; use super::{StringReader, UnmatchedBrace}; use crate::print::pprust::token_to_string; -use crate::parse::token::{self, Token}; use crate::parse::PResult; +use crate::token::{self, Token}; use crate::tokenstream::{DelimSpan, IsJoint::{self, *}, TokenStream, TokenTree, TreeAndJoint}; impl<'a> StringReader<'a> { diff --git a/src/libsyntax/parse/lexer/unicode_chars.rs b/src/libsyntax/parse/lexer/unicode_chars.rs index 525b4215aff..6eb995b61d3 100644 --- a/src/libsyntax/parse/lexer/unicode_chars.rs +++ b/src/libsyntax/parse/lexer/unicode_chars.rs @@ -4,7 +4,7 @@ use super::StringReader; use errors::{Applicability, DiagnosticBuilder}; use syntax_pos::{BytePos, Pos, Span, symbol::kw}; -use crate::parse::token; +use crate::token; #[rustfmt::skip] // for line breaks const UNICODE_ARRAY: &[(char, &str, char)] = &[ diff --git a/src/libsyntax/parse/literal.rs b/src/libsyntax/parse/literal.rs index a8eeac59954..d4c9b7850c5 100644 --- a/src/libsyntax/parse/literal.rs +++ b/src/libsyntax/parse/literal.rs @@ -1,8 +1,8 @@ //! Code related to parsing literals. use crate::ast::{self, Lit, LitKind}; -use crate::parse::token::{self, Token}; use crate::symbol::{kw, sym, Symbol}; +use crate::token::{self, Token}; use crate::tokenstream::TokenTree; use log::debug; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 5b020d3d288..7db0ca0b78d 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -2,7 +2,7 @@ use crate::ast; use crate::parse::parser::{Parser, emit_unclosed_delims, make_unclosed_delims_error}; -use crate::parse::token::Nonterminal; +use crate::token::{self, Nonterminal}; use crate::tokenstream::{self, TokenStream, TokenTree}; use crate::print::pprust; use crate::sess::ParseSess; @@ -25,7 +25,6 @@ mod tests; #[macro_use] pub mod parser; pub mod lexer; -pub mod token; crate mod classify; crate mod literal; diff --git a/src/libsyntax/parse/parser/attr.rs b/src/libsyntax/parse/parser/attr.rs index 1c292661f24..aa0542a09a9 100644 --- a/src/libsyntax/parse/parser/attr.rs +++ b/src/libsyntax/parse/parser/attr.rs @@ -1,7 +1,7 @@ use super::{SeqSep, PResult, Parser, TokenType, PathStyle}; use crate::attr; use crate::ast; -use crate::parse::token::{self, Nonterminal, DelimToken}; +use crate::token::{self, Nonterminal, DelimToken}; use crate::tokenstream::{TokenStream, TokenTree}; use crate::source_map::Span; diff --git a/src/libsyntax/parse/parser/diagnostics.rs b/src/libsyntax/parse/parser/diagnostics.rs index 49a517a5c44..09f0b9b74b2 100644 --- a/src/libsyntax/parse/parser/diagnostics.rs +++ b/src/libsyntax/parse/parser/diagnostics.rs @@ -6,7 +6,7 @@ use crate::ast::{ self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, }; -use crate::parse::token::{self, TokenKind, token_can_begin_expr}; +use crate::token::{self, TokenKind, token_can_begin_expr}; use crate::print::pprust; use crate::ptr::P; use crate::symbol::{kw, sym}; diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 509e6482dcc..4b962201e85 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -12,7 +12,7 @@ use crate::ast::{ }; use crate::maybe_recover_from_interpolated_ty_qpath; use crate::parse::classify; -use crate::parse::token::{self, Token, TokenKind}; +use crate::token::{self, Token, TokenKind}; use crate::print::pprust; use crate::ptr::P; use crate::source_map::{self, Span}; diff --git a/src/libsyntax/parse/parser/generics.rs b/src/libsyntax/parse/parser/generics.rs index 3c094750b4d..cfc3768cac5 100644 --- a/src/libsyntax/parse/parser/generics.rs +++ b/src/libsyntax/parse/parser/generics.rs @@ -1,7 +1,7 @@ use super::{Parser, PResult}; use crate::ast::{self, WhereClause, GenericParam, GenericParamKind, GenericBounds, Attribute}; -use crate::parse::token; +use crate::token; use crate::source_map::DUMMY_SP; use syntax_pos::symbol::{kw, sym}; diff --git a/src/libsyntax/parse/parser/mod.rs b/src/libsyntax/parse/parser/mod.rs index 1284e89f195..6498b674a3b 100644 --- a/src/libsyntax/parse/parser/mod.rs +++ b/src/libsyntax/parse/parser/mod.rs @@ -18,7 +18,7 @@ use crate::ast::{ use crate::parse::{PResult, Directory, DirectoryOwnership}; use crate::parse::lexer::UnmatchedBrace; use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; -use crate::parse::token::{self, Token, TokenKind, DelimToken}; +use crate::token::{self, Token, TokenKind, DelimToken}; use crate::print::pprust; use crate::ptr::P; use crate::sess::ParseSess; diff --git a/src/libsyntax/parse/parser/module.rs b/src/libsyntax/parse/parser/module.rs index 242a17659a0..70e0dfc3e88 100644 --- a/src/libsyntax/parse/parser/module.rs +++ b/src/libsyntax/parse/parser/module.rs @@ -5,7 +5,7 @@ use super::diagnostics::Error; use crate::attr; use crate::ast::{self, Ident, Attribute, ItemKind, Mod, Crate}; use crate::parse::{new_sub_parser_from_file, DirectoryOwnership}; -use crate::parse::token::{self, TokenKind}; +use crate::token::{self, TokenKind}; use crate::source_map::{SourceMap, Span, DUMMY_SP, FileName}; use crate::symbol::sym; diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index fcb7c4d1323..c4a983188fa 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -5,7 +5,7 @@ use crate::ptr::P; use crate::ast::{self, Attribute, Pat, PatKind, FieldPat, RangeEnd, RangeSyntax, Mac}; use crate::ast::{BindingMode, Ident, Mutability, Path, QSelf, Expr, ExprKind}; use crate::mut_visit::{noop_visit_pat, noop_visit_mac, MutVisitor}; -use crate::parse::token; +use crate::token; use crate::print::pprust; use crate::source_map::{respan, Span, Spanned}; use crate::ThinVec; diff --git a/src/libsyntax/parse/parser/path.rs b/src/libsyntax/parse/parser/path.rs index 4438d61d9ee..2659e0c680e 100644 --- a/src/libsyntax/parse/parser/path.rs +++ b/src/libsyntax/parse/parser/path.rs @@ -3,7 +3,7 @@ use super::{Parser, PResult, TokenType}; use crate::{maybe_whole, ThinVec}; use crate::ast::{self, QSelf, Path, PathSegment, Ident, ParenthesizedArgs, AngleBracketedArgs}; use crate::ast::{AnonConst, GenericArg, AssocTyConstraint, AssocTyConstraintKind, BlockCheckMode}; -use crate::parse::token::{self, Token}; +use crate::token::{self, Token}; use crate::source_map::{Span, BytePos}; use syntax_pos::symbol::{kw, sym}; diff --git a/src/libsyntax/parse/parser/stmt.rs b/src/libsyntax/parse/parser/stmt.rs index 12c530f3cbb..010fd9c37fd 100644 --- a/src/libsyntax/parse/parser/stmt.rs +++ b/src/libsyntax/parse/parser/stmt.rs @@ -9,7 +9,7 @@ use crate::{maybe_whole, ThinVec}; use crate::ast::{self, DUMMY_NODE_ID, Stmt, StmtKind, Local, Block, BlockCheckMode, Expr, ExprKind}; use crate::ast::{Attribute, AttrStyle, VisibilityKind, MacStmtStyle, Mac, MacDelimiter}; use crate::parse::{classify, DirectoryOwnership}; -use crate::parse::token; +use crate::token; use crate::source_map::{respan, Span}; use crate::symbol::{kw, sym}; diff --git a/src/libsyntax/parse/parser/ty.rs b/src/libsyntax/parse/parser/ty.rs index b770b90705c..4183416e628 100644 --- a/src/libsyntax/parse/parser/ty.rs +++ b/src/libsyntax/parse/parser/ty.rs @@ -6,7 +6,7 @@ use crate::ptr::P; use crate::ast::{self, Ty, TyKind, MutTy, BareFnTy, FunctionRetTy, GenericParam, Lifetime, Ident}; use crate::ast::{TraitBoundModifier, TraitObjectSyntax, GenericBound, GenericBounds, PolyTraitRef}; use crate::ast::{Mutability, AnonConst, Mac}; -use crate::parse::token::{self, Token}; +use crate::token::{self, Token}; use crate::source_map::Span; use crate::symbol::{kw}; diff --git a/src/libsyntax/parse/tests.rs b/src/libsyntax/parse/tests.rs index 201eaca947b..27ca2b6472f 100644 --- a/src/libsyntax/parse/tests.rs +++ b/src/libsyntax/parse/tests.rs @@ -4,7 +4,7 @@ use crate::ast::{self, Name, PatKind}; use crate::attr::first_attr_value_str_by_name; use crate::sess::ParseSess; use crate::parse::{PResult, new_parser_from_source_str}; -use crate::parse::token::Token; +use crate::token::Token; use crate::print::pprust::item_to_string; use crate::ptr::P; use crate::source_map::FilePathMapping; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs deleted file mode 100644 index 6f3da344ccf..00000000000 --- a/src/libsyntax/parse/token.rs +++ /dev/null @@ -1,728 +0,0 @@ -pub use BinOpToken::*; -pub use Nonterminal::*; -pub use DelimToken::*; -pub use LitKind::*; -pub use TokenKind::*; - -use crate::ast; -use crate::ptr::P; -use crate::symbol::kw; -use crate::tokenstream::TokenTree; - -use syntax_pos::symbol::Symbol; -use syntax_pos::{self, Span, DUMMY_SP}; - -use std::fmt; -use std::mem; -#[cfg(target_arch = "x86_64")] -use rustc_data_structures::static_assert_size; -use rustc_data_structures::sync::Lrc; - -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub enum BinOpToken { - Plus, - Minus, - Star, - Slash, - Percent, - Caret, - And, - Or, - Shl, - Shr, -} - -/// A delimiter token. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub enum DelimToken { - /// A round parenthesis (i.e., `(` or `)`). - Paren, - /// A square bracket (i.e., `[` or `]`). - Bracket, - /// A curly brace (i.e., `{` or `}`). - Brace, - /// An empty delimiter. - NoDelim, -} - -impl DelimToken { - pub fn len(self) -> usize { - if self == NoDelim { 0 } else { 1 } - } - - pub fn is_empty(self) -> bool { - self == NoDelim - } -} - -#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug)] -pub enum LitKind { - Bool, // AST only, must never appear in a `Token` - Byte, - Char, - Integer, - Float, - Str, - StrRaw(u16), // raw string delimited by `n` hash symbols - ByteStr, - ByteStrRaw(u16), // raw byte string delimited by `n` hash symbols - Err, -} - -/// A literal token. -#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug)] -pub struct Lit { - pub kind: LitKind, - pub symbol: Symbol, - pub suffix: Option, -} - -impl fmt::Display for Lit { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Lit { kind, symbol, suffix } = *self; - match kind { - Byte => write!(f, "b'{}'", symbol)?, - Char => write!(f, "'{}'", symbol)?, - Str => write!(f, "\"{}\"", symbol)?, - StrRaw(n) => write!(f, "r{delim}\"{string}\"{delim}", - delim="#".repeat(n as usize), - string=symbol)?, - ByteStr => write!(f, "b\"{}\"", symbol)?, - ByteStrRaw(n) => write!(f, "br{delim}\"{string}\"{delim}", - delim="#".repeat(n as usize), - string=symbol)?, - Integer | - Float | - Bool | - Err => write!(f, "{}", symbol)?, - } - - if let Some(suffix) = suffix { - write!(f, "{}", suffix)?; - } - - Ok(()) - } -} - -impl LitKind { - /// An English article for the literal token kind. - crate fn article(self) -> &'static str { - match self { - Integer | Err => "an", - _ => "a", - } - } - - crate fn descr(self) -> &'static str { - match self { - Bool => panic!("literal token contains `Lit::Bool`"), - Byte => "byte", - Char => "char", - Integer => "integer", - Float => "float", - Str | StrRaw(..) => "string", - ByteStr | ByteStrRaw(..) => "byte string", - Err => "error", - } - } - - crate fn may_have_suffix(self) -> bool { - match self { - Integer | Float | Err => true, - _ => false, - } - } -} - -impl Lit { - pub fn new(kind: LitKind, symbol: Symbol, suffix: Option) -> Lit { - Lit { kind, symbol, suffix } - } -} - -pub(crate) fn ident_can_begin_expr(name: ast::Name, span: Span, is_raw: bool) -> bool { - let ident_token = Token::new(Ident(name, is_raw), span); - token_can_begin_expr(&ident_token) -} - -pub(crate) fn token_can_begin_expr(ident_token: &Token) -> bool { - !ident_token.is_reserved_ident() || - ident_token.is_path_segment_keyword() || - match ident_token.kind { - TokenKind::Ident(ident, _) => [ - kw::Async, - kw::Do, - kw::Box, - kw::Break, - kw::Continue, - kw::False, - kw::For, - kw::If, - kw::Let, - kw::Loop, - kw::Match, - kw::Move, - kw::Return, - kw::True, - kw::Unsafe, - kw::While, - kw::Yield, - kw::Static, - ].contains(&ident), - _=> false, - } -} - -fn ident_can_begin_type(name: ast::Name, span: Span, is_raw: bool) -> bool { - let ident_token = Token::new(Ident(name, is_raw), span); - - !ident_token.is_reserved_ident() || - ident_token.is_path_segment_keyword() || - [ - kw::Underscore, - kw::For, - kw::Impl, - kw::Fn, - kw::Unsafe, - kw::Extern, - kw::Typeof, - kw::Dyn, - ].contains(&name) -} - -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)] -pub enum TokenKind { - /* Expression-operator symbols. */ - Eq, - Lt, - Le, - EqEq, - Ne, - Ge, - Gt, - AndAnd, - OrOr, - Not, - Tilde, - BinOp(BinOpToken), - BinOpEq(BinOpToken), - - /* Structural symbols */ - At, - Dot, - DotDot, - DotDotDot, - DotDotEq, - Comma, - Semi, - Colon, - ModSep, - RArrow, - LArrow, - FatArrow, - Pound, - Dollar, - Question, - /// Used by proc macros for representing lifetimes, not generated by lexer right now. - SingleQuote, - /// An opening delimiter (e.g., `{`). - OpenDelim(DelimToken), - /// A closing delimiter (e.g., `}`). - CloseDelim(DelimToken), - - /* Literals */ - Literal(Lit), - - /* Name components */ - Ident(ast::Name, /* is_raw */ bool), - Lifetime(ast::Name), - - Interpolated(Lrc), - - // Can be expanded into several tokens. - /// A doc comment. - DocComment(ast::Name), - - // Junk. These carry no data because we don't really care about the data - // they *would* carry, and don't really want to allocate a new ident for - // them. Instead, users could extract that from the associated span. - - /// Whitespace. - Whitespace, - /// A comment. - Comment, - Shebang(ast::Name), - /// A completely invalid token which should be skipped. - Unknown(ast::Name), - - Eof, -} - -// `TokenKind` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(target_arch = "x86_64")] -static_assert_size!(TokenKind, 16); - -#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)] -pub struct Token { - pub kind: TokenKind, - pub span: Span, -} - -impl TokenKind { - pub fn lit(kind: LitKind, symbol: Symbol, suffix: Option) -> TokenKind { - Literal(Lit::new(kind, symbol, suffix)) - } - - /// Returns tokens that are likely to be typed accidentally instead of the current token. - /// Enables better error recovery when the wrong token is found. - crate fn similar_tokens(&self) -> Option> { - match *self { - Comma => Some(vec![Dot, Lt, Semi]), - Semi => Some(vec![Colon, Comma]), - _ => None - } - } -} - -impl Token { - pub fn new(kind: TokenKind, span: Span) -> Self { - Token { kind, span } - } - - /// Some token that will be thrown away later. - crate fn dummy() -> Self { - Token::new(TokenKind::Whitespace, DUMMY_SP) - } - - /// Recovers a `Token` from an `ast::Ident`. This creates a raw identifier if necessary. - pub fn from_ast_ident(ident: ast::Ident) -> Self { - Token::new(Ident(ident.name, ident.is_raw_guess()), ident.span) - } - - /// Return this token by value and leave a dummy token in its place. - pub fn take(&mut self) -> Self { - mem::replace(self, Token::dummy()) - } - - crate fn is_op(&self) -> bool { - match self.kind { - OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | - Ident(..) | Lifetime(..) | Interpolated(..) | - Whitespace | Comment | Shebang(..) | Eof => false, - _ => true, - } - } - - crate fn is_like_plus(&self) -> bool { - match self.kind { - BinOp(Plus) | BinOpEq(Plus) => true, - _ => false, - } - } - - /// Returns `true` if the token can appear at the start of an expression. - pub fn can_begin_expr(&self) -> bool { - match self.kind { - Ident(name, is_raw) => - ident_can_begin_expr(name, self.span, is_raw), // value name or keyword - OpenDelim(..) | // tuple, array or block - Literal(..) | // literal - Not | // operator not - BinOp(Minus) | // unary minus - BinOp(Star) | // dereference - BinOp(Or) | OrOr | // closure - BinOp(And) | // reference - AndAnd | // double reference - // DotDotDot is no longer supported, but we need some way to display the error - DotDot | DotDotDot | DotDotEq | // range notation - Lt | BinOp(Shl) | // associated path - ModSep | // global path - Lifetime(..) | // labeled loop - Pound => true, // expression attributes - Interpolated(ref nt) => match **nt { - NtLiteral(..) | - NtIdent(..) | - NtExpr(..) | - NtBlock(..) | - NtPath(..) | - NtLifetime(..) => true, - _ => false, - }, - _ => false, - } - } - - /// Returns `true` if the token can appear at the start of a type. - pub fn can_begin_type(&self) -> bool { - match self.kind { - Ident(name, is_raw) => - ident_can_begin_type(name, self.span, is_raw), // type name or keyword - OpenDelim(Paren) | // tuple - OpenDelim(Bracket) | // array - Not | // never - BinOp(Star) | // raw pointer - BinOp(And) | // reference - AndAnd | // double reference - Question | // maybe bound in trait object - Lifetime(..) | // lifetime bound in trait object - Lt | BinOp(Shl) | // associated path - ModSep => true, // global path - Interpolated(ref nt) => match **nt { - NtIdent(..) | NtTy(..) | NtPath(..) | NtLifetime(..) => true, - _ => false, - }, - _ => false, - } - } - - /// Returns `true` if the token can appear at the start of a const param. - crate fn can_begin_const_arg(&self) -> bool { - match self.kind { - OpenDelim(Brace) => true, - Interpolated(ref nt) => match **nt { - NtExpr(..) | NtBlock(..) | NtLiteral(..) => true, - _ => false, - } - _ => self.can_begin_literal_or_bool(), - } - } - - /// Returns `true` if the token can appear at the start of a generic bound. - crate fn can_begin_bound(&self) -> bool { - self.is_path_start() || self.is_lifetime() || self.is_keyword(kw::For) || - self == &Question || self == &OpenDelim(Paren) - } - - /// Returns `true` if the token is any literal - pub fn is_lit(&self) -> bool { - match self.kind { - Literal(..) => true, - _ => false, - } - } - - /// 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). - 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, - _ => false, - }, - _ => false, - } - } - - /// Returns an identifier if this token is an identifier. - pub fn ident(&self) -> Option<(ast::Ident, /* is_raw */ bool)> { - match self.kind { - Ident(name, is_raw) => Some((ast::Ident::new(name, self.span), is_raw)), - Interpolated(ref nt) => match **nt { - NtIdent(ident, is_raw) => Some((ident, is_raw)), - _ => None, - }, - _ => None, - } - } - - /// Returns a lifetime identifier if this token is a lifetime. - pub fn lifetime(&self) -> Option { - match self.kind { - Lifetime(name) => Some(ast::Ident::new(name, self.span)), - Interpolated(ref nt) => match **nt { - NtLifetime(ident) => Some(ident), - _ => None, - }, - _ => None, - } - } - - /// Returns `true` if the token is an identifier. - pub fn is_ident(&self) -> bool { - self.ident().is_some() - } - - /// Returns `true` if the token is a lifetime. - crate fn is_lifetime(&self) -> bool { - self.lifetime().is_some() - } - - /// Returns `true` if the token is a identifier whose name is the given - /// string slice. - crate fn is_ident_named(&self, name: Symbol) -> bool { - self.ident().map_or(false, |(ident, _)| ident.name == name) - } - - /// Returns `true` if the token is an interpolated path. - fn is_path(&self) -> bool { - if let Interpolated(ref nt) = self.kind { - if let NtPath(..) = **nt { - return true; - } - } - false - } - - /// Would `maybe_whole_expr` in `parser.rs` return `Ok(..)`? - /// That is, is this a pre-parsed expression dropped into the token stream - /// (which happens while parsing the result of macro expansion)? - crate fn is_whole_expr(&self) -> bool { - if let Interpolated(ref nt) = self.kind { - if let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtIdent(..) | NtBlock(_) = **nt { - return true; - } - } - - false - } - - /// Returns `true` if the token is either the `mut` or `const` keyword. - crate fn is_mutability(&self) -> bool { - self.is_keyword(kw::Mut) || - self.is_keyword(kw::Const) - } - - crate fn is_qpath_start(&self) -> bool { - self == &Lt || self == &BinOp(Shl) - } - - crate fn is_path_start(&self) -> bool { - self == &ModSep || self.is_qpath_start() || self.is_path() || - self.is_path_segment_keyword() || self.is_ident() && !self.is_reserved_ident() - } - - /// Returns `true` if the token is a given keyword, `kw`. - pub fn is_keyword(&self, kw: Symbol) -> bool { - self.is_non_raw_ident_where(|id| id.name == kw) - } - - crate fn is_path_segment_keyword(&self) -> bool { - self.is_non_raw_ident_where(ast::Ident::is_path_segment_keyword) - } - - // Returns true for reserved identifiers used internally for elided lifetimes, - // unnamed method parameters, crate root module, error recovery etc. - crate fn is_special_ident(&self) -> bool { - self.is_non_raw_ident_where(ast::Ident::is_special) - } - - /// Returns `true` if the token is a keyword used in the language. - crate fn is_used_keyword(&self) -> bool { - self.is_non_raw_ident_where(ast::Ident::is_used_keyword) - } - - /// Returns `true` if the token is a keyword reserved for possible future use. - crate fn is_unused_keyword(&self) -> bool { - self.is_non_raw_ident_where(ast::Ident::is_unused_keyword) - } - - /// Returns `true` if the token is either a special identifier or a keyword. - pub fn is_reserved_ident(&self) -> bool { - self.is_non_raw_ident_where(ast::Ident::is_reserved) - } - - /// Returns `true` if the token is the identifier `true` or `false`. - crate fn is_bool_lit(&self) -> bool { - self.is_non_raw_ident_where(|id| id.name.is_bool_lit()) - } - - /// 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 { - match self.ident() { - Some((id, false)) => pred(id), - _ => false, - } - } - - crate fn glue(&self, joint: &Token) -> Option { - let kind = match self.kind { - Eq => match joint.kind { - Eq => EqEq, - Gt => FatArrow, - _ => return None, - }, - Lt => match joint.kind { - Eq => Le, - Lt => BinOp(Shl), - Le => BinOpEq(Shl), - BinOp(Minus) => LArrow, - _ => return None, - }, - Gt => match joint.kind { - Eq => Ge, - Gt => BinOp(Shr), - Ge => BinOpEq(Shr), - _ => return None, - }, - Not => match joint.kind { - Eq => Ne, - _ => return None, - }, - BinOp(op) => match joint.kind { - Eq => BinOpEq(op), - BinOp(And) if op == And => AndAnd, - BinOp(Or) if op == Or => OrOr, - Gt if op == Minus => RArrow, - _ => return None, - }, - Dot => match joint.kind { - Dot => DotDot, - DotDot => DotDotDot, - _ => return None, - }, - DotDot => match joint.kind { - Dot => DotDotDot, - Eq => DotDotEq, - _ => return None, - }, - Colon => match joint.kind { - Colon => ModSep, - _ => return None, - }, - SingleQuote => match joint.kind { - Ident(name, false) => Lifetime(Symbol::intern(&format!("'{}", name))), - _ => return None, - }, - - Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | - DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | - Question | OpenDelim(..) | CloseDelim(..) | - Literal(..) | Ident(..) | Lifetime(..) | Interpolated(..) | DocComment(..) | - Whitespace | Comment | Shebang(..) | Unknown(..) | Eof => return None, - }; - - Some(Token::new(kind, self.span.to(joint.span))) - } - - // See comments in `Nonterminal::to_tokenstream` for why we care about - // *probably* equal here rather than actual equality - crate fn probably_equal_for_proc_macro(&self, other: &Token) -> bool { - if mem::discriminant(&self.kind) != mem::discriminant(&other.kind) { - return false - } - match (&self.kind, &other.kind) { - (&Eq, &Eq) | - (&Lt, &Lt) | - (&Le, &Le) | - (&EqEq, &EqEq) | - (&Ne, &Ne) | - (&Ge, &Ge) | - (&Gt, &Gt) | - (&AndAnd, &AndAnd) | - (&OrOr, &OrOr) | - (&Not, &Not) | - (&Tilde, &Tilde) | - (&At, &At) | - (&Dot, &Dot) | - (&DotDot, &DotDot) | - (&DotDotDot, &DotDotDot) | - (&DotDotEq, &DotDotEq) | - (&Comma, &Comma) | - (&Semi, &Semi) | - (&Colon, &Colon) | - (&ModSep, &ModSep) | - (&RArrow, &RArrow) | - (&LArrow, &LArrow) | - (&FatArrow, &FatArrow) | - (&Pound, &Pound) | - (&Dollar, &Dollar) | - (&Question, &Question) | - (&Whitespace, &Whitespace) | - (&Comment, &Comment) | - (&Eof, &Eof) => true, - - (&BinOp(a), &BinOp(b)) | - (&BinOpEq(a), &BinOpEq(b)) => a == b, - - (&OpenDelim(a), &OpenDelim(b)) | - (&CloseDelim(a), &CloseDelim(b)) => a == b, - - (&DocComment(a), &DocComment(b)) | - (&Shebang(a), &Shebang(b)) => a == b, - - (&Literal(a), &Literal(b)) => a == b, - - (&Lifetime(a), &Lifetime(b)) => a == b, - (&Ident(a, b), &Ident(c, d)) => b == d && (a == c || - a == kw::DollarCrate || - c == kw::DollarCrate), - - (&Interpolated(_), &Interpolated(_)) => false, - - _ => panic!("forgot to add a token?"), - } - } -} - -impl PartialEq for Token { - fn eq(&self, rhs: &TokenKind) -> bool { - self.kind == *rhs - } -} - -#[derive(Clone, RustcEncodable, RustcDecodable)] -/// For interpolation during macro expansion. -pub enum Nonterminal { - NtItem(P), - NtBlock(P), - NtStmt(ast::Stmt), - NtPat(P), - NtExpr(P), - NtTy(P), - NtIdent(ast::Ident, /* is_raw */ bool), - NtLifetime(ast::Ident), - NtLiteral(P), - /// Stuff inside brackets for attributes - NtMeta(ast::AttrItem), - NtPath(ast::Path), - NtVis(ast::Visibility), - NtTT(TokenTree), - // Used only for passing items to proc macro attributes (they are not - // strictly necessary for that, `Annotatable` can be converted into - // tokens directly, but doing that naively regresses pretty-printing). - NtTraitItem(ast::TraitItem), - NtImplItem(ast::ImplItem), - NtForeignItem(ast::ForeignItem), -} - -impl PartialEq for Nonterminal { - fn eq(&self, rhs: &Self) -> bool { - match (self, rhs) { - (NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) => - ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs, - (NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs, - (NtTT(tt_lhs), NtTT(tt_rhs)) => tt_lhs == tt_rhs, - // FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them - // correctly based on data from AST. This will prevent them from matching each other - // in macros. The comparison will become possible only when each nonterminal has an - // attached token stream from which it was parsed. - _ => false, - } - } -} - -impl fmt::Debug for Nonterminal { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - NtItem(..) => f.pad("NtItem(..)"), - NtBlock(..) => f.pad("NtBlock(..)"), - NtStmt(..) => f.pad("NtStmt(..)"), - NtPat(..) => f.pad("NtPat(..)"), - NtExpr(..) => f.pad("NtExpr(..)"), - NtTy(..) => f.pad("NtTy(..)"), - NtIdent(..) => f.pad("NtIdent(..)"), - NtLiteral(..) => f.pad("NtLiteral(..)"), - NtMeta(..) => f.pad("NtMeta(..)"), - NtPath(..) => f.pad("NtPath(..)"), - NtTT(..) => f.pad("NtTT(..)"), - NtImplItem(..) => f.pad("NtImplItem(..)"), - NtTraitItem(..) => f.pad("NtTraitItem(..)"), - NtForeignItem(..) => f.pad("NtForeignItem(..)"), - NtVis(..) => f.pad("NtVis(..)"), - NtLifetime(..) => f.pad("NtLifetime(..)"), - } - } -} diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 1d59c13a9d0..049f34efc26 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -4,7 +4,7 @@ use crate::ast::{Attribute, MacDelimiter, GenericArg}; use crate::util::parser::{self, AssocOp, Fixity}; use crate::attr; use crate::source_map::{self, SourceMap, Spanned}; -use crate::parse::token::{self, BinOpToken, DelimToken, Nonterminal, Token, TokenKind}; +use crate::token::{self, BinOpToken, DelimToken, Nonterminal, Token, TokenKind}; use crate::parse::lexer::comments; use crate::parse; use crate::print::pp::{self, Breaks}; diff --git a/src/libsyntax/token.rs b/src/libsyntax/token.rs new file mode 100644 index 00000000000..6f3da344ccf --- /dev/null +++ b/src/libsyntax/token.rs @@ -0,0 +1,728 @@ +pub use BinOpToken::*; +pub use Nonterminal::*; +pub use DelimToken::*; +pub use LitKind::*; +pub use TokenKind::*; + +use crate::ast; +use crate::ptr::P; +use crate::symbol::kw; +use crate::tokenstream::TokenTree; + +use syntax_pos::symbol::Symbol; +use syntax_pos::{self, Span, DUMMY_SP}; + +use std::fmt; +use std::mem; +#[cfg(target_arch = "x86_64")] +use rustc_data_structures::static_assert_size; +use rustc_data_structures::sync::Lrc; + +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub enum BinOpToken { + Plus, + Minus, + Star, + Slash, + Percent, + Caret, + And, + Or, + Shl, + Shr, +} + +/// A delimiter token. +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub enum DelimToken { + /// A round parenthesis (i.e., `(` or `)`). + Paren, + /// A square bracket (i.e., `[` or `]`). + Bracket, + /// A curly brace (i.e., `{` or `}`). + Brace, + /// An empty delimiter. + NoDelim, +} + +impl DelimToken { + pub fn len(self) -> usize { + if self == NoDelim { 0 } else { 1 } + } + + pub fn is_empty(self) -> bool { + self == NoDelim + } +} + +#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug)] +pub enum LitKind { + Bool, // AST only, must never appear in a `Token` + Byte, + Char, + Integer, + Float, + Str, + StrRaw(u16), // raw string delimited by `n` hash symbols + ByteStr, + ByteStrRaw(u16), // raw byte string delimited by `n` hash symbols + Err, +} + +/// A literal token. +#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug)] +pub struct Lit { + pub kind: LitKind, + pub symbol: Symbol, + pub suffix: Option, +} + +impl fmt::Display for Lit { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Lit { kind, symbol, suffix } = *self; + match kind { + Byte => write!(f, "b'{}'", symbol)?, + Char => write!(f, "'{}'", symbol)?, + Str => write!(f, "\"{}\"", symbol)?, + StrRaw(n) => write!(f, "r{delim}\"{string}\"{delim}", + delim="#".repeat(n as usize), + string=symbol)?, + ByteStr => write!(f, "b\"{}\"", symbol)?, + ByteStrRaw(n) => write!(f, "br{delim}\"{string}\"{delim}", + delim="#".repeat(n as usize), + string=symbol)?, + Integer | + Float | + Bool | + Err => write!(f, "{}", symbol)?, + } + + if let Some(suffix) = suffix { + write!(f, "{}", suffix)?; + } + + Ok(()) + } +} + +impl LitKind { + /// An English article for the literal token kind. + crate fn article(self) -> &'static str { + match self { + Integer | Err => "an", + _ => "a", + } + } + + crate fn descr(self) -> &'static str { + match self { + Bool => panic!("literal token contains `Lit::Bool`"), + Byte => "byte", + Char => "char", + Integer => "integer", + Float => "float", + Str | StrRaw(..) => "string", + ByteStr | ByteStrRaw(..) => "byte string", + Err => "error", + } + } + + crate fn may_have_suffix(self) -> bool { + match self { + Integer | Float | Err => true, + _ => false, + } + } +} + +impl Lit { + pub fn new(kind: LitKind, symbol: Symbol, suffix: Option) -> Lit { + Lit { kind, symbol, suffix } + } +} + +pub(crate) fn ident_can_begin_expr(name: ast::Name, span: Span, is_raw: bool) -> bool { + let ident_token = Token::new(Ident(name, is_raw), span); + token_can_begin_expr(&ident_token) +} + +pub(crate) fn token_can_begin_expr(ident_token: &Token) -> bool { + !ident_token.is_reserved_ident() || + ident_token.is_path_segment_keyword() || + match ident_token.kind { + TokenKind::Ident(ident, _) => [ + kw::Async, + kw::Do, + kw::Box, + kw::Break, + kw::Continue, + kw::False, + kw::For, + kw::If, + kw::Let, + kw::Loop, + kw::Match, + kw::Move, + kw::Return, + kw::True, + kw::Unsafe, + kw::While, + kw::Yield, + kw::Static, + ].contains(&ident), + _=> false, + } +} + +fn ident_can_begin_type(name: ast::Name, span: Span, is_raw: bool) -> bool { + let ident_token = Token::new(Ident(name, is_raw), span); + + !ident_token.is_reserved_ident() || + ident_token.is_path_segment_keyword() || + [ + kw::Underscore, + kw::For, + kw::Impl, + kw::Fn, + kw::Unsafe, + kw::Extern, + kw::Typeof, + kw::Dyn, + ].contains(&name) +} + +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)] +pub enum TokenKind { + /* Expression-operator symbols. */ + Eq, + Lt, + Le, + EqEq, + Ne, + Ge, + Gt, + AndAnd, + OrOr, + Not, + Tilde, + BinOp(BinOpToken), + BinOpEq(BinOpToken), + + /* Structural symbols */ + At, + Dot, + DotDot, + DotDotDot, + DotDotEq, + Comma, + Semi, + Colon, + ModSep, + RArrow, + LArrow, + FatArrow, + Pound, + Dollar, + Question, + /// Used by proc macros for representing lifetimes, not generated by lexer right now. + SingleQuote, + /// An opening delimiter (e.g., `{`). + OpenDelim(DelimToken), + /// A closing delimiter (e.g., `}`). + CloseDelim(DelimToken), + + /* Literals */ + Literal(Lit), + + /* Name components */ + Ident(ast::Name, /* is_raw */ bool), + Lifetime(ast::Name), + + Interpolated(Lrc), + + // Can be expanded into several tokens. + /// A doc comment. + DocComment(ast::Name), + + // Junk. These carry no data because we don't really care about the data + // they *would* carry, and don't really want to allocate a new ident for + // them. Instead, users could extract that from the associated span. + + /// Whitespace. + Whitespace, + /// A comment. + Comment, + Shebang(ast::Name), + /// A completely invalid token which should be skipped. + Unknown(ast::Name), + + Eof, +} + +// `TokenKind` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(target_arch = "x86_64")] +static_assert_size!(TokenKind, 16); + +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)] +pub struct Token { + pub kind: TokenKind, + pub span: Span, +} + +impl TokenKind { + pub fn lit(kind: LitKind, symbol: Symbol, suffix: Option) -> TokenKind { + Literal(Lit::new(kind, symbol, suffix)) + } + + /// Returns tokens that are likely to be typed accidentally instead of the current token. + /// Enables better error recovery when the wrong token is found. + crate fn similar_tokens(&self) -> Option> { + match *self { + Comma => Some(vec![Dot, Lt, Semi]), + Semi => Some(vec![Colon, Comma]), + _ => None + } + } +} + +impl Token { + pub fn new(kind: TokenKind, span: Span) -> Self { + Token { kind, span } + } + + /// Some token that will be thrown away later. + crate fn dummy() -> Self { + Token::new(TokenKind::Whitespace, DUMMY_SP) + } + + /// Recovers a `Token` from an `ast::Ident`. This creates a raw identifier if necessary. + pub fn from_ast_ident(ident: ast::Ident) -> Self { + Token::new(Ident(ident.name, ident.is_raw_guess()), ident.span) + } + + /// Return this token by value and leave a dummy token in its place. + pub fn take(&mut self) -> Self { + mem::replace(self, Token::dummy()) + } + + crate fn is_op(&self) -> bool { + match self.kind { + OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | + Ident(..) | Lifetime(..) | Interpolated(..) | + Whitespace | Comment | Shebang(..) | Eof => false, + _ => true, + } + } + + crate fn is_like_plus(&self) -> bool { + match self.kind { + BinOp(Plus) | BinOpEq(Plus) => true, + _ => false, + } + } + + /// Returns `true` if the token can appear at the start of an expression. + pub fn can_begin_expr(&self) -> bool { + match self.kind { + Ident(name, is_raw) => + ident_can_begin_expr(name, self.span, is_raw), // value name or keyword + OpenDelim(..) | // tuple, array or block + Literal(..) | // literal + Not | // operator not + BinOp(Minus) | // unary minus + BinOp(Star) | // dereference + BinOp(Or) | OrOr | // closure + BinOp(And) | // reference + AndAnd | // double reference + // DotDotDot is no longer supported, but we need some way to display the error + DotDot | DotDotDot | DotDotEq | // range notation + Lt | BinOp(Shl) | // associated path + ModSep | // global path + Lifetime(..) | // labeled loop + Pound => true, // expression attributes + Interpolated(ref nt) => match **nt { + NtLiteral(..) | + NtIdent(..) | + NtExpr(..) | + NtBlock(..) | + NtPath(..) | + NtLifetime(..) => true, + _ => false, + }, + _ => false, + } + } + + /// Returns `true` if the token can appear at the start of a type. + pub fn can_begin_type(&self) -> bool { + match self.kind { + Ident(name, is_raw) => + ident_can_begin_type(name, self.span, is_raw), // type name or keyword + OpenDelim(Paren) | // tuple + OpenDelim(Bracket) | // array + Not | // never + BinOp(Star) | // raw pointer + BinOp(And) | // reference + AndAnd | // double reference + Question | // maybe bound in trait object + Lifetime(..) | // lifetime bound in trait object + Lt | BinOp(Shl) | // associated path + ModSep => true, // global path + Interpolated(ref nt) => match **nt { + NtIdent(..) | NtTy(..) | NtPath(..) | NtLifetime(..) => true, + _ => false, + }, + _ => false, + } + } + + /// Returns `true` if the token can appear at the start of a const param. + crate fn can_begin_const_arg(&self) -> bool { + match self.kind { + OpenDelim(Brace) => true, + Interpolated(ref nt) => match **nt { + NtExpr(..) | NtBlock(..) | NtLiteral(..) => true, + _ => false, + } + _ => self.can_begin_literal_or_bool(), + } + } + + /// Returns `true` if the token can appear at the start of a generic bound. + crate fn can_begin_bound(&self) -> bool { + self.is_path_start() || self.is_lifetime() || self.is_keyword(kw::For) || + self == &Question || self == &OpenDelim(Paren) + } + + /// Returns `true` if the token is any literal + pub fn is_lit(&self) -> bool { + match self.kind { + Literal(..) => true, + _ => false, + } + } + + /// 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). + 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, + _ => false, + }, + _ => false, + } + } + + /// Returns an identifier if this token is an identifier. + pub fn ident(&self) -> Option<(ast::Ident, /* is_raw */ bool)> { + match self.kind { + Ident(name, is_raw) => Some((ast::Ident::new(name, self.span), is_raw)), + Interpolated(ref nt) => match **nt { + NtIdent(ident, is_raw) => Some((ident, is_raw)), + _ => None, + }, + _ => None, + } + } + + /// Returns a lifetime identifier if this token is a lifetime. + pub fn lifetime(&self) -> Option { + match self.kind { + Lifetime(name) => Some(ast::Ident::new(name, self.span)), + Interpolated(ref nt) => match **nt { + NtLifetime(ident) => Some(ident), + _ => None, + }, + _ => None, + } + } + + /// Returns `true` if the token is an identifier. + pub fn is_ident(&self) -> bool { + self.ident().is_some() + } + + /// Returns `true` if the token is a lifetime. + crate fn is_lifetime(&self) -> bool { + self.lifetime().is_some() + } + + /// Returns `true` if the token is a identifier whose name is the given + /// string slice. + crate fn is_ident_named(&self, name: Symbol) -> bool { + self.ident().map_or(false, |(ident, _)| ident.name == name) + } + + /// Returns `true` if the token is an interpolated path. + fn is_path(&self) -> bool { + if let Interpolated(ref nt) = self.kind { + if let NtPath(..) = **nt { + return true; + } + } + false + } + + /// Would `maybe_whole_expr` in `parser.rs` return `Ok(..)`? + /// That is, is this a pre-parsed expression dropped into the token stream + /// (which happens while parsing the result of macro expansion)? + crate fn is_whole_expr(&self) -> bool { + if let Interpolated(ref nt) = self.kind { + if let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtIdent(..) | NtBlock(_) = **nt { + return true; + } + } + + false + } + + /// Returns `true` if the token is either the `mut` or `const` keyword. + crate fn is_mutability(&self) -> bool { + self.is_keyword(kw::Mut) || + self.is_keyword(kw::Const) + } + + crate fn is_qpath_start(&self) -> bool { + self == &Lt || self == &BinOp(Shl) + } + + crate fn is_path_start(&self) -> bool { + self == &ModSep || self.is_qpath_start() || self.is_path() || + self.is_path_segment_keyword() || self.is_ident() && !self.is_reserved_ident() + } + + /// Returns `true` if the token is a given keyword, `kw`. + pub fn is_keyword(&self, kw: Symbol) -> bool { + self.is_non_raw_ident_where(|id| id.name == kw) + } + + crate fn is_path_segment_keyword(&self) -> bool { + self.is_non_raw_ident_where(ast::Ident::is_path_segment_keyword) + } + + // Returns true for reserved identifiers used internally for elided lifetimes, + // unnamed method parameters, crate root module, error recovery etc. + crate fn is_special_ident(&self) -> bool { + self.is_non_raw_ident_where(ast::Ident::is_special) + } + + /// Returns `true` if the token is a keyword used in the language. + crate fn is_used_keyword(&self) -> bool { + self.is_non_raw_ident_where(ast::Ident::is_used_keyword) + } + + /// Returns `true` if the token is a keyword reserved for possible future use. + crate fn is_unused_keyword(&self) -> bool { + self.is_non_raw_ident_where(ast::Ident::is_unused_keyword) + } + + /// Returns `true` if the token is either a special identifier or a keyword. + pub fn is_reserved_ident(&self) -> bool { + self.is_non_raw_ident_where(ast::Ident::is_reserved) + } + + /// Returns `true` if the token is the identifier `true` or `false`. + crate fn is_bool_lit(&self) -> bool { + self.is_non_raw_ident_where(|id| id.name.is_bool_lit()) + } + + /// 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 { + match self.ident() { + Some((id, false)) => pred(id), + _ => false, + } + } + + crate fn glue(&self, joint: &Token) -> Option { + let kind = match self.kind { + Eq => match joint.kind { + Eq => EqEq, + Gt => FatArrow, + _ => return None, + }, + Lt => match joint.kind { + Eq => Le, + Lt => BinOp(Shl), + Le => BinOpEq(Shl), + BinOp(Minus) => LArrow, + _ => return None, + }, + Gt => match joint.kind { + Eq => Ge, + Gt => BinOp(Shr), + Ge => BinOpEq(Shr), + _ => return None, + }, + Not => match joint.kind { + Eq => Ne, + _ => return None, + }, + BinOp(op) => match joint.kind { + Eq => BinOpEq(op), + BinOp(And) if op == And => AndAnd, + BinOp(Or) if op == Or => OrOr, + Gt if op == Minus => RArrow, + _ => return None, + }, + Dot => match joint.kind { + Dot => DotDot, + DotDot => DotDotDot, + _ => return None, + }, + DotDot => match joint.kind { + Dot => DotDotDot, + Eq => DotDotEq, + _ => return None, + }, + Colon => match joint.kind { + Colon => ModSep, + _ => return None, + }, + SingleQuote => match joint.kind { + Ident(name, false) => Lifetime(Symbol::intern(&format!("'{}", name))), + _ => return None, + }, + + Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | + DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | + Question | OpenDelim(..) | CloseDelim(..) | + Literal(..) | Ident(..) | Lifetime(..) | Interpolated(..) | DocComment(..) | + Whitespace | Comment | Shebang(..) | Unknown(..) | Eof => return None, + }; + + Some(Token::new(kind, self.span.to(joint.span))) + } + + // See comments in `Nonterminal::to_tokenstream` for why we care about + // *probably* equal here rather than actual equality + crate fn probably_equal_for_proc_macro(&self, other: &Token) -> bool { + if mem::discriminant(&self.kind) != mem::discriminant(&other.kind) { + return false + } + match (&self.kind, &other.kind) { + (&Eq, &Eq) | + (&Lt, &Lt) | + (&Le, &Le) | + (&EqEq, &EqEq) | + (&Ne, &Ne) | + (&Ge, &Ge) | + (&Gt, &Gt) | + (&AndAnd, &AndAnd) | + (&OrOr, &OrOr) | + (&Not, &Not) | + (&Tilde, &Tilde) | + (&At, &At) | + (&Dot, &Dot) | + (&DotDot, &DotDot) | + (&DotDotDot, &DotDotDot) | + (&DotDotEq, &DotDotEq) | + (&Comma, &Comma) | + (&Semi, &Semi) | + (&Colon, &Colon) | + (&ModSep, &ModSep) | + (&RArrow, &RArrow) | + (&LArrow, &LArrow) | + (&FatArrow, &FatArrow) | + (&Pound, &Pound) | + (&Dollar, &Dollar) | + (&Question, &Question) | + (&Whitespace, &Whitespace) | + (&Comment, &Comment) | + (&Eof, &Eof) => true, + + (&BinOp(a), &BinOp(b)) | + (&BinOpEq(a), &BinOpEq(b)) => a == b, + + (&OpenDelim(a), &OpenDelim(b)) | + (&CloseDelim(a), &CloseDelim(b)) => a == b, + + (&DocComment(a), &DocComment(b)) | + (&Shebang(a), &Shebang(b)) => a == b, + + (&Literal(a), &Literal(b)) => a == b, + + (&Lifetime(a), &Lifetime(b)) => a == b, + (&Ident(a, b), &Ident(c, d)) => b == d && (a == c || + a == kw::DollarCrate || + c == kw::DollarCrate), + + (&Interpolated(_), &Interpolated(_)) => false, + + _ => panic!("forgot to add a token?"), + } + } +} + +impl PartialEq for Token { + fn eq(&self, rhs: &TokenKind) -> bool { + self.kind == *rhs + } +} + +#[derive(Clone, RustcEncodable, RustcDecodable)] +/// For interpolation during macro expansion. +pub enum Nonterminal { + NtItem(P), + NtBlock(P), + NtStmt(ast::Stmt), + NtPat(P), + NtExpr(P), + NtTy(P), + NtIdent(ast::Ident, /* is_raw */ bool), + NtLifetime(ast::Ident), + NtLiteral(P), + /// Stuff inside brackets for attributes + NtMeta(ast::AttrItem), + NtPath(ast::Path), + NtVis(ast::Visibility), + NtTT(TokenTree), + // Used only for passing items to proc macro attributes (they are not + // strictly necessary for that, `Annotatable` can be converted into + // tokens directly, but doing that naively regresses pretty-printing). + NtTraitItem(ast::TraitItem), + NtImplItem(ast::ImplItem), + NtForeignItem(ast::ForeignItem), +} + +impl PartialEq for Nonterminal { + fn eq(&self, rhs: &Self) -> bool { + match (self, rhs) { + (NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) => + ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs, + (NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs, + (NtTT(tt_lhs), NtTT(tt_rhs)) => tt_lhs == tt_rhs, + // FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them + // correctly based on data from AST. This will prevent them from matching each other + // in macros. The comparison will become possible only when each nonterminal has an + // attached token stream from which it was parsed. + _ => false, + } + } +} + +impl fmt::Debug for Nonterminal { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + NtItem(..) => f.pad("NtItem(..)"), + NtBlock(..) => f.pad("NtBlock(..)"), + NtStmt(..) => f.pad("NtStmt(..)"), + NtPat(..) => f.pad("NtPat(..)"), + NtExpr(..) => f.pad("NtExpr(..)"), + NtTy(..) => f.pad("NtTy(..)"), + NtIdent(..) => f.pad("NtIdent(..)"), + NtLiteral(..) => f.pad("NtLiteral(..)"), + NtMeta(..) => f.pad("NtMeta(..)"), + NtPath(..) => f.pad("NtPath(..)"), + NtTT(..) => f.pad("NtTT(..)"), + NtImplItem(..) => f.pad("NtImplItem(..)"), + NtTraitItem(..) => f.pad("NtTraitItem(..)"), + NtForeignItem(..) => f.pad("NtForeignItem(..)"), + NtVis(..) => f.pad("NtVis(..)"), + NtLifetime(..) => f.pad("NtLifetime(..)"), + } + } +} diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index a51d208704a..6e1bb85ce1a 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -13,7 +13,7 @@ //! and a borrowed `TokenStream` is sufficient to build an owned `TokenStream` without taking //! ownership of the original. -use crate::parse::token::{self, DelimToken, Token, TokenKind}; +use crate::token::{self, DelimToken, Token, TokenKind}; use syntax_pos::{Span, DUMMY_SP}; #[cfg(target_arch = "x86_64")] diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs index 982755e8680..edb708d7e97 100644 --- a/src/libsyntax/util/parser.rs +++ b/src/libsyntax/util/parser.rs @@ -1,4 +1,4 @@ -use crate::parse::token::{self, Token, BinOpToken}; +use crate::token::{self, Token, BinOpToken}; use crate::symbol::kw; use crate::ast::{self, BinOpKind}; diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 117787d08c7..cfd160fd577 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -14,7 +14,7 @@ //! those that are created by the expansion of a macro. use crate::ast::*; -use crate::parse::token::Token; +use crate::token::Token; use crate::tokenstream::{TokenTree, TokenStream}; use syntax_pos::Span; diff --git a/src/libsyntax_expand/base.rs b/src/libsyntax_expand/base.rs index d02251eb746..47835c92659 100644 --- a/src/libsyntax_expand/base.rs +++ b/src/libsyntax_expand/base.rs @@ -6,11 +6,11 @@ use syntax::source_map::SourceMap; use syntax::edition::Edition; use syntax::mut_visit::{self, MutVisitor}; use syntax::parse::{self, parser, DirectoryOwnership}; -use syntax::parse::token; use syntax::ptr::P; use syntax::sess::ParseSess; use syntax::symbol::{kw, sym, Ident, Symbol}; use syntax::{ThinVec, MACRO_ARGUMENTS}; +use syntax::token; use syntax::tokenstream::{self, TokenStream}; use syntax::visit::Visitor; diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs index 7dbc7787010..6d1f0abe49e 100644 --- a/src/libsyntax_expand/expand.rs +++ b/src/libsyntax_expand/expand.rs @@ -13,12 +13,12 @@ use syntax::config::StripUnconfigured; use syntax::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err}; use syntax::mut_visit::*; use syntax::parse::{DirectoryOwnership, PResult}; -use syntax::parse::token; use syntax::parse::parser::Parser; use syntax::print::pprust; use syntax::ptr::P; use syntax::sess::ParseSess; use syntax::symbol::{sym, Symbol}; +use syntax::token; use syntax::tokenstream::{TokenStream, TokenTree}; use syntax::visit::{self, Visitor}; use syntax::util::map_in_place::MapInPlace; diff --git a/src/libsyntax_expand/mbe.rs b/src/libsyntax_expand/mbe.rs index 06e0cde3ad8..6964d01b719 100644 --- a/src/libsyntax_expand/mbe.rs +++ b/src/libsyntax_expand/mbe.rs @@ -10,7 +10,7 @@ crate mod macro_rules; crate mod quoted; use syntax::ast; -use syntax::parse::token::{self, Token, TokenKind}; +use syntax::token::{self, Token, TokenKind}; use syntax::tokenstream::{DelimSpan}; use syntax_pos::Span; diff --git a/src/libsyntax_expand/mbe/macro_check.rs b/src/libsyntax_expand/mbe/macro_check.rs index 50abda8d45e..25754ed4217 100644 --- a/src/libsyntax_expand/mbe/macro_check.rs +++ b/src/libsyntax_expand/mbe/macro_check.rs @@ -108,7 +108,7 @@ use crate::mbe::{KleeneToken, TokenTree}; use syntax::ast::NodeId; use syntax::early_buffered_lints::BufferedEarlyLintId; -use syntax::parse::token::{DelimToken, Token, TokenKind}; +use syntax::token::{DelimToken, Token, TokenKind}; use syntax::sess::ParseSess; use syntax::symbol::{kw, sym}; diff --git a/src/libsyntax_expand/mbe/macro_parser.rs b/src/libsyntax_expand/mbe/macro_parser.rs index 3efe22626a9..950e7c0f286 100644 --- a/src/libsyntax_expand/mbe/macro_parser.rs +++ b/src/libsyntax_expand/mbe/macro_parser.rs @@ -79,10 +79,10 @@ use crate::mbe::{self, TokenTree}; use syntax::ast::{Ident, Name}; use syntax::parse::{Directory, PResult}; use syntax::parse::parser::{Parser, PathStyle}; -use syntax::parse::token::{self, DocComment, Nonterminal, Token}; use syntax::print::pprust; use syntax::sess::ParseSess; use syntax::symbol::{kw, sym, Symbol}; +use syntax::token::{self, DocComment, Nonterminal, Token}; use syntax::tokenstream::{DelimSpan, TokenStream}; use errors::FatalError; diff --git a/src/libsyntax_expand/mbe/macro_rules.rs b/src/libsyntax_expand/mbe/macro_rules.rs index 55719907403..a5fc301fbf6 100644 --- a/src/libsyntax_expand/mbe/macro_rules.rs +++ b/src/libsyntax_expand/mbe/macro_rules.rs @@ -13,12 +13,11 @@ use syntax::attr::{self, TransparencyError}; use syntax::edition::Edition; use syntax::feature_gate::Features; use syntax::parse::parser::Parser; -use syntax::parse::token::TokenKind::*; -use syntax::parse::token::{self, NtTT, Token}; use syntax::parse::Directory; use syntax::print::pprust; use syntax::sess::ParseSess; use syntax::symbol::{kw, sym, Symbol}; +use syntax::token::{self, NtTT, Token, TokenKind::*}; use syntax::tokenstream::{DelimSpan, TokenStream}; use errors::{DiagnosticBuilder, FatalError}; diff --git a/src/libsyntax_expand/mbe/quoted.rs b/src/libsyntax_expand/mbe/quoted.rs index cedd59233ad..dec504c0d97 100644 --- a/src/libsyntax_expand/mbe/quoted.rs +++ b/src/libsyntax_expand/mbe/quoted.rs @@ -2,10 +2,10 @@ use crate::mbe::macro_parser; use crate::mbe::{TokenTree, KleeneOp, KleeneToken, SequenceRepetition, Delimited}; use syntax::ast; -use syntax::parse::token::{self, Token}; use syntax::print::pprust; use syntax::sess::ParseSess; use syntax::symbol::kw; +use syntax::token::{self, Token}; use syntax::tokenstream; use syntax_pos::Span; diff --git a/src/libsyntax_expand/mbe/transcribe.rs b/src/libsyntax_expand/mbe/transcribe.rs index 6f060103ef4..4092d4b97de 100644 --- a/src/libsyntax_expand/mbe/transcribe.rs +++ b/src/libsyntax_expand/mbe/transcribe.rs @@ -4,7 +4,7 @@ use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch}; use syntax::ast::{Ident, Mac}; use syntax::mut_visit::{self, MutVisitor}; -use syntax::parse::token::{self, NtTT, Token}; +use syntax::token::{self, NtTT, Token}; use syntax::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; use smallvec::{smallvec, SmallVec}; diff --git a/src/libsyntax_expand/proc_macro.rs b/src/libsyntax_expand/proc_macro.rs index 1f4c481e3ea..51c368bbaa6 100644 --- a/src/libsyntax_expand/proc_macro.rs +++ b/src/libsyntax_expand/proc_macro.rs @@ -4,8 +4,9 @@ use crate::proc_macro_server; use syntax::ast::{self, ItemKind, Attribute, Mac}; use syntax::attr::{mark_used, mark_known}; use syntax::errors::{Applicability, FatalError}; -use syntax::parse::{self, token}; +use syntax::parse; use syntax::symbol::sym; +use syntax::token; use syntax::tokenstream::{self, TokenStream}; use syntax::visit::Visitor; diff --git a/src/libsyntax_expand/proc_macro_server.rs b/src/libsyntax_expand/proc_macro_server.rs index 4ce99cfe73b..67a15e48205 100644 --- a/src/libsyntax_expand/proc_macro_server.rs +++ b/src/libsyntax_expand/proc_macro_server.rs @@ -1,10 +1,11 @@ use crate::base::ExtCtxt; use syntax::ast; -use syntax::parse::{self, token}; +use syntax::parse::{self}; use syntax::parse::lexer::comments; use syntax::print::pprust; use syntax::sess::ParseSess; +use syntax::token; use syntax::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint}; use errors::Diagnostic; @@ -52,7 +53,7 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> { fn from_internal(((tree, is_joint), sess, stack): (TreeAndJoint, &ParseSess, &mut Vec)) -> Self { - use syntax::parse::token::*; + use syntax::token::*; let joint = is_joint == Joint; let Token { kind, span } = match tree { @@ -193,7 +194,7 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> impl ToInternal for TokenTree { fn to_internal(self) -> TokenStream { - use syntax::parse::token::*; + use syntax::token::*; let (ch, joint, span) = match self { TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span), diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index 8c9a34713ea..539d777105d 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -8,7 +8,7 @@ use errors::DiagnosticBuilder; use syntax::ast; use syntax_expand::base::{self, *}; -use syntax::parse::token::{self, Token}; +use syntax::token::{self, Token}; use syntax::ptr::P; use syntax::symbol::{kw, sym, Symbol}; use syntax::ast::AsmDialect; diff --git a/src/libsyntax_ext/assert.rs b/src/libsyntax_ext/assert.rs index f4d1f7fb09c..a15423b7ad8 100644 --- a/src/libsyntax_ext/assert.rs +++ b/src/libsyntax_ext/assert.rs @@ -2,7 +2,7 @@ use errors::{Applicability, DiagnosticBuilder}; use syntax::ast::{self, *}; use syntax_expand::base::*; -use syntax::parse::token::{self, TokenKind}; +use syntax::token::{self, TokenKind}; use syntax::parse::parser::Parser; use syntax::print::pprust; use syntax::ptr::P; diff --git a/src/libsyntax_ext/cfg.rs b/src/libsyntax_ext/cfg.rs index 9e693f29c5a..583236d9754 100644 --- a/src/libsyntax_ext/cfg.rs +++ b/src/libsyntax_ext/cfg.rs @@ -8,7 +8,7 @@ use syntax::ast; use syntax_expand::base::{self, *}; use syntax::attr; use syntax::tokenstream::TokenStream; -use syntax::parse::token; +use syntax::token; use syntax_pos::Span; pub fn expand_cfg( diff --git a/src/libsyntax_ext/cmdline_attrs.rs b/src/libsyntax_ext/cmdline_attrs.rs index 2d981526a39..171f2405573 100644 --- a/src/libsyntax_ext/cmdline_attrs.rs +++ b/src/libsyntax_ext/cmdline_attrs.rs @@ -2,7 +2,8 @@ use syntax::ast::{self, AttrItem, AttrStyle}; use syntax::attr::mk_attr; -use syntax::parse::{self, token}; +use syntax::parse; +use syntax::token; use syntax::sess::ParseSess; use syntax_expand::panictry; use syntax_pos::FileName; diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs index a132a4136ea..8a1bc56cf1c 100644 --- a/src/libsyntax_ext/concat_idents.rs +++ b/src/libsyntax_ext/concat_idents.rs @@ -2,7 +2,7 @@ use rustc_data_structures::thin_vec::ThinVec; use syntax::ast; use syntax_expand::base::{self, *}; -use syntax::parse::token::{self, Token}; +use syntax::token::{self, Token}; use syntax::ptr::P; use syntax_pos::Span; use syntax_pos::symbol::Symbol; diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 314c2eefd4c..e25ba7b1783 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -9,7 +9,7 @@ use errors::pluralize; use syntax::ast; use syntax_expand::base::{self, *}; -use syntax::parse::token; +use syntax::token; use syntax::ptr::P; use syntax::symbol::{Symbol, sym}; use syntax::tokenstream::TokenStream; diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs index 879ae1e4215..8a8ce9a7f14 100644 --- a/src/libsyntax_ext/global_asm.rs +++ b/src/libsyntax_ext/global_asm.rs @@ -13,7 +13,7 @@ use errors::DiagnosticBuilder; use syntax::ast; use syntax::source_map::respan; use syntax_expand::base::{self, *}; -use syntax::parse::token; +use syntax::token; use syntax::ptr::P; use syntax_pos::Span; use syntax::tokenstream::TokenStream; diff --git a/src/libsyntax_ext/plugin_macro_defs.rs b/src/libsyntax_ext/plugin_macro_defs.rs index 1ca9422eb9d..cee1b97af55 100644 --- a/src/libsyntax_ext/plugin_macro_defs.rs +++ b/src/libsyntax_ext/plugin_macro_defs.rs @@ -4,12 +4,12 @@ use syntax::ast::*; use syntax::attr; use syntax::edition::Edition; -use syntax_expand::base::{Resolver, NamedSyntaxExtension}; -use syntax::parse::token; use syntax::ptr::P; use syntax::source_map::respan; use syntax::symbol::sym; +use syntax::token; use syntax::tokenstream::*; +use syntax_expand::base::{Resolver, NamedSyntaxExtension}; use syntax_pos::{Span, DUMMY_SP}; use syntax_pos::hygiene::{ExpnData, ExpnKind, AstPass}; diff --git a/src/libsyntax_ext/source_util.rs b/src/libsyntax_ext/source_util.rs index f6c58fcdfa1..7e47b40714d 100644 --- a/src/libsyntax_ext/source_util.rs +++ b/src/libsyntax_ext/source_util.rs @@ -1,10 +1,11 @@ use syntax_expand::panictry; use syntax_expand::base::{self, *}; use syntax::ast; -use syntax::parse::{self, token, DirectoryOwnership}; +use syntax::parse::{self, DirectoryOwnership}; use syntax::print::pprust; use syntax::ptr::P; use syntax::symbol::Symbol; +use syntax::token; use syntax::tokenstream::TokenStream; use syntax::early_buffered_lints::BufferedEarlyLintId; diff --git a/src/test/ui-fulldeps/ast_stmt_expr_attr.rs b/src/test/ui-fulldeps/ast_stmt_expr_attr.rs index 927e2c0820e..6277e2e7ea9 100644 --- a/src/test/ui-fulldeps/ast_stmt_expr_attr.rs +++ b/src/test/ui-fulldeps/ast_stmt_expr_attr.rs @@ -16,7 +16,7 @@ use syntax::parse; use syntax::parse::PResult; use syntax::parse::new_parser_from_source_str; use syntax::parse::parser::Parser; -use syntax::parse::token; +use syntax::token; use syntax::ptr::P; use syntax::parse::parser::attr::*; use syntax::print::pprust; diff --git a/src/test/ui-fulldeps/auxiliary/roman-numerals.rs b/src/test/ui-fulldeps/auxiliary/roman-numerals.rs index 3524f449c74..520347faa15 100644 --- a/src/test/ui-fulldeps/auxiliary/roman-numerals.rs +++ b/src/test/ui-fulldeps/auxiliary/roman-numerals.rs @@ -15,7 +15,7 @@ extern crate syntax_pos; extern crate rustc; extern crate rustc_driver; -use syntax::parse::token::{self, Token}; +use syntax::token::{self, Token}; use syntax::tokenstream::{TokenTree, TokenStream}; use syntax_expand::base::{ExtCtxt, MacResult, DummyResult, MacEager}; use syntax_pos::Span; -- cgit 1.4.1-3-g733a5 From 3667e6248ec18740ce57db7997333a30c991929b Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 11 Oct 2019 13:06:36 +0200 Subject: move PResult to librustc_errors --- src/librustc_driver/lib.rs | 3 ++- src/librustc_errors/lib.rs | 10 +++++++++- src/librustc_interface/passes.rs | 3 ++- src/libsyntax/attr/mod.rs | 3 ++- src/libsyntax/parse/lexer/tokentrees.rs | 3 ++- src/libsyntax/parse/mod.rs | 11 +---------- src/libsyntax/parse/parser/attr.rs | 4 +++- src/libsyntax/parse/parser/diagnostics.rs | 8 +++----- src/libsyntax/parse/parser/expr.rs | 4 ++-- src/libsyntax/parse/parser/generics.rs | 4 +++- src/libsyntax/parse/parser/item.rs | 4 ++-- src/libsyntax/parse/parser/mod.rs | 4 ++-- src/libsyntax/parse/parser/module.rs | 4 +++- src/libsyntax/parse/parser/pat.rs | 4 ++-- src/libsyntax/parse/parser/path.rs | 4 ++-- src/libsyntax/parse/parser/stmt.rs | 4 ++-- src/libsyntax/parse/parser/ty.rs | 4 ++-- src/libsyntax/tests.rs | 4 ++-- src/libsyntax_expand/expand.rs | 4 ++-- src/libsyntax_expand/mbe/macro_parser.rs | 4 ++-- src/test/ui-fulldeps/ast_stmt_expr_attr.rs | 3 ++- 21 files changed, 52 insertions(+), 44 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 6e8bc11162f..611b891d99a 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -42,6 +42,7 @@ use rustc::ty::TyCtxt; use rustc::util::common::{set_time_depth, time, print_time_passes_entry, ErrorReported}; use rustc_metadata::locator; use rustc_codegen_utils::codegen_backend::CodegenBackend; +use errors::PResult; use rustc_interface::interface; use rustc_interface::util::get_codegen_sysroot; use rustc_data_structures::sync::SeqCst; @@ -64,7 +65,7 @@ use std::time::Instant; use syntax::ast; use syntax::source_map::FileLoader; use syntax::feature_gate::{GatedCfg, UnstableFeatures}; -use syntax::parse::{self, PResult}; +use syntax::parse; use syntax::symbol::sym; use syntax_pos::{DUMMY_SP, FileName}; diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 67c180a05e9..fb5cccf61a7 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -15,7 +15,8 @@ use Level::*; use emitter::{Emitter, EmitterWriter, is_case_difference}; use registry::Registry; - +#[cfg(target_arch = "x86_64")] +use rustc_data_structures::static_assert_size; use rustc_data_structures::sync::{self, Lrc, Lock}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::stable_hasher::StableHasher; @@ -48,6 +49,13 @@ use syntax_pos::{ SpanSnippetError, }; +pub type PResult<'a, T> = Result>; + +// `PResult` is used a lot. Make sure it doesn't unintentionally get bigger. +// (See also the comment on `DiagnosticBuilderInner`.) +#[cfg(target_arch = "x86_64")] +static_assert_size!(PResult<'_, bool>, 16); + /// Indicates the confidence in the correctness of a suggestion. /// /// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 52332744d1a..ce34caee6fa 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -22,6 +22,7 @@ use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_codegen_utils::link::filename_for_metadata; use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel}; use rustc_data_structures::sync::{Lrc, ParallelIterator, par_iter}; +use rustc_errors::PResult; use rustc_incremental; use rustc_metadata::cstore; use rustc_mir as mir; @@ -36,7 +37,7 @@ use syntax::{self, ast, visit}; use syntax::early_buffered_lints::BufferedEarlyLint; use syntax_expand::base::{NamedSyntaxExtension, ExtCtxt}; use syntax::mut_visit::MutVisitor; -use syntax::parse::{self, PResult}; +use syntax::parse; use syntax::util::node_count::NodeCounter; use syntax::symbol::Symbol; use syntax_pos::FileName; diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 1534d2723c8..d609225a54f 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -16,7 +16,6 @@ use crate::mut_visit::visit_clobber; use crate::source_map::{BytePos, Spanned}; use crate::parse::lexer::comments::doc_comment_style; use crate::parse; -use crate::parse::PResult; use crate::token::{self, Token}; use crate::ptr::P; use crate::sess::ParseSess; @@ -25,6 +24,8 @@ use crate::ThinVec; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; use crate::GLOBALS; +use errors::PResult; + use log::debug; use syntax_pos::Span; diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index 3c15a5e1dae..2b056434d4d 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -4,10 +4,11 @@ use syntax_pos::Span; use super::{StringReader, UnmatchedBrace}; use crate::print::pprust::token_to_string; -use crate::parse::PResult; use crate::token::{self, Token}; use crate::tokenstream::{DelimSpan, IsJoint::{self, *}, TokenStream, TokenTree, TreeAndJoint}; +use errors::PResult; + impl<'a> StringReader<'a> { crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec) { let mut tt_reader = TokenTreesReader { diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 7db0ca0b78d..badf8bcba57 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -7,9 +7,7 @@ use crate::tokenstream::{self, TokenStream, TokenTree}; use crate::print::pprust; use crate::sess::ParseSess; -use errors::{FatalError, Level, Diagnostic, DiagnosticBuilder}; -#[cfg(target_arch = "x86_64")] -use rustc_data_structures::static_assert_size; +use errors::{PResult, FatalError, Level, Diagnostic}; use rustc_data_structures::sync::Lrc; use syntax_pos::{Span, SourceFile, FileName}; @@ -29,13 +27,6 @@ pub mod lexer; crate mod classify; crate mod literal; -pub type PResult<'a, T> = Result>; - -// `PResult` is used a lot. Make sure it doesn't unintentionally get bigger. -// (See also the comment on `DiagnosticBuilderInner`.) -#[cfg(target_arch = "x86_64")] -static_assert_size!(PResult<'_, bool>, 16); - #[derive(Clone)] pub struct Directory<'a> { pub path: Cow<'a, Path>, diff --git a/src/libsyntax/parse/parser/attr.rs b/src/libsyntax/parse/parser/attr.rs index aa0542a09a9..2f1b87da7e9 100644 --- a/src/libsyntax/parse/parser/attr.rs +++ b/src/libsyntax/parse/parser/attr.rs @@ -1,10 +1,12 @@ -use super::{SeqSep, PResult, Parser, TokenType, PathStyle}; +use super::{SeqSep, Parser, TokenType, PathStyle}; use crate::attr; use crate::ast; use crate::token::{self, Nonterminal, DelimToken}; use crate::tokenstream::{TokenStream, TokenTree}; use crate::source_map::Span; +use errors::PResult; + use log::debug; #[derive(Debug)] diff --git a/src/libsyntax/parse/parser/diagnostics.rs b/src/libsyntax/parse/parser/diagnostics.rs index 09f0b9b74b2..26d7f48025e 100644 --- a/src/libsyntax/parse/parser/diagnostics.rs +++ b/src/libsyntax/parse/parser/diagnostics.rs @@ -1,7 +1,4 @@ -use super::{ - BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType, - SeqSep, PResult, Parser -}; +use super::{BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType, SeqSep, Parser}; use crate::ast::{ self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, @@ -12,7 +9,8 @@ use crate::ptr::P; use crate::symbol::{kw, sym}; use crate::ThinVec; use crate::util::parser::AssocOp; -use errors::{Applicability, DiagnosticBuilder, DiagnosticId, pluralize}; + +use errors::{PResult, Applicability, DiagnosticBuilder, DiagnosticId, pluralize}; use rustc_data_structures::fx::FxHashSet; use syntax_pos::{Span, DUMMY_SP, MultiSpan, SpanSnippetError}; use log::{debug, trace}; diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 4b962201e85..9faa4aefbb6 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -1,4 +1,4 @@ -use super::{Parser, PResult, Restrictions, PrevTokenKind, TokenType, PathStyle, BlockMode}; +use super::{Parser, Restrictions, PrevTokenKind, TokenType, PathStyle, BlockMode}; use super::{SemiColonMode, SeqSep, TokenExpectType}; use super::pat::{GateOr, PARAM_EXPECTED}; use super::diagnostics::Error; @@ -18,7 +18,7 @@ use crate::ptr::P; use crate::source_map::{self, Span}; use crate::util::parser::{AssocOp, Fixity, prec_let_scrutinee_needs_par}; -use errors::Applicability; +use errors::{PResult, Applicability}; use syntax_pos::symbol::{kw, sym}; use syntax_pos::Symbol; use std::mem; diff --git a/src/libsyntax/parse/parser/generics.rs b/src/libsyntax/parse/parser/generics.rs index cfc3768cac5..ae9ecd8fe39 100644 --- a/src/libsyntax/parse/parser/generics.rs +++ b/src/libsyntax/parse/parser/generics.rs @@ -1,4 +1,4 @@ -use super::{Parser, PResult}; +use super::Parser; use crate::ast::{self, WhereClause, GenericParam, GenericParamKind, GenericBounds, Attribute}; use crate::token; @@ -6,6 +6,8 @@ use crate::source_map::DUMMY_SP; use syntax_pos::symbol::{kw, sym}; +use errors::PResult; + impl<'a> Parser<'a> { /// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`. /// diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 9d543055f23..3c618d75d34 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -1,4 +1,4 @@ -use super::{Parser, PResult, PathStyle}; +use super::{Parser, PathStyle}; use super::diagnostics::{Error, dummy_arg, ConsumeClosingDelim}; use crate::maybe_whole; @@ -17,7 +17,7 @@ use crate::ThinVec; use log::debug; use std::mem; -use errors::{Applicability, DiagnosticBuilder, DiagnosticId, StashKey}; +use errors::{PResult, Applicability, DiagnosticBuilder, DiagnosticId, StashKey}; use syntax_pos::BytePos; /// Whether the type alias or associated type is a concrete type or an opaque type. diff --git a/src/libsyntax/parse/parser/mod.rs b/src/libsyntax/parse/parser/mod.rs index 6498b674a3b..f7f7b0e83d4 100644 --- a/src/libsyntax/parse/parser/mod.rs +++ b/src/libsyntax/parse/parser/mod.rs @@ -15,7 +15,7 @@ use crate::ast::{ self, Abi, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident, IsAsync, MacDelimiter, Mutability, StrStyle, Visibility, VisibilityKind, Unsafety, }; -use crate::parse::{PResult, Directory, DirectoryOwnership}; +use crate::parse::{Directory, DirectoryOwnership}; use crate::parse::lexer::UnmatchedBrace; use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use crate::token::{self, Token, TokenKind, DelimToken}; @@ -27,7 +27,7 @@ use crate::symbol::{kw, sym, Symbol}; use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint}; use crate::ThinVec; -use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError}; +use errors::{PResult, Applicability, DiagnosticBuilder, DiagnosticId, FatalError}; use syntax_pos::{Span, BytePos, DUMMY_SP, FileName}; use log::debug; diff --git a/src/libsyntax/parse/parser/module.rs b/src/libsyntax/parse/parser/module.rs index 70e0dfc3e88..72049daaed3 100644 --- a/src/libsyntax/parse/parser/module.rs +++ b/src/libsyntax/parse/parser/module.rs @@ -1,4 +1,4 @@ -use super::{Parser, PResult}; +use super::Parser; use super::item::ItemInfo; use super::diagnostics::Error; @@ -9,6 +9,8 @@ use crate::token::{self, TokenKind}; use crate::source_map::{SourceMap, Span, DUMMY_SP, FileName}; use crate::symbol::sym; +use errors::PResult; + use std::path::{self, Path, PathBuf}; /// Information about the path to a module. diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index c4a983188fa..f347300da71 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -1,4 +1,4 @@ -use super::{Parser, PResult, PathStyle}; +use super::{Parser, PathStyle}; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use crate::ptr::P; @@ -10,7 +10,7 @@ use crate::print::pprust; use crate::source_map::{respan, Span, Spanned}; use crate::ThinVec; use syntax_pos::symbol::{kw, sym}; -use errors::{Applicability, DiagnosticBuilder}; +use errors::{PResult, Applicability, DiagnosticBuilder}; type Expected = Option<&'static str>; diff --git a/src/libsyntax/parse/parser/path.rs b/src/libsyntax/parse/parser/path.rs index 2659e0c680e..9ceb3ba1eb4 100644 --- a/src/libsyntax/parse/parser/path.rs +++ b/src/libsyntax/parse/parser/path.rs @@ -1,4 +1,4 @@ -use super::{Parser, PResult, TokenType}; +use super::{Parser, TokenType}; use crate::{maybe_whole, ThinVec}; use crate::ast::{self, QSelf, Path, PathSegment, Ident, ParenthesizedArgs, AngleBracketedArgs}; @@ -9,7 +9,7 @@ use syntax_pos::symbol::{kw, sym}; use std::mem; use log::debug; -use errors::{Applicability, pluralize}; +use errors::{PResult, Applicability, pluralize}; /// Specifies how to parse a path. #[derive(Copy, Clone, PartialEq)] diff --git a/src/libsyntax/parse/parser/stmt.rs b/src/libsyntax/parse/parser/stmt.rs index 010fd9c37fd..2a3d6b05bb9 100644 --- a/src/libsyntax/parse/parser/stmt.rs +++ b/src/libsyntax/parse/parser/stmt.rs @@ -1,4 +1,4 @@ -use super::{Parser, PResult, Restrictions, PrevTokenKind, SemiColonMode, BlockMode}; +use super::{Parser, Restrictions, PrevTokenKind, SemiColonMode, BlockMode}; use super::expr::LhsExpr; use super::path::PathStyle; use super::pat::GateOr; @@ -14,7 +14,7 @@ use crate::source_map::{respan, Span}; use crate::symbol::{kw, sym}; use std::mem; -use errors::Applicability; +use errors::{PResult, Applicability}; impl<'a> Parser<'a> { /// Parses a statement. This stops just before trailing semicolons on everything but items. diff --git a/src/libsyntax/parse/parser/ty.rs b/src/libsyntax/parse/parser/ty.rs index 4183416e628..a891634e611 100644 --- a/src/libsyntax/parse/parser/ty.rs +++ b/src/libsyntax/parse/parser/ty.rs @@ -1,4 +1,4 @@ -use super::{Parser, PResult, PathStyle, PrevTokenKind, TokenType}; +use super::{Parser, PathStyle, PrevTokenKind, TokenType}; use super::item::ParamCfg; use crate::{maybe_whole, maybe_recover_from_interpolated_ty_qpath}; @@ -10,7 +10,7 @@ use crate::token::{self, Token}; use crate::source_map::Span; use crate::symbol::{kw}; -use errors::{Applicability, pluralize}; +use errors::{PResult, Applicability, pluralize}; /// Returns `true` if `IDENT t` can start a type -- `IDENT::a::b`, `IDENT`, /// `IDENT<::AssocTy>`. diff --git a/src/libsyntax/tests.rs b/src/libsyntax/tests.rs index e73c8b43bcc..ed457c3627f 100644 --- a/src/libsyntax/tests.rs +++ b/src/libsyntax/tests.rs @@ -1,5 +1,5 @@ use crate::ast; -use crate::parse::{PResult, source_file_to_stream}; +use crate::parse::source_file_to_stream; use crate::parse::new_parser_from_source_str; use crate::parse::parser::Parser; use crate::sess::ParseSess; @@ -8,7 +8,7 @@ use crate::tokenstream::TokenStream; use crate::with_default_globals; use errors::emitter::EmitterWriter; -use errors::Handler; +use errors::{PResult, Handler}; use rustc_data_structures::sync::Lrc; use syntax_pos::{BytePos, Span, MultiSpan}; diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs index 6d1f0abe49e..e91dd2aba15 100644 --- a/src/libsyntax_expand/expand.rs +++ b/src/libsyntax_expand/expand.rs @@ -12,7 +12,7 @@ use syntax::configure; use syntax::config::StripUnconfigured; use syntax::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err}; use syntax::mut_visit::*; -use syntax::parse::{DirectoryOwnership, PResult}; +use syntax::parse::DirectoryOwnership; use syntax::parse::parser::Parser; use syntax::print::pprust; use syntax::ptr::P; @@ -23,7 +23,7 @@ use syntax::tokenstream::{TokenStream, TokenTree}; use syntax::visit::{self, Visitor}; use syntax::util::map_in_place::MapInPlace; -use errors::{Applicability, FatalError}; +use errors::{PResult, Applicability, FatalError}; use smallvec::{smallvec, SmallVec}; use syntax_pos::{Span, DUMMY_SP, FileName}; diff --git a/src/libsyntax_expand/mbe/macro_parser.rs b/src/libsyntax_expand/mbe/macro_parser.rs index 950e7c0f286..80bf27e1a94 100644 --- a/src/libsyntax_expand/mbe/macro_parser.rs +++ b/src/libsyntax_expand/mbe/macro_parser.rs @@ -77,7 +77,7 @@ use TokenTreeOrTokenTreeSlice::*; use crate::mbe::{self, TokenTree}; use syntax::ast::{Ident, Name}; -use syntax::parse::{Directory, PResult}; +use syntax::parse::Directory; use syntax::parse::parser::{Parser, PathStyle}; use syntax::print::pprust; use syntax::sess::ParseSess; @@ -85,7 +85,7 @@ use syntax::symbol::{kw, sym, Symbol}; use syntax::token::{self, DocComment, Nonterminal, Token}; use syntax::tokenstream::{DelimSpan, TokenStream}; -use errors::FatalError; +use errors::{PResult, FatalError}; use smallvec::{smallvec, SmallVec}; use syntax_pos::Span; diff --git a/src/test/ui-fulldeps/ast_stmt_expr_attr.rs b/src/test/ui-fulldeps/ast_stmt_expr_attr.rs index 6277e2e7ea9..ac864e76784 100644 --- a/src/test/ui-fulldeps/ast_stmt_expr_attr.rs +++ b/src/test/ui-fulldeps/ast_stmt_expr_attr.rs @@ -6,14 +6,15 @@ #![feature(rustc_private)] extern crate syntax; +extern crate rustc_errors; +use rustc_errors::PResult; use syntax::ast::*; use syntax::attr::*; use syntax::ast; use syntax::sess::ParseSess; use syntax::source_map::{FilePathMapping, FileName}; use syntax::parse; -use syntax::parse::PResult; use syntax::parse::new_parser_from_source_str; use syntax::parse::parser::Parser; use syntax::token; -- cgit 1.4.1-3-g733a5 From 255b12a8d3ef3639b4b389fc56d93bd80f03d087 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 11 Oct 2019 13:17:20 +0200 Subject: move parse::classify -> util::classify --- src/libsyntax/lib.rs | 1 + src/libsyntax/parse/classify.rs | 25 ------------------------- src/libsyntax/parse/mod.rs | 1 - src/libsyntax/parse/parser/expr.rs | 2 +- src/libsyntax/parse/parser/stmt.rs | 3 ++- src/libsyntax/print/pprust.rs | 4 ++-- src/libsyntax/util/classify.rs | 25 +++++++++++++++++++++++++ 7 files changed, 31 insertions(+), 30 deletions(-) delete mode 100644 src/libsyntax/parse/classify.rs create mode 100644 src/libsyntax/util/classify.rs (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 4c134430f30..205fbe3c52e 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -85,6 +85,7 @@ pub mod diagnostics { pub mod error_codes; pub mod util { + crate mod classify; pub mod lev_distance; pub mod node_count; pub mod parser; diff --git a/src/libsyntax/parse/classify.rs b/src/libsyntax/parse/classify.rs deleted file mode 100644 index 44560688750..00000000000 --- a/src/libsyntax/parse/classify.rs +++ /dev/null @@ -1,25 +0,0 @@ -//! Routines the parser uses to classify AST nodes - -// Predicates on exprs and stmts that the pretty-printer and parser use - -use crate::ast; - -/// Does this expression require a semicolon to be treated -/// as a statement? The negation of this: 'can this expression -/// be used as a statement without a semicolon' -- is used -/// as an early-bail-out in the parser so that, for instance, -/// if true {...} else {...} -/// |x| 5 -/// isn't parsed as (if true {...} else {...} | x) | 5 -pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool { - match e.kind { - ast::ExprKind::If(..) | - ast::ExprKind::Match(..) | - ast::ExprKind::Block(..) | - ast::ExprKind::While(..) | - ast::ExprKind::Loop(..) | - ast::ExprKind::ForLoop(..) | - ast::ExprKind::TryBlock(..) => false, - _ => true, - } -} diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index badf8bcba57..44fd39448e5 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -24,7 +24,6 @@ mod tests; pub mod parser; pub mod lexer; -crate mod classify; crate mod literal; #[derive(Clone)] diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index 9faa4aefbb6..cc984f03c7d 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -11,11 +11,11 @@ use crate::ast::{ FunctionRetTy, Param, FnDecl, BinOpKind, BinOp, UnOp, Mac, AnonConst, Field, Lit, }; use crate::maybe_recover_from_interpolated_ty_qpath; -use crate::parse::classify; use crate::token::{self, Token, TokenKind}; use crate::print::pprust; use crate::ptr::P; use crate::source_map::{self, Span}; +use crate::util::classify; use crate::util::parser::{AssocOp, Fixity, prec_let_scrutinee_needs_par}; use errors::{PResult, Applicability}; diff --git a/src/libsyntax/parse/parser/stmt.rs b/src/libsyntax/parse/parser/stmt.rs index 2a3d6b05bb9..30e47b7a0b2 100644 --- a/src/libsyntax/parse/parser/stmt.rs +++ b/src/libsyntax/parse/parser/stmt.rs @@ -8,7 +8,8 @@ use crate::ptr::P; use crate::{maybe_whole, ThinVec}; use crate::ast::{self, DUMMY_NODE_ID, Stmt, StmtKind, Local, Block, BlockCheckMode, Expr, ExprKind}; use crate::ast::{Attribute, AttrStyle, VisibilityKind, MacStmtStyle, Mac, MacDelimiter}; -use crate::parse::{classify, DirectoryOwnership}; +use crate::parse::DirectoryOwnership; +use crate::util::classify; use crate::token; use crate::source_map::{respan, Span}; use crate::symbol::{kw, sym}; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 049f34efc26..0b72b034c20 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -6,10 +6,10 @@ use crate::attr; use crate::source_map::{self, SourceMap, Spanned}; use crate::token::{self, BinOpToken, DelimToken, Nonterminal, Token, TokenKind}; use crate::parse::lexer::comments; -use crate::parse; use crate::print::pp::{self, Breaks}; use crate::print::pp::Breaks::{Consistent, Inconsistent}; use crate::ptr::P; +use crate::util::classify; use crate::sess::ParseSess; use crate::symbol::{kw, sym}; use crate::tokenstream::{self, TokenStream, TokenTree}; @@ -1659,7 +1659,7 @@ impl<'a> State<'a> { ast::StmtKind::Expr(ref expr) => { self.space_if_not_bol(); self.print_expr_outer_attr_style(expr, false); - if parse::classify::expr_requires_semi_to_be_stmt(expr) { + if classify::expr_requires_semi_to_be_stmt(expr) { self.s.word(";"); } } diff --git a/src/libsyntax/util/classify.rs b/src/libsyntax/util/classify.rs new file mode 100644 index 00000000000..44560688750 --- /dev/null +++ b/src/libsyntax/util/classify.rs @@ -0,0 +1,25 @@ +//! Routines the parser uses to classify AST nodes + +// Predicates on exprs and stmts that the pretty-printer and parser use + +use crate::ast; + +/// Does this expression require a semicolon to be treated +/// as a statement? The negation of this: 'can this expression +/// be used as a statement without a semicolon' -- is used +/// as an early-bail-out in the parser so that, for instance, +/// if true {...} else {...} +/// |x| 5 +/// isn't parsed as (if true {...} else {...} | x) | 5 +pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool { + match e.kind { + ast::ExprKind::If(..) | + ast::ExprKind::Match(..) | + ast::ExprKind::Block(..) | + ast::ExprKind::While(..) | + ast::ExprKind::Loop(..) | + ast::ExprKind::ForLoop(..) | + ast::ExprKind::TryBlock(..) => false, + _ => true, + } +} -- cgit 1.4.1-3-g733a5 From a1571b68552b0d56d85080c5f92fdab233775de4 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 11 Oct 2019 14:14:30 +0200 Subject: syntax::attr: remove usage of lexer --- src/libsyntax/attr/mod.rs | 5 ++--- src/libsyntax/parse/parser/attr.rs | 11 +++++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index d609225a54f..c639431794c 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -14,7 +14,6 @@ use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem}; use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam}; use crate::mut_visit::visit_clobber; use crate::source_map::{BytePos, Spanned}; -use crate::parse::lexer::comments::doc_comment_style; use crate::parse; use crate::token::{self, Token}; use crate::ptr::P; @@ -401,11 +400,11 @@ pub fn mk_attr_outer(item: MetaItem) -> Attribute { mk_attr(AttrStyle::Outer, item.path, item.kind.tokens(item.span), item.span) } -pub fn mk_doc_comment(comment: Symbol, span: Span) -> Attribute { +pub fn mk_doc_comment(style: AttrStyle, comment: Symbol, span: Span) -> Attribute { Attribute { kind: AttrKind::DocComment(comment), id: mk_attr_id(), - style: doc_comment_style(&comment.as_str()), + style, span, } } diff --git a/src/libsyntax/parse/parser/attr.rs b/src/libsyntax/parse/parser/attr.rs index 2f1b87da7e9..920e7a521ef 100644 --- a/src/libsyntax/parse/parser/attr.rs +++ b/src/libsyntax/parse/parser/attr.rs @@ -1,10 +1,12 @@ use super::{SeqSep, Parser, TokenType, PathStyle}; use crate::attr; use crate::ast; +use crate::parse::lexer::comments; use crate::token::{self, Nonterminal, DelimToken}; use crate::tokenstream::{TokenStream, TokenTree}; use crate::source_map::Span; +use syntax_pos::Symbol; use errors::PResult; use log::debug; @@ -45,7 +47,7 @@ impl<'a> Parser<'a> { just_parsed_doc_comment = false; } token::DocComment(s) => { - let attr = attr::mk_doc_comment(s, self.token.span); + let attr = self.mk_doc_comment(s); if attr.style != ast::AttrStyle::Outer { let mut err = self.fatal("expected outer doc comment"); err.note("inner doc comments like this (starting with \ @@ -62,6 +64,11 @@ impl<'a> Parser<'a> { Ok(attrs) } + fn mk_doc_comment(&self, s: Symbol) -> ast::Attribute { + let style = comments::doc_comment_style(&s.as_str()); + attr::mk_doc_comment(style, s, self.token.span) + } + /// Matches `attribute = # ! [ meta_item ]`. /// /// If `permit_inner` is `true`, then a leading `!` indicates an inner @@ -230,7 +237,7 @@ impl<'a> Parser<'a> { } token::DocComment(s) => { // We need to get the position of this token before we bump. - let attr = attr::mk_doc_comment(s, self.token.span); + let attr = self.mk_doc_comment(s); if attr.style == ast::AttrStyle::Inner { attrs.push(attr); self.bump(); -- cgit 1.4.1-3-g733a5 From 27f97aa468b5079bfd159e6fee9a04d5501a8818 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 11 Oct 2019 14:39:52 +0200 Subject: move syntax::parse::lexer::comments -> syntax::util::comments --- src/librustc_save_analysis/lib.rs | 2 +- src/librustdoc/clean/mod.rs | 2 +- src/libsyntax/lib.rs | 1 + src/libsyntax/parse/lexer/comments.rs | 255 -------------------------- src/libsyntax/parse/lexer/comments/tests.rs | 47 ----- src/libsyntax/parse/lexer/mod.rs | 21 +-- src/libsyntax/parse/lexer/tests.rs | 1 + src/libsyntax/parse/parser/attr.rs | 2 +- src/libsyntax/parse/parser/mod.rs | 2 +- src/libsyntax/print/pprust.rs | 2 +- src/libsyntax/util/comments.rs | 270 ++++++++++++++++++++++++++++ src/libsyntax/util/comments/tests.rs | 47 +++++ src/libsyntax_expand/proc_macro_server.rs | 4 +- 13 files changed, 329 insertions(+), 327 deletions(-) delete mode 100644 src/libsyntax/parse/lexer/comments.rs delete mode 100644 src/libsyntax/parse/lexer/comments/tests.rs create mode 100644 src/libsyntax/util/comments.rs create mode 100644 src/libsyntax/util/comments/tests.rs (limited to 'src/libsyntax/parse') diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 9408bbe557a..a2f8837c581 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -29,7 +29,7 @@ use std::path::{Path, PathBuf}; use syntax::ast::{self, Attribute, DUMMY_NODE_ID, NodeId, PatKind}; use syntax::source_map::Spanned; -use syntax::parse::lexer::comments::strip_doc_comment_decoration; +use syntax::util::comments::strip_doc_comment_decoration; use syntax::print::pprust; use syntax::visit::{self, Visitor}; use syntax::print::pprust::{param_to_string, ty_to_string}; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0c670e5e717..f6cac8ca48d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -28,7 +28,7 @@ use rustc::ty::layout::VariantIdx; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use syntax::ast::{self, Attribute, AttrStyle, AttrKind, Ident}; use syntax::attr; -use syntax::parse::lexer::comments; +use syntax::util::comments; use syntax::source_map::DUMMY_SP; use syntax_pos::symbol::{Symbol, kw, sym}; use syntax_pos::hygiene::MacroKind; diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 205fbe3c52e..bdad52bfb45 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -86,6 +86,7 @@ pub mod error_codes; pub mod util { crate mod classify; + pub mod comments; pub mod lev_distance; pub mod node_count; pub mod parser; diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs deleted file mode 100644 index 33415bdcb62..00000000000 --- a/src/libsyntax/parse/lexer/comments.rs +++ /dev/null @@ -1,255 +0,0 @@ -pub use CommentStyle::*; - -use super::is_block_doc_comment; - -use crate::ast; -use crate::source_map::SourceMap; -use crate::sess::ParseSess; - -use syntax_pos::{BytePos, CharPos, Pos, FileName}; - -use std::usize; - -#[cfg(test)] -mod tests; - -#[derive(Clone, Copy, PartialEq, Debug)] -pub enum CommentStyle { - /// No code on either side of each line of the comment - Isolated, - /// Code exists to the left of the comment - Trailing, - /// Code before /* foo */ and after the comment - Mixed, - /// Just a manual blank line "\n\n", for layout - BlankLine, -} - -#[derive(Clone)] -pub struct Comment { - pub style: CommentStyle, - pub lines: Vec, - pub pos: BytePos, -} - -fn is_doc_comment(s: &str) -> bool { - (s.starts_with("///") && super::is_doc_comment(s)) || s.starts_with("//!") || - (s.starts_with("/**") && is_block_doc_comment(s)) || s.starts_with("/*!") -} - -pub fn doc_comment_style(comment: &str) -> ast::AttrStyle { - assert!(is_doc_comment(comment)); - if comment.starts_with("//!") || comment.starts_with("/*!") { - ast::AttrStyle::Inner - } else { - ast::AttrStyle::Outer - } -} - -pub fn strip_doc_comment_decoration(comment: &str) -> String { - /// remove whitespace-only lines from the start/end of lines - fn vertical_trim(lines: Vec) -> Vec { - let mut i = 0; - let mut j = lines.len(); - // first line of all-stars should be omitted - if !lines.is_empty() && lines[0].chars().all(|c| c == '*') { - i += 1; - } - - while i < j && lines[i].trim().is_empty() { - i += 1; - } - // like the first, a last line of all stars should be omitted - if j > i && - lines[j - 1] - .chars() - .skip(1) - .all(|c| c == '*') { - j -= 1; - } - - while j > i && lines[j - 1].trim().is_empty() { - j -= 1; - } - - lines[i..j].to_vec() - } - - /// remove a "[ \t]*\*" block from each line, if possible - fn horizontal_trim(lines: Vec) -> Vec { - let mut i = usize::MAX; - let mut can_trim = true; - let mut first = true; - - for line in &lines { - for (j, c) in line.chars().enumerate() { - if j > i || !"* \t".contains(c) { - can_trim = false; - break; - } - if c == '*' { - if first { - i = j; - first = false; - } else if i != j { - can_trim = false; - } - break; - } - } - if i >= line.len() { - can_trim = false; - } - if !can_trim { - break; - } - } - - if can_trim { - lines.iter() - .map(|line| (&line[i + 1..line.len()]).to_string()) - .collect() - } else { - lines - } - } - - // one-line comments lose their prefix - const ONELINERS: &[&str] = &["///!", "///", "//!", "//"]; - - for prefix in ONELINERS { - if comment.starts_with(*prefix) { - return (&comment[prefix.len()..]).to_string(); - } - } - - if comment.starts_with("/*") { - let lines = comment[3..comment.len() - 2] - .lines() - .map(|s| s.to_string()) - .collect::>(); - - let lines = vertical_trim(lines); - let lines = horizontal_trim(lines); - - return lines.join("\n"); - } - - panic!("not a doc-comment: {}", comment); -} - -/// Returns `None` if the first `col` chars of `s` contain a non-whitespace char. -/// Otherwise returns `Some(k)` where `k` is first char offset after that leading -/// whitespace. Note that `k` may be outside bounds of `s`. -fn all_whitespace(s: &str, col: CharPos) -> Option { - let mut idx = 0; - for (i, ch) in s.char_indices().take(col.to_usize()) { - if !ch.is_whitespace() { - return None; - } - idx = i + ch.len_utf8(); - } - Some(idx) -} - -fn trim_whitespace_prefix(s: &str, col: CharPos) -> &str { - let len = s.len(); - match all_whitespace(&s, col) { - Some(col) => if col < len { &s[col..] } else { "" }, - None => s, - } -} - -fn split_block_comment_into_lines( - text: &str, - col: CharPos, -) -> Vec { - let mut res: Vec = vec![]; - let mut lines = text.lines(); - // just push the first line - res.extend(lines.next().map(|it| it.to_string())); - // for other lines, strip common whitespace prefix - for line in lines { - res.push(trim_whitespace_prefix(line, col).to_string()) - } - res -} - -// it appears this function is called only from pprust... that's -// probably not a good thing. -crate fn gather_comments(sess: &ParseSess, path: FileName, src: String) -> Vec { - let cm = SourceMap::new(sess.source_map().path_mapping().clone()); - let source_file = cm.new_source_file(path, src); - let text = (*source_file.src.as_ref().unwrap()).clone(); - - let text: &str = text.as_str(); - let start_bpos = source_file.start_pos; - let mut pos = 0; - let mut comments: Vec = Vec::new(); - let mut code_to_the_left = false; - - if let Some(shebang_len) = rustc_lexer::strip_shebang(text) { - comments.push(Comment { - style: Isolated, - lines: vec![text[..shebang_len].to_string()], - pos: start_bpos, - }); - pos += shebang_len; - } - - for token in rustc_lexer::tokenize(&text[pos..]) { - let token_text = &text[pos..pos + token.len]; - match token.kind { - rustc_lexer::TokenKind::Whitespace => { - if let Some(mut idx) = token_text.find('\n') { - code_to_the_left = false; - while let Some(next_newline) = &token_text[idx + 1..].find('\n') { - idx = idx + 1 + next_newline; - comments.push(Comment { - style: BlankLine, - lines: vec![], - pos: start_bpos + BytePos((pos + idx) as u32), - }); - } - } - } - rustc_lexer::TokenKind::BlockComment { terminated: _ } => { - if !is_block_doc_comment(token_text) { - let code_to_the_right = match text[pos + token.len..].chars().next() { - Some('\r') | Some('\n') => false, - _ => true, - }; - let style = match (code_to_the_left, code_to_the_right) { - (true, true) | (false, true) => Mixed, - (false, false) => Isolated, - (true, false) => Trailing, - }; - - // Count the number of chars since the start of the line by rescanning. - let pos_in_file = start_bpos + BytePos(pos as u32); - let line_begin_in_file = source_file.line_begin_pos(pos_in_file); - let line_begin_pos = (line_begin_in_file - start_bpos).to_usize(); - let col = CharPos(text[line_begin_pos..pos].chars().count()); - - let lines = split_block_comment_into_lines(token_text, col); - comments.push(Comment { style, lines, pos: pos_in_file }) - } - } - rustc_lexer::TokenKind::LineComment => { - if !is_doc_comment(token_text) { - comments.push(Comment { - style: if code_to_the_left { Trailing } else { Isolated }, - lines: vec![token_text.to_string()], - pos: start_bpos + BytePos(pos as u32), - }) - } - } - _ => { - code_to_the_left = true; - } - } - pos += token.len; - } - - comments -} diff --git a/src/libsyntax/parse/lexer/comments/tests.rs b/src/libsyntax/parse/lexer/comments/tests.rs deleted file mode 100644 index f9cd69fb50d..00000000000 --- a/src/libsyntax/parse/lexer/comments/tests.rs +++ /dev/null @@ -1,47 +0,0 @@ -use super::*; - -#[test] -fn test_block_doc_comment_1() { - let comment = "/**\n * Test \n ** Test\n * Test\n*/"; - let stripped = strip_doc_comment_decoration(comment); - assert_eq!(stripped, " Test \n* Test\n Test"); -} - -#[test] -fn test_block_doc_comment_2() { - let comment = "/**\n * Test\n * Test\n*/"; - let stripped = strip_doc_comment_decoration(comment); - assert_eq!(stripped, " Test\n Test"); -} - -#[test] -fn test_block_doc_comment_3() { - let comment = "/**\n let a: *i32;\n *a = 5;\n*/"; - let stripped = strip_doc_comment_decoration(comment); - assert_eq!(stripped, " let a: *i32;\n *a = 5;"); -} - -#[test] -fn test_block_doc_comment_4() { - let comment = "/*******************\n test\n *********************/"; - let stripped = strip_doc_comment_decoration(comment); - assert_eq!(stripped, " test"); -} - -#[test] -fn test_line_doc_comment() { - let stripped = strip_doc_comment_decoration("/// test"); - assert_eq!(stripped, " test"); - let stripped = strip_doc_comment_decoration("///! test"); - assert_eq!(stripped, " test"); - let stripped = strip_doc_comment_decoration("// test"); - assert_eq!(stripped, " test"); - let stripped = strip_doc_comment_decoration("// test"); - assert_eq!(stripped, " test"); - let stripped = strip_doc_comment_decoration("///test"); - assert_eq!(stripped, "test"); - let stripped = strip_doc_comment_decoration("///!test"); - assert_eq!(stripped, "test"); - let stripped = strip_doc_comment_decoration("//test"); - assert_eq!(stripped, "test"); -} diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 5499a3cae5f..b1b7b08c78a 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1,6 +1,7 @@ use crate::token::{self, Token, TokenKind}; use crate::sess::ParseSess; use crate::symbol::{sym, Symbol}; +use crate::util::comments; use errors::{FatalError, DiagnosticBuilder}; use syntax_pos::{BytePos, Pos, Span}; @@ -15,7 +16,6 @@ use log::debug; #[cfg(test)] mod tests; -pub mod comments; mod tokentrees; mod unicode_chars; mod unescape_error_reporting; @@ -179,7 +179,7 @@ impl<'a> StringReader<'a> { rustc_lexer::TokenKind::LineComment => { let string = self.str_from(start); // comments with only more "/"s are not doc comments - let tok = if is_doc_comment(string) { + let tok = if comments::is_line_doc_comment(string) { self.forbid_bare_cr(start, string, "bare CR not allowed in doc-comment"); token::DocComment(Symbol::intern(string)) } else { @@ -192,7 +192,7 @@ impl<'a> StringReader<'a> { let string = self.str_from(start); // block comments starting with "/**" or "/*!" are doc-comments // but comments with only "*"s between two "/"s are not - let is_doc_comment = is_block_doc_comment(string); + let is_doc_comment = comments::is_block_doc_comment(string); if !terminated { let msg = if is_doc_comment { @@ -643,18 +643,3 @@ impl<'a> StringReader<'a> { } } } - -fn is_doc_comment(s: &str) -> bool { - let res = (s.starts_with("///") && *s.as_bytes().get(3).unwrap_or(&b' ') != b'/') || - s.starts_with("//!"); - debug!("is {:?} a doc comment? {}", s, res); - res -} - -fn is_block_doc_comment(s: &str) -> bool { - // Prevent `/**/` from being parsed as a doc comment - let res = ((s.starts_with("/**") && *s.as_bytes().get(3).unwrap_or(&b' ') != b'*') || - s.starts_with("/*!")) && s.len() >= 5; - debug!("is {:?} a doc comment? {}", s, res); - res -} diff --git a/src/libsyntax/parse/lexer/tests.rs b/src/libsyntax/parse/lexer/tests.rs index b9b82b2bcef..baa6fb59537 100644 --- a/src/libsyntax/parse/lexer/tests.rs +++ b/src/libsyntax/parse/lexer/tests.rs @@ -3,6 +3,7 @@ use super::*; use crate::symbol::Symbol; use crate::source_map::{SourceMap, FilePathMapping}; use crate::token; +use crate::util::comments::is_doc_comment; use crate::with_default_globals; use errors::{Handler, emitter::EmitterWriter}; diff --git a/src/libsyntax/parse/parser/attr.rs b/src/libsyntax/parse/parser/attr.rs index 920e7a521ef..31f0a02a483 100644 --- a/src/libsyntax/parse/parser/attr.rs +++ b/src/libsyntax/parse/parser/attr.rs @@ -1,7 +1,7 @@ use super::{SeqSep, Parser, TokenType, PathStyle}; use crate::attr; use crate::ast; -use crate::parse::lexer::comments; +use crate::util::comments; use crate::token::{self, Nonterminal, DelimToken}; use crate::tokenstream::{TokenStream, TokenTree}; use crate::source_map::Span; diff --git a/src/libsyntax/parse/parser/mod.rs b/src/libsyntax/parse/parser/mod.rs index f7f7b0e83d4..455f4172f5f 100644 --- a/src/libsyntax/parse/parser/mod.rs +++ b/src/libsyntax/parse/parser/mod.rs @@ -17,7 +17,7 @@ use crate::ast::{ }; use crate::parse::{Directory, DirectoryOwnership}; use crate::parse::lexer::UnmatchedBrace; -use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; +use crate::util::comments::{doc_comment_style, strip_doc_comment_decoration}; use crate::token::{self, Token, TokenKind, DelimToken}; use crate::print::pprust; use crate::ptr::P; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 0b72b034c20..4ca4bdeb046 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2,10 +2,10 @@ use crate::ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax}; use crate::ast::{SelfKind, GenericBound, TraitBoundModifier}; use crate::ast::{Attribute, MacDelimiter, GenericArg}; use crate::util::parser::{self, AssocOp, Fixity}; +use crate::util::comments; use crate::attr; use crate::source_map::{self, SourceMap, Spanned}; use crate::token::{self, BinOpToken, DelimToken, Nonterminal, Token, TokenKind}; -use crate::parse::lexer::comments; use crate::print::pp::{self, Breaks}; use crate::print::pp::Breaks::{Consistent, Inconsistent}; use crate::ptr::P; diff --git a/src/libsyntax/util/comments.rs b/src/libsyntax/util/comments.rs new file mode 100644 index 00000000000..448b4f3b825 --- /dev/null +++ b/src/libsyntax/util/comments.rs @@ -0,0 +1,270 @@ +pub use CommentStyle::*; + +use crate::ast; +use crate::source_map::SourceMap; +use crate::sess::ParseSess; + +use syntax_pos::{BytePos, CharPos, Pos, FileName}; + +use std::usize; + +use log::debug; + +#[cfg(test)] +mod tests; + +#[derive(Clone, Copy, PartialEq, Debug)] +pub enum CommentStyle { + /// No code on either side of each line of the comment + Isolated, + /// Code exists to the left of the comment + Trailing, + /// Code before /* foo */ and after the comment + Mixed, + /// Just a manual blank line "\n\n", for layout + BlankLine, +} + +#[derive(Clone)] +pub struct Comment { + pub style: CommentStyle, + pub lines: Vec, + pub pos: BytePos, +} + +crate fn is_line_doc_comment(s: &str) -> bool { + let res = (s.starts_with("///") && *s.as_bytes().get(3).unwrap_or(&b' ') != b'/') || + s.starts_with("//!"); + debug!("is {:?} a doc comment? {}", s, res); + res +} + +crate fn is_block_doc_comment(s: &str) -> bool { + // Prevent `/**/` from being parsed as a doc comment + let res = ((s.starts_with("/**") && *s.as_bytes().get(3).unwrap_or(&b' ') != b'*') || + s.starts_with("/*!")) && s.len() >= 5; + debug!("is {:?} a doc comment? {}", s, res); + res +} + +crate fn is_doc_comment(s: &str) -> bool { + (s.starts_with("///") && is_line_doc_comment(s)) || s.starts_with("//!") || + (s.starts_with("/**") && is_block_doc_comment(s)) || s.starts_with("/*!") +} + +pub fn doc_comment_style(comment: &str) -> ast::AttrStyle { + assert!(is_doc_comment(comment)); + if comment.starts_with("//!") || comment.starts_with("/*!") { + ast::AttrStyle::Inner + } else { + ast::AttrStyle::Outer + } +} + +pub fn strip_doc_comment_decoration(comment: &str) -> String { + /// remove whitespace-only lines from the start/end of lines + fn vertical_trim(lines: Vec) -> Vec { + let mut i = 0; + let mut j = lines.len(); + // first line of all-stars should be omitted + if !lines.is_empty() && lines[0].chars().all(|c| c == '*') { + i += 1; + } + + while i < j && lines[i].trim().is_empty() { + i += 1; + } + // like the first, a last line of all stars should be omitted + if j > i && + lines[j - 1] + .chars() + .skip(1) + .all(|c| c == '*') { + j -= 1; + } + + while j > i && lines[j - 1].trim().is_empty() { + j -= 1; + } + + lines[i..j].to_vec() + } + + /// remove a "[ \t]*\*" block from each line, if possible + fn horizontal_trim(lines: Vec) -> Vec { + let mut i = usize::MAX; + let mut can_trim = true; + let mut first = true; + + for line in &lines { + for (j, c) in line.chars().enumerate() { + if j > i || !"* \t".contains(c) { + can_trim = false; + break; + } + if c == '*' { + if first { + i = j; + first = false; + } else if i != j { + can_trim = false; + } + break; + } + } + if i >= line.len() { + can_trim = false; + } + if !can_trim { + break; + } + } + + if can_trim { + lines.iter() + .map(|line| (&line[i + 1..line.len()]).to_string()) + .collect() + } else { + lines + } + } + + // one-line comments lose their prefix + const ONELINERS: &[&str] = &["///!", "///", "//!", "//"]; + + for prefix in ONELINERS { + if comment.starts_with(*prefix) { + return (&comment[prefix.len()..]).to_string(); + } + } + + if comment.starts_with("/*") { + let lines = comment[3..comment.len() - 2] + .lines() + .map(|s| s.to_string()) + .collect::>(); + + let lines = vertical_trim(lines); + let lines = horizontal_trim(lines); + + return lines.join("\n"); + } + + panic!("not a doc-comment: {}", comment); +} + +/// Returns `None` if the first `col` chars of `s` contain a non-whitespace char. +/// Otherwise returns `Some(k)` where `k` is first char offset after that leading +/// whitespace. Note that `k` may be outside bounds of `s`. +fn all_whitespace(s: &str, col: CharPos) -> Option { + let mut idx = 0; + for (i, ch) in s.char_indices().take(col.to_usize()) { + if !ch.is_whitespace() { + return None; + } + idx = i + ch.len_utf8(); + } + Some(idx) +} + +fn trim_whitespace_prefix(s: &str, col: CharPos) -> &str { + let len = s.len(); + match all_whitespace(&s, col) { + Some(col) => if col < len { &s[col..] } else { "" }, + None => s, + } +} + +fn split_block_comment_into_lines( + text: &str, + col: CharPos, +) -> Vec { + let mut res: Vec = vec![]; + let mut lines = text.lines(); + // just push the first line + res.extend(lines.next().map(|it| it.to_string())); + // for other lines, strip common whitespace prefix + for line in lines { + res.push(trim_whitespace_prefix(line, col).to_string()) + } + res +} + +// it appears this function is called only from pprust... that's +// probably not a good thing. +crate fn gather_comments(sess: &ParseSess, path: FileName, src: String) -> Vec { + let cm = SourceMap::new(sess.source_map().path_mapping().clone()); + let source_file = cm.new_source_file(path, src); + let text = (*source_file.src.as_ref().unwrap()).clone(); + + let text: &str = text.as_str(); + let start_bpos = source_file.start_pos; + let mut pos = 0; + let mut comments: Vec = Vec::new(); + let mut code_to_the_left = false; + + if let Some(shebang_len) = rustc_lexer::strip_shebang(text) { + comments.push(Comment { + style: Isolated, + lines: vec![text[..shebang_len].to_string()], + pos: start_bpos, + }); + pos += shebang_len; + } + + for token in rustc_lexer::tokenize(&text[pos..]) { + let token_text = &text[pos..pos + token.len]; + match token.kind { + rustc_lexer::TokenKind::Whitespace => { + if let Some(mut idx) = token_text.find('\n') { + code_to_the_left = false; + while let Some(next_newline) = &token_text[idx + 1..].find('\n') { + idx = idx + 1 + next_newline; + comments.push(Comment { + style: BlankLine, + lines: vec![], + pos: start_bpos + BytePos((pos + idx) as u32), + }); + } + } + } + rustc_lexer::TokenKind::BlockComment { terminated: _ } => { + if !is_block_doc_comment(token_text) { + let code_to_the_right = match text[pos + token.len..].chars().next() { + Some('\r') | Some('\n') => false, + _ => true, + }; + let style = match (code_to_the_left, code_to_the_right) { + (true, true) | (false, true) => Mixed, + (false, false) => Isolated, + (true, false) => Trailing, + }; + + // Count the number of chars since the start of the line by rescanning. + let pos_in_file = start_bpos + BytePos(pos as u32); + let line_begin_in_file = source_file.line_begin_pos(pos_in_file); + let line_begin_pos = (line_begin_in_file - start_bpos).to_usize(); + let col = CharPos(text[line_begin_pos..pos].chars().count()); + + let lines = split_block_comment_into_lines(token_text, col); + comments.push(Comment { style, lines, pos: pos_in_file }) + } + } + rustc_lexer::TokenKind::LineComment => { + if !is_doc_comment(token_text) { + comments.push(Comment { + style: if code_to_the_left { Trailing } else { Isolated }, + lines: vec![token_text.to_string()], + pos: start_bpos + BytePos(pos as u32), + }) + } + } + _ => { + code_to_the_left = true; + } + } + pos += token.len; + } + + comments +} diff --git a/src/libsyntax/util/comments/tests.rs b/src/libsyntax/util/comments/tests.rs new file mode 100644 index 00000000000..f9cd69fb50d --- /dev/null +++ b/src/libsyntax/util/comments/tests.rs @@ -0,0 +1,47 @@ +use super::*; + +#[test] +fn test_block_doc_comment_1() { + let comment = "/**\n * Test \n ** Test\n * Test\n*/"; + let stripped = strip_doc_comment_decoration(comment); + assert_eq!(stripped, " Test \n* Test\n Test"); +} + +#[test] +fn test_block_doc_comment_2() { + let comment = "/**\n * Test\n * Test\n*/"; + let stripped = strip_doc_comment_decoration(comment); + assert_eq!(stripped, " Test\n Test"); +} + +#[test] +fn test_block_doc_comment_3() { + let comment = "/**\n let a: *i32;\n *a = 5;\n*/"; + let stripped = strip_doc_comment_decoration(comment); + assert_eq!(stripped, " let a: *i32;\n *a = 5;"); +} + +#[test] +fn test_block_doc_comment_4() { + let comment = "/*******************\n test\n *********************/"; + let stripped = strip_doc_comment_decoration(comment); + assert_eq!(stripped, " test"); +} + +#[test] +fn test_line_doc_comment() { + let stripped = strip_doc_comment_decoration("/// test"); + assert_eq!(stripped, " test"); + let stripped = strip_doc_comment_decoration("///! test"); + assert_eq!(stripped, " test"); + let stripped = strip_doc_comment_decoration("// test"); + assert_eq!(stripped, " test"); + let stripped = strip_doc_comment_decoration("// test"); + assert_eq!(stripped, " test"); + let stripped = strip_doc_comment_decoration("///test"); + assert_eq!(stripped, "test"); + let stripped = strip_doc_comment_decoration("///!test"); + assert_eq!(stripped, "test"); + let stripped = strip_doc_comment_decoration("//test"); + assert_eq!(stripped, "test"); +} diff --git a/src/libsyntax_expand/proc_macro_server.rs b/src/libsyntax_expand/proc_macro_server.rs index 67a15e48205..e96b6092787 100644 --- a/src/libsyntax_expand/proc_macro_server.rs +++ b/src/libsyntax_expand/proc_macro_server.rs @@ -1,8 +1,8 @@ use crate::base::ExtCtxt; use syntax::ast; -use syntax::parse::{self}; -use syntax::parse::lexer::comments; +use syntax::parse; +use syntax::util::comments; use syntax::print::pprust; use syntax::sess::ParseSess; use syntax::token; -- cgit 1.4.1-3-g733a5 From cc9c139694389c8df158640d4bcc20a2fe31f1ea Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 11 Oct 2019 18:47:14 +0200 Subject: move syntax::{parse::literal -> util::literal} --- src/libsyntax/lib.rs | 1 + src/libsyntax/parse/literal.rs | 305 ------------------------------------- src/libsyntax/parse/mod.rs | 2 - src/libsyntax/parse/parser/expr.rs | 3 +- src/libsyntax/util/literal.rs | 305 +++++++++++++++++++++++++++++++++++++ 5 files changed, 307 insertions(+), 309 deletions(-) delete mode 100644 src/libsyntax/parse/literal.rs create mode 100644 src/libsyntax/util/literal.rs (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index bdad52bfb45..1b17de529c4 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -88,6 +88,7 @@ pub mod util { crate mod classify; pub mod comments; pub mod lev_distance; + crate mod literal; pub mod node_count; pub mod parser; pub mod map_in_place; diff --git a/src/libsyntax/parse/literal.rs b/src/libsyntax/parse/literal.rs deleted file mode 100644 index d4c9b7850c5..00000000000 --- a/src/libsyntax/parse/literal.rs +++ /dev/null @@ -1,305 +0,0 @@ -//! Code related to parsing literals. - -use crate::ast::{self, Lit, LitKind}; -use crate::symbol::{kw, sym, Symbol}; -use crate::token::{self, Token}; -use crate::tokenstream::TokenTree; - -use log::debug; -use rustc_data_structures::sync::Lrc; -use syntax_pos::Span; -use rustc_lexer::unescape::{unescape_char, unescape_byte}; -use rustc_lexer::unescape::{unescape_str, unescape_byte_str}; -use rustc_lexer::unescape::{unescape_raw_str, unescape_raw_byte_str}; - -use std::ascii; - -crate enum LitError { - NotLiteral, - LexerError, - InvalidSuffix, - InvalidIntSuffix, - InvalidFloatSuffix, - NonDecimalFloat(u32), - IntTooLarge, -} - -impl LitKind { - /// Converts literal token into a semantic literal. - fn from_lit_token(lit: token::Lit) -> Result { - let token::Lit { kind, symbol, suffix } = lit; - if suffix.is_some() && !kind.may_have_suffix() { - return Err(LitError::InvalidSuffix); - } - - Ok(match kind { - token::Bool => { - assert!(symbol.is_bool_lit()); - LitKind::Bool(symbol == kw::True) - } - token::Byte => return unescape_byte(&symbol.as_str()) - .map(LitKind::Byte).map_err(|_| LitError::LexerError), - token::Char => return unescape_char(&symbol.as_str()) - .map(LitKind::Char).map_err(|_| LitError::LexerError), - - // There are some valid suffixes for integer and float literals, - // so all the handling is done internally. - token::Integer => return integer_lit(symbol, suffix), - token::Float => return float_lit(symbol, suffix), - - token::Str => { - // If there are no characters requiring special treatment we can - // reuse the symbol from the token. Otherwise, we must generate a - // new symbol because the string in the LitKind is different to the - // string in the token. - let s = symbol.as_str(); - let symbol = if s.contains(&['\\', '\r'][..]) { - let mut buf = String::with_capacity(s.len()); - let mut error = Ok(()); - unescape_str(&s, &mut |_, unescaped_char| { - match unescaped_char { - Ok(c) => buf.push(c), - Err(_) => error = Err(LitError::LexerError), - } - }); - error?; - Symbol::intern(&buf) - } else { - symbol - }; - LitKind::Str(symbol, ast::StrStyle::Cooked) - } - token::StrRaw(n) => { - // Ditto. - let s = symbol.as_str(); - let symbol = if s.contains('\r') { - let mut buf = String::with_capacity(s.len()); - let mut error = Ok(()); - unescape_raw_str(&s, &mut |_, unescaped_char| { - match unescaped_char { - Ok(c) => buf.push(c), - Err(_) => error = Err(LitError::LexerError), - } - }); - error?; - buf.shrink_to_fit(); - Symbol::intern(&buf) - } else { - symbol - }; - LitKind::Str(symbol, ast::StrStyle::Raw(n)) - } - token::ByteStr => { - let s = symbol.as_str(); - let mut buf = Vec::with_capacity(s.len()); - let mut error = Ok(()); - unescape_byte_str(&s, &mut |_, unescaped_byte| { - match unescaped_byte { - Ok(c) => buf.push(c), - Err(_) => error = Err(LitError::LexerError), - } - }); - error?; - buf.shrink_to_fit(); - LitKind::ByteStr(Lrc::new(buf)) - } - token::ByteStrRaw(_) => { - let s = symbol.as_str(); - let bytes = if s.contains('\r') { - let mut buf = Vec::with_capacity(s.len()); - let mut error = Ok(()); - unescape_raw_byte_str(&s, &mut |_, unescaped_byte| { - match unescaped_byte { - Ok(c) => buf.push(c), - Err(_) => error = Err(LitError::LexerError), - } - }); - error?; - buf.shrink_to_fit(); - buf - } else { - symbol.to_string().into_bytes() - }; - - LitKind::ByteStr(Lrc::new(bytes)) - }, - token::Err => LitKind::Err(symbol), - }) - } - - /// Attempts to recover a token from semantic literal. - /// This function is used when the original token doesn't exist (e.g. the literal is created - /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing). - pub fn to_lit_token(&self) -> token::Lit { - let (kind, symbol, suffix) = match *self { - LitKind::Str(symbol, ast::StrStyle::Cooked) => { - // Don't re-intern unless the escaped string is different. - let s = symbol.as_str(); - let escaped = s.escape_default().to_string(); - let symbol = if s == escaped { symbol } else { Symbol::intern(&escaped) }; - (token::Str, symbol, None) - } - LitKind::Str(symbol, ast::StrStyle::Raw(n)) => { - (token::StrRaw(n), symbol, None) - } - LitKind::ByteStr(ref bytes) => { - let string = bytes.iter().cloned().flat_map(ascii::escape_default) - .map(Into::::into).collect::(); - (token::ByteStr, Symbol::intern(&string), None) - } - LitKind::Byte(byte) => { - let string: String = ascii::escape_default(byte).map(Into::::into).collect(); - (token::Byte, Symbol::intern(&string), None) - } - LitKind::Char(ch) => { - let string: String = ch.escape_default().map(Into::::into).collect(); - (token::Char, Symbol::intern(&string), None) - } - LitKind::Int(n, ty) => { - let suffix = match ty { - ast::LitIntType::Unsigned(ty) => Some(ty.name()), - ast::LitIntType::Signed(ty) => Some(ty.name()), - ast::LitIntType::Unsuffixed => None, - }; - (token::Integer, sym::integer(n), suffix) - } - LitKind::Float(symbol, ty) => { - let suffix = match ty { - ast::LitFloatType::Suffixed(ty) => Some(ty.name()), - ast::LitFloatType::Unsuffixed => None, - }; - (token::Float, symbol, suffix) - } - LitKind::Bool(value) => { - let symbol = if value { kw::True } else { kw::False }; - (token::Bool, symbol, None) - } - LitKind::Err(symbol) => { - (token::Err, symbol, None) - } - }; - - token::Lit::new(kind, symbol, suffix) - } -} - -impl Lit { - /// Converts literal token into an AST literal. - crate fn from_lit_token(token: token::Lit, span: Span) -> Result { - Ok(Lit { token, kind: LitKind::from_lit_token(token)?, span }) - } - - /// Converts arbitrary token into an AST literal. - crate fn from_token(token: &Token) -> Result { - let lit = match token.kind { - token::Ident(name, false) if name.is_bool_lit() => - token::Lit::new(token::Bool, name, None), - token::Literal(lit) => - lit, - token::Interpolated(ref nt) => { - if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt { - if let ast::ExprKind::Lit(lit) = &expr.kind { - return Ok(lit.clone()); - } - } - return Err(LitError::NotLiteral); - } - _ => return Err(LitError::NotLiteral) - }; - - Lit::from_lit_token(lit, token.span) - } - - /// Attempts to recover an AST literal from semantic literal. - /// This function is used when the original token doesn't exist (e.g. the literal is created - /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing). - pub fn from_lit_kind(kind: LitKind, span: Span) -> Lit { - Lit { token: kind.to_lit_token(), kind, span } - } - - /// Losslessly convert an AST literal into a token tree. - crate fn token_tree(&self) -> TokenTree { - let token = match self.token.kind { - token::Bool => token::Ident(self.token.symbol, false), - _ => token::Literal(self.token), - }; - TokenTree::token(token, self.span) - } -} - -fn strip_underscores(symbol: Symbol) -> Symbol { - // Do not allocate a new string unless necessary. - let s = symbol.as_str(); - if s.contains('_') { - let mut s = s.to_string(); - s.retain(|c| c != '_'); - return Symbol::intern(&s); - } - symbol -} - -fn filtered_float_lit(symbol: Symbol, suffix: Option, base: u32) - -> Result { - debug!("filtered_float_lit: {:?}, {:?}, {:?}", symbol, suffix, base); - if base != 10 { - return Err(LitError::NonDecimalFloat(base)); - } - Ok(match suffix { - Some(suf) => LitKind::Float(symbol, ast::LitFloatType::Suffixed(match suf { - sym::f32 => ast::FloatTy::F32, - sym::f64 => ast::FloatTy::F64, - _ => return Err(LitError::InvalidFloatSuffix), - })), - None => LitKind::Float(symbol, ast::LitFloatType::Unsuffixed) - }) -} - -fn float_lit(symbol: Symbol, suffix: Option) -> Result { - debug!("float_lit: {:?}, {:?}", symbol, suffix); - filtered_float_lit(strip_underscores(symbol), suffix, 10) -} - -fn integer_lit(symbol: Symbol, suffix: Option) -> Result { - debug!("integer_lit: {:?}, {:?}", symbol, suffix); - let symbol = strip_underscores(symbol); - let s = symbol.as_str(); - - let base = match s.as_bytes() { - [b'0', b'x', ..] => 16, - [b'0', b'o', ..] => 8, - [b'0', b'b', ..] => 2, - _ => 10, - }; - - let ty = match suffix { - Some(suf) => match suf { - sym::isize => ast::LitIntType::Signed(ast::IntTy::Isize), - sym::i8 => ast::LitIntType::Signed(ast::IntTy::I8), - sym::i16 => ast::LitIntType::Signed(ast::IntTy::I16), - sym::i32 => ast::LitIntType::Signed(ast::IntTy::I32), - sym::i64 => ast::LitIntType::Signed(ast::IntTy::I64), - sym::i128 => ast::LitIntType::Signed(ast::IntTy::I128), - sym::usize => ast::LitIntType::Unsigned(ast::UintTy::Usize), - sym::u8 => ast::LitIntType::Unsigned(ast::UintTy::U8), - sym::u16 => ast::LitIntType::Unsigned(ast::UintTy::U16), - sym::u32 => ast::LitIntType::Unsigned(ast::UintTy::U32), - sym::u64 => ast::LitIntType::Unsigned(ast::UintTy::U64), - sym::u128 => ast::LitIntType::Unsigned(ast::UintTy::U128), - // `1f64` and `2f32` etc. are valid float literals, and - // `fxxx` looks more like an invalid float literal than invalid integer literal. - _ if suf.as_str().starts_with('f') => return filtered_float_lit(symbol, suffix, base), - _ => return Err(LitError::InvalidIntSuffix), - } - _ => ast::LitIntType::Unsuffixed - }; - - let s = &s[if base != 10 { 2 } else { 0 } ..]; - u128::from_str_radix(s, base).map(|i| LitKind::Int(i, ty)).map_err(|_| { - // Small bases are lexed as if they were base 10, e.g, the string - // might be `0b10201`. This will cause the conversion above to fail, - // but these kinds of errors are already reported by the lexer. - let from_lexer = - base < 10 && s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base)); - if from_lexer { LitError::LexerError } else { LitError::IntTooLarge } - }) -} diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 44fd39448e5..18550762017 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -24,8 +24,6 @@ mod tests; pub mod parser; pub mod lexer; -crate mod literal; - #[derive(Clone)] pub struct Directory<'a> { pub path: Cow<'a, Path>, diff --git a/src/libsyntax/parse/parser/expr.rs b/src/libsyntax/parse/parser/expr.rs index cc984f03c7d..800074035ce 100644 --- a/src/libsyntax/parse/parser/expr.rs +++ b/src/libsyntax/parse/parser/expr.rs @@ -3,8 +3,6 @@ use super::{SemiColonMode, SeqSep, TokenExpectType}; use super::pat::{GateOr, PARAM_EXPECTED}; use super::diagnostics::Error; -use crate::parse::literal::LitError; - use crate::ast::{ self, DUMMY_NODE_ID, Attribute, AttrStyle, Ident, CaptureBy, BlockCheckMode, Expr, ExprKind, RangeLimits, Label, Movability, IsAsync, Arm, Ty, TyKind, @@ -16,6 +14,7 @@ use crate::print::pprust; use crate::ptr::P; use crate::source_map::{self, Span}; use crate::util::classify; +use crate::util::literal::LitError; use crate::util::parser::{AssocOp, Fixity, prec_let_scrutinee_needs_par}; use errors::{PResult, Applicability}; diff --git a/src/libsyntax/util/literal.rs b/src/libsyntax/util/literal.rs new file mode 100644 index 00000000000..d4c9b7850c5 --- /dev/null +++ b/src/libsyntax/util/literal.rs @@ -0,0 +1,305 @@ +//! Code related to parsing literals. + +use crate::ast::{self, Lit, LitKind}; +use crate::symbol::{kw, sym, Symbol}; +use crate::token::{self, Token}; +use crate::tokenstream::TokenTree; + +use log::debug; +use rustc_data_structures::sync::Lrc; +use syntax_pos::Span; +use rustc_lexer::unescape::{unescape_char, unescape_byte}; +use rustc_lexer::unescape::{unescape_str, unescape_byte_str}; +use rustc_lexer::unescape::{unescape_raw_str, unescape_raw_byte_str}; + +use std::ascii; + +crate enum LitError { + NotLiteral, + LexerError, + InvalidSuffix, + InvalidIntSuffix, + InvalidFloatSuffix, + NonDecimalFloat(u32), + IntTooLarge, +} + +impl LitKind { + /// Converts literal token into a semantic literal. + fn from_lit_token(lit: token::Lit) -> Result { + let token::Lit { kind, symbol, suffix } = lit; + if suffix.is_some() && !kind.may_have_suffix() { + return Err(LitError::InvalidSuffix); + } + + Ok(match kind { + token::Bool => { + assert!(symbol.is_bool_lit()); + LitKind::Bool(symbol == kw::True) + } + token::Byte => return unescape_byte(&symbol.as_str()) + .map(LitKind::Byte).map_err(|_| LitError::LexerError), + token::Char => return unescape_char(&symbol.as_str()) + .map(LitKind::Char).map_err(|_| LitError::LexerError), + + // There are some valid suffixes for integer and float literals, + // so all the handling is done internally. + token::Integer => return integer_lit(symbol, suffix), + token::Float => return float_lit(symbol, suffix), + + token::Str => { + // If there are no characters requiring special treatment we can + // reuse the symbol from the token. Otherwise, we must generate a + // new symbol because the string in the LitKind is different to the + // string in the token. + let s = symbol.as_str(); + let symbol = if s.contains(&['\\', '\r'][..]) { + let mut buf = String::with_capacity(s.len()); + let mut error = Ok(()); + unescape_str(&s, &mut |_, unescaped_char| { + match unescaped_char { + Ok(c) => buf.push(c), + Err(_) => error = Err(LitError::LexerError), + } + }); + error?; + Symbol::intern(&buf) + } else { + symbol + }; + LitKind::Str(symbol, ast::StrStyle::Cooked) + } + token::StrRaw(n) => { + // Ditto. + let s = symbol.as_str(); + let symbol = if s.contains('\r') { + let mut buf = String::with_capacity(s.len()); + let mut error = Ok(()); + unescape_raw_str(&s, &mut |_, unescaped_char| { + match unescaped_char { + Ok(c) => buf.push(c), + Err(_) => error = Err(LitError::LexerError), + } + }); + error?; + buf.shrink_to_fit(); + Symbol::intern(&buf) + } else { + symbol + }; + LitKind::Str(symbol, ast::StrStyle::Raw(n)) + } + token::ByteStr => { + let s = symbol.as_str(); + let mut buf = Vec::with_capacity(s.len()); + let mut error = Ok(()); + unescape_byte_str(&s, &mut |_, unescaped_byte| { + match unescaped_byte { + Ok(c) => buf.push(c), + Err(_) => error = Err(LitError::LexerError), + } + }); + error?; + buf.shrink_to_fit(); + LitKind::ByteStr(Lrc::new(buf)) + } + token::ByteStrRaw(_) => { + let s = symbol.as_str(); + let bytes = if s.contains('\r') { + let mut buf = Vec::with_capacity(s.len()); + let mut error = Ok(()); + unescape_raw_byte_str(&s, &mut |_, unescaped_byte| { + match unescaped_byte { + Ok(c) => buf.push(c), + Err(_) => error = Err(LitError::LexerError), + } + }); + error?; + buf.shrink_to_fit(); + buf + } else { + symbol.to_string().into_bytes() + }; + + LitKind::ByteStr(Lrc::new(bytes)) + }, + token::Err => LitKind::Err(symbol), + }) + } + + /// Attempts to recover a token from semantic literal. + /// This function is used when the original token doesn't exist (e.g. the literal is created + /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing). + pub fn to_lit_token(&self) -> token::Lit { + let (kind, symbol, suffix) = match *self { + LitKind::Str(symbol, ast::StrStyle::Cooked) => { + // Don't re-intern unless the escaped string is different. + let s = symbol.as_str(); + let escaped = s.escape_default().to_string(); + let symbol = if s == escaped { symbol } else { Symbol::intern(&escaped) }; + (token::Str, symbol, None) + } + LitKind::Str(symbol, ast::StrStyle::Raw(n)) => { + (token::StrRaw(n), symbol, None) + } + LitKind::ByteStr(ref bytes) => { + let string = bytes.iter().cloned().flat_map(ascii::escape_default) + .map(Into::::into).collect::(); + (token::ByteStr, Symbol::intern(&string), None) + } + LitKind::Byte(byte) => { + let string: String = ascii::escape_default(byte).map(Into::::into).collect(); + (token::Byte, Symbol::intern(&string), None) + } + LitKind::Char(ch) => { + let string: String = ch.escape_default().map(Into::::into).collect(); + (token::Char, Symbol::intern(&string), None) + } + LitKind::Int(n, ty) => { + let suffix = match ty { + ast::LitIntType::Unsigned(ty) => Some(ty.name()), + ast::LitIntType::Signed(ty) => Some(ty.name()), + ast::LitIntType::Unsuffixed => None, + }; + (token::Integer, sym::integer(n), suffix) + } + LitKind::Float(symbol, ty) => { + let suffix = match ty { + ast::LitFloatType::Suffixed(ty) => Some(ty.name()), + ast::LitFloatType::Unsuffixed => None, + }; + (token::Float, symbol, suffix) + } + LitKind::Bool(value) => { + let symbol = if value { kw::True } else { kw::False }; + (token::Bool, symbol, None) + } + LitKind::Err(symbol) => { + (token::Err, symbol, None) + } + }; + + token::Lit::new(kind, symbol, suffix) + } +} + +impl Lit { + /// Converts literal token into an AST literal. + crate fn from_lit_token(token: token::Lit, span: Span) -> Result { + Ok(Lit { token, kind: LitKind::from_lit_token(token)?, span }) + } + + /// Converts arbitrary token into an AST literal. + crate fn from_token(token: &Token) -> Result { + let lit = match token.kind { + token::Ident(name, false) if name.is_bool_lit() => + token::Lit::new(token::Bool, name, None), + token::Literal(lit) => + lit, + token::Interpolated(ref nt) => { + if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt { + if let ast::ExprKind::Lit(lit) = &expr.kind { + return Ok(lit.clone()); + } + } + return Err(LitError::NotLiteral); + } + _ => return Err(LitError::NotLiteral) + }; + + Lit::from_lit_token(lit, token.span) + } + + /// Attempts to recover an AST literal from semantic literal. + /// This function is used when the original token doesn't exist (e.g. the literal is created + /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing). + pub fn from_lit_kind(kind: LitKind, span: Span) -> Lit { + Lit { token: kind.to_lit_token(), kind, span } + } + + /// Losslessly convert an AST literal into a token tree. + crate fn token_tree(&self) -> TokenTree { + let token = match self.token.kind { + token::Bool => token::Ident(self.token.symbol, false), + _ => token::Literal(self.token), + }; + TokenTree::token(token, self.span) + } +} + +fn strip_underscores(symbol: Symbol) -> Symbol { + // Do not allocate a new string unless necessary. + let s = symbol.as_str(); + if s.contains('_') { + let mut s = s.to_string(); + s.retain(|c| c != '_'); + return Symbol::intern(&s); + } + symbol +} + +fn filtered_float_lit(symbol: Symbol, suffix: Option, base: u32) + -> Result { + debug!("filtered_float_lit: {:?}, {:?}, {:?}", symbol, suffix, base); + if base != 10 { + return Err(LitError::NonDecimalFloat(base)); + } + Ok(match suffix { + Some(suf) => LitKind::Float(symbol, ast::LitFloatType::Suffixed(match suf { + sym::f32 => ast::FloatTy::F32, + sym::f64 => ast::FloatTy::F64, + _ => return Err(LitError::InvalidFloatSuffix), + })), + None => LitKind::Float(symbol, ast::LitFloatType::Unsuffixed) + }) +} + +fn float_lit(symbol: Symbol, suffix: Option) -> Result { + debug!("float_lit: {:?}, {:?}", symbol, suffix); + filtered_float_lit(strip_underscores(symbol), suffix, 10) +} + +fn integer_lit(symbol: Symbol, suffix: Option) -> Result { + debug!("integer_lit: {:?}, {:?}", symbol, suffix); + let symbol = strip_underscores(symbol); + let s = symbol.as_str(); + + let base = match s.as_bytes() { + [b'0', b'x', ..] => 16, + [b'0', b'o', ..] => 8, + [b'0', b'b', ..] => 2, + _ => 10, + }; + + let ty = match suffix { + Some(suf) => match suf { + sym::isize => ast::LitIntType::Signed(ast::IntTy::Isize), + sym::i8 => ast::LitIntType::Signed(ast::IntTy::I8), + sym::i16 => ast::LitIntType::Signed(ast::IntTy::I16), + sym::i32 => ast::LitIntType::Signed(ast::IntTy::I32), + sym::i64 => ast::LitIntType::Signed(ast::IntTy::I64), + sym::i128 => ast::LitIntType::Signed(ast::IntTy::I128), + sym::usize => ast::LitIntType::Unsigned(ast::UintTy::Usize), + sym::u8 => ast::LitIntType::Unsigned(ast::UintTy::U8), + sym::u16 => ast::LitIntType::Unsigned(ast::UintTy::U16), + sym::u32 => ast::LitIntType::Unsigned(ast::UintTy::U32), + sym::u64 => ast::LitIntType::Unsigned(ast::UintTy::U64), + sym::u128 => ast::LitIntType::Unsigned(ast::UintTy::U128), + // `1f64` and `2f32` etc. are valid float literals, and + // `fxxx` looks more like an invalid float literal than invalid integer literal. + _ if suf.as_str().starts_with('f') => return filtered_float_lit(symbol, suffix, base), + _ => return Err(LitError::InvalidIntSuffix), + } + _ => ast::LitIntType::Unsuffixed + }; + + let s = &s[if base != 10 { 2 } else { 0 } ..]; + u128::from_str_radix(s, base).map(|i| LitKind::Int(i, ty)).map_err(|_| { + // Small bases are lexed as if they were base 10, e.g, the string + // might be `0b10201`. This will cause the conversion above to fail, + // but these kinds of errors are already reported by the lexer. + let from_lexer = + base < 10 && s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base)); + if from_lexer { LitError::LexerError } else { LitError::IntTooLarge } + }) +} -- cgit 1.4.1-3-g733a5 From 2cd48e8a3b71256d7db1ac61e8994c06620238b6 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 7 Nov 2019 13:11:59 +0100 Subject: ast::MethodSig -> ast::FnSig --- src/librustc/hir/lowering/item.rs | 2 +- src/librustc/hir/map/def_collector.rs | 2 +- src/librustc_interface/util.rs | 4 ++-- src/librustc_save_analysis/dump_visitor.rs | 2 +- src/librustc_save_analysis/sig.rs | 4 ++-- src/libsyntax/ast.rs | 10 +++++----- src/libsyntax/mut_visit.rs | 2 +- src/libsyntax/parse/parser/item.rs | 6 +++--- src/libsyntax/print/pprust.rs | 2 +- src/libsyntax/visit.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 2 +- 11 files changed, 19 insertions(+), 19 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/librustc/hir/lowering/item.rs b/src/librustc/hir/lowering/item.rs index a01f59eea0b..861130f0c69 100644 --- a/src/librustc/hir/lowering/item.rs +++ b/src/librustc/hir/lowering/item.rs @@ -1255,7 +1255,7 @@ impl LoweringContext<'_> { fn lower_method_sig( &mut self, generics: &Generics, - sig: &MethodSig, + sig: &FnSig, fn_def_id: DefId, impl_trait_return_allow: bool, is_async: Option, diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 57c1421bde6..d705737cc93 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -228,7 +228,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_impl_item(&mut self, ii: &'a ImplItem) { let def_data = match ii.kind { - ImplItemKind::Method(MethodSig { + ImplItemKind::Method(FnSig { ref header, ref decl, }, ref body) if header.asyncness.node.is_async() => { diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index d0c15073f16..cd7af3be9b5 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -802,7 +802,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a> { fn flat_map_trait_item(&mut self, i: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> { let is_const = match i.kind { ast::TraitItemKind::Const(..) => true, - ast::TraitItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) => + ast::TraitItemKind::Method(ast::FnSig { ref decl, ref header, .. }, _) => header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), _ => false, }; @@ -812,7 +812,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a> { fn flat_map_impl_item(&mut self, i: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> { let is_const = match i.kind { ast::ImplItemKind::Const(..) => true, - ast::ImplItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) => + ast::ImplItemKind::Method(ast::FnSig { ref decl, ref header, .. }, _) => header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), _ => false, }; diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 5c5fbcc07de..883d8964564 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -272,7 +272,7 @@ impl<'l, 'tcx> DumpVisitor<'l, 'tcx> { fn process_method( &mut self, - sig: &'l ast::MethodSig, + sig: &'l ast::FnSig, body: Option<&'l ast::Block>, id: ast::NodeId, ident: ast::Ident, diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 019e92717b5..887aeb03b89 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -72,7 +72,7 @@ pub fn method_signature( id: NodeId, ident: ast::Ident, generics: &ast::Generics, - m: &ast::MethodSig, + m: &ast::FnSig, scx: &SaveContext<'_, '_>, ) -> Option { if !scx.config.signatures { @@ -932,7 +932,7 @@ fn make_method_signature( id: NodeId, ident: ast::Ident, generics: &ast::Generics, - m: &ast::MethodSig, + m: &ast::FnSig, scx: &SaveContext<'_, '_>, ) -> Result { // FIXME code dup with function signature diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 18151a1586c..86a353cdfd2 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1501,10 +1501,10 @@ pub struct MutTy { pub mutbl: Mutability, } -/// Represents a method's signature in a trait declaration, -/// or in an implementation. +/// Represents a function's signature in a trait declaration, +/// trait implementation, or free function. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub struct MethodSig { +pub struct FnSig { pub header: FnHeader, pub decl: P, } @@ -1528,7 +1528,7 @@ pub struct TraitItem { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum TraitItemKind { Const(P, Option>), - Method(MethodSig, Option>), + Method(FnSig, Option>), Type(GenericBounds, Option>), Macro(Mac), } @@ -1552,7 +1552,7 @@ pub struct ImplItem { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum ImplItemKind { Const(P, P), - Method(MethodSig, P), + Method(FnSig, P), TyAlias(P), OpaqueTy(GenericBounds), Macro(Mac), diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 0c90652526d..f2ad7dea73b 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -357,7 +357,7 @@ pub fn visit_bounds(bounds: &mut GenericBounds, vis: &mut T) { } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_method_sig(MethodSig { header, decl }: &mut MethodSig, vis: &mut T) { +pub fn visit_method_sig(FnSig { header, decl }: &mut FnSig, vis: &mut T) { vis.visit_fn_header(header); vis.visit_fn_decl(decl); } diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 3c618d75d34..500e70ae8e5 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -8,7 +8,7 @@ use crate::ast::{ItemKind, ImplItem, ImplItemKind, TraitItem, TraitItemKind, Use use crate::ast::{PathSegment, IsAuto, Constness, IsAsync, Unsafety, Defaultness}; use crate::ast::{Visibility, VisibilityKind, Mutability, FnHeader, ForeignItem, ForeignItemKind}; use crate::ast::{Ty, TyKind, Generics, GenericBounds, TraitRef, EnumDef, VariantData, StructField}; -use crate::ast::{Mac, MacDelimiter, Block, BindingMode, FnDecl, MethodSig, SelfKind, Param}; +use crate::ast::{Mac, MacDelimiter, Block, BindingMode, FnDecl, FnSig, SelfKind, Param}; use crate::parse::token; use crate::tokenstream::{TokenTree, TokenStream}; use crate::symbol::{kw, sym}; @@ -1897,14 +1897,14 @@ impl<'a> Parser<'a> { fn parse_method_sig( &mut self, is_name_required: fn(&token::Token) -> bool, - ) -> PResult<'a, (Ident, MethodSig, Generics)> { + ) -> PResult<'a, (Ident, FnSig, Generics)> { let header = self.parse_fn_front_matter()?; let (ident, decl, generics) = self.parse_fn_sig(ParamCfg { is_self_allowed: true, allow_c_variadic: false, is_name_required, })?; - Ok((ident, MethodSig { header, decl }, generics)) + Ok((ident, FnSig { header, decl }, generics)) } /// Parses all the "front matter" for a `fn` declaration, up to diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 4ca4bdeb046..e7335a00cb0 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1541,7 +1541,7 @@ impl<'a> State<'a> { crate fn print_method_sig(&mut self, ident: ast::Ident, generics: &ast::Generics, - m: &ast::MethodSig, + m: &ast::FnSig, vis: &ast::Visibility) { self.print_fn(&m.decl, diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index cfd160fd577..e2983db4318 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -25,7 +25,7 @@ pub enum FnKind<'a> { ItemFn(Ident, &'a FnHeader, &'a Visibility, &'a Block), /// E.g., `fn foo(&self)`. - Method(Ident, &'a MethodSig, Option<&'a Visibility>, &'a Block), + Method(Ident, &'a FnSig, Option<&'a Visibility>, &'a Block), /// E.g., `|x, y| body`. Closure(&'a Expr), diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index b18fd50ae76..b24306def74 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -950,7 +950,7 @@ impl<'a> MethodDef<'a> { let trait_lo_sp = trait_.span.shrink_to_lo(); - let sig = ast::MethodSig { + let sig = ast::FnSig { header: ast::FnHeader { unsafety, abi: Abi::new(abi, trait_lo_sp), -- cgit 1.4.1-3-g733a5 From b4c6abcf9e6c1d2710e7ad6a9ce44b3ca6b10d52 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 7 Nov 2019 13:33:37 +0100 Subject: ast::ItemKind::Fn: use ast::FnSig --- src/librustc/hir/lowering/item.rs | 2 +- src/librustc/hir/map/def_collector.rs | 13 ++++--------- src/librustc_interface/util.rs | 13 +++++++------ src/librustc_passes/ast_validation.rs | 8 ++++---- src/librustc_resolve/late.rs | 2 +- src/librustc_save_analysis/dump_visitor.rs | 4 ++-- src/librustc_save_analysis/lib.rs | 4 ++-- src/librustc_save_analysis/sig.rs | 2 +- src/libsyntax/ast.rs | 2 +- src/libsyntax/mut_visit.rs | 11 +++++------ src/libsyntax/parse/parser/item.rs | 2 +- src/libsyntax/print/pprust.rs | 6 +++--- src/libsyntax/visit.rs | 9 ++++----- src/libsyntax_ext/global_allocator.rs | 15 +++++---------- src/libsyntax_ext/test.rs | 14 +++++++------- src/libsyntax_ext/test_harness.rs | 7 +++---- 16 files changed, 51 insertions(+), 63 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/librustc/hir/lowering/item.rs b/src/librustc/hir/lowering/item.rs index 861130f0c69..7aa1aa8bb51 100644 --- a/src/librustc/hir/lowering/item.rs +++ b/src/librustc/hir/lowering/item.rs @@ -306,7 +306,7 @@ impl LoweringContext<'_> { self.lower_const_body(e) ) } - ItemKind::Fn(ref decl, header, ref generics, ref body) => { + ItemKind::Fn(FnSig { ref decl, header }, ref generics, ref body) => { let fn_def_id = self.resolver.definitions().local_def_id(id); self.with_new_scopes(|this| { this.current_item = Some(ident.span); diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index d705737cc93..d858e00a2e9 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -100,7 +100,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { // Pick the def data. This need not be unique, but the more // information we encapsulate into, the better - let def_data = match i.kind { + let def_data = match &i.kind { ItemKind::Impl(..) => DefPathData::Impl, ItemKind::Mod(..) if i.ident.name == kw::Invalid => { return visit::walk_item(self, i); @@ -109,19 +109,14 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | ItemKind::OpaqueTy(..) | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::TyAlias(..) => DefPathData::TypeNs(i.ident.name), - ItemKind::Fn( - ref decl, - ref header, - ref generics, - ref body, - ) if header.asyncness.node.is_async() => { + ItemKind::Fn(sig, generics, body) if sig.header.asyncness.node.is_async() => { return self.visit_async_fn( i.id, i.ident.name, i.span, - header, + &sig.header, generics, - decl, + &sig.decl, body, ) } diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index cd7af3be9b5..a74ea4bca39 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -786,14 +786,17 @@ impl<'a> ReplaceBodyWithLoop<'a> { false } } + + fn is_sig_const(sig: &ast::FnSig) -> bool { + sig.header.constness.node == ast::Constness::Const || Self::should_ignore_fn(&sig.decl) + } } impl<'a> MutVisitor for ReplaceBodyWithLoop<'a> { fn visit_item_kind(&mut self, i: &mut ast::ItemKind) { let is_const = match i { ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => true, - ast::ItemKind::Fn(ref decl, ref header, _, _) => - header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), + ast::ItemKind::Fn(ref sig, _, _) => Self::is_sig_const(sig), _ => false, }; self.run(is_const, |s| noop_visit_item_kind(i, s)) @@ -802,8 +805,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a> { fn flat_map_trait_item(&mut self, i: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> { let is_const = match i.kind { ast::TraitItemKind::Const(..) => true, - ast::TraitItemKind::Method(ast::FnSig { ref decl, ref header, .. }, _) => - header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), + ast::TraitItemKind::Method(ref sig, _) => Self::is_sig_const(sig), _ => false, }; self.run(is_const, |s| noop_flat_map_trait_item(i, s)) @@ -812,8 +814,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a> { fn flat_map_impl_item(&mut self, i: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> { let is_const = match i.kind { ast::ImplItemKind::Const(..) => true, - ast::ImplItemKind::Method(ast::FnSig { ref decl, ref header, .. }, _) => - header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), + ast::ImplItemKind::Method(ref sig, _) => Self::is_sig_const(sig), _ => false, }; self.run(is_const, |s| noop_flat_map_impl_item(i, s)) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index d1a801b3006..6151fc58d89 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -575,12 +575,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .note("only trait implementations may be annotated with default").emit(); } } - ItemKind::Fn(ref decl, ref header, ref generics, _) => { - self.visit_fn_header(header); - self.check_fn_decl(decl); + ItemKind::Fn(ref sig, ref generics, _) => { + self.visit_fn_header(&sig.header); + self.check_fn_decl(&sig.decl); // We currently do not permit const generics in `const fn`, as // this is tantamount to allowing compile-time dependent typing. - if header.constness.node == Constness::Const { + if sig.header.constness.node == Constness::Const { // Look for const generics and error if we find any. for param in &generics.params { match param.kind { diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 58af4b817d2..a23684ea649 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -731,7 +731,7 @@ impl<'a, 'b> LateResolutionVisitor<'a, '_> { match item.kind { ItemKind::TyAlias(_, ref generics) | ItemKind::OpaqueTy(_, ref generics) | - ItemKind::Fn(_, _, ref generics, _) => { + ItemKind::Fn(_, ref generics, _) => { self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| visit::walk_item(this, item)); } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 883d8964564..92c391fb4a3 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1334,8 +1334,8 @@ impl<'l, 'tcx> Visitor<'l> for DumpVisitor<'l, 'tcx> { ); } } - Fn(ref decl, ref header, ref ty_params, ref body) => { - self.process_fn(item, &decl, &header, ty_params, &body) + Fn(ref sig, ref ty_params, ref body) => { + self.process_fn(item, &sig.decl, &sig.header, ty_params, &body) } Static(ref typ, _, ref expr) => self.process_static_or_const_item(item, typ, expr), Const(ref typ, ref expr) => self.process_static_or_const_item(item, &typ, &expr), diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index a2f8837c581..424d57c8fe7 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -180,7 +180,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { pub fn get_item_data(&self, item: &ast::Item) -> Option { match item.kind { - ast::ItemKind::Fn(ref decl, .., ref generics, _) => { + ast::ItemKind::Fn(ref sig, .., ref generics, _) => { let qualname = format!("::{}", self.tcx.def_path_str(self.tcx.hir().local_def_id_from_node_id(item.id))); filter!(self.span_utils, item.ident.span); @@ -190,7 +190,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { span: self.span_from_span(item.ident.span), name: item.ident.to_string(), qualname, - value: make_signature(decl, generics), + value: make_signature(&sig.decl, generics), parent: None, children: vec![], decl_id: None, diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 887aeb03b89..d1b9b8ff44d 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -376,7 +376,7 @@ impl Sig for ast::Item { Ok(extend_sig(ty, text, defs, vec![])) } - ast::ItemKind::Fn(ref decl, header, ref generics, _) => { + ast::ItemKind::Fn(ast::FnSig { ref decl, header }, ref generics, _) => { let mut text = String::new(); if header.constness.node == ast::Constness::Const { text.push_str("const "); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 86a353cdfd2..b57d2238991 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2433,7 +2433,7 @@ pub enum ItemKind { /// A function declaration (`fn`). /// /// E.g., `fn foo(bar: usize) -> usize { .. }`. - Fn(P, FnHeader, Generics, P), + Fn(FnSig, Generics, P), /// A module declaration (`mod`). /// /// E.g., `mod foo;` or `mod foo { .. }`. diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index f2ad7dea73b..7696ea48f93 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -357,7 +357,7 @@ pub fn visit_bounds(bounds: &mut GenericBounds, vis: &mut T) { } // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. -pub fn visit_method_sig(FnSig { header, decl }: &mut FnSig, vis: &mut T) { +pub fn visit_fn_sig(FnSig { header, decl }: &mut FnSig, vis: &mut T) { vis.visit_fn_header(header); vis.visit_fn_decl(decl); } @@ -878,9 +878,8 @@ pub fn noop_visit_item_kind(kind: &mut ItemKind, vis: &mut T) { vis.visit_ty(ty); vis.visit_expr(expr); } - ItemKind::Fn(decl, header, generics, body) => { - vis.visit_fn_decl(decl); - vis.visit_fn_header(header); + ItemKind::Fn(sig, generics, body) => { + visit_fn_sig(sig, vis); vis.visit_generics(generics); vis.visit_block(body); } @@ -938,7 +937,7 @@ pub fn noop_flat_map_trait_item(mut item: TraitItem, vis: &mut T) visit_opt(default, |default| vis.visit_expr(default)); } TraitItemKind::Method(sig, body) => { - visit_method_sig(sig, vis); + visit_fn_sig(sig, vis); visit_opt(body, |body| vis.visit_block(body)); } TraitItemKind::Type(bounds, default) => { @@ -970,7 +969,7 @@ pub fn noop_flat_map_impl_item(mut item: ImplItem, visitor: &mut visitor.visit_expr(expr); } ImplItemKind::Method(sig, body) => { - visit_method_sig(sig, visitor); + visit_fn_sig(sig, visitor); visitor.visit_block(body); } ImplItemKind::TyAlias(ty) => visitor.visit_ty(ty), diff --git a/src/libsyntax/parse/parser/item.rs b/src/libsyntax/parse/parser/item.rs index 500e70ae8e5..531ad532a54 100644 --- a/src/libsyntax/parse/parser/item.rs +++ b/src/libsyntax/parse/parser/item.rs @@ -1800,7 +1800,7 @@ impl<'a> Parser<'a> { is_name_required: |_| true, })?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - let kind = ItemKind::Fn(decl, header, generics, body); + let kind = ItemKind::Fn(FnSig { decl, header }, generics, body); self.mk_item_with_info(attrs, lo, vis, (ident, kind, Some(inner_attrs))) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index e7335a00cb0..2203e8d9d06 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1199,11 +1199,11 @@ impl<'a> State<'a> { self.s.word(";"); self.end(); // end the outer cbox } - ast::ItemKind::Fn(ref decl, header, ref param_names, ref body) => { + ast::ItemKind::Fn(ref sig, ref param_names, ref body) => { self.head(""); self.print_fn( - decl, - header, + &sig.decl, + sig.header, Some(item.ident), param_names, &item.vis diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index e2983db4318..ea2dc357e6e 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -244,12 +244,11 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { visitor.visit_ty(typ); visitor.visit_expr(expr); } - ItemKind::Fn(ref declaration, ref header, ref generics, ref body) => { + ItemKind::Fn(ref sig, ref generics, ref body) => { visitor.visit_generics(generics); - visitor.visit_fn_header(header); - visitor.visit_fn(FnKind::ItemFn(item.ident, header, - &item.vis, body), - declaration, + visitor.visit_fn_header(&sig.header); + visitor.visit_fn(FnKind::ItemFn(item.ident, &sig.header, &item.vis, body), + &sig.decl, item.span, item.id) } diff --git a/src/libsyntax_ext/global_allocator.rs b/src/libsyntax_ext/global_allocator.rs index 90d2ea38bc3..dc29e057455 100644 --- a/src/libsyntax_ext/global_allocator.rs +++ b/src/libsyntax_ext/global_allocator.rs @@ -1,7 +1,7 @@ use crate::util::check_builtin_macro_attribute; use syntax::ast::{ItemKind, Mutability, Stmt, Ty, TyKind, Unsafety}; -use syntax::ast::{self, Param, Attribute, Expr, FnHeader, Generics, Ident}; +use syntax::ast::{self, Param, Attribute, Expr, FnSig, FnHeader, Generics, Ident}; use syntax::expand::allocator::{AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}; use syntax::ptr::P; use syntax::symbol::{kw, sym, Symbol}; @@ -73,15 +73,10 @@ impl AllocFnFactory<'_, '_> { .collect(); let result = self.call_allocator(method.name, args); let (output_ty, output_expr) = self.ret_ty(&method.output, result); - let kind = ItemKind::Fn( - self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)), - FnHeader { - unsafety: Unsafety::Unsafe, - ..FnHeader::default() - }, - Generics::default(), - self.cx.block_expr(output_expr), - ); + let decl = self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)); + let header = FnHeader { unsafety: Unsafety::Unsafe, ..FnHeader::default() }; + let sig = FnSig { decl, header }; + let kind = ItemKind::Fn(sig, Generics::default(), self.cx.block_expr(output_expr)); let item = self.cx.item( self.span, self.cx.ident_of(&self.kind.fn_name(method.name), self.span), diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs index b0da413d63a..8656100c921 100644 --- a/src/libsyntax_ext/test.rs +++ b/src/libsyntax_ext/test.rs @@ -310,15 +310,15 @@ fn test_type(cx: &ExtCtxt<'_>) -> TestType { 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 decl, ref header, ref generics, _) = i.kind { - if header.unsafety == ast::Unsafety::Unsafe { + 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" ); return false } - if header.asyncness.node.is_async() { + if sig.header.asyncness.node.is_async() { sd.span_err( i.span, "async functions cannot be used for tests" @@ -329,13 +329,13 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { // If the termination trait is active, the compiler will check that the output // type implements the `Termination` trait as `libtest` enforces that. - let has_output = match decl.output { + let has_output = match sig.decl.output { ast::FunctionRetTy::Default(..) => false, ast::FunctionRetTy::Ty(ref t) if t.kind.is_unit() => false, _ => true }; - if !decl.inputs.is_empty() { + if !sig.decl.inputs.is_empty() { sd.span_err(i.span, "functions used as tests can not have any arguments"); return false; } @@ -361,10 +361,10 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { } fn has_bench_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { - let has_sig = if let ast::ItemKind::Fn(ref decl, _, _, _) = i.kind { + let has_sig = if let ast::ItemKind::Fn(ref sig, _, _) = i.kind { // N.B., inadequate check, but we're running // well before resolve, can't get too deep. - decl.inputs.len() == 1 + sig.decl.inputs.len() == 1 } else { false }; diff --git a/src/libsyntax_ext/test_harness.rs b/src/libsyntax_ext/test_harness.rs index 33d41a7f53e..1492f6f575f 100644 --- a/src/libsyntax_ext/test_harness.rs +++ b/src/libsyntax_ext/test_harness.rs @@ -306,10 +306,9 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { ecx.block(sp, vec![call_test_main]) }; - let main = ast::ItemKind::Fn(ecx.fn_decl(vec![], ast::FunctionRetTy::Ty(main_ret_ty)), - ast::FnHeader::default(), - ast::Generics::default(), - main_body); + let decl = ecx.fn_decl(vec![], ast::FunctionRetTy::Ty(main_ret_ty)); + let sig = ast::FnSig { decl, header: ast::FnHeader::default() }; + let main = ast::ItemKind::Fn(sig, ast::Generics::default(), main_body); // Honor the reexport_test_harness_main attribute let main_id = match cx.reexport_test_harness_main { -- cgit 1.4.1-3-g733a5 From 5011ec7fedffe34d943654ffb4308875fc5ec8f3 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Fri, 11 Oct 2019 21:00:09 +0200 Subject: move attr meta grammar to parse::validate_atr + ast_validation --- src/librustc_passes/ast_validation.rs | 5 ++ src/libsyntax/attr/builtin.rs | 69 +------------------- src/libsyntax/attr/mod.rs | 19 ------ src/libsyntax/config.rs | 4 +- src/libsyntax/feature_gate/check.rs | 23 +------ src/libsyntax/parse/mod.rs | 1 + src/libsyntax/parse/validate_attr.rs | 112 ++++++++++++++++++++++++++++++++ src/libsyntax_expand/expand.rs | 4 +- src/libsyntax_ext/util.rs | 5 +- src/test/ui/proc-macro/attribute.stderr | 24 +++---- 10 files changed, 142 insertions(+), 124 deletions(-) create mode 100644 src/libsyntax/parse/validate_attr.rs (limited to 'src/libsyntax/parse') diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 8cf83d41ac2..a45035f123f 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -15,6 +15,7 @@ use syntax::ast::*; use syntax::attr; use syntax::expand::is_proc_macro_attr; use syntax::feature_gate::is_builtin_attr; +use syntax::parse::validate_attr; use syntax::source_map::Spanned; use syntax::symbol::{kw, sym}; use syntax::visit::{self, Visitor}; @@ -369,6 +370,10 @@ fn validate_generics_order<'a>( } impl<'a> Visitor<'a> for AstValidator<'a> { + fn visit_attribute(&mut self, attr: &Attribute) { + validate_attr::check_meta(&self.session.parse_sess, attr); + } + fn visit_expr(&mut self, expr: &'a Expr) { match &expr.kind { ExprKind::Closure(_, _, _, fn_decl, _, _) => { diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index 787d69f5e99..3ac9abb7223 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -1,7 +1,6 @@ //! Parsing and validation of builtin attributes use crate::ast::{self, Attribute, MetaItem, NestedMetaItem}; -use crate::early_buffered_lints::BufferedEarlyLintId; use crate::feature_gate::{Features, GatedCfg}; use crate::print::pprust; use crate::sess::ParseSess; @@ -36,7 +35,7 @@ impl AttributeTemplate { } /// Checks that the given meta-item is compatible with this template. - fn compatible(&self, meta_item_kind: &ast::MetaItemKind) -> bool { + pub fn compatible(&self, meta_item_kind: &ast::MetaItemKind) -> bool { match meta_item_kind { ast::MetaItemKind::Word => self.word, ast::MetaItemKind::List(..) => self.list.is_some(), @@ -938,69 +937,3 @@ pub fn find_transparency( let fallback = if is_legacy { Transparency::SemiTransparent } else { Transparency::Opaque }; (transparency.map_or(fallback, |t| t.0), error) } - -pub fn check_builtin_attribute( - sess: &ParseSess, attr: &ast::Attribute, name: Symbol, template: AttributeTemplate -) { - // Some special attributes like `cfg` must be checked - // before the generic check, so we skip them here. - let should_skip = |name| name == sym::cfg; - // Some of previously accepted forms were used in practice, - // report them as warnings for now. - let should_warn = |name| name == sym::doc || name == sym::ignore || - name == sym::inline || name == sym::link || - name == sym::test || name == sym::bench; - - match attr.parse_meta(sess) { - Ok(meta) => if !should_skip(name) && !template.compatible(&meta.kind) { - let error_msg = format!("malformed `{}` attribute input", name); - let mut msg = "attribute must be of the form ".to_owned(); - let mut suggestions = vec![]; - let mut first = true; - if template.word { - first = false; - let code = format!("#[{}]", name); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if let Some(descr) = template.list { - if !first { - msg.push_str(" or "); - } - first = false; - let code = format!("#[{}({})]", name, descr); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if let Some(descr) = template.name_value_str { - if !first { - msg.push_str(" or "); - } - let code = format!("#[{} = \"{}\"]", name, descr); - msg.push_str(&format!("`{}`", &code)); - suggestions.push(code); - } - if should_warn(name) { - sess.buffer_lint( - BufferedEarlyLintId::IllFormedAttributeInput, - meta.span, - ast::CRATE_NODE_ID, - &msg, - ); - } else { - sess.span_diagnostic.struct_span_err(meta.span, &error_msg) - .span_suggestions( - meta.span, - if suggestions.len() == 1 { - "must be of the form" - } else { - "the following are the possible correct uses" - }, - suggestions.into_iter(), - Applicability::HasPlaceholders, - ).emit(); - } - } - Err(mut err) => err.emit(), - } -} diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index c639431794c..2c011b06470 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -14,17 +14,13 @@ use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem}; use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam}; use crate::mut_visit::visit_clobber; use crate::source_map::{BytePos, Spanned}; -use crate::parse; use crate::token::{self, Token}; use crate::ptr::P; -use crate::sess::ParseSess; use crate::symbol::{sym, Symbol}; use crate::ThinVec; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; use crate::GLOBALS; -use errors::PResult; - use log::debug; use syntax_pos::Span; @@ -328,21 +324,6 @@ impl Attribute { Some(mk_name_value_item_str(Ident::new(sym::doc, self.span), comment, self.span)), } } - - pub fn parse_meta<'a>(&self, sess: &'a ParseSess) -> PResult<'a, MetaItem> { - match self.kind { - AttrKind::Normal(ref item) => { - Ok(MetaItem { - path: item.path.clone(), - kind: parse::parse_in_attr(sess, self, |parser| parser.parse_meta_item_kind())?, - span: self.span, - }) - } - AttrKind::DocComment(comment) => { - Ok(mk_name_value_item_str(Ident::new(sym::doc, self.span), comment, self.span)) - } - } - } } /* Constructors */ diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 5f89ed36e2a..a460fc2b99a 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -10,7 +10,7 @@ use crate::attr; use crate::ast; use crate::edition::Edition; use crate::mut_visit::*; -use crate::parse; +use crate::parse::{self, validate_attr}; use crate::ptr::P; use crate::sess::ParseSess; use crate::symbol::sym; @@ -168,7 +168,7 @@ impl<'a> StripUnconfigured<'a> { true }; - let meta_item = match attr.parse_meta(self.sess) { + let meta_item = match validate_attr::parse_meta(self.sess, attr) { Ok(meta_item) => meta_item, Err(mut err) => { err.emit(); return true; } }; diff --git a/src/libsyntax/feature_gate/check.rs b/src/libsyntax/feature_gate/check.rs index ecff89ad59b..4742e01d7f4 100644 --- a/src/libsyntax/feature_gate/check.rs +++ b/src/libsyntax/feature_gate/check.rs @@ -3,18 +3,14 @@ use super::accepted::ACCEPTED_FEATURES; use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES}; use super::builtin_attrs::{AttributeGate, BUILTIN_ATTRIBUTE_MAP}; -use crate::ast::{ - self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind, - PatKind, RangeEnd, VariantData, -}; -use crate::attr::{self, check_builtin_attribute}; +use crate::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId}; +use crate::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData}; +use crate::attr; use crate::source_map::Spanned; use crate::edition::{ALL_EDITIONS, Edition}; use crate::visit::{self, FnKind, Visitor}; -use crate::token; use crate::sess::ParseSess; use crate::symbol::{Symbol, sym}; -use crate::tokenstream::TokenTree; use errors::{Applicability, DiagnosticBuilder, Handler}; use rustc_data_structures::fx::FxHashMap; @@ -331,19 +327,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { if let Some((.., AttributeGate::Gated(_, name, descr, has_feature))) = attr_info { gate_feature_fn!(self, has_feature, attr.span, name, descr, GateStrength::Hard); } - // Check input tokens for built-in and key-value attributes. - match attr_info { - // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. - Some((name, _, template, _)) if name != sym::rustc_dummy => - check_builtin_attribute(self.parse_sess, attr, name, template), - _ => if let Some(TokenTree::Token(token)) = - attr.get_normal_item().tokens.trees().next() { - if token == token::Eq { - // All key-value attributes are restricted to meta-item syntax. - attr.parse_meta(self.parse_sess).map_err(|mut err| err.emit()).ok(); - } - } - } // Check unstable flavors of the `#[doc]` attribute. if attr.check_name(sym::doc) { for nested_meta in attr.meta_item_list().unwrap_or_default() { diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index b54f4862f12..9155cbe5dd8 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -23,6 +23,7 @@ mod tests; #[macro_use] pub mod parser; pub mod lexer; +pub mod validate_attr; #[derive(Clone)] pub struct Directory<'a> { diff --git a/src/libsyntax/parse/validate_attr.rs b/src/libsyntax/parse/validate_attr.rs new file mode 100644 index 00000000000..6cc8a1ec33e --- /dev/null +++ b/src/libsyntax/parse/validate_attr.rs @@ -0,0 +1,112 @@ +//! Meta-syntax validation logic of attributes for post-expansion. + +use crate::ast::{self, Attribute, AttrKind, Ident, MetaItem}; +use crate::attr::{AttributeTemplate, mk_name_value_item_str}; +use crate::sess::ParseSess; +use crate::feature_gate::BUILTIN_ATTRIBUTE_MAP; +use crate::early_buffered_lints::BufferedEarlyLintId; +use crate::token; +use crate::tokenstream::TokenTree; + +use errors::{PResult, Applicability}; +use syntax_pos::{Symbol, sym}; + +pub fn check_meta(sess: &ParseSess, attr: &Attribute) { + let attr_info = + attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).map(|a| **a); + + // Check input tokens for built-in and key-value attributes. + match attr_info { + // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. + Some((name, _, template, _)) if name != sym::rustc_dummy => + check_builtin_attribute(sess, attr, name, template), + _ => if let Some(TokenTree::Token(token)) = attr.get_normal_item().tokens.trees().next() { + if token == token::Eq { + // All key-value attributes are restricted to meta-item syntax. + parse_meta(sess, attr).map_err(|mut err| err.emit()).ok(); + } + } + } +} + +pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, MetaItem> { + Ok(match attr.kind { + AttrKind::Normal(ref item) => MetaItem { + path: item.path.clone(), + kind: super::parse_in_attr(sess, attr, |p| p.parse_meta_item_kind())?, + span: attr.span, + }, + AttrKind::DocComment(comment) => { + mk_name_value_item_str(Ident::new(sym::doc, attr.span), comment, attr.span) + } + }) +} + +pub fn check_builtin_attribute( + sess: &ParseSess, + attr: &Attribute, + name: Symbol, + template: AttributeTemplate, +) { + // Some special attributes like `cfg` must be checked + // before the generic check, so we skip them here. + let should_skip = |name| name == sym::cfg; + // Some of previously accepted forms were used in practice, + // report them as warnings for now. + let should_warn = |name| name == sym::doc || name == sym::ignore || + name == sym::inline || name == sym::link || + name == sym::test || name == sym::bench; + + match parse_meta(sess, attr) { + Ok(meta) => if !should_skip(name) && !template.compatible(&meta.kind) { + let error_msg = format!("malformed `{}` attribute input", name); + let mut msg = "attribute must be of the form ".to_owned(); + let mut suggestions = vec![]; + let mut first = true; + if template.word { + first = false; + let code = format!("#[{}]", name); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if let Some(descr) = template.list { + if !first { + msg.push_str(" or "); + } + first = false; + let code = format!("#[{}({})]", name, descr); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if let Some(descr) = template.name_value_str { + if !first { + msg.push_str(" or "); + } + let code = format!("#[{} = \"{}\"]", name, descr); + msg.push_str(&format!("`{}`", &code)); + suggestions.push(code); + } + if should_warn(name) { + sess.buffer_lint( + BufferedEarlyLintId::IllFormedAttributeInput, + meta.span, + ast::CRATE_NODE_ID, + &msg, + ); + } else { + sess.span_diagnostic.struct_span_err(meta.span, &error_msg) + .span_suggestions( + meta.span, + if suggestions.len() == 1 { + "must be of the form" + } else { + "the following are the possible correct uses" + }, + suggestions.into_iter(), + Applicability::HasPlaceholders, + ).emit(); + } + } + Err(mut err) => err.emit(), + } +} diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs index 516b284cecd..d0b60fa308d 100644 --- a/src/libsyntax_expand/expand.rs +++ b/src/libsyntax_expand/expand.rs @@ -14,6 +14,7 @@ use syntax::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feat use syntax::mut_visit::*; use syntax::parse::DirectoryOwnership; use syntax::parse::parser::Parser; +use syntax::parse::validate_attr; use syntax::print::pprust; use syntax::ptr::P; use syntax::sess::ParseSess; @@ -640,7 +641,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.parse_ast_fragment(tok_result, fragment_kind, &item.path, span) } SyntaxExtensionKind::LegacyAttr(expander) => { - match attr.parse_meta(self.cx.parse_sess) { + match validate_attr::parse_meta(self.cx.parse_sess, &attr) { Ok(meta) => { let item = expander.expand(self.cx, span, &meta, item); fragment_kind.expect_from_annotatables(item) @@ -1031,6 +1032,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { let features = self.cx.ecfg.features.unwrap(); for attr in attrs.iter() { feature_gate::check_attribute(attr, self.cx.parse_sess, features); + validate_attr::check_meta(self.cx.parse_sess, attr); // macros are expanded before any lint passes so this warning has to be hardcoded if attr.has_name(sym::derive) { diff --git a/src/libsyntax_ext/util.rs b/src/libsyntax_ext/util.rs index d84fe19b3ea..c8f0eb4ad25 100644 --- a/src/libsyntax_ext/util.rs +++ b/src/libsyntax_ext/util.rs @@ -1,11 +1,12 @@ use syntax_pos::Symbol; use syntax::ast::MetaItem; -use syntax::attr::{check_builtin_attribute, AttributeTemplate}; +use syntax::attr::AttributeTemplate; +use syntax::parse::validate_attr; use syntax_expand::base::ExtCtxt; pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) { // All the built-in macro attributes are "words" at the moment. let template = AttributeTemplate::only_word(); let attr = ecx.attribute(meta_item.clone()); - check_builtin_attribute(ecx.parse_sess, &attr, name, template); + validate_attr::check_builtin_attribute(ecx.parse_sess, &attr, name, template); } diff --git a/src/test/ui/proc-macro/attribute.stderr b/src/test/ui/proc-macro/attribute.stderr index 1503f62cb6c..021e7cad09b 100644 --- a/src/test/ui/proc-macro/attribute.stderr +++ b/src/test/ui/proc-macro/attribute.stderr @@ -1,3 +1,15 @@ +error: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:9:1 + | +LL | #[proc_macro_derive] + | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` + +error: malformed `proc_macro_derive` attribute input + --> $DIR/attribute.rs:12:1 + | +LL | #[proc_macro_derive = ""] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` + error: attribute must have either one or two arguments --> $DIR/attribute.rs:15:1 | @@ -88,17 +100,5 @@ error: `self` cannot be a name of derive helper attribute LL | #[proc_macro_derive(d17, attributes(self))] | ^^^^ -error: malformed `proc_macro_derive` attribute input - --> $DIR/attribute.rs:9:1 - | -LL | #[proc_macro_derive] - | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` - -error: malformed `proc_macro_derive` attribute input - --> $DIR/attribute.rs:12:1 - | -LL | #[proc_macro_derive = ""] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]` - error: aborting due to 17 previous errors -- cgit 1.4.1-3-g733a5 From be023ebe850261c6bb202a02a686827d821c3697 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Thu, 10 Oct 2019 10:26:10 +0200 Subject: move config.rs to libsyntax_expand --- src/librustc/session/mod.rs | 16 +- src/librustc_interface/interface.rs | 7 +- src/librustc_interface/passes.rs | 2 +- src/librustc_interface/tests.rs | 59 +- src/librustc_interface/util.rs | 2 + src/librustdoc/html/highlight.rs | 3 +- src/librustdoc/passes/check_code_block_syntax.rs | 3 +- src/librustdoc/test.rs | 3 +- src/libsyntax/attr/mod.rs | 6 +- src/libsyntax/config.rs | 352 ------ src/libsyntax/json/tests.rs | 15 +- src/libsyntax/lib.rs | 4 - src/libsyntax/mut_visit.rs | 3 - src/libsyntax/mut_visit/tests.rs | 71 -- src/libsyntax/parse/lexer/mod.rs | 6 +- src/libsyntax/parse/lexer/tests.rs | 270 ----- src/libsyntax/parse/mod.rs | 3 +- src/libsyntax/parse/parser/attr.rs | 2 +- src/libsyntax/parse/parser/module.rs | 19 +- src/libsyntax/parse/tests.rs | 339 ------ src/libsyntax/print/pprust.rs | 7 +- src/libsyntax/sess.rs | 29 +- src/libsyntax/tests.rs | 1255 -------------------- src/libsyntax/tokenstream.rs | 5 +- src/libsyntax/tokenstream/tests.rs | 108 -- src/libsyntax/util/comments.rs | 3 +- src/libsyntax_expand/config.rs | 365 ++++++ src/libsyntax_expand/expand.rs | 4 +- src/libsyntax_expand/lib.rs | 29 + src/libsyntax_expand/mut_visit/tests.rs | 70 ++ src/libsyntax_expand/parse/lexer/tests.rs | 277 +++++ src/libsyntax_expand/parse/tests.rs | 338 ++++++ src/libsyntax_expand/tests.rs | 1254 +++++++++++++++++++ src/libsyntax_expand/tokenstream/tests.rs | 110 ++ src/test/ui-fulldeps/ast_stmt_expr_attr.rs | 21 +- src/test/ui-fulldeps/mod_dir_path_canonicalized.rs | 8 +- src/test/ui-fulldeps/pprust-expr-roundtrip.rs | 8 +- 37 files changed, 2580 insertions(+), 2496 deletions(-) delete mode 100644 src/libsyntax/config.rs delete mode 100644 src/libsyntax/mut_visit/tests.rs delete mode 100644 src/libsyntax/parse/lexer/tests.rs delete mode 100644 src/libsyntax/parse/tests.rs delete mode 100644 src/libsyntax/tests.rs delete mode 100644 src/libsyntax/tokenstream/tests.rs create mode 100644 src/libsyntax_expand/config.rs create mode 100644 src/libsyntax_expand/mut_visit/tests.rs create mode 100644 src/libsyntax_expand/parse/lexer/tests.rs create mode 100644 src/libsyntax_expand/parse/tests.rs create mode 100644 src/libsyntax_expand/tests.rs create mode 100644 src/libsyntax_expand/tokenstream/tests.rs (limited to 'src/libsyntax/parse') diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 403b32df20e..9d702e7d6bf 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -27,7 +27,7 @@ use syntax::expand::allocator::AllocatorKind; use syntax::feature_gate::{self, AttributeType}; use syntax::json::JsonEmitter; use syntax::source_map; -use syntax::sess::ParseSess; +use syntax::sess::{ParseSess, ProcessCfgMod}; use syntax::symbol::Symbol; use syntax_pos::{MultiSpan, Span}; use crate::util::profiling::{SelfProfiler, SelfProfilerRef}; @@ -952,6 +952,7 @@ pub fn build_session( sopts: config::Options, local_crate_source_file: Option, registry: errors::registry::Registry, + process_cfg_mod: ProcessCfgMod, ) -> Session { let file_path_mapping = sopts.file_path_mapping(); @@ -962,6 +963,7 @@ pub fn build_session( Lrc::new(source_map::SourceMap::new(file_path_mapping)), DiagnosticOutput::Default, Default::default(), + process_cfg_mod, ) } @@ -1040,6 +1042,7 @@ pub fn build_session_with_source_map( source_map: Lrc, diagnostics_output: DiagnosticOutput, lint_caps: FxHashMap, + process_cfg_mod: ProcessCfgMod, ) -> Session { // FIXME: This is not general enough to make the warning lint completely override // normal diagnostic warnings, since the warning lint can also be denied and changed @@ -1080,7 +1083,14 @@ pub fn build_session_with_source_map( }, ); - build_session_(sopts, local_crate_source_file, diagnostic_handler, source_map, lint_caps) + build_session_( + sopts, + local_crate_source_file, + diagnostic_handler, + source_map, + lint_caps, + process_cfg_mod, + ) } fn build_session_( @@ -1089,6 +1099,7 @@ fn build_session_( span_diagnostic: errors::Handler, source_map: Lrc, driver_lint_caps: FxHashMap, + process_cfg_mod: ProcessCfgMod, ) -> Session { let self_profiler = if let SwitchWithOptPath::Enabled(ref d) = sopts.debugging_opts.self_profile { @@ -1127,6 +1138,7 @@ fn build_session_( let parse_sess = ParseSess::with_span_handler( span_diagnostic, source_map, + process_cfg_mod, ); let sysroot = match &sopts.maybe_sysroot { Some(sysroot) => sysroot.clone(), diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs index 034e861b212..61f30392e06 100644 --- a/src/librustc_interface/interface.rs +++ b/src/librustc_interface/interface.rs @@ -14,11 +14,12 @@ use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use std::path::PathBuf; use std::result; use std::sync::{Arc, Mutex}; -use syntax::{self, parse}; use syntax::ast::{self, MetaItemKind}; +use syntax::parse::new_parser_from_source_str; use syntax::token; use syntax::source_map::{FileName, FileLoader, SourceMap}; use syntax::sess::ParseSess; +use syntax_expand::config::process_configure_mod; use syntax_pos::edition; pub type Result = result::Result; @@ -64,9 +65,9 @@ impl Compiler { pub fn parse_cfgspecs(cfgspecs: Vec) -> FxHashSet<(String, Option)> { syntax::with_default_globals(move || { let cfg = cfgspecs.into_iter().map(|s| { - let sess = ParseSess::with_silent_emitter(); + let sess = ParseSess::with_silent_emitter(process_configure_mod); let filename = FileName::cfg_spec_source_code(&s); - let mut parser = parse::new_parser_from_source_str(&sess, filename, s.to_string()); + let mut parser = new_parser_from_source_str(&sess, filename, s.to_string()); macro_rules! error {($reason: expr) => { early_error(ErrorOutputType::default(), diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index ce34caee6fa..c874e94124d 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -181,7 +181,7 @@ pub fn register_plugins<'a>( ) }); - let (krate, features) = syntax::config::features( + let (krate, features) = syntax_expand::config::features( krate, &sess.parse_sess, sess.edition(), diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index 7a57605da58..8c1dac21576 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -8,7 +8,7 @@ use rustc::session::config::{build_configuration, build_session_options, to_crat use rustc::session::config::{LtoCli, LinkerPluginLto, SwitchWithOptPath, ExternEntry}; use rustc::session::config::{Externs, OutputType, OutputTypes, SymbolManglingVersion}; use rustc::session::config::{rustc_optgroups, Options, ErrorOutputType, Passes}; -use rustc::session::build_session; +use rustc::session::{build_session, Session}; use rustc::session::search_paths::SearchPath; use std::collections::{BTreeMap, BTreeSet}; use std::iter::FromIterator; @@ -17,16 +17,23 @@ use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel}; use syntax::symbol::sym; use syntax::edition::{Edition, DEFAULT_EDITION}; use syntax; +use syntax_expand::config::process_configure_mod; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ColorConfig, emitter::HumanReadableErrorType, registry}; -pub fn build_session_options_and_crate_config( - matches: &getopts::Matches, -) -> (Options, FxHashSet<(String, Option)>) { - ( - build_session_options(matches), - parse_cfgspecs(matches.opt_strs("cfg")), - ) +type CfgSpecs = FxHashSet<(String, Option)>; + +fn build_session_options_and_crate_config(matches: getopts::Matches) -> (Options, CfgSpecs) { + let sessopts = build_session_options(&matches); + let cfg = parse_cfgspecs(matches.opt_strs("cfg")); + (sessopts, cfg) +} + +fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) { + let registry = registry::Registry::new(&[]); + let (sessopts, cfg) = build_session_options_and_crate_config(matches); + let sess = build_session(sessopts, None, registry, process_configure_mod); + (sess, cfg) } fn new_public_extern_entry(locations: I) -> ExternEntry @@ -59,31 +66,19 @@ fn mk_map(entries: Vec<(K, V)>) -> BTreeMap { #[test] fn test_switch_implies_cfg_test() { syntax::with_default_globals(|| { - let matches = &match optgroups().parse(&["--test".to_string()]) { - Ok(m) => m, - Err(f) => panic!("test_switch_implies_cfg_test: {}", f), - }; - let registry = registry::Registry::new(&[]); - let (sessopts, cfg) = build_session_options_and_crate_config(matches); - let sess = build_session(sessopts, None, registry); + let matches = optgroups().parse(&["--test".to_string()]).unwrap(); + let (sess, cfg) = mk_session(matches); let cfg = build_configuration(&sess, to_crate_config(cfg)); assert!(cfg.contains(&(sym::test, None))); }); } -// When the user supplies --test and --cfg test, don't implicitly add -// another --cfg test +// When the user supplies --test and --cfg test, don't implicitly add another --cfg test #[test] fn test_switch_implies_cfg_test_unless_cfg_test() { syntax::with_default_globals(|| { - let matches = &match optgroups().parse(&["--test".to_string(), - "--cfg=test".to_string()]) { - Ok(m) => m, - Err(f) => panic!("test_switch_implies_cfg_test_unless_cfg_test: {}", f), - }; - let registry = registry::Registry::new(&[]); - let (sessopts, cfg) = build_session_options_and_crate_config(matches); - let sess = build_session(sessopts, None, registry); + let matches = optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]).unwrap(); + let (sess, cfg) = mk_session(matches); let cfg = build_configuration(&sess, to_crate_config(cfg)); let mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test); assert!(test_items.next().is_some()); @@ -95,9 +90,7 @@ fn test_switch_implies_cfg_test_unless_cfg_test() { fn test_can_print_warnings() { syntax::with_default_globals(|| { let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap(); - let registry = registry::Registry::new(&[]); - let (sessopts, _) = build_session_options_and_crate_config(&matches); - let sess = build_session(sessopts, None, registry); + let (sess, _) = mk_session(matches); assert!(!sess.diagnostic().can_emit_warnings()); }); @@ -105,17 +98,13 @@ fn test_can_print_warnings() { let matches = optgroups() .parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()]) .unwrap(); - let registry = registry::Registry::new(&[]); - let (sessopts, _) = build_session_options_and_crate_config(&matches); - let sess = build_session(sessopts, None, registry); + let (sess, _) = mk_session(matches); assert!(sess.diagnostic().can_emit_warnings()); }); syntax::with_default_globals(|| { let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap(); - let registry = registry::Registry::new(&[]); - let (sessopts, _) = build_session_options_and_crate_config(&matches); - let sess = build_session(sessopts, None, registry); + let (sess, _) = mk_session(matches); assert!(sess.diagnostic().can_emit_warnings()); }); } @@ -704,6 +693,6 @@ fn test_edition_parsing() { let matches = optgroups() .parse(&["--edition=2018".to_string()]) .unwrap(); - let (sessopts, _) = build_session_options_and_crate_config(&matches); + let (sessopts, _) = build_session_options_and_crate_config(matches); assert!(sessopts.edition == Edition::Edition2018) } diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index a74ea4bca39..c02e5b9ae28 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -36,6 +36,7 @@ use syntax::util::lev_distance::find_best_match_for_name; use syntax::source_map::{FileLoader, RealFileLoader, SourceMap}; use syntax::symbol::{Symbol, sym}; use syntax::{self, ast, attr}; +use syntax_expand::config::process_configure_mod; use syntax_pos::edition::Edition; #[cfg(not(parallel_compiler))] use std::{thread, panic}; @@ -103,6 +104,7 @@ pub fn create_session( source_map.clone(), diagnostic_output, lint_caps, + process_configure_mod, ); let codegen_backend = get_codegen_backend(&sess); diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 4bd72f7e61c..71a44c0ebdb 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -16,6 +16,7 @@ use syntax::parse::lexer; use syntax::token::{self, Token}; use syntax::sess::ParseSess; use syntax::symbol::{kw, sym}; +use syntax_expand::config::process_configure_mod; use syntax_pos::{Span, FileName}; /// Highlights `src`, returning the HTML output. @@ -33,7 +34,7 @@ pub fn render_with_highlighting( class, tooltip).unwrap(); } - let sess = ParseSess::with_silent_emitter(); + let sess = ParseSess::with_silent_emitter(process_configure_mod); let fm = sess.source_map().new_source_file( FileName::Custom(String::from("rustdoc-highlighting")), src.to_owned(), diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index 4603e77b0fd..405f3a70e0e 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -3,6 +3,7 @@ use syntax::parse::lexer::{StringReader as Lexer}; use syntax::token; use syntax::sess::ParseSess; use syntax::source_map::FilePathMapping; +use syntax_expand::config::process_configure_mod; use syntax_pos::{InnerSpan, FileName}; use crate::clean; @@ -27,7 +28,7 @@ struct SyntaxChecker<'a, 'tcx> { impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeBlock) { - let sess = ParseSess::new(FilePathMapping::empty()); + let sess = ParseSess::new(FilePathMapping::empty(), process_configure_mod); let source_file = sess.source_map().new_source_file( FileName::Custom(String::from("doctest")), dox[code_block.code].to_owned(), diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 07dc1e4e915..e4cf1bb0bb9 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -17,6 +17,7 @@ use std::path::PathBuf; use std::process::{self, Command, Stdio}; use std::str; use syntax::symbol::sym; +use syntax_expand::config::process_configure_mod; use syntax_pos::{BytePos, DUMMY_SP, Pos, Span, FileName}; use tempfile::Builder as TempFileBuilder; use testing; @@ -411,7 +412,7 @@ pub fn make_test(s: &str, let emitter = EmitterWriter::new(box io::sink(), None, false, false, false, None, false); // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser let handler = Handler::with_emitter(false, None, box emitter); - let sess = ParseSess::with_span_handler(handler, cm); + let sess = ParseSess::with_span_handler(handler, cm, process_configure_mod); let mut found_main = false; let mut found_extern_crate = cratename.is_none(); diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 2c011b06470..d458549e298 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -363,8 +363,12 @@ crate fn mk_attr_id() -> AttrId { } pub fn mk_attr(style: AttrStyle, path: Path, tokens: TokenStream, span: Span) -> Attribute { + mk_attr_from_item(style, AttrItem { path, tokens }, span) +} + +pub fn mk_attr_from_item(style: AttrStyle, item: AttrItem, span: Span) -> Attribute { Attribute { - kind: AttrKind::Normal(AttrItem { path, tokens }), + kind: AttrKind::Normal(item), id: mk_attr_id(), style, span, diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs deleted file mode 100644 index a460fc2b99a..00000000000 --- a/src/libsyntax/config.rs +++ /dev/null @@ -1,352 +0,0 @@ -use crate::attr::HasAttrs; -use crate::feature_gate::{ - feature_err, - EXPLAIN_STMT_ATTR_SYNTAX, - Features, - get_features, - GateIssue, -}; -use crate::attr; -use crate::ast; -use crate::edition::Edition; -use crate::mut_visit::*; -use crate::parse::{self, validate_attr}; -use crate::ptr::P; -use crate::sess::ParseSess; -use crate::symbol::sym; -use crate::util::map_in_place::MapInPlace; - -use errors::Applicability; -use smallvec::SmallVec; - -/// A folder that strips out items that do not belong in the current configuration. -pub struct StripUnconfigured<'a> { - pub sess: &'a ParseSess, - pub features: Option<&'a Features>, -} - -// `cfg_attr`-process the crate's attributes and compute the crate's features. -pub fn features(mut krate: ast::Crate, sess: &ParseSess, edition: Edition, - allow_features: &Option>) -> (ast::Crate, Features) { - let features; - { - let mut strip_unconfigured = StripUnconfigured { - sess, - features: None, - }; - - let unconfigured_attrs = krate.attrs.clone(); - let err_count = sess.span_diagnostic.err_count(); - if let Some(attrs) = strip_unconfigured.configure(krate.attrs) { - krate.attrs = attrs; - } else { // the entire crate is unconfigured - krate.attrs = Vec::new(); - krate.module.items = Vec::new(); - return (krate, Features::new()); - } - - features = get_features(&sess.span_diagnostic, &krate.attrs, edition, allow_features); - - // Avoid reconfiguring malformed `cfg_attr`s - if err_count == sess.span_diagnostic.err_count() { - strip_unconfigured.features = Some(&features); - strip_unconfigured.configure(unconfigured_attrs); - } - } - - (krate, features) -} - -#[macro_export] -macro_rules! configure { - ($this:ident, $node:ident) => { - match $this.configure($node) { - Some(node) => node, - None => return Default::default(), - } - } -} - -impl<'a> StripUnconfigured<'a> { - pub fn configure(&mut self, mut node: T) -> Option { - self.process_cfg_attrs(&mut node); - if self.in_cfg(node.attrs()) { Some(node) } else { None } - } - - /// Parse and expand all `cfg_attr` attributes into a list of attributes - /// that are within each `cfg_attr` that has a true configuration predicate. - /// - /// Gives compiler warnigns if any `cfg_attr` does not contain any - /// attributes and is in the original source code. Gives compiler errors if - /// the syntax of any `cfg_attr` is incorrect. - pub fn process_cfg_attrs(&mut self, node: &mut T) { - node.visit_attrs(|attrs| { - attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); - }); - } - - /// Parse and expand a single `cfg_attr` attribute into a list of attributes - /// when the configuration predicate is true, or otherwise expand into an - /// empty list of attributes. - /// - /// Gives a compiler warning when the `cfg_attr` contains no attributes and - /// is in the original source file. Gives a compiler error if the syntax of - /// the attribute is incorrect. - fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec { - if !attr.has_name(sym::cfg_attr) { - return vec![attr]; - } - if attr.get_normal_item().tokens.is_empty() { - self.sess.span_diagnostic - .struct_span_err( - attr.span, - "malformed `cfg_attr` attribute input", - ).span_suggestion( - attr.span, - "missing condition and attribute", - "#[cfg_attr(condition, attribute, other_attribute, ...)]".to_owned(), - Applicability::HasPlaceholders, - ).note("for more information, visit \ - ") - .emit(); - return vec![]; - } - - let res = parse::parse_in_attr(self.sess, &attr, |p| p.parse_cfg_attr()); - let (cfg_predicate, expanded_attrs) = match res { - Ok(result) => result, - Err(mut e) => { - e.emit(); - return vec![]; - } - }; - - // Lint on zero attributes in source. - if expanded_attrs.is_empty() { - return vec![attr]; - } - - // At this point we know the attribute is considered used. - attr::mark_used(&attr); - - if attr::cfg_matches(&cfg_predicate, self.sess, self.features) { - // We call `process_cfg_attr` recursively in case there's a - // `cfg_attr` inside of another `cfg_attr`. E.g. - // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. - expanded_attrs.into_iter() - .flat_map(|(item, span)| self.process_cfg_attr(ast::Attribute { - kind: ast::AttrKind::Normal(item), - id: attr::mk_attr_id(), - style: attr.style, - span, - })) - .collect() - } else { - vec![] - } - } - - /// Determines if a node with the given attributes should be included in this configuration. - pub fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool { - attrs.iter().all(|attr| { - if !is_cfg(attr) { - return true; - } - - let error = |span, msg, suggestion: &str| { - let mut err = self.sess.span_diagnostic.struct_span_err(span, msg); - if !suggestion.is_empty() { - err.span_suggestion( - span, - "expected syntax is", - suggestion.into(), - Applicability::MaybeIncorrect, - ); - } - err.emit(); - true - }; - - let meta_item = match validate_attr::parse_meta(self.sess, attr) { - Ok(meta_item) => meta_item, - Err(mut err) => { err.emit(); return true; } - }; - let nested_meta_items = if let Some(nested_meta_items) = meta_item.meta_item_list() { - nested_meta_items - } else { - return error(meta_item.span, "`cfg` is not followed by parentheses", - "cfg(/* predicate */)"); - }; - - if nested_meta_items.is_empty() { - return error(meta_item.span, "`cfg` predicate is not specified", ""); - } else if nested_meta_items.len() > 1 { - return error(nested_meta_items.last().unwrap().span(), - "multiple `cfg` predicates are specified", ""); - } - - match nested_meta_items[0].meta_item() { - Some(meta_item) => attr::cfg_matches(meta_item, self.sess, self.features), - None => error(nested_meta_items[0].span(), - "`cfg` predicate key cannot be a literal", ""), - } - }) - } - - /// Visit attributes on expression and statements (but not attributes on items in blocks). - fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) { - // flag the offending attributes - for attr in attrs.iter() { - self.maybe_emit_expr_attr_err(attr); - } - } - - /// If attributes are not allowed on expressions, emit an error for `attr` - pub fn maybe_emit_expr_attr_err(&self, attr: &ast::Attribute) { - if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) { - let mut err = feature_err(self.sess, - sym::stmt_expr_attributes, - attr.span, - GateIssue::Language, - EXPLAIN_STMT_ATTR_SYNTAX); - - if attr.is_doc_comment() { - err.help("`///` is for documentation comments. For a plain comment, use `//`."); - } - - err.emit(); - } - } - - pub fn configure_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) { - let ast::ForeignMod { abi: _, items } = foreign_mod; - items.flat_map_in_place(|item| self.configure(item)); - } - - pub fn configure_generic_params(&mut self, params: &mut Vec) { - params.flat_map_in_place(|param| self.configure(param)); - } - - fn configure_variant_data(&mut self, vdata: &mut ast::VariantData) { - match vdata { - ast::VariantData::Struct(fields, ..) | ast::VariantData::Tuple(fields, _) => - fields.flat_map_in_place(|field| self.configure(field)), - ast::VariantData::Unit(_) => {} - } - } - - pub fn configure_item_kind(&mut self, item: &mut ast::ItemKind) { - match item { - ast::ItemKind::Struct(def, _generics) | - ast::ItemKind::Union(def, _generics) => self.configure_variant_data(def), - ast::ItemKind::Enum(ast::EnumDef { variants }, _generics) => { - variants.flat_map_in_place(|variant| self.configure(variant)); - for variant in variants { - self.configure_variant_data(&mut variant.data); - } - } - _ => {} - } - } - - pub fn configure_expr_kind(&mut self, expr_kind: &mut ast::ExprKind) { - match expr_kind { - ast::ExprKind::Match(_m, arms) => { - arms.flat_map_in_place(|arm| self.configure(arm)); - } - ast::ExprKind::Struct(_path, fields, _base) => { - fields.flat_map_in_place(|field| self.configure(field)); - } - _ => {} - } - } - - pub fn configure_expr(&mut self, expr: &mut P) { - self.visit_expr_attrs(expr.attrs()); - - // If an expr is valid to cfg away it will have been removed by the - // outer stmt or expression folder before descending in here. - // Anything else is always required, and thus has to error out - // in case of a cfg attr. - // - // N.B., this is intentionally not part of the visit_expr() function - // in order for filter_map_expr() to be able to avoid this check - if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) { - let msg = "removing an expression is not supported in this position"; - self.sess.span_diagnostic.span_err(attr.span, msg); - } - - self.process_cfg_attrs(expr) - } - - pub fn configure_pat(&mut self, pat: &mut P) { - if let ast::PatKind::Struct(_path, fields, _etc) = &mut pat.kind { - fields.flat_map_in_place(|field| self.configure(field)); - } - } - - pub fn configure_fn_decl(&mut self, fn_decl: &mut ast::FnDecl) { - fn_decl.inputs.flat_map_in_place(|arg| self.configure(arg)); - } -} - -impl<'a> MutVisitor for StripUnconfigured<'a> { - fn visit_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) { - self.configure_foreign_mod(foreign_mod); - noop_visit_foreign_mod(foreign_mod, self); - } - - fn visit_item_kind(&mut self, item: &mut ast::ItemKind) { - self.configure_item_kind(item); - noop_visit_item_kind(item, self); - } - - fn visit_expr(&mut self, expr: &mut P) { - self.configure_expr(expr); - self.configure_expr_kind(&mut expr.kind); - noop_visit_expr(expr, self); - } - - fn filter_map_expr(&mut self, expr: P) -> Option> { - let mut expr = configure!(self, expr); - self.configure_expr_kind(&mut expr.kind); - noop_visit_expr(&mut expr, self); - Some(expr) - } - - fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { - noop_flat_map_stmt(configure!(self, stmt), self) - } - - fn flat_map_item(&mut self, item: P) -> SmallVec<[P; 1]> { - noop_flat_map_item(configure!(self, item), self) - } - - fn flat_map_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> { - noop_flat_map_impl_item(configure!(self, item), self) - } - - fn flat_map_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> { - noop_flat_map_trait_item(configure!(self, item), self) - } - - fn visit_mac(&mut self, _mac: &mut ast::Mac) { - // Don't configure interpolated AST (cf. issue #34171). - // Interpolated AST will get configured once the surrounding tokens are parsed. - } - - fn visit_pat(&mut self, pat: &mut P) { - self.configure_pat(pat); - noop_visit_pat(pat, self) - } - - fn visit_fn_decl(&mut self, mut fn_decl: &mut P) { - self.configure_fn_decl(&mut fn_decl); - noop_visit_fn_decl(fn_decl, self); - } -} - -fn is_cfg(attr: &ast::Attribute) -> bool { - attr.check_name(sym::cfg) -} diff --git a/src/libsyntax/json/tests.rs b/src/libsyntax/json/tests.rs index eb0d9ef3947..1edefd5bc4b 100644 --- a/src/libsyntax/json/tests.rs +++ b/src/libsyntax/json/tests.rs @@ -2,7 +2,6 @@ use super::*; use crate::json::JsonEmitter; use crate::source_map::{FilePathMapping, SourceMap}; -use crate::tests::Shared; use crate::with_default_globals; use errors::emitter::{ColorConfig, HumanReadableErrorType}; @@ -27,6 +26,20 @@ struct SpanTestData { pub column_end: u32, } +struct Shared { + data: Arc>, +} + +impl Write for Shared { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.data.lock().unwrap().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.data.lock().unwrap().flush() + } +} + /// Test the span yields correct positions in JSON. fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) { let expected_output = TestData { spans: vec![expected_output] }; diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 1b17de529c4..7fecc87a18f 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -26,9 +26,6 @@ pub use rustc_data_structures::thin_vec::ThinVec; use ast::AttrId; use syntax_pos::edition::Edition; -#[cfg(test)] -mod tests; - pub const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments"); #[macro_export] @@ -100,7 +97,6 @@ pub mod ast; pub mod attr; pub mod expand; pub mod source_map; -#[macro_use] pub mod config; pub mod entry; pub mod feature_gate; pub mod mut_visit; diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 7696ea48f93..376323a83ea 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -22,9 +22,6 @@ use rustc_data_structures::sync::Lrc; use std::ops::DerefMut; use std::{panic, process, ptr}; -#[cfg(test)] -mod tests; - pub trait ExpectOne { fn expect_one(self, err: &'static str) -> A::Item; } diff --git a/src/libsyntax/mut_visit/tests.rs b/src/libsyntax/mut_visit/tests.rs deleted file mode 100644 index f779e0d0a60..00000000000 --- a/src/libsyntax/mut_visit/tests.rs +++ /dev/null @@ -1,71 +0,0 @@ -use super::*; - -use crate::ast::{self, Ident}; -use crate::tests::{string_to_crate, matches_codepattern}; -use crate::print::pprust; -use crate::mut_visit; -use crate::with_default_globals; - -// This version doesn't care about getting comments or doc-strings in. -fn fake_print_crate(s: &mut pprust::State<'_>, - krate: &ast::Crate) { - s.print_mod(&krate.module, &krate.attrs) -} - -// Change every identifier to "zz". -struct ToZzIdentMutVisitor; - -impl MutVisitor for ToZzIdentMutVisitor { - fn visit_ident(&mut self, ident: &mut ast::Ident) { - *ident = Ident::from_str("zz"); - } - fn visit_mac(&mut self, mac: &mut ast::Mac) { - mut_visit::noop_visit_mac(mac, self) - } -} - -// Maybe add to `expand.rs`. -macro_rules! assert_pred { - ($pred:expr, $predname:expr, $a:expr , $b:expr) => ( - { - let pred_val = $pred; - let a_val = $a; - let b_val = $b; - if !(pred_val(&a_val, &b_val)) { - panic!("expected args satisfying {}, got {} and {}", - $predname, a_val, b_val); - } - } - ) -} - -// Make sure idents get transformed everywhere. -#[test] fn ident_transformation () { - with_default_globals(|| { - let mut zz_visitor = ToZzIdentMutVisitor; - let mut krate = string_to_crate( - "#[a] mod b {fn c (d : e, f : g) {h!(i,j,k);l;m}}".to_string()); - zz_visitor.visit_crate(&mut krate); - assert_pred!( - matches_codepattern, - "matches_codepattern", - pprust::to_string(|s| fake_print_crate(s, &krate)), - "#[zz]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string()); - }) -} - -// Make sure idents get transformed even inside macro defs. -#[test] fn ident_transformation_in_defs () { - with_default_globals(|| { - let mut zz_visitor = ToZzIdentMutVisitor; - let mut krate = string_to_crate( - "macro_rules! a {(b $c:expr $(d $e:token)f+ => \ - (g $(d $d $e)+))} ".to_string()); - zz_visitor.visit_crate(&mut krate); - assert_pred!( - matches_codepattern, - "matches_codepattern", - pprust::to_string(|s| fake_print_crate(s, &krate)), - "macro_rules! zz{(zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+))}".to_string()); - }) -} diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index b1b7b08c78a..f2d5ff3440e 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -13,9 +13,6 @@ use std::convert::TryInto; use rustc_data_structures::sync::Lrc; use log::debug; -#[cfg(test)] -mod tests; - mod tokentrees; mod unicode_chars; mod unescape_error_reporting; @@ -35,7 +32,8 @@ pub struct StringReader<'a> { /// Initial position, read-only. start_pos: BytePos, /// The absolute offset within the source_map of the current character. - pos: BytePos, + // FIXME(#64197): `pub` is needed by tests for now. + pub pos: BytePos, /// Stop reading src at this index. end_src_index: usize, /// Source text to tokenize. diff --git a/src/libsyntax/parse/lexer/tests.rs b/src/libsyntax/parse/lexer/tests.rs deleted file mode 100644 index baa6fb59537..00000000000 --- a/src/libsyntax/parse/lexer/tests.rs +++ /dev/null @@ -1,270 +0,0 @@ -use super::*; - -use crate::symbol::Symbol; -use crate::source_map::{SourceMap, FilePathMapping}; -use crate::token; -use crate::util::comments::is_doc_comment; -use crate::with_default_globals; - -use errors::{Handler, emitter::EmitterWriter}; -use std::io; -use std::path::PathBuf; -use syntax_pos::{BytePos, Span}; - -fn mk_sess(sm: Lrc) -> ParseSess { - let emitter = EmitterWriter::new( - Box::new(io::sink()), - Some(sm.clone()), - false, - false, - false, - None, - false, - ); - ParseSess::with_span_handler(Handler::with_emitter(true, None, Box::new(emitter)), sm) -} - -// Creates a string reader for the given string. -fn setup<'a>(sm: &SourceMap, - sess: &'a ParseSess, - teststr: String) - -> StringReader<'a> { - let sf = sm.new_source_file(PathBuf::from(teststr.clone()).into(), teststr); - StringReader::new(sess, sf, None) -} - -#[test] -fn t1() { - with_default_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - let mut string_reader = setup( - &sm, - &sh, - "/* my source file */ fn main() { println!(\"zebra\"); }\n".to_string(), - ); - assert_eq!(string_reader.next_token(), token::Comment); - assert_eq!(string_reader.next_token(), token::Whitespace); - let tok1 = string_reader.next_token(); - let tok2 = Token::new( - mk_ident("fn"), - Span::with_root_ctxt(BytePos(21), BytePos(23)), - ); - assert_eq!(tok1.kind, tok2.kind); - assert_eq!(tok1.span, tok2.span); - assert_eq!(string_reader.next_token(), token::Whitespace); - // Read another token. - let tok3 = string_reader.next_token(); - assert_eq!(string_reader.pos.clone(), BytePos(28)); - let tok4 = Token::new( - mk_ident("main"), - Span::with_root_ctxt(BytePos(24), BytePos(28)), - ); - assert_eq!(tok3.kind, tok4.kind); - assert_eq!(tok3.span, tok4.span); - - assert_eq!(string_reader.next_token(), token::OpenDelim(token::Paren)); - assert_eq!(string_reader.pos.clone(), BytePos(29)) - }) -} - -// Checks that the given reader produces the desired stream -// of tokens (stop checking after exhausting `expected`). -fn check_tokenization(mut string_reader: StringReader<'_>, expected: Vec) { - for expected_tok in &expected { - assert_eq!(&string_reader.next_token(), expected_tok); - } -} - -// Makes the identifier by looking up the string in the interner. -fn mk_ident(id: &str) -> TokenKind { - token::Ident(Symbol::intern(id), false) -} - -fn mk_lit(kind: token::LitKind, symbol: &str, suffix: Option<&str>) -> TokenKind { - TokenKind::lit(kind, Symbol::intern(symbol), suffix.map(Symbol::intern)) -} - -#[test] -fn doublecolon_parsing() { - with_default_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - check_tokenization( - setup(&sm, &sh, "a b".to_string()), - vec![mk_ident("a"), token::Whitespace, mk_ident("b")], - ); - }) -} - -#[test] -fn doublecolon_parsing_2() { - with_default_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - check_tokenization( - setup(&sm, &sh, "a::b".to_string()), - vec![mk_ident("a"), token::Colon, token::Colon, mk_ident("b")], - ); - }) -} - -#[test] -fn doublecolon_parsing_3() { - with_default_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - check_tokenization( - setup(&sm, &sh, "a ::b".to_string()), - vec![mk_ident("a"), token::Whitespace, token::Colon, token::Colon, mk_ident("b")], - ); - }) -} - -#[test] -fn doublecolon_parsing_4() { - with_default_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - check_tokenization( - setup(&sm, &sh, "a:: b".to_string()), - vec![mk_ident("a"), token::Colon, token::Colon, token::Whitespace, mk_ident("b")], - ); - }) -} - -#[test] -fn character_a() { - with_default_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - assert_eq!( - setup(&sm, &sh, "'a'".to_string()).next_token(), - mk_lit(token::Char, "a", None), - ); - }) -} - -#[test] -fn character_space() { - with_default_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - assert_eq!( - setup(&sm, &sh, "' '".to_string()).next_token(), - mk_lit(token::Char, " ", None), - ); - }) -} - -#[test] -fn character_escaped() { - with_default_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - assert_eq!( - setup(&sm, &sh, "'\\n'".to_string()).next_token(), - mk_lit(token::Char, "\\n", None), - ); - }) -} - -#[test] -fn lifetime_name() { - with_default_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - assert_eq!( - setup(&sm, &sh, "'abc".to_string()).next_token(), - token::Lifetime(Symbol::intern("'abc")), - ); - }) -} - -#[test] -fn raw_string() { - with_default_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - assert_eq!( - setup(&sm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token(), - mk_lit(token::StrRaw(3), "\"#a\\b\x00c\"", None), - ); - }) -} - -#[test] -fn literal_suffixes() { - with_default_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - macro_rules! test { - ($input: expr, $tok_type: ident, $tok_contents: expr) => {{ - assert_eq!( - setup(&sm, &sh, format!("{}suffix", $input)).next_token(), - mk_lit(token::$tok_type, $tok_contents, Some("suffix")), - ); - // with a whitespace separator - assert_eq!( - setup(&sm, &sh, format!("{} suffix", $input)).next_token(), - mk_lit(token::$tok_type, $tok_contents, None), - ); - }} - } - - test!("'a'", Char, "a"); - test!("b'a'", Byte, "a"); - test!("\"a\"", Str, "a"); - test!("b\"a\"", ByteStr, "a"); - test!("1234", Integer, "1234"); - test!("0b101", Integer, "0b101"); - test!("0xABC", Integer, "0xABC"); - test!("1.0", Float, "1.0"); - test!("1.0e10", Float, "1.0e10"); - - assert_eq!( - setup(&sm, &sh, "2us".to_string()).next_token(), - mk_lit(token::Integer, "2", Some("us")), - ); - assert_eq!( - setup(&sm, &sh, "r###\"raw\"###suffix".to_string()).next_token(), - mk_lit(token::StrRaw(3), "raw", Some("suffix")), - ); - assert_eq!( - setup(&sm, &sh, "br###\"raw\"###suffix".to_string()).next_token(), - mk_lit(token::ByteStrRaw(3), "raw", Some("suffix")), - ); - }) -} - -#[test] -fn line_doc_comments() { - assert!(is_doc_comment("///")); - assert!(is_doc_comment("/// blah")); - assert!(!is_doc_comment("////")); -} - -#[test] -fn nested_block_comments() { - with_default_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - let mut lexer = setup(&sm, &sh, "/* /* */ */'a'".to_string()); - assert_eq!(lexer.next_token(), token::Comment); - assert_eq!(lexer.next_token(), mk_lit(token::Char, "a", None)); - }) -} - -#[test] -fn crlf_comments() { - with_default_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - let mut lexer = setup(&sm, &sh, "// test\r\n/// test\r\n".to_string()); - let comment = lexer.next_token(); - assert_eq!(comment.kind, token::Comment); - assert_eq!((comment.span.lo(), comment.span.hi()), (BytePos(0), BytePos(7))); - assert_eq!(lexer.next_token(), token::Whitespace); - assert_eq!(lexer.next_token(), token::DocComment(Symbol::intern("/// test"))); - }) -} diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 9155cbe5dd8..af3f8ecb45a 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -17,8 +17,7 @@ use std::str; use log::info; -#[cfg(test)] -mod tests; +pub const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments"); #[macro_use] pub mod parser; diff --git a/src/libsyntax/parse/parser/attr.rs b/src/libsyntax/parse/parser/attr.rs index 31f0a02a483..0f9e573af82 100644 --- a/src/libsyntax/parse/parser/attr.rs +++ b/src/libsyntax/parse/parser/attr.rs @@ -268,7 +268,7 @@ impl<'a> Parser<'a> { } /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited. - crate fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> { + pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> { self.expect(&token::OpenDelim(token::Paren))?; let cfg_predicate = self.parse_meta_item()?; diff --git a/src/libsyntax/parse/parser/module.rs b/src/libsyntax/parse/parser/module.rs index 3e5974c2eee..ad72b3a1dea 100644 --- a/src/libsyntax/parse/parser/module.rs +++ b/src/libsyntax/parse/parser/module.rs @@ -7,8 +7,8 @@ use crate::ast::{self, Ident, Attribute, ItemKind, Mod, Crate}; use crate::parse::{new_sub_parser_from_file, DirectoryOwnership}; use crate::token::{self, TokenKind}; use crate::source_map::{SourceMap, Span, DUMMY_SP, FileName}; -use crate::symbol::sym; +use syntax_pos::symbol::sym; use errors::PResult; use std::path::{self, Path, PathBuf}; @@ -39,17 +39,12 @@ impl<'a> Parser<'a> { /// Parses a `mod { ... }` or `mod ;` item. pub(super) fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> PResult<'a, ItemInfo> { - let (in_cfg, outer_attrs) = { - // FIXME(Centril): This results in a cycle between config and parsing. - // Consider using dynamic dispatch via `self.sess` to disentangle the knot. - let mut strip_unconfigured = crate::config::StripUnconfigured { - sess: self.sess, - features: None, // Don't perform gated feature checking. - }; - let mut outer_attrs = outer_attrs.to_owned(); - strip_unconfigured.process_cfg_attrs(&mut outer_attrs); - (!self.cfg_mods || strip_unconfigured.in_cfg(&outer_attrs), outer_attrs) - }; + // HACK(Centril): See documentation on `ParseSess::process_cfg_mod`. + let (in_cfg, outer_attrs) = (self.sess.process_cfg_mod)( + self.sess, + self.cfg_mods, + outer_attrs, + ); let id_span = self.token.span; let id = self.parse_ident()?; diff --git a/src/libsyntax/parse/tests.rs b/src/libsyntax/parse/tests.rs deleted file mode 100644 index 27ca2b6472f..00000000000 --- a/src/libsyntax/parse/tests.rs +++ /dev/null @@ -1,339 +0,0 @@ -use super::*; - -use crate::ast::{self, Name, PatKind}; -use crate::attr::first_attr_value_str_by_name; -use crate::sess::ParseSess; -use crate::parse::{PResult, new_parser_from_source_str}; -use crate::token::Token; -use crate::print::pprust::item_to_string; -use crate::ptr::P; -use crate::source_map::FilePathMapping; -use crate::symbol::{kw, sym}; -use crate::tests::{matches_codepattern, string_to_stream, with_error_checking_parse}; -use crate::tokenstream::{DelimSpan, TokenTree, TokenStream}; -use crate::with_default_globals; -use syntax_pos::{Span, BytePos, Pos}; - -use std::path::PathBuf; - -/// Parses an item. -/// -/// Returns `Ok(Some(item))` when successful, `Ok(None)` when no item was found, and `Err` -/// when a syntax error occurred. -fn parse_item_from_source_str(name: FileName, source: String, sess: &ParseSess) - -> PResult<'_, Option>> { - new_parser_from_source_str(sess, name, source).parse_item() -} - -// Produces a `syntax_pos::span`. -fn sp(a: u32, b: u32) -> Span { - Span::with_root_ctxt(BytePos(a), BytePos(b)) -} - -/// Parses a string, return an expression. -fn string_to_expr(source_str : String) -> P { - let ps = ParseSess::new(FilePathMapping::empty()); - with_error_checking_parse(source_str, &ps, |p| { - p.parse_expr() - }) -} - -/// Parses a string, returns an item. -fn string_to_item(source_str : String) -> Option> { - let ps = ParseSess::new(FilePathMapping::empty()); - with_error_checking_parse(source_str, &ps, |p| { - p.parse_item() - }) -} - -#[should_panic] -#[test] fn bad_path_expr_1() { - with_default_globals(|| { - string_to_expr("::abc::def::return".to_string()); - }) -} - -// Checks the token-tree-ization of macros. -#[test] -fn string_to_tts_macro () { - with_default_globals(|| { - let tts: Vec<_> = - string_to_stream("macro_rules! zip (($a)=>($a))".to_string()).trees().collect(); - let tts: &[TokenTree] = &tts[..]; - - match tts { - [ - TokenTree::Token(Token { kind: token::Ident(name_macro_rules, false), .. }), - TokenTree::Token(Token { kind: token::Not, .. }), - TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }), - TokenTree::Delimited(_, macro_delim, macro_tts) - ] - if name_macro_rules == &sym::macro_rules && name_zip.as_str() == "zip" => { - let tts = ¯o_tts.trees().collect::>(); - match &tts[..] { - [ - TokenTree::Delimited(_, first_delim, first_tts), - TokenTree::Token(Token { kind: token::FatArrow, .. }), - TokenTree::Delimited(_, second_delim, second_tts), - ] - if macro_delim == &token::Paren => { - let tts = &first_tts.trees().collect::>(); - match &tts[..] { - [ - TokenTree::Token(Token { kind: token::Dollar, .. }), - TokenTree::Token(Token { kind: token::Ident(name, false), .. }), - ] - if first_delim == &token::Paren && name.as_str() == "a" => {}, - _ => panic!("value 3: {:?} {:?}", first_delim, first_tts), - } - let tts = &second_tts.trees().collect::>(); - match &tts[..] { - [ - TokenTree::Token(Token { kind: token::Dollar, .. }), - TokenTree::Token(Token { kind: token::Ident(name, false), .. }), - ] - if second_delim == &token::Paren && name.as_str() == "a" => {}, - _ => panic!("value 4: {:?} {:?}", second_delim, second_tts), - } - }, - _ => panic!("value 2: {:?} {:?}", macro_delim, macro_tts), - } - }, - _ => panic!("value: {:?}",tts), - } - }) -} - -#[test] -fn string_to_tts_1() { - with_default_globals(|| { - let tts = string_to_stream("fn a (b : i32) { b; }".to_string()); - - let expected = TokenStream::new(vec![ - TokenTree::token(token::Ident(kw::Fn, false), sp(0, 2)).into(), - TokenTree::token(token::Ident(Name::intern("a"), false), sp(3, 4)).into(), - TokenTree::Delimited( - DelimSpan::from_pair(sp(5, 6), sp(13, 14)), - token::DelimToken::Paren, - TokenStream::new(vec![ - TokenTree::token(token::Ident(Name::intern("b"), false), sp(6, 7)).into(), - TokenTree::token(token::Colon, sp(8, 9)).into(), - TokenTree::token(token::Ident(sym::i32, false), sp(10, 13)).into(), - ]).into(), - ).into(), - TokenTree::Delimited( - DelimSpan::from_pair(sp(15, 16), sp(20, 21)), - token::DelimToken::Brace, - TokenStream::new(vec![ - TokenTree::token(token::Ident(Name::intern("b"), false), sp(17, 18)).into(), - TokenTree::token(token::Semi, sp(18, 19)).into(), - ]).into(), - ).into() - ]); - - assert_eq!(tts, expected); - }) -} - -#[test] fn parse_use() { - with_default_globals(|| { - let use_s = "use foo::bar::baz;"; - let vitem = string_to_item(use_s.to_string()).unwrap(); - let vitem_s = item_to_string(&vitem); - assert_eq!(&vitem_s[..], use_s); - - let use_s = "use foo::bar as baz;"; - let vitem = string_to_item(use_s.to_string()).unwrap(); - let vitem_s = item_to_string(&vitem); - assert_eq!(&vitem_s[..], use_s); - }) -} - -#[test] fn parse_extern_crate() { - with_default_globals(|| { - let ex_s = "extern crate foo;"; - let vitem = string_to_item(ex_s.to_string()).unwrap(); - let vitem_s = item_to_string(&vitem); - assert_eq!(&vitem_s[..], ex_s); - - let ex_s = "extern crate foo as bar;"; - let vitem = string_to_item(ex_s.to_string()).unwrap(); - let vitem_s = item_to_string(&vitem); - assert_eq!(&vitem_s[..], ex_s); - }) -} - -fn get_spans_of_pat_idents(src: &str) -> Vec { - let item = string_to_item(src.to_string()).unwrap(); - - struct PatIdentVisitor { - spans: Vec - } - impl<'a> crate::visit::Visitor<'a> for PatIdentVisitor { - fn visit_pat(&mut self, p: &'a ast::Pat) { - match p.kind { - PatKind::Ident(_ , ref ident, _) => { - self.spans.push(ident.span.clone()); - } - _ => { - crate::visit::walk_pat(self, p); - } - } - } - } - let mut v = PatIdentVisitor { spans: Vec::new() }; - crate::visit::walk_item(&mut v, &item); - return v.spans; -} - -#[test] fn span_of_self_arg_pat_idents_are_correct() { - with_default_globals(|| { - - let srcs = ["impl z { fn a (&self, &myarg: i32) {} }", - "impl z { fn a (&mut self, &myarg: i32) {} }", - "impl z { fn a (&'a self, &myarg: i32) {} }", - "impl z { fn a (self, &myarg: i32) {} }", - "impl z { fn a (self: Foo, &myarg: i32) {} }", - ]; - - for &src in &srcs { - let spans = get_spans_of_pat_idents(src); - let (lo, hi) = (spans[0].lo(), spans[0].hi()); - assert!("self" == &src[lo.to_usize()..hi.to_usize()], - "\"{}\" != \"self\". src=\"{}\"", - &src[lo.to_usize()..hi.to_usize()], src) - } - }) -} - -#[test] fn parse_exprs () { - with_default_globals(|| { - // just make sure that they parse.... - string_to_expr("3 + 4".to_string()); - string_to_expr("a::z.froob(b,&(987+3))".to_string()); - }) -} - -#[test] fn attrs_fix_bug () { - with_default_globals(|| { - string_to_item("pub fn mk_file_writer(path: &Path, flags: &[FileFlag]) - -> Result, String> { -#[cfg(windows)] -fn wb() -> c_int { - (O_WRONLY | libc::consts::os::extra::O_BINARY) as c_int -} - -#[cfg(unix)] -fn wb() -> c_int { O_WRONLY as c_int } - -let mut fflags: c_int = wb(); -}".to_string()); - }) -} - -#[test] fn crlf_doc_comments() { - with_default_globals(|| { - let sess = ParseSess::new(FilePathMapping::empty()); - - let name_1 = FileName::Custom("crlf_source_1".to_string()); - let source = "/// doc comment\r\nfn foo() {}".to_string(); - let item = parse_item_from_source_str(name_1, source, &sess) - .unwrap().unwrap(); - let doc = first_attr_value_str_by_name(&item.attrs, sym::doc).unwrap(); - assert_eq!(doc.as_str(), "/// doc comment"); - - let name_2 = FileName::Custom("crlf_source_2".to_string()); - let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string(); - let item = parse_item_from_source_str(name_2, source, &sess) - .unwrap().unwrap(); - let docs = item.attrs.iter().filter(|a| a.has_name(sym::doc)) - .map(|a| a.value_str().unwrap().to_string()).collect::>(); - let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()]; - assert_eq!(&docs[..], b); - - let name_3 = FileName::Custom("clrf_source_3".to_string()); - let source = "/** doc comment\r\n * with CRLF */\r\nfn foo() {}".to_string(); - let item = parse_item_from_source_str(name_3, source, &sess).unwrap().unwrap(); - let doc = first_attr_value_str_by_name(&item.attrs, sym::doc).unwrap(); - assert_eq!(doc.as_str(), "/** doc comment\n * with CRLF */"); - }); -} - -#[test] -fn ttdelim_span() { - fn parse_expr_from_source_str( - name: FileName, source: String, sess: &ParseSess - ) -> PResult<'_, P> { - new_parser_from_source_str(sess, name, source).parse_expr() - } - - with_default_globals(|| { - let sess = ParseSess::new(FilePathMapping::empty()); - let expr = parse_expr_from_source_str(PathBuf::from("foo").into(), - "foo!( fn main() { body } )".to_string(), &sess).unwrap(); - - let tts: Vec<_> = match expr.kind { - ast::ExprKind::Mac(ref mac) => mac.stream().trees().collect(), - _ => panic!("not a macro"), - }; - - let span = tts.iter().rev().next().unwrap().span(); - - match sess.source_map().span_to_snippet(span) { - Ok(s) => assert_eq!(&s[..], "{ body }"), - Err(_) => panic!("could not get snippet"), - } - }); -} - -// This tests that when parsing a string (rather than a file) we don't try -// and read in a file for a module declaration and just parse a stub. -// See `recurse_into_file_modules` in the parser. -#[test] -fn out_of_line_mod() { - with_default_globals(|| { - let sess = ParseSess::new(FilePathMapping::empty()); - let item = parse_item_from_source_str( - PathBuf::from("foo").into(), - "mod foo { struct S; mod this_does_not_exist; }".to_owned(), - &sess, - ).unwrap().unwrap(); - - if let ast::ItemKind::Mod(ref m) = item.kind { - assert!(m.items.len() == 2); - } else { - panic!(); - } - }); -} - -#[test] -fn eqmodws() { - assert_eq!(matches_codepattern("",""),true); - assert_eq!(matches_codepattern("","a"),false); - assert_eq!(matches_codepattern("a",""),false); - assert_eq!(matches_codepattern("a","a"),true); - assert_eq!(matches_codepattern("a b","a \n\t\r b"),true); - assert_eq!(matches_codepattern("a b ","a \n\t\r b"),true); - assert_eq!(matches_codepattern("a b","a \n\t\r b "),false); - assert_eq!(matches_codepattern("a b","a b"),true); - assert_eq!(matches_codepattern("ab","a b"),false); - assert_eq!(matches_codepattern("a b","ab"),true); - assert_eq!(matches_codepattern(" a b","ab"),true); -} - -#[test] -fn pattern_whitespace() { - assert_eq!(matches_codepattern("","\x0C"), false); - assert_eq!(matches_codepattern("a b ","a \u{0085}\n\t\r b"),true); - assert_eq!(matches_codepattern("a b","a \u{0085}\n\t\r b "),false); -} - -#[test] -fn non_pattern_whitespace() { - // These have the property 'White_Space' but not 'Pattern_White_Space' - assert_eq!(matches_codepattern("a b","a\u{2002}b"), false); - assert_eq!(matches_codepattern("a b","a\u{2002}b"), false); - assert_eq!(matches_codepattern("\u{205F}a b","ab"), false); - assert_eq!(matches_codepattern("a \u{3000}b","ab"), false); -} diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 2203e8d9d06..04f096200b8 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -939,8 +939,11 @@ impl<'a> State<'a> { self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span) } - crate fn print_mod(&mut self, _mod: &ast::Mod, - attrs: &[ast::Attribute]) { + pub fn print_mod( + &mut self, + _mod: &ast::Mod, + attrs: &[ast::Attribute], + ) { self.print_inner_attributes(attrs); for item in &_mod.items { self.print_item(item); diff --git a/src/libsyntax/sess.rs b/src/libsyntax/sess.rs index faad3e4af1e..5e96b27c970 100644 --- a/src/libsyntax/sess.rs +++ b/src/libsyntax/sess.rs @@ -1,7 +1,7 @@ //! Contains `ParseSess` which holds state living beyond what one `Parser` might. //! It also serves as an input to the parser itself. -use crate::ast::{CrateConfig, NodeId}; +use crate::ast::{CrateConfig, NodeId, Attribute}; use crate::early_buffered_lints::{BufferedEarlyLint, BufferedEarlyLintId}; use crate::source_map::{SourceMap, FilePathMapping}; use crate::feature_gate::UnstableFeatures; @@ -89,10 +89,22 @@ pub struct ParseSess { pub gated_spans: GatedSpans, /// The parser has reached `Eof` due to an unclosed brace. Used to silence unnecessary errors. pub reached_eof: Lock, + /// Process the potential `cfg` attributes on a module. + /// Also determine if the module should be included in this configuration. + /// + /// HACK(Centril): This is used to break a cyclic dependency between + /// the parser and cfg-stripping as defined in `syntax_expand::config`. + /// The dependency edge from the parser comes from `parse_item_mod`. + /// A principled solution to this hack would be to implement [#64197]. + /// + /// [#64197]: https://github.com/rust-lang/rust/issues/64197 + pub process_cfg_mod: ProcessCfgMod, } +pub type ProcessCfgMod = fn(&ParseSess, bool, &[Attribute]) -> (bool, Vec); + impl ParseSess { - pub fn new(file_path_mapping: FilePathMapping) -> Self { + pub fn new(file_path_mapping: FilePathMapping, process_cfg_mod: ProcessCfgMod) -> Self { let cm = Lrc::new(SourceMap::new(file_path_mapping)); let handler = Handler::with_tty_emitter( ColorConfig::Auto, @@ -100,12 +112,17 @@ impl ParseSess { None, Some(cm.clone()), ); - ParseSess::with_span_handler(handler, cm) + ParseSess::with_span_handler(handler, cm, process_cfg_mod) } - pub fn with_span_handler(handler: Handler, source_map: Lrc) -> Self { + pub fn with_span_handler( + handler: Handler, + source_map: Lrc, + process_cfg_mod: ProcessCfgMod, + ) -> Self { Self { span_diagnostic: handler, + process_cfg_mod, unstable_features: UnstableFeatures::from_environment(), config: FxHashSet::default(), edition: ExpnId::root().expn_data().edition, @@ -121,10 +138,10 @@ impl ParseSess { } } - pub fn with_silent_emitter() -> Self { + pub fn with_silent_emitter(process_cfg_mod: ProcessCfgMod) -> Self { let cm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let handler = Handler::with_emitter(false, None, Box::new(SilentEmitter)); - ParseSess::with_span_handler(handler, cm) + ParseSess::with_span_handler(handler, cm, process_cfg_mod) } #[inline] diff --git a/src/libsyntax/tests.rs b/src/libsyntax/tests.rs deleted file mode 100644 index ed457c3627f..00000000000 --- a/src/libsyntax/tests.rs +++ /dev/null @@ -1,1255 +0,0 @@ -use crate::ast; -use crate::parse::source_file_to_stream; -use crate::parse::new_parser_from_source_str; -use crate::parse::parser::Parser; -use crate::sess::ParseSess; -use crate::source_map::{SourceMap, FilePathMapping}; -use crate::tokenstream::TokenStream; -use crate::with_default_globals; - -use errors::emitter::EmitterWriter; -use errors::{PResult, Handler}; -use rustc_data_structures::sync::Lrc; -use syntax_pos::{BytePos, Span, MultiSpan}; - -use std::io; -use std::io::prelude::*; -use std::iter::Peekable; -use std::path::{Path, PathBuf}; -use std::str; -use std::sync::{Arc, Mutex}; - -/// Map string to parser (via tts). -fn string_to_parser(ps: &ParseSess, source_str: String) -> Parser<'_> { - new_parser_from_source_str(ps, PathBuf::from("bogofile").into(), source_str) -} - -crate fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> T where - F: FnOnce(&mut Parser<'a>) -> PResult<'a, T>, -{ - let mut p = string_to_parser(&ps, s); - let x = f(&mut p).unwrap(); - p.sess.span_diagnostic.abort_if_errors(); - x -} - -/// Maps a string to tts, using a made-up filename. -crate fn string_to_stream(source_str: String) -> TokenStream { - let ps = ParseSess::new(FilePathMapping::empty()); - source_file_to_stream( - &ps, - ps.source_map().new_source_file(PathBuf::from("bogofile").into(), - source_str, - ), None).0 -} - -/// Parses a string, returns a crate. -crate fn string_to_crate(source_str : String) -> ast::Crate { - let ps = ParseSess::new(FilePathMapping::empty()); - with_error_checking_parse(source_str, &ps, |p| { - p.parse_crate_mod() - }) -} - -/// Does the given string match the pattern? whitespace in the first string -/// may be deleted or replaced with other whitespace to match the pattern. -/// This function is relatively Unicode-ignorant; fortunately, the careful design -/// of UTF-8 mitigates this ignorance. It doesn't do NKF-normalization(?). -crate fn matches_codepattern(a : &str, b : &str) -> bool { - let mut a_iter = a.chars().peekable(); - let mut b_iter = b.chars().peekable(); - - loop { - let (a, b) = match (a_iter.peek(), b_iter.peek()) { - (None, None) => return true, - (None, _) => return false, - (Some(&a), None) => { - if rustc_lexer::is_whitespace(a) { - break // Trailing whitespace check is out of loop for borrowck. - } else { - return false - } - } - (Some(&a), Some(&b)) => (a, b) - }; - - if rustc_lexer::is_whitespace(a) && rustc_lexer::is_whitespace(b) { - // Skip whitespace for `a` and `b`. - scan_for_non_ws_or_end(&mut a_iter); - scan_for_non_ws_or_end(&mut b_iter); - } else if rustc_lexer::is_whitespace(a) { - // Skip whitespace for `a`. - scan_for_non_ws_or_end(&mut a_iter); - } else if a == b { - a_iter.next(); - b_iter.next(); - } else { - return false - } - } - - // Check if a has *only* trailing whitespace. - a_iter.all(rustc_lexer::is_whitespace) -} - -/// Advances the given peekable `Iterator` until it reaches a non-whitespace character. -fn scan_for_non_ws_or_end>(iter: &mut Peekable) { - while iter.peek().copied().map(|c| rustc_lexer::is_whitespace(c)) == Some(true) { - iter.next(); - } -} - -/// Identifies a position in the text by the n'th occurrence of a string. -struct Position { - string: &'static str, - count: usize, -} - -struct SpanLabel { - start: Position, - end: Position, - label: &'static str, -} - -crate struct Shared { - pub data: Arc>, -} - -impl Write for Shared { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.data.lock().unwrap().write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.data.lock().unwrap().flush() - } -} - -fn test_harness(file_text: &str, span_labels: Vec, expected_output: &str) { - with_default_globals(|| { - let output = Arc::new(Mutex::new(Vec::new())); - - let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty())); - source_map.new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned()); - - let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end); - let mut msp = MultiSpan::from_span(primary_span); - for span_label in span_labels { - let span = make_span(&file_text, &span_label.start, &span_label.end); - msp.push_span_label(span, span_label.label.to_string()); - println!("span: {:?} label: {:?}", span, span_label.label); - println!("text: {:?}", source_map.span_to_snippet(span)); - } - - let emitter = EmitterWriter::new( - Box::new(Shared { data: output.clone() }), - Some(source_map.clone()), - false, - false, - false, - None, - false, - ); - let handler = Handler::with_emitter(true, None, Box::new(emitter)); - handler.span_err(msp, "foo"); - - assert!(expected_output.chars().next() == Some('\n'), - "expected output should begin with newline"); - let expected_output = &expected_output[1..]; - - let bytes = output.lock().unwrap(); - let actual_output = str::from_utf8(&bytes).unwrap(); - println!("expected output:\n------\n{}------", expected_output); - println!("actual output:\n------\n{}------", actual_output); - - assert!(expected_output == actual_output) - }) -} - -fn make_span(file_text: &str, start: &Position, end: &Position) -> Span { - let start = make_pos(file_text, start); - let end = make_pos(file_text, end) + end.string.len(); // just after matching thing ends - assert!(start <= end); - Span::with_root_ctxt(BytePos(start as u32), BytePos(end as u32)) -} - -fn make_pos(file_text: &str, pos: &Position) -> usize { - let mut remainder = file_text; - let mut offset = 0; - for _ in 0..pos.count { - if let Some(n) = remainder.find(&pos.string) { - offset += n; - remainder = &remainder[n + 1..]; - } else { - panic!("failed to find {} instances of {:?} in {:?}", - pos.count, - pos.string, - file_text); - } - } - offset -} - -#[test] -fn ends_on_col0() { - test_harness(r#" -fn foo() { -} -"#, - vec![ - SpanLabel { - start: Position { - string: "{", - count: 1, - }, - end: Position { - string: "}", - count: 1, - }, - label: "test", - }, - ], - r#" -error: foo - --> test.rs:2:10 - | -2 | fn foo() { - | __________^ -3 | | } - | |_^ test - -"#); -} - -#[test] -fn ends_on_col2() { - test_harness(r#" -fn foo() { - - - } -"#, - vec![ - SpanLabel { - start: Position { - string: "{", - count: 1, - }, - end: Position { - string: "}", - count: 1, - }, - label: "test", - }, - ], - r#" -error: foo - --> test.rs:2:10 - | -2 | fn foo() { - | __________^ -3 | | -4 | | -5 | | } - | |___^ test - -"#); -} -#[test] -fn non_nested() { - test_harness(r#" -fn foo() { - X0 Y0 - X1 Y1 - X2 Y2 -} -"#, - vec![ - SpanLabel { - start: Position { - string: "X0", - count: 1, - }, - end: Position { - string: "X2", - count: 1, - }, - label: "`X` is a good letter", - }, - SpanLabel { - start: Position { - string: "Y0", - count: 1, - }, - end: Position { - string: "Y2", - count: 1, - }, - label: "`Y` is a good letter too", - }, - ], - r#" -error: foo - --> test.rs:3:3 - | -3 | X0 Y0 - | ____^__- - | | ___| - | || -4 | || X1 Y1 -5 | || X2 Y2 - | ||____^__- `Y` is a good letter too - | |____| - | `X` is a good letter - -"#); -} - -#[test] -fn nested() { - test_harness(r#" -fn foo() { - X0 Y0 - Y1 X1 -} -"#, - vec![ - SpanLabel { - start: Position { - string: "X0", - count: 1, - }, - end: Position { - string: "X1", - count: 1, - }, - label: "`X` is a good letter", - }, - SpanLabel { - start: Position { - string: "Y0", - count: 1, - }, - end: Position { - string: "Y1", - count: 1, - }, - label: "`Y` is a good letter too", - }, - ], -r#" -error: foo - --> test.rs:3:3 - | -3 | X0 Y0 - | ____^__- - | | ___| - | || -4 | || Y1 X1 - | ||____-__^ `X` is a good letter - | |_____| - | `Y` is a good letter too - -"#); -} - -#[test] -fn different_overlap() { - test_harness(r#" -fn foo() { - X0 Y0 Z0 - X1 Y1 Z1 - X2 Y2 Z2 - X3 Y3 Z3 -} -"#, - vec![ - SpanLabel { - start: Position { - string: "Y0", - count: 1, - }, - end: Position { - string: "X2", - count: 1, - }, - label: "`X` is a good letter", - }, - SpanLabel { - start: Position { - string: "Z1", - count: 1, - }, - end: Position { - string: "X3", - count: 1, - }, - label: "`Y` is a good letter too", - }, - ], - r#" -error: foo - --> test.rs:3:6 - | -3 | X0 Y0 Z0 - | ______^ -4 | | X1 Y1 Z1 - | |_________- -5 | || X2 Y2 Z2 - | ||____^ `X` is a good letter -6 | | X3 Y3 Z3 - | |_____- `Y` is a good letter too - -"#); -} - -#[test] -fn triple_overlap() { - test_harness(r#" -fn foo() { - X0 Y0 Z0 - X1 Y1 Z1 - X2 Y2 Z2 -} -"#, - vec![ - SpanLabel { - start: Position { - string: "X0", - count: 1, - }, - end: Position { - string: "X2", - count: 1, - }, - label: "`X` is a good letter", - }, - SpanLabel { - start: Position { - string: "Y0", - count: 1, - }, - end: Position { - string: "Y2", - count: 1, - }, - label: "`Y` is a good letter too", - }, - SpanLabel { - start: Position { - string: "Z0", - count: 1, - }, - end: Position { - string: "Z2", - count: 1, - }, - label: "`Z` label", - }, - ], - r#" -error: foo - --> test.rs:3:3 - | -3 | X0 Y0 Z0 - | _____^__-__- - | | ____|__| - | || ___| - | ||| -4 | ||| X1 Y1 Z1 -5 | ||| X2 Y2 Z2 - | |||____^__-__- `Z` label - | ||____|__| - | |____| `Y` is a good letter too - | `X` is a good letter - -"#); -} - -#[test] -fn triple_exact_overlap() { - test_harness(r#" -fn foo() { - X0 Y0 Z0 - X1 Y1 Z1 - X2 Y2 Z2 -} -"#, - vec![ - SpanLabel { - start: Position { - string: "X0", - count: 1, - }, - end: Position { - string: "X2", - count: 1, - }, - label: "`X` is a good letter", - }, - SpanLabel { - start: Position { - string: "X0", - count: 1, - }, - end: Position { - string: "X2", - count: 1, - }, - label: "`Y` is a good letter too", - }, - SpanLabel { - start: Position { - string: "X0", - count: 1, - }, - end: Position { - string: "X2", - count: 1, - }, - label: "`Z` label", - }, - ], - r#" -error: foo - --> test.rs:3:3 - | -3 | / X0 Y0 Z0 -4 | | X1 Y1 Z1 -5 | | X2 Y2 Z2 - | | ^ - | | | - | | `X` is a good letter - | |____`Y` is a good letter too - | `Z` label - -"#); -} - -#[test] -fn minimum_depth() { - test_harness(r#" -fn foo() { - X0 Y0 Z0 - X1 Y1 Z1 - X2 Y2 Z2 - X3 Y3 Z3 -} -"#, - vec![ - SpanLabel { - start: Position { - string: "Y0", - count: 1, - }, - end: Position { - string: "X1", - count: 1, - }, - label: "`X` is a good letter", - }, - SpanLabel { - start: Position { - string: "Y1", - count: 1, - }, - end: Position { - string: "Z2", - count: 1, - }, - label: "`Y` is a good letter too", - }, - SpanLabel { - start: Position { - string: "X2", - count: 1, - }, - end: Position { - string: "Y3", - count: 1, - }, - label: "`Z`", - }, - ], - r#" -error: foo - --> test.rs:3:6 - | -3 | X0 Y0 Z0 - | ______^ -4 | | X1 Y1 Z1 - | |____^_- - | ||____| - | | `X` is a good letter -5 | | X2 Y2 Z2 - | |____-______- `Y` is a good letter too - | ____| - | | -6 | | X3 Y3 Z3 - | |________- `Z` - -"#); -} - -#[test] -fn non_overlaping() { - test_harness(r#" -fn foo() { - X0 Y0 Z0 - X1 Y1 Z1 - X2 Y2 Z2 - X3 Y3 Z3 -} -"#, - vec![ - SpanLabel { - start: Position { - string: "X0", - count: 1, - }, - end: Position { - string: "X1", - count: 1, - }, - label: "`X` is a good letter", - }, - SpanLabel { - start: Position { - string: "Y2", - count: 1, - }, - end: Position { - string: "Z3", - count: 1, - }, - label: "`Y` is a good letter too", - }, - ], - r#" -error: foo - --> test.rs:3:3 - | -3 | / X0 Y0 Z0 -4 | | X1 Y1 Z1 - | |____^ `X` is a good letter -5 | X2 Y2 Z2 - | ______- -6 | | X3 Y3 Z3 - | |__________- `Y` is a good letter too - -"#); -} - -#[test] -fn overlaping_start_and_end() { - test_harness(r#" -fn foo() { - X0 Y0 Z0 - X1 Y1 Z1 - X2 Y2 Z2 - X3 Y3 Z3 -} -"#, - vec![ - SpanLabel { - start: Position { - string: "Y0", - count: 1, - }, - end: Position { - string: "X1", - count: 1, - }, - label: "`X` is a good letter", - }, - SpanLabel { - start: Position { - string: "Z1", - count: 1, - }, - end: Position { - string: "Z3", - count: 1, - }, - label: "`Y` is a good letter too", - }, - ], - r#" -error: foo - --> test.rs:3:6 - | -3 | X0 Y0 Z0 - | ______^ -4 | | X1 Y1 Z1 - | |____^____- - | ||____| - | | `X` is a good letter -5 | | X2 Y2 Z2 -6 | | X3 Y3 Z3 - | |___________- `Y` is a good letter too - -"#); -} - -#[test] -fn multiple_labels_primary_without_message() { - test_harness(r#" -fn foo() { - a { b { c } d } -} -"#, - vec![ - SpanLabel { - start: Position { - string: "b", - count: 1, - }, - end: Position { - string: "}", - count: 1, - }, - label: "", - }, - SpanLabel { - start: Position { - string: "a", - count: 1, - }, - end: Position { - string: "d", - count: 1, - }, - label: "`a` is a good letter", - }, - SpanLabel { - start: Position { - string: "c", - count: 1, - }, - end: Position { - string: "c", - count: 1, - }, - label: "", - }, - ], - r#" -error: foo - --> test.rs:3:7 - | -3 | a { b { c } d } - | ----^^^^-^^-- `a` is a good letter - -"#); -} - -#[test] -fn multiple_labels_secondary_without_message() { - test_harness(r#" -fn foo() { - a { b { c } d } -} -"#, - vec![ - SpanLabel { - start: Position { - string: "a", - count: 1, - }, - end: Position { - string: "d", - count: 1, - }, - label: "`a` is a good letter", - }, - SpanLabel { - start: Position { - string: "b", - count: 1, - }, - end: Position { - string: "}", - count: 1, - }, - label: "", - }, - ], - r#" -error: foo - --> test.rs:3:3 - | -3 | a { b { c } d } - | ^^^^-------^^ `a` is a good letter - -"#); -} - -#[test] -fn multiple_labels_primary_without_message_2() { - test_harness(r#" -fn foo() { - a { b { c } d } -} -"#, - vec![ - SpanLabel { - start: Position { - string: "b", - count: 1, - }, - end: Position { - string: "}", - count: 1, - }, - label: "`b` is a good letter", - }, - SpanLabel { - start: Position { - string: "a", - count: 1, - }, - end: Position { - string: "d", - count: 1, - }, - label: "", - }, - SpanLabel { - start: Position { - string: "c", - count: 1, - }, - end: Position { - string: "c", - count: 1, - }, - label: "", - }, - ], - r#" -error: foo - --> test.rs:3:7 - | -3 | a { b { c } d } - | ----^^^^-^^-- - | | - | `b` is a good letter - -"#); -} - -#[test] -fn multiple_labels_secondary_without_message_2() { - test_harness(r#" -fn foo() { - a { b { c } d } -} -"#, - vec![ - SpanLabel { - start: Position { - string: "a", - count: 1, - }, - end: Position { - string: "d", - count: 1, - }, - label: "", - }, - SpanLabel { - start: Position { - string: "b", - count: 1, - }, - end: Position { - string: "}", - count: 1, - }, - label: "`b` is a good letter", - }, - ], - r#" -error: foo - --> test.rs:3:3 - | -3 | a { b { c } d } - | ^^^^-------^^ - | | - | `b` is a good letter - -"#); -} - -#[test] -fn multiple_labels_secondary_without_message_3() { - test_harness(r#" -fn foo() { - a bc d -} -"#, - vec![ - SpanLabel { - start: Position { - string: "a", - count: 1, - }, - end: Position { - string: "b", - count: 1, - }, - label: "`a` is a good letter", - }, - SpanLabel { - start: Position { - string: "c", - count: 1, - }, - end: Position { - string: "d", - count: 1, - }, - label: "", - }, - ], - r#" -error: foo - --> test.rs:3:3 - | -3 | a bc d - | ^^^^---- - | | - | `a` is a good letter - -"#); -} - -#[test] -fn multiple_labels_without_message() { - test_harness(r#" -fn foo() { - a { b { c } d } -} -"#, - vec![ - SpanLabel { - start: Position { - string: "a", - count: 1, - }, - end: Position { - string: "d", - count: 1, - }, - label: "", - }, - SpanLabel { - start: Position { - string: "b", - count: 1, - }, - end: Position { - string: "}", - count: 1, - }, - label: "", - }, - ], - r#" -error: foo - --> test.rs:3:3 - | -3 | a { b { c } d } - | ^^^^-------^^ - -"#); -} - -#[test] -fn multiple_labels_without_message_2() { - test_harness(r#" -fn foo() { - a { b { c } d } -} -"#, - vec![ - SpanLabel { - start: Position { - string: "b", - count: 1, - }, - end: Position { - string: "}", - count: 1, - }, - label: "", - }, - SpanLabel { - start: Position { - string: "a", - count: 1, - }, - end: Position { - string: "d", - count: 1, - }, - label: "", - }, - SpanLabel { - start: Position { - string: "c", - count: 1, - }, - end: Position { - string: "c", - count: 1, - }, - label: "", - }, - ], - r#" -error: foo - --> test.rs:3:7 - | -3 | a { b { c } d } - | ----^^^^-^^-- - -"#); -} - -#[test] -fn multiple_labels_with_message() { - test_harness(r#" -fn foo() { - a { b { c } d } -} -"#, - vec![ - SpanLabel { - start: Position { - string: "a", - count: 1, - }, - end: Position { - string: "d", - count: 1, - }, - label: "`a` is a good letter", - }, - SpanLabel { - start: Position { - string: "b", - count: 1, - }, - end: Position { - string: "}", - count: 1, - }, - label: "`b` is a good letter", - }, - ], - r#" -error: foo - --> test.rs:3:3 - | -3 | a { b { c } d } - | ^^^^-------^^ - | | | - | | `b` is a good letter - | `a` is a good letter - -"#); -} - -#[test] -fn single_label_with_message() { - test_harness(r#" -fn foo() { - a { b { c } d } -} -"#, - vec![ - SpanLabel { - start: Position { - string: "a", - count: 1, - }, - end: Position { - string: "d", - count: 1, - }, - label: "`a` is a good letter", - }, - ], - r#" -error: foo - --> test.rs:3:3 - | -3 | a { b { c } d } - | ^^^^^^^^^^^^^ `a` is a good letter - -"#); -} - -#[test] -fn single_label_without_message() { - test_harness(r#" -fn foo() { - a { b { c } d } -} -"#, - vec![ - SpanLabel { - start: Position { - string: "a", - count: 1, - }, - end: Position { - string: "d", - count: 1, - }, - label: "", - }, - ], - r#" -error: foo - --> test.rs:3:3 - | -3 | a { b { c } d } - | ^^^^^^^^^^^^^ - -"#); -} - -#[test] -fn long_snippet() { - test_harness(r#" -fn foo() { - X0 Y0 Z0 - X1 Y1 Z1 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 - X2 Y2 Z2 - X3 Y3 Z3 -} -"#, - vec![ - SpanLabel { - start: Position { - string: "Y0", - count: 1, - }, - end: Position { - string: "X1", - count: 1, - }, - label: "`X` is a good letter", - }, - SpanLabel { - start: Position { - string: "Z1", - count: 1, - }, - end: Position { - string: "Z3", - count: 1, - }, - label: "`Y` is a good letter too", - }, - ], - r#" -error: foo - --> test.rs:3:6 - | -3 | X0 Y0 Z0 - | ______^ -4 | | X1 Y1 Z1 - | |____^____- - | ||____| - | | `X` is a good letter -5 | | 1 -6 | | 2 -7 | | 3 -... | -15 | | X2 Y2 Z2 -16 | | X3 Y3 Z3 - | |___________- `Y` is a good letter too - -"#); -} - -#[test] -fn long_snippet_multiple_spans() { - test_harness(r#" -fn foo() { - X0 Y0 Z0 -1 -2 -3 - X1 Y1 Z1 -4 -5 -6 - X2 Y2 Z2 -7 -8 -9 -10 - X3 Y3 Z3 -} -"#, - vec![ - SpanLabel { - start: Position { - string: "Y0", - count: 1, - }, - end: Position { - string: "Y3", - count: 1, - }, - label: "`Y` is a good letter", - }, - SpanLabel { - start: Position { - string: "Z1", - count: 1, - }, - end: Position { - string: "Z2", - count: 1, - }, - label: "`Z` is a good letter too", - }, - ], - r#" -error: foo - --> test.rs:3:6 - | -3 | X0 Y0 Z0 - | ______^ -4 | | 1 -5 | | 2 -6 | | 3 -7 | | X1 Y1 Z1 - | |_________- -8 | || 4 -9 | || 5 -10 | || 6 -11 | || X2 Y2 Z2 - | ||__________- `Z` is a good letter too -... | -15 | | 10 -16 | | X3 Y3 Z3 - | |_______^ `Y` is a good letter - -"#); -} diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 6e1bb85ce1a..4d08d0974c1 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -23,9 +23,6 @@ use smallvec::{SmallVec, smallvec}; use std::{iter, mem}; -#[cfg(test)] -mod tests; - /// When the main rust parser encounters a syntax-extension invocation, it /// parses the arguments to the invocation as a token-tree. This is a very /// loose structure, such that all sorts of different AST-fragments can @@ -218,7 +215,7 @@ impl TokenStream { self.0.len() } - pub(crate) fn from_streams(mut streams: SmallVec<[TokenStream; 2]>) -> TokenStream { + pub fn from_streams(mut streams: SmallVec<[TokenStream; 2]>) -> TokenStream { match streams.len() { 0 => TokenStream::default(), 1 => streams.pop().unwrap(), diff --git a/src/libsyntax/tokenstream/tests.rs b/src/libsyntax/tokenstream/tests.rs deleted file mode 100644 index 5017e5f5424..00000000000 --- a/src/libsyntax/tokenstream/tests.rs +++ /dev/null @@ -1,108 +0,0 @@ -use super::*; - -use crate::ast::Name; -use crate::with_default_globals; -use crate::tests::string_to_stream; -use syntax_pos::{Span, BytePos}; - -fn string_to_ts(string: &str) -> TokenStream { - string_to_stream(string.to_owned()) -} - -fn sp(a: u32, b: u32) -> Span { - Span::with_root_ctxt(BytePos(a), BytePos(b)) -} - -#[test] -fn test_concat() { - with_default_globals(|| { - let test_res = string_to_ts("foo::bar::baz"); - let test_fst = string_to_ts("foo::bar"); - let test_snd = string_to_ts("::baz"); - let eq_res = TokenStream::from_streams(smallvec![test_fst, test_snd]); - assert_eq!(test_res.trees().count(), 5); - assert_eq!(eq_res.trees().count(), 5); - assert_eq!(test_res.eq_unspanned(&eq_res), true); - }) -} - -#[test] -fn test_to_from_bijection() { - with_default_globals(|| { - let test_start = string_to_ts("foo::bar(baz)"); - let test_end = test_start.trees().collect(); - assert_eq!(test_start, test_end) - }) -} - -#[test] -fn test_eq_0() { - with_default_globals(|| { - let test_res = string_to_ts("foo"); - let test_eqs = string_to_ts("foo"); - assert_eq!(test_res, test_eqs) - }) -} - -#[test] -fn test_eq_1() { - with_default_globals(|| { - let test_res = string_to_ts("::bar::baz"); - let test_eqs = string_to_ts("::bar::baz"); - assert_eq!(test_res, test_eqs) - }) -} - -#[test] -fn test_eq_3() { - with_default_globals(|| { - let test_res = string_to_ts(""); - let test_eqs = string_to_ts(""); - assert_eq!(test_res, test_eqs) - }) -} - -#[test] -fn test_diseq_0() { - with_default_globals(|| { - let test_res = string_to_ts("::bar::baz"); - let test_eqs = string_to_ts("bar::baz"); - assert_eq!(test_res == test_eqs, false) - }) -} - -#[test] -fn test_diseq_1() { - with_default_globals(|| { - let test_res = string_to_ts("(bar,baz)"); - let test_eqs = string_to_ts("bar,baz"); - assert_eq!(test_res == test_eqs, false) - }) -} - -#[test] -fn test_is_empty() { - with_default_globals(|| { - let test0: TokenStream = Vec::::new().into_iter().collect(); - let test1: TokenStream = - TokenTree::token(token::Ident(Name::intern("a"), false), sp(0, 1)).into(); - let test2 = string_to_ts("foo(bar::baz)"); - - assert_eq!(test0.is_empty(), true); - assert_eq!(test1.is_empty(), false); - assert_eq!(test2.is_empty(), false); - }) -} - -#[test] -fn test_dotdotdot() { - with_default_globals(|| { - let mut builder = TokenStreamBuilder::new(); - builder.push(TokenTree::token(token::Dot, sp(0, 1)).joint()); - builder.push(TokenTree::token(token::Dot, sp(1, 2)).joint()); - builder.push(TokenTree::token(token::Dot, sp(2, 3))); - let stream = builder.build(); - assert!(stream.eq_unspanned(&string_to_ts("..."))); - assert_eq!(stream.trees().count(), 1); - }) -} diff --git a/src/libsyntax/util/comments.rs b/src/libsyntax/util/comments.rs index 448b4f3b825..ef9226a8879 100644 --- a/src/libsyntax/util/comments.rs +++ b/src/libsyntax/util/comments.rs @@ -47,7 +47,8 @@ crate fn is_block_doc_comment(s: &str) -> bool { res } -crate fn is_doc_comment(s: &str) -> bool { +// FIXME(#64197): Try to privatize this again. +pub fn is_doc_comment(s: &str) -> bool { (s.starts_with("///") && is_line_doc_comment(s)) || s.starts_with("//!") || (s.starts_with("/**") && is_block_doc_comment(s)) || s.starts_with("/*!") } diff --git a/src/libsyntax_expand/config.rs b/src/libsyntax_expand/config.rs new file mode 100644 index 00000000000..9acb9948926 --- /dev/null +++ b/src/libsyntax_expand/config.rs @@ -0,0 +1,365 @@ +use syntax::attr::HasAttrs; +use syntax::feature_gate::{ + feature_err, + EXPLAIN_STMT_ATTR_SYNTAX, + Features, + get_features, + GateIssue, +}; +use syntax::attr; +use syntax::ast; +use syntax::edition::Edition; +use syntax::mut_visit::*; +use syntax::parse::{self, validate_attr}; +use syntax::ptr::P; +use syntax::sess::ParseSess; +use syntax::symbol::sym; +use syntax::util::map_in_place::MapInPlace; + +use errors::Applicability; +use smallvec::SmallVec; + +/// A folder that strips out items that do not belong in the current configuration. +pub struct StripUnconfigured<'a> { + pub sess: &'a ParseSess, + pub features: Option<&'a Features>, +} + +// `cfg_attr`-process the crate's attributes and compute the crate's features. +pub fn features(mut krate: ast::Crate, sess: &ParseSess, edition: Edition, + allow_features: &Option>) -> (ast::Crate, Features) { + let features; + { + let mut strip_unconfigured = StripUnconfigured { + sess, + features: None, + }; + + let unconfigured_attrs = krate.attrs.clone(); + let err_count = sess.span_diagnostic.err_count(); + if let Some(attrs) = strip_unconfigured.configure(krate.attrs) { + krate.attrs = attrs; + } else { // the entire crate is unconfigured + krate.attrs = Vec::new(); + krate.module.items = Vec::new(); + return (krate, Features::new()); + } + + features = get_features(&sess.span_diagnostic, &krate.attrs, edition, allow_features); + + // Avoid reconfiguring malformed `cfg_attr`s + if err_count == sess.span_diagnostic.err_count() { + strip_unconfigured.features = Some(&features); + strip_unconfigured.configure(unconfigured_attrs); + } + } + + (krate, features) +} + +#[macro_export] +macro_rules! configure { + ($this:ident, $node:ident) => { + match $this.configure($node) { + Some(node) => node, + None => return Default::default(), + } + } +} + +impl<'a> StripUnconfigured<'a> { + pub fn configure(&mut self, mut node: T) -> Option { + self.process_cfg_attrs(&mut node); + if self.in_cfg(node.attrs()) { Some(node) } else { None } + } + + /// Parse and expand all `cfg_attr` attributes into a list of attributes + /// that are within each `cfg_attr` that has a true configuration predicate. + /// + /// Gives compiler warnigns if any `cfg_attr` does not contain any + /// attributes and is in the original source code. Gives compiler errors if + /// the syntax of any `cfg_attr` is incorrect. + pub fn process_cfg_attrs(&mut self, node: &mut T) { + node.visit_attrs(|attrs| { + attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr)); + }); + } + + /// Parse and expand a single `cfg_attr` attribute into a list of attributes + /// when the configuration predicate is true, or otherwise expand into an + /// empty list of attributes. + /// + /// Gives a compiler warning when the `cfg_attr` contains no attributes and + /// is in the original source file. Gives a compiler error if the syntax of + /// the attribute is incorrect. + fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec { + if !attr.has_name(sym::cfg_attr) { + return vec![attr]; + } + if attr.get_normal_item().tokens.is_empty() { + self.sess.span_diagnostic + .struct_span_err( + attr.span, + "malformed `cfg_attr` attribute input", + ).span_suggestion( + attr.span, + "missing condition and attribute", + "#[cfg_attr(condition, attribute, other_attribute, ...)]".to_owned(), + Applicability::HasPlaceholders, + ).note("for more information, visit \ + ") + .emit(); + return vec![]; + } + + let res = parse::parse_in_attr(self.sess, &attr, |p| p.parse_cfg_attr()); + let (cfg_predicate, expanded_attrs) = match res { + Ok(result) => result, + Err(mut e) => { + e.emit(); + return vec![]; + } + }; + + // Lint on zero attributes in source. + if expanded_attrs.is_empty() { + return vec![attr]; + } + + // At this point we know the attribute is considered used. + attr::mark_used(&attr); + + if attr::cfg_matches(&cfg_predicate, self.sess, self.features) { + // We call `process_cfg_attr` recursively in case there's a + // `cfg_attr` inside of another `cfg_attr`. E.g. + // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. + expanded_attrs.into_iter() + .flat_map(|(item, span)| self.process_cfg_attr(attr::mk_attr_from_item( + attr.style, + item, + span, + ))) + .collect() + } else { + vec![] + } + } + + /// Determines if a node with the given attributes should be included in this configuration. + pub fn in_cfg(&self, attrs: &[ast::Attribute]) -> bool { + attrs.iter().all(|attr| { + if !is_cfg(attr) { + return true; + } + + let error = |span, msg, suggestion: &str| { + let mut err = self.sess.span_diagnostic.struct_span_err(span, msg); + if !suggestion.is_empty() { + err.span_suggestion( + span, + "expected syntax is", + suggestion.into(), + Applicability::MaybeIncorrect, + ); + } + err.emit(); + true + }; + + let meta_item = match validate_attr::parse_meta(self.sess, attr) { + Ok(meta_item) => meta_item, + Err(mut err) => { err.emit(); return true; } + }; + let nested_meta_items = if let Some(nested_meta_items) = meta_item.meta_item_list() { + nested_meta_items + } else { + return error(meta_item.span, "`cfg` is not followed by parentheses", + "cfg(/* predicate */)"); + }; + + if nested_meta_items.is_empty() { + return error(meta_item.span, "`cfg` predicate is not specified", ""); + } else if nested_meta_items.len() > 1 { + return error(nested_meta_items.last().unwrap().span(), + "multiple `cfg` predicates are specified", ""); + } + + match nested_meta_items[0].meta_item() { + Some(meta_item) => attr::cfg_matches(meta_item, self.sess, self.features), + None => error(nested_meta_items[0].span(), + "`cfg` predicate key cannot be a literal", ""), + } + }) + } + + /// Visit attributes on expression and statements (but not attributes on items in blocks). + fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) { + // flag the offending attributes + for attr in attrs.iter() { + self.maybe_emit_expr_attr_err(attr); + } + } + + /// If attributes are not allowed on expressions, emit an error for `attr` + pub fn maybe_emit_expr_attr_err(&self, attr: &ast::Attribute) { + if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) { + let mut err = feature_err(self.sess, + sym::stmt_expr_attributes, + attr.span, + GateIssue::Language, + EXPLAIN_STMT_ATTR_SYNTAX); + + if attr.is_doc_comment() { + err.help("`///` is for documentation comments. For a plain comment, use `//`."); + } + + err.emit(); + } + } + + pub fn configure_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) { + let ast::ForeignMod { abi: _, items } = foreign_mod; + items.flat_map_in_place(|item| self.configure(item)); + } + + pub fn configure_generic_params(&mut self, params: &mut Vec) { + params.flat_map_in_place(|param| self.configure(param)); + } + + fn configure_variant_data(&mut self, vdata: &mut ast::VariantData) { + match vdata { + ast::VariantData::Struct(fields, ..) | ast::VariantData::Tuple(fields, _) => + fields.flat_map_in_place(|field| self.configure(field)), + ast::VariantData::Unit(_) => {} + } + } + + pub fn configure_item_kind(&mut self, item: &mut ast::ItemKind) { + match item { + ast::ItemKind::Struct(def, _generics) | + ast::ItemKind::Union(def, _generics) => self.configure_variant_data(def), + ast::ItemKind::Enum(ast::EnumDef { variants }, _generics) => { + variants.flat_map_in_place(|variant| self.configure(variant)); + for variant in variants { + self.configure_variant_data(&mut variant.data); + } + } + _ => {} + } + } + + pub fn configure_expr_kind(&mut self, expr_kind: &mut ast::ExprKind) { + match expr_kind { + ast::ExprKind::Match(_m, arms) => { + arms.flat_map_in_place(|arm| self.configure(arm)); + } + ast::ExprKind::Struct(_path, fields, _base) => { + fields.flat_map_in_place(|field| self.configure(field)); + } + _ => {} + } + } + + pub fn configure_expr(&mut self, expr: &mut P) { + self.visit_expr_attrs(expr.attrs()); + + // If an expr is valid to cfg away it will have been removed by the + // outer stmt or expression folder before descending in here. + // Anything else is always required, and thus has to error out + // in case of a cfg attr. + // + // N.B., this is intentionally not part of the visit_expr() function + // in order for filter_map_expr() to be able to avoid this check + if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) { + let msg = "removing an expression is not supported in this position"; + self.sess.span_diagnostic.span_err(attr.span, msg); + } + + self.process_cfg_attrs(expr) + } + + pub fn configure_pat(&mut self, pat: &mut P) { + if let ast::PatKind::Struct(_path, fields, _etc) = &mut pat.kind { + fields.flat_map_in_place(|field| self.configure(field)); + } + } + + pub fn configure_fn_decl(&mut self, fn_decl: &mut ast::FnDecl) { + fn_decl.inputs.flat_map_in_place(|arg| self.configure(arg)); + } +} + +impl<'a> MutVisitor for StripUnconfigured<'a> { + fn visit_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) { + self.configure_foreign_mod(foreign_mod); + noop_visit_foreign_mod(foreign_mod, self); + } + + fn visit_item_kind(&mut self, item: &mut ast::ItemKind) { + self.configure_item_kind(item); + noop_visit_item_kind(item, self); + } + + fn visit_expr(&mut self, expr: &mut P) { + self.configure_expr(expr); + self.configure_expr_kind(&mut expr.kind); + noop_visit_expr(expr, self); + } + + fn filter_map_expr(&mut self, expr: P) -> Option> { + let mut expr = configure!(self, expr); + self.configure_expr_kind(&mut expr.kind); + noop_visit_expr(&mut expr, self); + Some(expr) + } + + fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { + noop_flat_map_stmt(configure!(self, stmt), self) + } + + fn flat_map_item(&mut self, item: P) -> SmallVec<[P; 1]> { + noop_flat_map_item(configure!(self, item), self) + } + + fn flat_map_impl_item(&mut self, item: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> { + noop_flat_map_impl_item(configure!(self, item), self) + } + + fn flat_map_trait_item(&mut self, item: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> { + noop_flat_map_trait_item(configure!(self, item), self) + } + + fn visit_mac(&mut self, _mac: &mut ast::Mac) { + // Don't configure interpolated AST (cf. issue #34171). + // Interpolated AST will get configured once the surrounding tokens are parsed. + } + + fn visit_pat(&mut self, pat: &mut P) { + self.configure_pat(pat); + noop_visit_pat(pat, self) + } + + fn visit_fn_decl(&mut self, mut fn_decl: &mut P) { + self.configure_fn_decl(&mut fn_decl); + noop_visit_fn_decl(fn_decl, self); + } +} + +fn is_cfg(attr: &ast::Attribute) -> bool { + attr.check_name(sym::cfg) +} + +/// Process the potential `cfg` attributes on a module. +/// Also determine if the module should be included in this configuration. +pub fn process_configure_mod( + sess: &ParseSess, + cfg_mods: bool, + attrs: &[ast::Attribute], +) -> (bool, Vec) { + // Don't perform gated feature checking. + let mut strip_unconfigured = StripUnconfigured { sess, features: None }; + let mut attrs = attrs.to_owned(); + strip_unconfigured.process_cfg_attrs(&mut attrs); + (!cfg_mods || strip_unconfigured.in_cfg(&attrs), attrs) +} diff --git a/src/libsyntax_expand/expand.rs b/src/libsyntax_expand/expand.rs index d0b60fa308d..1e6c23087d8 100644 --- a/src/libsyntax_expand/expand.rs +++ b/src/libsyntax_expand/expand.rs @@ -3,13 +3,13 @@ use crate::proc_macro::{collect_derives, MarkAttrs}; use crate::hygiene::{ExpnId, SyntaxContext, ExpnData, ExpnKind}; use crate::mbe::macro_rules::annotate_err_with_kind; use crate::placeholders::{placeholder, PlaceholderExpander}; +use crate::config::StripUnconfigured; +use crate::configure; use syntax::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path}; use syntax::ast::{MacStmtStyle, StmtKind, ItemKind}; use syntax::attr::{self, HasAttrs}; use syntax::source_map::respan; -use syntax::configure; -use syntax::config::StripUnconfigured; use syntax::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err}; use syntax::mut_visit::*; use syntax::parse::DirectoryOwnership; diff --git a/src/libsyntax_expand/lib.rs b/src/libsyntax_expand/lib.rs index 10eb3ecb20b..46d59dd249c 100644 --- a/src/libsyntax_expand/lib.rs +++ b/src/libsyntax_expand/lib.rs @@ -33,6 +33,35 @@ pub use mbe::macro_rules::compile_declarative_macro; pub mod base; pub mod build; pub mod expand; +#[macro_use] pub mod config; pub mod proc_macro; crate mod mbe; + +// HACK(Centril, #64197): These shouldn't really be here. +// Rather, they should be with their respective modules which are defined in other crates. +// However, since for now constructing a `ParseSess` sorta requires `config` from this crate, +// these tests will need to live here in the iterim. + +#[cfg(test)] +mod tests; +#[cfg(test)] +mod parse { + #[cfg(test)] + mod tests; + #[cfg(test)] + mod lexer { + #[cfg(test)] + mod tests; + } +} +#[cfg(test)] +mod tokenstream { + #[cfg(test)] + mod tests; +} +#[cfg(test)] +mod mut_visit { + #[cfg(test)] + mod tests; +} diff --git a/src/libsyntax_expand/mut_visit/tests.rs b/src/libsyntax_expand/mut_visit/tests.rs new file mode 100644 index 00000000000..30e812a1179 --- /dev/null +++ b/src/libsyntax_expand/mut_visit/tests.rs @@ -0,0 +1,70 @@ +use crate::tests::{string_to_crate, matches_codepattern}; + +use syntax::ast::{self, Ident}; +use syntax::print::pprust; +use syntax::mut_visit::{self, MutVisitor}; +use syntax::with_default_globals; + +// This version doesn't care about getting comments or doc-strings in. +fn fake_print_crate(s: &mut pprust::State<'_>, + krate: &ast::Crate) { + s.print_mod(&krate.module, &krate.attrs) +} + +// Change every identifier to "zz". +struct ToZzIdentMutVisitor; + +impl MutVisitor for ToZzIdentMutVisitor { + fn visit_ident(&mut self, ident: &mut ast::Ident) { + *ident = Ident::from_str("zz"); + } + fn visit_mac(&mut self, mac: &mut ast::Mac) { + mut_visit::noop_visit_mac(mac, self) + } +} + +// Maybe add to `expand.rs`. +macro_rules! assert_pred { + ($pred:expr, $predname:expr, $a:expr , $b:expr) => ( + { + let pred_val = $pred; + let a_val = $a; + let b_val = $b; + if !(pred_val(&a_val, &b_val)) { + panic!("expected args satisfying {}, got {} and {}", + $predname, a_val, b_val); + } + } + ) +} + +// Make sure idents get transformed everywhere. +#[test] fn ident_transformation () { + with_default_globals(|| { + let mut zz_visitor = ToZzIdentMutVisitor; + let mut krate = string_to_crate( + "#[a] mod b {fn c (d : e, f : g) {h!(i,j,k);l;m}}".to_string()); + zz_visitor.visit_crate(&mut krate); + assert_pred!( + matches_codepattern, + "matches_codepattern", + pprust::to_string(|s| fake_print_crate(s, &krate)), + "#[zz]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string()); + }) +} + +// Make sure idents get transformed even inside macro defs. +#[test] fn ident_transformation_in_defs () { + with_default_globals(|| { + let mut zz_visitor = ToZzIdentMutVisitor; + let mut krate = string_to_crate( + "macro_rules! a {(b $c:expr $(d $e:token)f+ => \ + (g $(d $d $e)+))} ".to_string()); + zz_visitor.visit_crate(&mut krate); + assert_pred!( + matches_codepattern, + "matches_codepattern", + pprust::to_string(|s| fake_print_crate(s, &krate)), + "macro_rules! zz{(zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+))}".to_string()); + }) +} diff --git a/src/libsyntax_expand/parse/lexer/tests.rs b/src/libsyntax_expand/parse/lexer/tests.rs new file mode 100644 index 00000000000..3d5726fa601 --- /dev/null +++ b/src/libsyntax_expand/parse/lexer/tests.rs @@ -0,0 +1,277 @@ +use crate::config::process_configure_mod; + +use rustc_data_structures::sync::Lrc; +use syntax::token::{self, Token, TokenKind}; +use syntax::sess::ParseSess; +use syntax::source_map::{SourceMap, FilePathMapping}; +use syntax::util::comments::is_doc_comment; +use syntax::with_default_globals; +use syntax::parse::lexer::StringReader; +use syntax_pos::symbol::Symbol; + +use errors::{Handler, emitter::EmitterWriter}; +use std::io; +use std::path::PathBuf; +use syntax_pos::{BytePos, Span}; + +fn mk_sess(sm: Lrc) -> ParseSess { + let emitter = EmitterWriter::new( + Box::new(io::sink()), + Some(sm.clone()), + false, + false, + false, + None, + false, + ); + ParseSess::with_span_handler( + Handler::with_emitter(true, None, Box::new(emitter)), + sm, + process_configure_mod, + ) +} + +// Creates a string reader for the given string. +fn setup<'a>(sm: &SourceMap, + sess: &'a ParseSess, + teststr: String) + -> StringReader<'a> { + let sf = sm.new_source_file(PathBuf::from(teststr.clone()).into(), teststr); + StringReader::new(sess, sf, None) +} + +#[test] +fn t1() { + with_default_globals(|| { + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let sh = mk_sess(sm.clone()); + let mut string_reader = setup( + &sm, + &sh, + "/* my source file */ fn main() { println!(\"zebra\"); }\n".to_string(), + ); + assert_eq!(string_reader.next_token(), token::Comment); + assert_eq!(string_reader.next_token(), token::Whitespace); + let tok1 = string_reader.next_token(); + let tok2 = Token::new( + mk_ident("fn"), + Span::with_root_ctxt(BytePos(21), BytePos(23)), + ); + assert_eq!(tok1.kind, tok2.kind); + assert_eq!(tok1.span, tok2.span); + assert_eq!(string_reader.next_token(), token::Whitespace); + // Read another token. + let tok3 = string_reader.next_token(); + assert_eq!(string_reader.pos.clone(), BytePos(28)); + let tok4 = Token::new( + mk_ident("main"), + Span::with_root_ctxt(BytePos(24), BytePos(28)), + ); + assert_eq!(tok3.kind, tok4.kind); + assert_eq!(tok3.span, tok4.span); + + assert_eq!(string_reader.next_token(), token::OpenDelim(token::Paren)); + assert_eq!(string_reader.pos.clone(), BytePos(29)) + }) +} + +// Checks that the given reader produces the desired stream +// of tokens (stop checking after exhausting `expected`). +fn check_tokenization(mut string_reader: StringReader<'_>, expected: Vec) { + for expected_tok in &expected { + assert_eq!(&string_reader.next_token(), expected_tok); + } +} + +// Makes the identifier by looking up the string in the interner. +fn mk_ident(id: &str) -> TokenKind { + token::Ident(Symbol::intern(id), false) +} + +fn mk_lit(kind: token::LitKind, symbol: &str, suffix: Option<&str>) -> TokenKind { + TokenKind::lit(kind, Symbol::intern(symbol), suffix.map(Symbol::intern)) +} + +#[test] +fn doublecolon_parsing() { + with_default_globals(|| { + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let sh = mk_sess(sm.clone()); + check_tokenization( + setup(&sm, &sh, "a b".to_string()), + vec![mk_ident("a"), token::Whitespace, mk_ident("b")], + ); + }) +} + +#[test] +fn doublecolon_parsing_2() { + with_default_globals(|| { + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let sh = mk_sess(sm.clone()); + check_tokenization( + setup(&sm, &sh, "a::b".to_string()), + vec![mk_ident("a"), token::Colon, token::Colon, mk_ident("b")], + ); + }) +} + +#[test] +fn doublecolon_parsing_3() { + with_default_globals(|| { + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let sh = mk_sess(sm.clone()); + check_tokenization( + setup(&sm, &sh, "a ::b".to_string()), + vec![mk_ident("a"), token::Whitespace, token::Colon, token::Colon, mk_ident("b")], + ); + }) +} + +#[test] +fn doublecolon_parsing_4() { + with_default_globals(|| { + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let sh = mk_sess(sm.clone()); + check_tokenization( + setup(&sm, &sh, "a:: b".to_string()), + vec![mk_ident("a"), token::Colon, token::Colon, token::Whitespace, mk_ident("b")], + ); + }) +} + +#[test] +fn character_a() { + with_default_globals(|| { + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let sh = mk_sess(sm.clone()); + assert_eq!( + setup(&sm, &sh, "'a'".to_string()).next_token(), + mk_lit(token::Char, "a", None), + ); + }) +} + +#[test] +fn character_space() { + with_default_globals(|| { + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let sh = mk_sess(sm.clone()); + assert_eq!( + setup(&sm, &sh, "' '".to_string()).next_token(), + mk_lit(token::Char, " ", None), + ); + }) +} + +#[test] +fn character_escaped() { + with_default_globals(|| { + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let sh = mk_sess(sm.clone()); + assert_eq!( + setup(&sm, &sh, "'\\n'".to_string()).next_token(), + mk_lit(token::Char, "\\n", None), + ); + }) +} + +#[test] +fn lifetime_name() { + with_default_globals(|| { + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let sh = mk_sess(sm.clone()); + assert_eq!( + setup(&sm, &sh, "'abc".to_string()).next_token(), + token::Lifetime(Symbol::intern("'abc")), + ); + }) +} + +#[test] +fn raw_string() { + with_default_globals(|| { + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let sh = mk_sess(sm.clone()); + assert_eq!( + setup(&sm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token(), + mk_lit(token::StrRaw(3), "\"#a\\b\x00c\"", None), + ); + }) +} + +#[test] +fn literal_suffixes() { + with_default_globals(|| { + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let sh = mk_sess(sm.clone()); + macro_rules! test { + ($input: expr, $tok_type: ident, $tok_contents: expr) => {{ + assert_eq!( + setup(&sm, &sh, format!("{}suffix", $input)).next_token(), + mk_lit(token::$tok_type, $tok_contents, Some("suffix")), + ); + // with a whitespace separator + assert_eq!( + setup(&sm, &sh, format!("{} suffix", $input)).next_token(), + mk_lit(token::$tok_type, $tok_contents, None), + ); + }} + } + + test!("'a'", Char, "a"); + test!("b'a'", Byte, "a"); + test!("\"a\"", Str, "a"); + test!("b\"a\"", ByteStr, "a"); + test!("1234", Integer, "1234"); + test!("0b101", Integer, "0b101"); + test!("0xABC", Integer, "0xABC"); + test!("1.0", Float, "1.0"); + test!("1.0e10", Float, "1.0e10"); + + assert_eq!( + setup(&sm, &sh, "2us".to_string()).next_token(), + mk_lit(token::Integer, "2", Some("us")), + ); + assert_eq!( + setup(&sm, &sh, "r###\"raw\"###suffix".to_string()).next_token(), + mk_lit(token::StrRaw(3), "raw", Some("suffix")), + ); + assert_eq!( + setup(&sm, &sh, "br###\"raw\"###suffix".to_string()).next_token(), + mk_lit(token::ByteStrRaw(3), "raw", Some("suffix")), + ); + }) +} + +#[test] +fn line_doc_comments() { + assert!(is_doc_comment("///")); + assert!(is_doc_comment("/// blah")); + assert!(!is_doc_comment("////")); +} + +#[test] +fn nested_block_comments() { + with_default_globals(|| { + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let sh = mk_sess(sm.clone()); + let mut lexer = setup(&sm, &sh, "/* /* */ */'a'".to_string()); + assert_eq!(lexer.next_token(), token::Comment); + assert_eq!(lexer.next_token(), mk_lit(token::Char, "a", None)); + }) +} + +#[test] +fn crlf_comments() { + with_default_globals(|| { + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let sh = mk_sess(sm.clone()); + let mut lexer = setup(&sm, &sh, "// test\r\n/// test\r\n".to_string()); + let comment = lexer.next_token(); + assert_eq!(comment.kind, token::Comment); + assert_eq!((comment.span.lo(), comment.span.hi()), (BytePos(0), BytePos(7))); + assert_eq!(lexer.next_token(), token::Whitespace); + assert_eq!(lexer.next_token(), token::DocComment(Symbol::intern("/// test"))); + }) +} diff --git a/src/libsyntax_expand/parse/tests.rs b/src/libsyntax_expand/parse/tests.rs new file mode 100644 index 00000000000..01739809f7f --- /dev/null +++ b/src/libsyntax_expand/parse/tests.rs @@ -0,0 +1,338 @@ +use crate::config::process_configure_mod; +use crate::tests::{matches_codepattern, string_to_stream, with_error_checking_parse}; + +use syntax::ast::{self, Name, PatKind}; +use syntax::attr::first_attr_value_str_by_name; +use syntax::sess::ParseSess; +use syntax::token::{self, Token}; +use syntax::print::pprust::item_to_string; +use syntax::ptr::P; +use syntax::source_map::FilePathMapping; +use syntax::symbol::{kw, sym}; +use syntax::tokenstream::{DelimSpan, TokenTree, TokenStream}; +use syntax::visit; +use syntax::with_default_globals; +use syntax::parse::new_parser_from_source_str; +use syntax_pos::{Span, BytePos, Pos, FileName}; +use errors::PResult; + +use std::path::PathBuf; + +fn sess() -> ParseSess { + ParseSess::new(FilePathMapping::empty(), process_configure_mod) +} + +/// Parses an item. +/// +/// Returns `Ok(Some(item))` when successful, `Ok(None)` when no item was found, and `Err` +/// when a syntax error occurred. +fn parse_item_from_source_str(name: FileName, source: String, sess: &ParseSess) + -> PResult<'_, Option>> { + new_parser_from_source_str(sess, name, source).parse_item() +} + +// Produces a `syntax_pos::span`. +fn sp(a: u32, b: u32) -> Span { + Span::with_root_ctxt(BytePos(a), BytePos(b)) +} + +/// Parses a string, return an expression. +fn string_to_expr(source_str : String) -> P { + with_error_checking_parse(source_str, &sess(), |p| p.parse_expr()) +} + +/// Parses a string, returns an item. +fn string_to_item(source_str : String) -> Option> { + with_error_checking_parse(source_str, &sess(), |p| p.parse_item()) +} + +#[should_panic] +#[test] fn bad_path_expr_1() { + with_default_globals(|| { + string_to_expr("::abc::def::return".to_string()); + }) +} + +// Checks the token-tree-ization of macros. +#[test] +fn string_to_tts_macro () { + with_default_globals(|| { + let tts: Vec<_> = + string_to_stream("macro_rules! zip (($a)=>($a))".to_string()).trees().collect(); + let tts: &[TokenTree] = &tts[..]; + + match tts { + [ + TokenTree::Token(Token { kind: token::Ident(name_macro_rules, false), .. }), + TokenTree::Token(Token { kind: token::Not, .. }), + TokenTree::Token(Token { kind: token::Ident(name_zip, false), .. }), + TokenTree::Delimited(_, macro_delim, macro_tts) + ] + if name_macro_rules == &sym::macro_rules && name_zip.as_str() == "zip" => { + let tts = ¯o_tts.trees().collect::>(); + match &tts[..] { + [ + TokenTree::Delimited(_, first_delim, first_tts), + TokenTree::Token(Token { kind: token::FatArrow, .. }), + TokenTree::Delimited(_, second_delim, second_tts), + ] + if macro_delim == &token::Paren => { + let tts = &first_tts.trees().collect::>(); + match &tts[..] { + [ + TokenTree::Token(Token { kind: token::Dollar, .. }), + TokenTree::Token(Token { kind: token::Ident(name, false), .. }), + ] + if first_delim == &token::Paren && name.as_str() == "a" => {}, + _ => panic!("value 3: {:?} {:?}", first_delim, first_tts), + } + let tts = &second_tts.trees().collect::>(); + match &tts[..] { + [ + TokenTree::Token(Token { kind: token::Dollar, .. }), + TokenTree::Token(Token { kind: token::Ident(name, false), .. }), + ] + if second_delim == &token::Paren && name.as_str() == "a" => {}, + _ => panic!("value 4: {:?} {:?}", second_delim, second_tts), + } + }, + _ => panic!("value 2: {:?} {:?}", macro_delim, macro_tts), + } + }, + _ => panic!("value: {:?}",tts), + } + }) +} + +#[test] +fn string_to_tts_1() { + with_default_globals(|| { + let tts = string_to_stream("fn a (b : i32) { b; }".to_string()); + + let expected = TokenStream::new(vec![ + TokenTree::token(token::Ident(kw::Fn, false), sp(0, 2)).into(), + TokenTree::token(token::Ident(Name::intern("a"), false), sp(3, 4)).into(), + TokenTree::Delimited( + DelimSpan::from_pair(sp(5, 6), sp(13, 14)), + token::DelimToken::Paren, + TokenStream::new(vec![ + TokenTree::token(token::Ident(Name::intern("b"), false), sp(6, 7)).into(), + TokenTree::token(token::Colon, sp(8, 9)).into(), + TokenTree::token(token::Ident(sym::i32, false), sp(10, 13)).into(), + ]).into(), + ).into(), + TokenTree::Delimited( + DelimSpan::from_pair(sp(15, 16), sp(20, 21)), + token::DelimToken::Brace, + TokenStream::new(vec![ + TokenTree::token(token::Ident(Name::intern("b"), false), sp(17, 18)).into(), + TokenTree::token(token::Semi, sp(18, 19)).into(), + ]).into(), + ).into() + ]); + + assert_eq!(tts, expected); + }) +} + +#[test] fn parse_use() { + with_default_globals(|| { + let use_s = "use foo::bar::baz;"; + let vitem = string_to_item(use_s.to_string()).unwrap(); + let vitem_s = item_to_string(&vitem); + assert_eq!(&vitem_s[..], use_s); + + let use_s = "use foo::bar as baz;"; + let vitem = string_to_item(use_s.to_string()).unwrap(); + let vitem_s = item_to_string(&vitem); + assert_eq!(&vitem_s[..], use_s); + }) +} + +#[test] fn parse_extern_crate() { + with_default_globals(|| { + let ex_s = "extern crate foo;"; + let vitem = string_to_item(ex_s.to_string()).unwrap(); + let vitem_s = item_to_string(&vitem); + assert_eq!(&vitem_s[..], ex_s); + + let ex_s = "extern crate foo as bar;"; + let vitem = string_to_item(ex_s.to_string()).unwrap(); + let vitem_s = item_to_string(&vitem); + assert_eq!(&vitem_s[..], ex_s); + }) +} + +fn get_spans_of_pat_idents(src: &str) -> Vec { + let item = string_to_item(src.to_string()).unwrap(); + + struct PatIdentVisitor { + spans: Vec + } + impl<'a> visit::Visitor<'a> for PatIdentVisitor { + fn visit_pat(&mut self, p: &'a ast::Pat) { + match p.kind { + PatKind::Ident(_ , ref ident, _) => { + self.spans.push(ident.span.clone()); + } + _ => { + visit::walk_pat(self, p); + } + } + } + } + let mut v = PatIdentVisitor { spans: Vec::new() }; + visit::walk_item(&mut v, &item); + return v.spans; +} + +#[test] fn span_of_self_arg_pat_idents_are_correct() { + with_default_globals(|| { + + let srcs = ["impl z { fn a (&self, &myarg: i32) {} }", + "impl z { fn a (&mut self, &myarg: i32) {} }", + "impl z { fn a (&'a self, &myarg: i32) {} }", + "impl z { fn a (self, &myarg: i32) {} }", + "impl z { fn a (self: Foo, &myarg: i32) {} }", + ]; + + for &src in &srcs { + let spans = get_spans_of_pat_idents(src); + let (lo, hi) = (spans[0].lo(), spans[0].hi()); + assert!("self" == &src[lo.to_usize()..hi.to_usize()], + "\"{}\" != \"self\". src=\"{}\"", + &src[lo.to_usize()..hi.to_usize()], src) + } + }) +} + +#[test] fn parse_exprs () { + with_default_globals(|| { + // just make sure that they parse.... + string_to_expr("3 + 4".to_string()); + string_to_expr("a::z.froob(b,&(987+3))".to_string()); + }) +} + +#[test] fn attrs_fix_bug () { + with_default_globals(|| { + string_to_item("pub fn mk_file_writer(path: &Path, flags: &[FileFlag]) + -> Result, String> { +#[cfg(windows)] +fn wb() -> c_int { + (O_WRONLY | libc::consts::os::extra::O_BINARY) as c_int +} + +#[cfg(unix)] +fn wb() -> c_int { O_WRONLY as c_int } + +let mut fflags: c_int = wb(); +}".to_string()); + }) +} + +#[test] fn crlf_doc_comments() { + with_default_globals(|| { + let sess = sess(); + + let name_1 = FileName::Custom("crlf_source_1".to_string()); + let source = "/// doc comment\r\nfn foo() {}".to_string(); + let item = parse_item_from_source_str(name_1, source, &sess) + .unwrap().unwrap(); + let doc = first_attr_value_str_by_name(&item.attrs, sym::doc).unwrap(); + assert_eq!(doc.as_str(), "/// doc comment"); + + let name_2 = FileName::Custom("crlf_source_2".to_string()); + let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string(); + let item = parse_item_from_source_str(name_2, source, &sess) + .unwrap().unwrap(); + let docs = item.attrs.iter().filter(|a| a.has_name(sym::doc)) + .map(|a| a.value_str().unwrap().to_string()).collect::>(); + let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()]; + assert_eq!(&docs[..], b); + + let name_3 = FileName::Custom("clrf_source_3".to_string()); + let source = "/** doc comment\r\n * with CRLF */\r\nfn foo() {}".to_string(); + let item = parse_item_from_source_str(name_3, source, &sess).unwrap().unwrap(); + let doc = first_attr_value_str_by_name(&item.attrs, sym::doc).unwrap(); + assert_eq!(doc.as_str(), "/** doc comment\n * with CRLF */"); + }); +} + +#[test] +fn ttdelim_span() { + fn parse_expr_from_source_str( + name: FileName, source: String, sess: &ParseSess + ) -> PResult<'_, P> { + new_parser_from_source_str(sess, name, source).parse_expr() + } + + with_default_globals(|| { + let sess = sess(); + let expr = parse_expr_from_source_str(PathBuf::from("foo").into(), + "foo!( fn main() { body } )".to_string(), &sess).unwrap(); + + let tts: Vec<_> = match expr.kind { + ast::ExprKind::Mac(ref mac) => mac.stream().trees().collect(), + _ => panic!("not a macro"), + }; + + let span = tts.iter().rev().next().unwrap().span(); + + match sess.source_map().span_to_snippet(span) { + Ok(s) => assert_eq!(&s[..], "{ body }"), + Err(_) => panic!("could not get snippet"), + } + }); +} + +// This tests that when parsing a string (rather than a file) we don't try +// and read in a file for a module declaration and just parse a stub. +// See `recurse_into_file_modules` in the parser. +#[test] +fn out_of_line_mod() { + with_default_globals(|| { + let item = parse_item_from_source_str( + PathBuf::from("foo").into(), + "mod foo { struct S; mod this_does_not_exist; }".to_owned(), + &sess(), + ).unwrap().unwrap(); + + if let ast::ItemKind::Mod(ref m) = item.kind { + assert!(m.items.len() == 2); + } else { + panic!(); + } + }); +} + +#[test] +fn eqmodws() { + assert_eq!(matches_codepattern("",""),true); + assert_eq!(matches_codepattern("","a"),false); + assert_eq!(matches_codepattern("a",""),false); + assert_eq!(matches_codepattern("a","a"),true); + assert_eq!(matches_codepattern("a b","a \n\t\r b"),true); + assert_eq!(matches_codepattern("a b ","a \n\t\r b"),true); + assert_eq!(matches_codepattern("a b","a \n\t\r b "),false); + assert_eq!(matches_codepattern("a b","a b"),true); + assert_eq!(matches_codepattern("ab","a b"),false); + assert_eq!(matches_codepattern("a b","ab"),true); + assert_eq!(matches_codepattern(" a b","ab"),true); +} + +#[test] +fn pattern_whitespace() { + assert_eq!(matches_codepattern("","\x0C"), false); + assert_eq!(matches_codepattern("a b ","a \u{0085}\n\t\r b"),true); + assert_eq!(matches_codepattern("a b","a \u{0085}\n\t\r b "),false); +} + +#[test] +fn non_pattern_whitespace() { + // These have the property 'White_Space' but not 'Pattern_White_Space' + assert_eq!(matches_codepattern("a b","a\u{2002}b"), false); + assert_eq!(matches_codepattern("a b","a\u{2002}b"), false); + assert_eq!(matches_codepattern("\u{205F}a b","ab"), false); + assert_eq!(matches_codepattern("a \u{3000}b","ab"), false); +} diff --git a/src/libsyntax_expand/tests.rs b/src/libsyntax_expand/tests.rs new file mode 100644 index 00000000000..461d9a43954 --- /dev/null +++ b/src/libsyntax_expand/tests.rs @@ -0,0 +1,1254 @@ +use crate::config::process_configure_mod; +use syntax::ast; +use syntax::tokenstream::TokenStream; +use syntax::sess::ParseSess; +use syntax::source_map::{SourceMap, FilePathMapping}; +use syntax::with_default_globals; +use syntax::parse::{source_file_to_stream, new_parser_from_source_str, parser::Parser}; +use syntax_pos::{BytePos, Span, MultiSpan}; + +use errors::emitter::EmitterWriter; +use errors::{PResult, Handler}; +use rustc_data_structures::sync::Lrc; + +use std::io; +use std::io::prelude::*; +use std::iter::Peekable; +use std::path::{Path, PathBuf}; +use std::str; +use std::sync::{Arc, Mutex}; + +/// Map string to parser (via tts). +fn string_to_parser(ps: &ParseSess, source_str: String) -> Parser<'_> { + new_parser_from_source_str(ps, PathBuf::from("bogofile").into(), source_str) +} + +crate fn with_error_checking_parse<'a, T, F>(s: String, ps: &'a ParseSess, f: F) -> T where + F: FnOnce(&mut Parser<'a>) -> PResult<'a, T>, +{ + let mut p = string_to_parser(&ps, s); + let x = f(&mut p).unwrap(); + p.sess.span_diagnostic.abort_if_errors(); + x +} + +/// Maps a string to tts, using a made-up filename. +crate fn string_to_stream(source_str: String) -> TokenStream { + let ps = ParseSess::new(FilePathMapping::empty(), process_configure_mod); + source_file_to_stream( + &ps, + ps.source_map().new_source_file(PathBuf::from("bogofile").into(), + source_str, + ), None).0 +} + +/// Parses a string, returns a crate. +crate fn string_to_crate(source_str : String) -> ast::Crate { + let ps = ParseSess::new(FilePathMapping::empty(), process_configure_mod); + with_error_checking_parse(source_str, &ps, |p| { + p.parse_crate_mod() + }) +} + +/// Does the given string match the pattern? whitespace in the first string +/// may be deleted or replaced with other whitespace to match the pattern. +/// This function is relatively Unicode-ignorant; fortunately, the careful design +/// of UTF-8 mitigates this ignorance. It doesn't do NKF-normalization(?). +crate fn matches_codepattern(a : &str, b : &str) -> bool { + let mut a_iter = a.chars().peekable(); + let mut b_iter = b.chars().peekable(); + + loop { + let (a, b) = match (a_iter.peek(), b_iter.peek()) { + (None, None) => return true, + (None, _) => return false, + (Some(&a), None) => { + if rustc_lexer::is_whitespace(a) { + break // Trailing whitespace check is out of loop for borrowck. + } else { + return false + } + } + (Some(&a), Some(&b)) => (a, b) + }; + + if rustc_lexer::is_whitespace(a) && rustc_lexer::is_whitespace(b) { + // Skip whitespace for `a` and `b`. + scan_for_non_ws_or_end(&mut a_iter); + scan_for_non_ws_or_end(&mut b_iter); + } else if rustc_lexer::is_whitespace(a) { + // Skip whitespace for `a`. + scan_for_non_ws_or_end(&mut a_iter); + } else if a == b { + a_iter.next(); + b_iter.next(); + } else { + return false + } + } + + // Check if a has *only* trailing whitespace. + a_iter.all(rustc_lexer::is_whitespace) +} + +/// Advances the given peekable `Iterator` until it reaches a non-whitespace character. +fn scan_for_non_ws_or_end>(iter: &mut Peekable) { + while iter.peek().copied().map(|c| rustc_lexer::is_whitespace(c)) == Some(true) { + iter.next(); + } +} + +/// Identifies a position in the text by the n'th occurrence of a string. +struct Position { + string: &'static str, + count: usize, +} + +struct SpanLabel { + start: Position, + end: Position, + label: &'static str, +} + +crate struct Shared { + pub data: Arc>, +} + +impl Write for Shared { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.data.lock().unwrap().write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.data.lock().unwrap().flush() + } +} + +fn test_harness(file_text: &str, span_labels: Vec, expected_output: &str) { + with_default_globals(|| { + let output = Arc::new(Mutex::new(Vec::new())); + + let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty())); + source_map.new_source_file(Path::new("test.rs").to_owned().into(), file_text.to_owned()); + + let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end); + let mut msp = MultiSpan::from_span(primary_span); + for span_label in span_labels { + let span = make_span(&file_text, &span_label.start, &span_label.end); + msp.push_span_label(span, span_label.label.to_string()); + println!("span: {:?} label: {:?}", span, span_label.label); + println!("text: {:?}", source_map.span_to_snippet(span)); + } + + let emitter = EmitterWriter::new( + Box::new(Shared { data: output.clone() }), + Some(source_map.clone()), + false, + false, + false, + None, + false, + ); + let handler = Handler::with_emitter(true, None, Box::new(emitter)); + handler.span_err(msp, "foo"); + + assert!(expected_output.chars().next() == Some('\n'), + "expected output should begin with newline"); + let expected_output = &expected_output[1..]; + + let bytes = output.lock().unwrap(); + let actual_output = str::from_utf8(&bytes).unwrap(); + println!("expected output:\n------\n{}------", expected_output); + println!("actual output:\n------\n{}------", actual_output); + + assert!(expected_output == actual_output) + }) +} + +fn make_span(file_text: &str, start: &Position, end: &Position) -> Span { + let start = make_pos(file_text, start); + let end = make_pos(file_text, end) + end.string.len(); // just after matching thing ends + assert!(start <= end); + Span::with_root_ctxt(BytePos(start as u32), BytePos(end as u32)) +} + +fn make_pos(file_text: &str, pos: &Position) -> usize { + let mut remainder = file_text; + let mut offset = 0; + for _ in 0..pos.count { + if let Some(n) = remainder.find(&pos.string) { + offset += n; + remainder = &remainder[n + 1..]; + } else { + panic!("failed to find {} instances of {:?} in {:?}", + pos.count, + pos.string, + file_text); + } + } + offset +} + +#[test] +fn ends_on_col0() { + test_harness(r#" +fn foo() { +} +"#, + vec![ + SpanLabel { + start: Position { + string: "{", + count: 1, + }, + end: Position { + string: "}", + count: 1, + }, + label: "test", + }, + ], + r#" +error: foo + --> test.rs:2:10 + | +2 | fn foo() { + | __________^ +3 | | } + | |_^ test + +"#); +} + +#[test] +fn ends_on_col2() { + test_harness(r#" +fn foo() { + + + } +"#, + vec![ + SpanLabel { + start: Position { + string: "{", + count: 1, + }, + end: Position { + string: "}", + count: 1, + }, + label: "test", + }, + ], + r#" +error: foo + --> test.rs:2:10 + | +2 | fn foo() { + | __________^ +3 | | +4 | | +5 | | } + | |___^ test + +"#); +} +#[test] +fn non_nested() { + test_harness(r#" +fn foo() { + X0 Y0 + X1 Y1 + X2 Y2 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "X0", + count: 1, + }, + end: Position { + string: "X2", + count: 1, + }, + label: "`X` is a good letter", + }, + SpanLabel { + start: Position { + string: "Y0", + count: 1, + }, + end: Position { + string: "Y2", + count: 1, + }, + label: "`Y` is a good letter too", + }, + ], + r#" +error: foo + --> test.rs:3:3 + | +3 | X0 Y0 + | ____^__- + | | ___| + | || +4 | || X1 Y1 +5 | || X2 Y2 + | ||____^__- `Y` is a good letter too + | |____| + | `X` is a good letter + +"#); +} + +#[test] +fn nested() { + test_harness(r#" +fn foo() { + X0 Y0 + Y1 X1 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "X0", + count: 1, + }, + end: Position { + string: "X1", + count: 1, + }, + label: "`X` is a good letter", + }, + SpanLabel { + start: Position { + string: "Y0", + count: 1, + }, + end: Position { + string: "Y1", + count: 1, + }, + label: "`Y` is a good letter too", + }, + ], +r#" +error: foo + --> test.rs:3:3 + | +3 | X0 Y0 + | ____^__- + | | ___| + | || +4 | || Y1 X1 + | ||____-__^ `X` is a good letter + | |_____| + | `Y` is a good letter too + +"#); +} + +#[test] +fn different_overlap() { + test_harness(r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "Y0", + count: 1, + }, + end: Position { + string: "X2", + count: 1, + }, + label: "`X` is a good letter", + }, + SpanLabel { + start: Position { + string: "Z1", + count: 1, + }, + end: Position { + string: "X3", + count: 1, + }, + label: "`Y` is a good letter too", + }, + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ______^ +4 | | X1 Y1 Z1 + | |_________- +5 | || X2 Y2 Z2 + | ||____^ `X` is a good letter +6 | | X3 Y3 Z3 + | |_____- `Y` is a good letter too + +"#); +} + +#[test] +fn triple_overlap() { + test_harness(r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "X0", + count: 1, + }, + end: Position { + string: "X2", + count: 1, + }, + label: "`X` is a good letter", + }, + SpanLabel { + start: Position { + string: "Y0", + count: 1, + }, + end: Position { + string: "Y2", + count: 1, + }, + label: "`Y` is a good letter too", + }, + SpanLabel { + start: Position { + string: "Z0", + count: 1, + }, + end: Position { + string: "Z2", + count: 1, + }, + label: "`Z` label", + }, + ], + r#" +error: foo + --> test.rs:3:3 + | +3 | X0 Y0 Z0 + | _____^__-__- + | | ____|__| + | || ___| + | ||| +4 | ||| X1 Y1 Z1 +5 | ||| X2 Y2 Z2 + | |||____^__-__- `Z` label + | ||____|__| + | |____| `Y` is a good letter too + | `X` is a good letter + +"#); +} + +#[test] +fn triple_exact_overlap() { + test_harness(r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "X0", + count: 1, + }, + end: Position { + string: "X2", + count: 1, + }, + label: "`X` is a good letter", + }, + SpanLabel { + start: Position { + string: "X0", + count: 1, + }, + end: Position { + string: "X2", + count: 1, + }, + label: "`Y` is a good letter too", + }, + SpanLabel { + start: Position { + string: "X0", + count: 1, + }, + end: Position { + string: "X2", + count: 1, + }, + label: "`Z` label", + }, + ], + r#" +error: foo + --> test.rs:3:3 + | +3 | / X0 Y0 Z0 +4 | | X1 Y1 Z1 +5 | | X2 Y2 Z2 + | | ^ + | | | + | | `X` is a good letter + | |____`Y` is a good letter too + | `Z` label + +"#); +} + +#[test] +fn minimum_depth() { + test_harness(r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "Y0", + count: 1, + }, + end: Position { + string: "X1", + count: 1, + }, + label: "`X` is a good letter", + }, + SpanLabel { + start: Position { + string: "Y1", + count: 1, + }, + end: Position { + string: "Z2", + count: 1, + }, + label: "`Y` is a good letter too", + }, + SpanLabel { + start: Position { + string: "X2", + count: 1, + }, + end: Position { + string: "Y3", + count: 1, + }, + label: "`Z`", + }, + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ______^ +4 | | X1 Y1 Z1 + | |____^_- + | ||____| + | | `X` is a good letter +5 | | X2 Y2 Z2 + | |____-______- `Y` is a good letter too + | ____| + | | +6 | | X3 Y3 Z3 + | |________- `Z` + +"#); +} + +#[test] +fn non_overlaping() { + test_harness(r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "X0", + count: 1, + }, + end: Position { + string: "X1", + count: 1, + }, + label: "`X` is a good letter", + }, + SpanLabel { + start: Position { + string: "Y2", + count: 1, + }, + end: Position { + string: "Z3", + count: 1, + }, + label: "`Y` is a good letter too", + }, + ], + r#" +error: foo + --> test.rs:3:3 + | +3 | / X0 Y0 Z0 +4 | | X1 Y1 Z1 + | |____^ `X` is a good letter +5 | X2 Y2 Z2 + | ______- +6 | | X3 Y3 Z3 + | |__________- `Y` is a good letter too + +"#); +} + +#[test] +fn overlaping_start_and_end() { + test_harness(r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "Y0", + count: 1, + }, + end: Position { + string: "X1", + count: 1, + }, + label: "`X` is a good letter", + }, + SpanLabel { + start: Position { + string: "Z1", + count: 1, + }, + end: Position { + string: "Z3", + count: 1, + }, + label: "`Y` is a good letter too", + }, + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ______^ +4 | | X1 Y1 Z1 + | |____^____- + | ||____| + | | `X` is a good letter +5 | | X2 Y2 Z2 +6 | | X3 Y3 Z3 + | |___________- `Y` is a good letter too + +"#); +} + +#[test] +fn multiple_labels_primary_without_message() { + test_harness(r#" +fn foo() { + a { b { c } d } +} +"#, + vec![ + SpanLabel { + start: Position { + string: "b", + count: 1, + }, + end: Position { + string: "}", + count: 1, + }, + label: "", + }, + SpanLabel { + start: Position { + string: "a", + count: 1, + }, + end: Position { + string: "d", + count: 1, + }, + label: "`a` is a good letter", + }, + SpanLabel { + start: Position { + string: "c", + count: 1, + }, + end: Position { + string: "c", + count: 1, + }, + label: "", + }, + ], + r#" +error: foo + --> test.rs:3:7 + | +3 | a { b { c } d } + | ----^^^^-^^-- `a` is a good letter + +"#); +} + +#[test] +fn multiple_labels_secondary_without_message() { + test_harness(r#" +fn foo() { + a { b { c } d } +} +"#, + vec![ + SpanLabel { + start: Position { + string: "a", + count: 1, + }, + end: Position { + string: "d", + count: 1, + }, + label: "`a` is a good letter", + }, + SpanLabel { + start: Position { + string: "b", + count: 1, + }, + end: Position { + string: "}", + count: 1, + }, + label: "", + }, + ], + r#" +error: foo + --> test.rs:3:3 + | +3 | a { b { c } d } + | ^^^^-------^^ `a` is a good letter + +"#); +} + +#[test] +fn multiple_labels_primary_without_message_2() { + test_harness(r#" +fn foo() { + a { b { c } d } +} +"#, + vec![ + SpanLabel { + start: Position { + string: "b", + count: 1, + }, + end: Position { + string: "}", + count: 1, + }, + label: "`b` is a good letter", + }, + SpanLabel { + start: Position { + string: "a", + count: 1, + }, + end: Position { + string: "d", + count: 1, + }, + label: "", + }, + SpanLabel { + start: Position { + string: "c", + count: 1, + }, + end: Position { + string: "c", + count: 1, + }, + label: "", + }, + ], + r#" +error: foo + --> test.rs:3:7 + | +3 | a { b { c } d } + | ----^^^^-^^-- + | | + | `b` is a good letter + +"#); +} + +#[test] +fn multiple_labels_secondary_without_message_2() { + test_harness(r#" +fn foo() { + a { b { c } d } +} +"#, + vec![ + SpanLabel { + start: Position { + string: "a", + count: 1, + }, + end: Position { + string: "d", + count: 1, + }, + label: "", + }, + SpanLabel { + start: Position { + string: "b", + count: 1, + }, + end: Position { + string: "}", + count: 1, + }, + label: "`b` is a good letter", + }, + ], + r#" +error: foo + --> test.rs:3:3 + | +3 | a { b { c } d } + | ^^^^-------^^ + | | + | `b` is a good letter + +"#); +} + +#[test] +fn multiple_labels_secondary_without_message_3() { + test_harness(r#" +fn foo() { + a bc d +} +"#, + vec![ + SpanLabel { + start: Position { + string: "a", + count: 1, + }, + end: Position { + string: "b", + count: 1, + }, + label: "`a` is a good letter", + }, + SpanLabel { + start: Position { + string: "c", + count: 1, + }, + end: Position { + string: "d", + count: 1, + }, + label: "", + }, + ], + r#" +error: foo + --> test.rs:3:3 + | +3 | a bc d + | ^^^^---- + | | + | `a` is a good letter + +"#); +} + +#[test] +fn multiple_labels_without_message() { + test_harness(r#" +fn foo() { + a { b { c } d } +} +"#, + vec![ + SpanLabel { + start: Position { + string: "a", + count: 1, + }, + end: Position { + string: "d", + count: 1, + }, + label: "", + }, + SpanLabel { + start: Position { + string: "b", + count: 1, + }, + end: Position { + string: "}", + count: 1, + }, + label: "", + }, + ], + r#" +error: foo + --> test.rs:3:3 + | +3 | a { b { c } d } + | ^^^^-------^^ + +"#); +} + +#[test] +fn multiple_labels_without_message_2() { + test_harness(r#" +fn foo() { + a { b { c } d } +} +"#, + vec![ + SpanLabel { + start: Position { + string: "b", + count: 1, + }, + end: Position { + string: "}", + count: 1, + }, + label: "", + }, + SpanLabel { + start: Position { + string: "a", + count: 1, + }, + end: Position { + string: "d", + count: 1, + }, + label: "", + }, + SpanLabel { + start: Position { + string: "c", + count: 1, + }, + end: Position { + string: "c", + count: 1, + }, + label: "", + }, + ], + r#" +error: foo + --> test.rs:3:7 + | +3 | a { b { c } d } + | ----^^^^-^^-- + +"#); +} + +#[test] +fn multiple_labels_with_message() { + test_harness(r#" +fn foo() { + a { b { c } d } +} +"#, + vec![ + SpanLabel { + start: Position { + string: "a", + count: 1, + }, + end: Position { + string: "d", + count: 1, + }, + label: "`a` is a good letter", + }, + SpanLabel { + start: Position { + string: "b", + count: 1, + }, + end: Position { + string: "}", + count: 1, + }, + label: "`b` is a good letter", + }, + ], + r#" +error: foo + --> test.rs:3:3 + | +3 | a { b { c } d } + | ^^^^-------^^ + | | | + | | `b` is a good letter + | `a` is a good letter + +"#); +} + +#[test] +fn single_label_with_message() { + test_harness(r#" +fn foo() { + a { b { c } d } +} +"#, + vec![ + SpanLabel { + start: Position { + string: "a", + count: 1, + }, + end: Position { + string: "d", + count: 1, + }, + label: "`a` is a good letter", + }, + ], + r#" +error: foo + --> test.rs:3:3 + | +3 | a { b { c } d } + | ^^^^^^^^^^^^^ `a` is a good letter + +"#); +} + +#[test] +fn single_label_without_message() { + test_harness(r#" +fn foo() { + a { b { c } d } +} +"#, + vec![ + SpanLabel { + start: Position { + string: "a", + count: 1, + }, + end: Position { + string: "d", + count: 1, + }, + label: "", + }, + ], + r#" +error: foo + --> test.rs:3:3 + | +3 | a { b { c } d } + | ^^^^^^^^^^^^^ + +"#); +} + +#[test] +fn long_snippet() { + test_harness(r#" +fn foo() { + X0 Y0 Z0 + X1 Y1 Z1 +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 + X2 Y2 Z2 + X3 Y3 Z3 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "Y0", + count: 1, + }, + end: Position { + string: "X1", + count: 1, + }, + label: "`X` is a good letter", + }, + SpanLabel { + start: Position { + string: "Z1", + count: 1, + }, + end: Position { + string: "Z3", + count: 1, + }, + label: "`Y` is a good letter too", + }, + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ______^ +4 | | X1 Y1 Z1 + | |____^____- + | ||____| + | | `X` is a good letter +5 | | 1 +6 | | 2 +7 | | 3 +... | +15 | | X2 Y2 Z2 +16 | | X3 Y3 Z3 + | |___________- `Y` is a good letter too + +"#); +} + +#[test] +fn long_snippet_multiple_spans() { + test_harness(r#" +fn foo() { + X0 Y0 Z0 +1 +2 +3 + X1 Y1 Z1 +4 +5 +6 + X2 Y2 Z2 +7 +8 +9 +10 + X3 Y3 Z3 +} +"#, + vec![ + SpanLabel { + start: Position { + string: "Y0", + count: 1, + }, + end: Position { + string: "Y3", + count: 1, + }, + label: "`Y` is a good letter", + }, + SpanLabel { + start: Position { + string: "Z1", + count: 1, + }, + end: Position { + string: "Z2", + count: 1, + }, + label: "`Z` is a good letter too", + }, + ], + r#" +error: foo + --> test.rs:3:6 + | +3 | X0 Y0 Z0 + | ______^ +4 | | 1 +5 | | 2 +6 | | 3 +7 | | X1 Y1 Z1 + | |_________- +8 | || 4 +9 | || 5 +10 | || 6 +11 | || X2 Y2 Z2 + | ||__________- `Z` is a good letter too +... | +15 | | 10 +16 | | X3 Y3 Z3 + | |_______^ `Y` is a good letter + +"#); +} diff --git a/src/libsyntax_expand/tokenstream/tests.rs b/src/libsyntax_expand/tokenstream/tests.rs new file mode 100644 index 00000000000..cf9fead638e --- /dev/null +++ b/src/libsyntax_expand/tokenstream/tests.rs @@ -0,0 +1,110 @@ +use crate::tests::string_to_stream; + +use syntax::ast::Name; +use syntax::token; +use syntax::tokenstream::{TokenStream, TokenStreamBuilder, TokenTree}; +use syntax::with_default_globals; +use syntax_pos::{Span, BytePos}; +use smallvec::smallvec; + +fn string_to_ts(string: &str) -> TokenStream { + string_to_stream(string.to_owned()) +} + +fn sp(a: u32, b: u32) -> Span { + Span::with_root_ctxt(BytePos(a), BytePos(b)) +} + +#[test] +fn test_concat() { + with_default_globals(|| { + let test_res = string_to_ts("foo::bar::baz"); + let test_fst = string_to_ts("foo::bar"); + let test_snd = string_to_ts("::baz"); + let eq_res = TokenStream::from_streams(smallvec![test_fst, test_snd]); + assert_eq!(test_res.trees().count(), 5); + assert_eq!(eq_res.trees().count(), 5); + assert_eq!(test_res.eq_unspanned(&eq_res), true); + }) +} + +#[test] +fn test_to_from_bijection() { + with_default_globals(|| { + let test_start = string_to_ts("foo::bar(baz)"); + let test_end = test_start.trees().collect(); + assert_eq!(test_start, test_end) + }) +} + +#[test] +fn test_eq_0() { + with_default_globals(|| { + let test_res = string_to_ts("foo"); + let test_eqs = string_to_ts("foo"); + assert_eq!(test_res, test_eqs) + }) +} + +#[test] +fn test_eq_1() { + with_default_globals(|| { + let test_res = string_to_ts("::bar::baz"); + let test_eqs = string_to_ts("::bar::baz"); + assert_eq!(test_res, test_eqs) + }) +} + +#[test] +fn test_eq_3() { + with_default_globals(|| { + let test_res = string_to_ts(""); + let test_eqs = string_to_ts(""); + assert_eq!(test_res, test_eqs) + }) +} + +#[test] +fn test_diseq_0() { + with_default_globals(|| { + let test_res = string_to_ts("::bar::baz"); + let test_eqs = string_to_ts("bar::baz"); + assert_eq!(test_res == test_eqs, false) + }) +} + +#[test] +fn test_diseq_1() { + with_default_globals(|| { + let test_res = string_to_ts("(bar,baz)"); + let test_eqs = string_to_ts("bar,baz"); + assert_eq!(test_res == test_eqs, false) + }) +} + +#[test] +fn test_is_empty() { + with_default_globals(|| { + let test0: TokenStream = Vec::::new().into_iter().collect(); + let test1: TokenStream = + TokenTree::token(token::Ident(Name::intern("a"), false), sp(0, 1)).into(); + let test2 = string_to_ts("foo(bar::baz)"); + + assert_eq!(test0.is_empty(), true); + assert_eq!(test1.is_empty(), false); + assert_eq!(test2.is_empty(), false); + }) +} + +#[test] +fn test_dotdotdot() { + with_default_globals(|| { + let mut builder = TokenStreamBuilder::new(); + builder.push(TokenTree::token(token::Dot, sp(0, 1)).joint()); + builder.push(TokenTree::token(token::Dot, sp(1, 2)).joint()); + builder.push(TokenTree::token(token::Dot, sp(2, 3))); + let stream = builder.build(); + assert!(stream.eq_unspanned(&string_to_ts("..."))); + assert_eq!(stream.trees().count(), 1); + }) +} diff --git a/src/test/ui-fulldeps/ast_stmt_expr_attr.rs b/src/test/ui-fulldeps/ast_stmt_expr_attr.rs index ac864e76784..3d2181d4e37 100644 --- a/src/test/ui-fulldeps/ast_stmt_expr_attr.rs +++ b/src/test/ui-fulldeps/ast_stmt_expr_attr.rs @@ -6,6 +6,7 @@ #![feature(rustc_private)] extern crate syntax; +extern crate syntax_expand; extern crate rustc_errors; use rustc_errors::PResult; @@ -14,13 +15,13 @@ use syntax::attr::*; use syntax::ast; use syntax::sess::ParseSess; use syntax::source_map::{FilePathMapping, FileName}; -use syntax::parse; +use syntax::ptr::P; +use syntax::print::pprust; +use syntax::parse::parser::attr::*; use syntax::parse::new_parser_from_source_str; use syntax::parse::parser::Parser; use syntax::token; -use syntax::ptr::P; -use syntax::parse::parser::attr::*; -use syntax::print::pprust; +use syntax_expand::config::process_configure_mod; use std::fmt; // Copied out of syntax::util::parser_testing @@ -72,8 +73,12 @@ fn str_compare String>(e: &str, expected: &[T], actual: &[T], f: } } +fn sess() -> ParseSess { + ParseSess::new(FilePathMapping::empty(), process_configure_mod) +} + fn check_expr_attrs(es: &str, expected: &[&str]) { - let ps = ParseSess::new(FilePathMapping::empty()); + let ps = sess(); let e = expr(es, &ps).expect("parse error"); let actual = &e.attrs; str_compare(es, @@ -83,7 +88,7 @@ fn check_expr_attrs(es: &str, expected: &[&str]) { } fn check_stmt_attrs(es: &str, expected: &[&str]) { - let ps = ParseSess::new(FilePathMapping::empty()); + let ps = sess(); let e = stmt(es, &ps).expect("parse error"); let actual = e.kind.attrs(); str_compare(es, @@ -93,7 +98,7 @@ fn check_stmt_attrs(es: &str, expected: &[&str]) { } fn reject_expr_parse(es: &str) { - let ps = ParseSess::new(FilePathMapping::empty()); + let ps = sess(); match expr(es, &ps) { Ok(_) => panic!("parser did not reject `{}`", es), Err(mut e) => e.cancel(), @@ -101,7 +106,7 @@ fn reject_expr_parse(es: &str) { } fn reject_stmt_parse(es: &str) { - let ps = ParseSess::new(FilePathMapping::empty()); + let ps = sess(); match stmt(es, &ps) { Ok(_) => panic!("parser did not reject `{}`", es), Err(mut e) => e.cancel(), diff --git a/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs b/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs index ac97ec70be2..472440e2e14 100644 --- a/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs +++ b/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs @@ -5,11 +5,13 @@ #![feature(rustc_private)] extern crate syntax; +extern crate syntax_expand; use std::path::Path; use syntax::sess::ParseSess; use syntax::source_map::FilePathMapping; -use syntax::parse; +use syntax::parse::new_parser_from_file; +use syntax_expand::config::process_configure_mod; #[path = "mod_dir_simple/test.rs"] mod gravy; @@ -21,10 +23,10 @@ pub fn main() { } fn parse() { - let parse_session = ParseSess::new(FilePathMapping::empty()); + let parse_session = ParseSess::new(FilePathMapping::empty(), process_configure_mod); let path = Path::new(file!()); let path = path.canonicalize().unwrap(); - let mut parser = parse::new_parser_from_file(&parse_session, &path); + let mut parser = new_parser_from_file(&parse_session, &path); let _ = parser.parse_crate_mod(); } diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index 932a173bc67..99da605f357 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -21,6 +21,7 @@ extern crate rustc_data_structures; extern crate syntax; +extern crate syntax_expand; use rustc_data_structures::thin_vec::ThinVec; use syntax::ast::*; @@ -28,14 +29,15 @@ use syntax::sess::ParseSess; use syntax::source_map::{Spanned, DUMMY_SP, FileName}; use syntax::source_map::FilePathMapping; use syntax::mut_visit::{self, MutVisitor, visit_clobber}; -use syntax::parse; +use syntax::parse::new_parser_from_source_str; use syntax::print::pprust; use syntax::ptr::P; +use syntax_expand::config::process_configure_mod; fn parse_expr(ps: &ParseSess, src: &str) -> Option> { let src_as_string = src.to_string(); - let mut p = parse::new_parser_from_source_str( + let mut p = new_parser_from_source_str( ps, FileName::Custom(src_as_string.clone()), src_as_string, @@ -202,7 +204,7 @@ fn main() { } fn run() { - let ps = ParseSess::new(FilePathMapping::empty()); + let ps = ParseSess::new(FilePathMapping::empty(), process_configure_mod); iter_exprs(2, &mut |mut e| { // If the pretty printer is correct, then `parse(print(e))` should be identical to `e`, -- cgit 1.4.1-3-g733a5 From 4ae2728fa8052915414127dce28245eb8f70842a Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 15 Oct 2019 22:48:13 +0200 Subject: move syntax::parse -> librustc_parse also move MACRO_ARGUMENTS -> librustc_parse --- Cargo.lock | 26 +- src/librustc_driver/Cargo.toml | 1 + src/librustc_driver/lib.rs | 17 +- src/librustc_interface/Cargo.toml | 1 + src/librustc_interface/interface.rs | 2 +- src/librustc_interface/passes.rs | 15 +- src/librustc_interface/util.rs | 1 + src/librustc_lexer/src/lib.rs | 2 +- src/librustc_metadata/Cargo.toml | 1 + src/librustc_metadata/rmeta/decoder/cstore_impl.rs | 4 +- src/librustc_parse/Cargo.toml | 21 + src/librustc_parse/error_codes.rs | 174 ++ src/librustc_parse/lexer/mod.rs | 643 ++++++ src/librustc_parse/lexer/tokentrees.rs | 280 +++ .../lexer/unescape_error_reporting.rs | 215 ++ src/librustc_parse/lexer/unicode_chars.rs | 392 ++++ src/librustc_parse/lib.rs | 423 ++++ src/librustc_parse/parser/attr.rs | 351 +++ src/librustc_parse/parser/diagnostics.rs | 1549 ++++++++++++++ src/librustc_parse/parser/expr.rs | 1963 +++++++++++++++++ src/librustc_parse/parser/generics.rs | 308 +++ src/librustc_parse/parser/item.rs | 2238 ++++++++++++++++++++ src/librustc_parse/parser/mod.rs | 1393 ++++++++++++ src/librustc_parse/parser/module.rs | 316 +++ src/librustc_parse/parser/pat.rs | 1015 +++++++++ src/librustc_parse/parser/path.rs | 497 +++++ src/librustc_parse/parser/stmt.rs | 482 +++++ src/librustc_parse/parser/ty.rs | 460 ++++ src/librustc_parse/validate_attr.rs | 111 + src/librustc_passes/Cargo.toml | 5 +- src/librustc_passes/ast_validation.rs | 4 +- src/librustc_save_analysis/Cargo.toml | 1 + src/librustc_save_analysis/span_utils.rs | 6 +- src/librustdoc/html/highlight.rs | 4 +- src/librustdoc/lib.rs | 1 + src/librustdoc/passes/check_code_block_syntax.rs | 2 +- src/librustdoc/test.rs | 5 +- src/libsyntax/ast.rs | 6 +- src/libsyntax/attr/builtin.rs | 6 +- src/libsyntax/attr/mod.rs | 2 +- src/libsyntax/error_codes.rs | 165 -- src/libsyntax/lib.rs | 7 +- src/libsyntax/parse/lexer/mod.rs | 643 ------ src/libsyntax/parse/lexer/tokentrees.rs | 280 --- .../parse/lexer/unescape_error_reporting.rs | 215 -- src/libsyntax/parse/lexer/unicode_chars.rs | 392 ---- src/libsyntax/parse/mod.rs | 420 ---- src/libsyntax/parse/parser/attr.rs | 358 ---- src/libsyntax/parse/parser/diagnostics.rs | 1547 -------------- src/libsyntax/parse/parser/expr.rs | 1964 ----------------- src/libsyntax/parse/parser/generics.rs | 309 --- src/libsyntax/parse/parser/item.rs | 2237 ------------------- src/libsyntax/parse/parser/mod.rs | 1391 ------------ src/libsyntax/parse/parser/module.rs | 315 --- src/libsyntax/parse/parser/pat.rs | 1016 --------- src/libsyntax/parse/parser/path.rs | 497 ----- src/libsyntax/parse/parser/stmt.rs | 480 ----- src/libsyntax/parse/parser/ty.rs | 458 ---- src/libsyntax/parse/validate_attr.rs | 112 - src/libsyntax/print/pprust.rs | 14 +- src/libsyntax/sess.rs | 4 +- src/libsyntax/token.rs | 44 +- src/libsyntax/util/comments.rs | 4 +- src/libsyntax/util/literal.rs | 10 +- src/libsyntax/util/parser.rs | 4 +- src/libsyntax_expand/Cargo.toml | 5 +- src/libsyntax_expand/base.rs | 8 +- src/libsyntax_expand/config.rs | 6 +- src/libsyntax_expand/expand.rs | 6 +- src/libsyntax_expand/mbe/macro_parser.rs | 6 +- src/libsyntax_expand/mbe/macro_rules.rs | 10 +- src/libsyntax_expand/parse/lexer/tests.rs | 4 +- src/libsyntax_expand/parse/tests.rs | 2 +- src/libsyntax_expand/proc_macro.rs | 9 +- src/libsyntax_expand/proc_macro_server.rs | 10 +- src/libsyntax_expand/tests.rs | 2 +- src/libsyntax_ext/Cargo.toml | 1 + src/libsyntax_ext/assert.rs | 4 +- src/libsyntax_ext/cmdline_attrs.rs | 3 +- src/libsyntax_ext/source_util.rs | 10 +- src/libsyntax_ext/util.rs | 2 +- src/test/ui-fulldeps/ast_stmt_expr_attr.rs | 7 +- src/test/ui-fulldeps/mod_dir_path_canonicalized.rs | 3 +- src/test/ui-fulldeps/pprust-expr-roundtrip.rs | 3 +- 84 files changed, 12993 insertions(+), 12937 deletions(-) create mode 100644 src/librustc_parse/Cargo.toml create mode 100644 src/librustc_parse/error_codes.rs create mode 100644 src/librustc_parse/lexer/mod.rs create mode 100644 src/librustc_parse/lexer/tokentrees.rs create mode 100644 src/librustc_parse/lexer/unescape_error_reporting.rs create mode 100644 src/librustc_parse/lexer/unicode_chars.rs create mode 100644 src/librustc_parse/lib.rs create mode 100644 src/librustc_parse/parser/attr.rs create mode 100644 src/librustc_parse/parser/diagnostics.rs create mode 100644 src/librustc_parse/parser/expr.rs create mode 100644 src/librustc_parse/parser/generics.rs create mode 100644 src/librustc_parse/parser/item.rs create mode 100644 src/librustc_parse/parser/mod.rs create mode 100644 src/librustc_parse/parser/module.rs create mode 100644 src/librustc_parse/parser/pat.rs create mode 100644 src/librustc_parse/parser/path.rs create mode 100644 src/librustc_parse/parser/stmt.rs create mode 100644 src/librustc_parse/parser/ty.rs create mode 100644 src/librustc_parse/validate_attr.rs delete mode 100644 src/libsyntax/parse/lexer/mod.rs delete mode 100644 src/libsyntax/parse/lexer/tokentrees.rs delete mode 100644 src/libsyntax/parse/lexer/unescape_error_reporting.rs delete mode 100644 src/libsyntax/parse/lexer/unicode_chars.rs delete mode 100644 src/libsyntax/parse/mod.rs delete mode 100644 src/libsyntax/parse/parser/attr.rs delete mode 100644 src/libsyntax/parse/parser/diagnostics.rs delete mode 100644 src/libsyntax/parse/parser/expr.rs delete mode 100644 src/libsyntax/parse/parser/generics.rs delete mode 100644 src/libsyntax/parse/parser/item.rs delete mode 100644 src/libsyntax/parse/parser/mod.rs delete mode 100644 src/libsyntax/parse/parser/module.rs delete mode 100644 src/libsyntax/parse/parser/pat.rs delete mode 100644 src/libsyntax/parse/parser/path.rs delete mode 100644 src/libsyntax/parse/parser/stmt.rs delete mode 100644 src/libsyntax/parse/parser/ty.rs delete mode 100644 src/libsyntax/parse/validate_attr.rs (limited to 'src/libsyntax/parse') diff --git a/Cargo.lock b/Cargo.lock index 0f770f3eadb..7e51f96cfb8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3504,6 +3504,7 @@ dependencies = [ "rustc_lint", "rustc_metadata", "rustc_mir", + "rustc_parse", "rustc_plugin", "rustc_plugin_impl", "rustc_save_analysis", @@ -3571,6 +3572,7 @@ dependencies = [ "rustc_lint", "rustc_metadata", "rustc_mir", + "rustc_parse", "rustc_passes", "rustc_plugin_impl", "rustc_privacy", @@ -3648,6 +3650,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_index", + "rustc_parse", "rustc_target", "serialize", "smallvec 1.0.0", @@ -3691,6 +3694,21 @@ dependencies = [ "core", ] +[[package]] +name = "rustc_parse" +version = "0.0.0" +dependencies = [ + "bitflags", + "log", + "rustc_data_structures", + "rustc_errors", + "rustc_lexer", + "rustc_target", + "smallvec 1.0.0", + "syntax", + "syntax_pos", +] + [[package]] name = "rustc_passes" version = "0.0.0" @@ -3700,6 +3718,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_index", + "rustc_parse", "rustc_target", "syntax", "syntax_pos", @@ -3762,6 +3781,7 @@ dependencies = [ "rustc", "rustc_codegen_utils", "rustc_data_structures", + "rustc_parse", "serde_json", "syntax", "syntax_pos", @@ -4371,14 +4391,11 @@ dependencies = [ name = "syntax_expand" version = "0.0.0" dependencies = [ - "bitflags", - "lazy_static 1.3.0", "log", "rustc_data_structures", "rustc_errors", - "rustc_index", "rustc_lexer", - "scoped-tls", + "rustc_parse", "serialize", "smallvec 1.0.0", "syntax", @@ -4393,6 +4410,7 @@ dependencies = [ "log", "rustc_data_structures", "rustc_errors", + "rustc_parse", "rustc_target", "smallvec 1.0.0", "syntax", diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index a9e4e6db1c7..19726d6aff2 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -21,6 +21,7 @@ rustc_data_structures = { path = "../librustc_data_structures" } errors = { path = "../librustc_errors", package = "rustc_errors" } rustc_metadata = { path = "../librustc_metadata" } rustc_mir = { path = "../librustc_mir" } +rustc_parse = { path = "../librustc_parse" } rustc_plugin = { path = "../librustc_plugin/deprecated" } # To get this in the sysroot rustc_plugin_impl = { path = "../librustc_plugin" } rustc_save_analysis = { path = "../librustc_save_analysis" } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 611b891d99a..380cbed4b21 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -65,7 +65,6 @@ use std::time::Instant; use syntax::ast; use syntax::source_map::FileLoader; use syntax::feature_gate::{GatedCfg, UnstableFeatures}; -use syntax::parse; use syntax::symbol::sym; use syntax_pos::{DUMMY_SP, FileName}; @@ -1096,14 +1095,16 @@ pub fn handle_options(args: &[String]) -> Option { } fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec> { - match *input { - Input::File(ref ifile) => { - parse::parse_crate_attrs_from_file(ifile, &sess.parse_sess) + match input { + Input::File(ifile) => { + rustc_parse::parse_crate_attrs_from_file(ifile, &sess.parse_sess) } - Input::Str { ref name, ref input } => { - parse::parse_crate_attrs_from_source_str(name.clone(), - input.clone(), - &sess.parse_sess) + Input::Str { name, input } => { + rustc_parse::parse_crate_attrs_from_source_str( + name.clone(), + input.clone(), + &sess.parse_sess, + ) } } } diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml index 35b93db1d65..de59882bbdf 100644 --- a/src/librustc_interface/Cargo.toml +++ b/src/librustc_interface/Cargo.toml @@ -16,6 +16,7 @@ smallvec = { version = "1.0", features = ["union", "may_dangle"] } syntax = { path = "../libsyntax" } syntax_ext = { path = "../libsyntax_ext" } syntax_expand = { path = "../libsyntax_expand" } +rustc_parse = { path = "../librustc_parse" } syntax_pos = { path = "../libsyntax_pos" } rustc_serialize = { path = "../libserialize", package = "serialize" } rustc = { path = "../librustc" } diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs index 61f30392e06..02068b2ce38 100644 --- a/src/librustc_interface/interface.rs +++ b/src/librustc_interface/interface.rs @@ -11,11 +11,11 @@ use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_data_structures::OnDrop; use rustc_data_structures::sync::Lrc; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; +use rustc_parse::new_parser_from_source_str; use std::path::PathBuf; use std::result; use std::sync::{Arc, Mutex}; use syntax::ast::{self, MetaItemKind}; -use syntax::parse::new_parser_from_source_str; use syntax::token; use syntax::source_map::{FileName, FileLoader, SourceMap}; use syntax::sess::ParseSess; diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index c874e94124d..0e38de9a0ed 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -26,6 +26,7 @@ use rustc_errors::PResult; use rustc_incremental; use rustc_metadata::cstore; use rustc_mir as mir; +use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str}; use rustc_passes::{self, ast_validation, hir_stats, layout_test}; use rustc_plugin as plugin; use rustc_plugin::registry::Registry; @@ -37,7 +38,6 @@ use syntax::{self, ast, visit}; use syntax::early_buffered_lints::BufferedEarlyLint; use syntax_expand::base::{NamedSyntaxExtension, ExtCtxt}; use syntax::mut_visit::MutVisitor; -use syntax::parse; use syntax::util::node_count::NodeCounter; use syntax::symbol::Symbol; use syntax_pos::FileName; @@ -60,12 +60,11 @@ pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> { let krate = time(sess, "parsing", || { let _prof_timer = sess.prof.generic_activity("parse_crate"); - match *input { - Input::File(ref file) => parse::parse_crate_from_file(file, &sess.parse_sess), - Input::Str { - ref input, - ref name, - } => parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess), + match input { + Input::File(file) => parse_crate_from_file(file, &sess.parse_sess), + Input::Str { input, name } => { + parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess) + } } })?; @@ -484,7 +483,7 @@ pub fn lower_to_hir( ) -> Result { // Lower AST to HIR. let hir_forest = time(sess, "lowering AST -> HIR", || { - let nt_to_tokenstream = syntax::parse::nt_to_tokenstream; + let nt_to_tokenstream = rustc_parse::nt_to_tokenstream; let hir_crate = lower_crate(sess, &dep_graph, &krate, resolver, nt_to_tokenstream); if sess.opts.debugging_opts.hir_stats { diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index c02e5b9ae28..1cdb0ac87c5 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -50,6 +50,7 @@ pub fn diagnostics_registry() -> Registry { // FIXME: need to figure out a way to get these back in here // all_errors.extend_from_slice(get_codegen_backend(sess).diagnostics()); all_errors.extend_from_slice(&rustc_metadata::error_codes::DIAGNOSTICS); + all_errors.extend_from_slice(&rustc_parse::error_codes::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_passes::error_codes::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_plugin::error_codes::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_mir::error_codes::DIAGNOSTICS); diff --git a/src/librustc_lexer/src/lib.rs b/src/librustc_lexer/src/lib.rs index c50808adec1..3cecb4317b1 100644 --- a/src/librustc_lexer/src/lib.rs +++ b/src/librustc_lexer/src/lib.rs @@ -1,7 +1,7 @@ //! Low-level Rust lexer. //! //! Tokens produced by this lexer are not yet ready for parsing the Rust syntax, -//! for that see `libsyntax::parse::lexer`, which converts this basic token stream +//! for that see `librustc_parse::lexer`, which converts this basic token stream //! into wide tokens used by actual parser. //! //! The purpose of this crate is to convert raw sources into a labeled sequence diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 5bc047e001b..b1431563f21 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -23,4 +23,5 @@ rustc_serialize = { path = "../libserialize", package = "serialize" } stable_deref_trait = "1.0.0" syntax = { path = "../libsyntax" } syntax_expand = { path = "../libsyntax_expand" } +rustc_parse = { path = "../librustc_parse" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs index 6eacfc28de2..19cfdeac57e 100644 --- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs +++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs @@ -18,6 +18,8 @@ use rustc::hir::map::{DefKey, DefPath, DefPathHash}; use rustc::hir::map::definitions::DefPathTable; use rustc::util::nodemap::DefIdMap; use rustc_data_structures::svh::Svh; +use rustc_parse::source_file_to_stream; +use rustc_parse::parser::emit_unclosed_delims; use smallvec::SmallVec; use std::any::Any; @@ -27,8 +29,6 @@ use std::sync::Arc; use syntax::ast; use syntax::attr; use syntax::source_map; -use syntax::parse::source_file_to_stream; -use syntax::parse::parser::emit_unclosed_delims; use syntax::source_map::Spanned; use syntax::symbol::Symbol; use syntax_pos::{Span, FileName}; diff --git a/src/librustc_parse/Cargo.toml b/src/librustc_parse/Cargo.toml new file mode 100644 index 00000000000..4579f9d472d --- /dev/null +++ b/src/librustc_parse/Cargo.toml @@ -0,0 +1,21 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_parse" +version = "0.0.0" +edition = "2018" + +[lib] +name = "rustc_parse" +path = "lib.rs" +doctest = false + +[dependencies] +bitflags = "1.0" +log = "0.4" +syntax_pos = { path = "../libsyntax_pos" } +syntax = { path = "../libsyntax" } +errors = { path = "../librustc_errors", package = "rustc_errors" } +rustc_data_structures = { path = "../librustc_data_structures" } +rustc_lexer = { path = "../librustc_lexer" } +rustc_target = { path = "../librustc_target" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_parse/error_codes.rs b/src/librustc_parse/error_codes.rs new file mode 100644 index 00000000000..cf74e09a377 --- /dev/null +++ b/src/librustc_parse/error_codes.rs @@ -0,0 +1,174 @@ +// Error messages for EXXXX errors. +// Each message should start and end with a new line, and be wrapped to 80 +// characters. In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use +// `:set tw=0` to disable. +syntax::register_diagnostics! { + +E0178: r##" +In types, the `+` type operator has low precedence, so it is often necessary +to use parentheses. + +For example: + +```compile_fail,E0178 +trait Foo {} + +struct Bar<'a> { + w: &'a Foo + Copy, // error, use &'a (Foo + Copy) + x: &'a Foo + 'a, // error, use &'a (Foo + 'a) + y: &'a mut Foo + 'a, // error, use &'a mut (Foo + 'a) + z: fn() -> Foo + 'a, // error, use fn() -> (Foo + 'a) +} +``` + +More details can be found in [RFC 438]. + +[RFC 438]: https://github.com/rust-lang/rfcs/pull/438 +"##, + +E0583: r##" +A file wasn't found for an out-of-line module. + +Erroneous code example: + +```ignore (compile_fail not working here; see Issue #43707) +mod file_that_doesnt_exist; // error: file not found for module + +fn main() {} +``` + +Please be sure that a file corresponding to the module exists. If you +want to use a module named `file_that_doesnt_exist`, you need to have a file +named `file_that_doesnt_exist.rs` or `file_that_doesnt_exist/mod.rs` in the +same directory. +"##, + +E0584: r##" +A doc comment that is not attached to anything has been encountered. + +Erroneous code example: + +```compile_fail,E0584 +trait Island { + fn lost(); + + /// I'm lost! +} +``` + +A little reminder: a doc comment has to be placed before the item it's supposed +to document. So if you want to document the `Island` trait, you need to put a +doc comment before it, not inside it. Same goes for the `lost` method: the doc +comment needs to be before it: + +``` +/// I'm THE island! +trait Island { + /// I'm lost! + fn lost(); +} +``` +"##, + +E0585: r##" +A documentation comment that doesn't document anything was found. + +Erroneous code example: + +```compile_fail,E0585 +fn main() { + // The following doc comment will fail: + /// This is a useless doc comment! +} +``` + +Documentation comments need to be followed by items, including functions, +types, modules, etc. Examples: + +``` +/// I'm documenting the following struct: +struct Foo; + +/// I'm documenting the following function: +fn foo() {} +``` +"##, + +E0586: r##" +An inclusive range was used with no end. + +Erroneous code example: + +```compile_fail,E0586 +fn main() { + let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1]; + let x = &tmp[1..=]; // error: inclusive range was used with no end +} +``` + +An inclusive range needs an end in order to *include* it. If you just need a +start and no end, use a non-inclusive range (with `..`): + +``` +fn main() { + let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1]; + let x = &tmp[1..]; // ok! +} +``` + +Or put an end to your inclusive range: + +``` +fn main() { + let tmp = vec![0, 1, 2, 3, 4, 4, 3, 3, 2, 1]; + let x = &tmp[1..=3]; // ok! +} +``` +"##, + +E0704: r##" +This error indicates that a incorrect visibility restriction was specified. + +Example of erroneous code: + +```compile_fail,E0704 +mod foo { + pub(foo) struct Bar { + x: i32 + } +} +``` + +To make struct `Bar` only visible in module `foo` the `in` keyword should be +used: +``` +mod foo { + pub(in crate::foo) struct Bar { + x: i32 + } +} +# fn main() {} +``` + +For more information see the Rust Reference on [Visibility]. + +[Visibility]: https://doc.rust-lang.org/reference/visibility-and-privacy.html +"##, + +E0743: r##" +C-variadic has been used on a non-foreign function. + +Erroneous code example: + +```compile_fail,E0743 +fn foo2(x: u8, ...) {} // error! +``` + +Only foreign functions can use C-variadic (`...`). It is used to give an +undefined number of parameters to a given function (like `printf` in C). The +equivalent in Rust would be to use macros directly. +"##, + +; + +} diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs new file mode 100644 index 00000000000..5de63cb39d1 --- /dev/null +++ b/src/librustc_parse/lexer/mod.rs @@ -0,0 +1,643 @@ +use syntax::token::{self, Token, TokenKind}; +use syntax::sess::ParseSess; +use syntax::symbol::{sym, Symbol}; +use syntax::util::comments; + +use errors::{FatalError, DiagnosticBuilder}; +use syntax_pos::{BytePos, Pos, Span}; +use rustc_lexer::Base; +use rustc_lexer::unescape; + +use std::char; +use std::convert::TryInto; +use rustc_data_structures::sync::Lrc; +use log::debug; + +mod tokentrees; +mod unicode_chars; +mod unescape_error_reporting; +use unescape_error_reporting::{emit_unescape_error, push_escaped_char}; + +#[derive(Clone, Debug)] +pub struct UnmatchedBrace { + pub expected_delim: token::DelimToken, + pub found_delim: Option, + pub found_span: Span, + pub unclosed_span: Option, + pub candidate_span: Option, +} + +pub struct StringReader<'a> { + sess: &'a ParseSess, + /// Initial position, read-only. + start_pos: BytePos, + /// The absolute offset within the source_map of the current character. + // FIXME(#64197): `pub` is needed by tests for now. + pub pos: BytePos, + /// Stop reading src at this index. + end_src_index: usize, + /// Source text to tokenize. + src: Lrc, + override_span: Option, +} + +impl<'a> StringReader<'a> { + pub fn new(sess: &'a ParseSess, + source_file: Lrc, + override_span: Option) -> Self { + if source_file.src.is_none() { + sess.span_diagnostic.bug(&format!("cannot lex `source_file` without source: {}", + source_file.name)); + } + + let src = (*source_file.src.as_ref().unwrap()).clone(); + + StringReader { + sess, + start_pos: source_file.start_pos, + pos: source_file.start_pos, + end_src_index: src.len(), + src, + override_span, + } + } + + pub fn retokenize(sess: &'a ParseSess, mut span: Span) -> Self { + let begin = sess.source_map().lookup_byte_offset(span.lo()); + let end = sess.source_map().lookup_byte_offset(span.hi()); + + // Make the range zero-length if the span is invalid. + if begin.sf.start_pos != end.sf.start_pos { + span = span.shrink_to_lo(); + } + + let mut sr = StringReader::new(sess, begin.sf, None); + + // Seek the lexer to the right byte range. + sr.end_src_index = sr.src_index(span.hi()); + + sr + } + + + fn mk_sp(&self, lo: BytePos, hi: BytePos) -> Span { + self.override_span.unwrap_or_else(|| Span::with_root_ctxt(lo, hi)) + } + + /// Returns the next token, including trivia like whitespace or comments. + /// + /// `Err(())` means that some errors were encountered, which can be + /// retrieved using `buffer_fatal_errors`. + pub fn next_token(&mut self) -> Token { + let start_src_index = self.src_index(self.pos); + let text: &str = &self.src[start_src_index..self.end_src_index]; + + if text.is_empty() { + let span = self.mk_sp(self.pos, self.pos); + return Token::new(token::Eof, span); + } + + { + let is_beginning_of_file = self.pos == self.start_pos; + if is_beginning_of_file { + if let Some(shebang_len) = rustc_lexer::strip_shebang(text) { + let start = self.pos; + self.pos = self.pos + BytePos::from_usize(shebang_len); + + let sym = self.symbol_from(start + BytePos::from_usize("#!".len())); + let kind = token::Shebang(sym); + + let span = self.mk_sp(start, self.pos); + return Token::new(kind, span); + } + } + } + + let token = rustc_lexer::first_token(text); + + let start = self.pos; + self.pos = self.pos + BytePos::from_usize(token.len); + + debug!("try_next_token: {:?}({:?})", token.kind, self.str_from(start)); + + // This could use `?`, but that makes code significantly (10-20%) slower. + // https://github.com/rust-lang/rust/issues/37939 + let kind = self.cook_lexer_token(token.kind, start); + + let span = self.mk_sp(start, self.pos); + Token::new(kind, span) + } + + /// Report a fatal lexical error with a given span. + fn fatal_span(&self, sp: Span, m: &str) -> FatalError { + self.sess.span_diagnostic.span_fatal(sp, m) + } + + /// Report a lexical error with a given span. + fn err_span(&self, sp: Span, m: &str) { + self.sess.span_diagnostic.struct_span_err(sp, m).emit(); + } + + + /// Report a fatal error spanning [`from_pos`, `to_pos`). + fn fatal_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) -> FatalError { + self.fatal_span(self.mk_sp(from_pos, to_pos), m) + } + + /// Report a lexical error spanning [`from_pos`, `to_pos`). + fn err_span_(&self, from_pos: BytePos, to_pos: BytePos, m: &str) { + self.err_span(self.mk_sp(from_pos, to_pos), m) + } + + fn struct_span_fatal(&self, from_pos: BytePos, to_pos: BytePos, m: &str) + -> DiagnosticBuilder<'a> + { + self.sess.span_diagnostic.struct_span_fatal(self.mk_sp(from_pos, to_pos), m) + } + + fn struct_fatal_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) + -> DiagnosticBuilder<'a> + { + let mut m = m.to_string(); + m.push_str(": "); + push_escaped_char(&mut m, c); + + self.sess.span_diagnostic.struct_span_fatal(self.mk_sp(from_pos, to_pos), &m[..]) + } + + /// Turns simple `rustc_lexer::TokenKind` enum into a rich + /// `libsyntax::TokenKind`. This turns strings into interned + /// symbols and runs additional validation. + fn cook_lexer_token( + &self, + token: rustc_lexer::TokenKind, + start: BytePos, + ) -> TokenKind { + match token { + rustc_lexer::TokenKind::LineComment => { + let string = self.str_from(start); + // comments with only more "/"s are not doc comments + let tok = if comments::is_line_doc_comment(string) { + self.forbid_bare_cr(start, string, "bare CR not allowed in doc-comment"); + token::DocComment(Symbol::intern(string)) + } else { + token::Comment + }; + + tok + } + rustc_lexer::TokenKind::BlockComment { terminated } => { + let string = self.str_from(start); + // block comments starting with "/**" or "/*!" are doc-comments + // but comments with only "*"s between two "/"s are not + let is_doc_comment = comments::is_block_doc_comment(string); + + if !terminated { + let msg = if is_doc_comment { + "unterminated block doc-comment" + } else { + "unterminated block comment" + }; + let last_bpos = self.pos; + self.fatal_span_(start, last_bpos, msg).raise(); + } + + let tok = if is_doc_comment { + self.forbid_bare_cr(start, + string, + "bare CR not allowed in block doc-comment"); + token::DocComment(Symbol::intern(string)) + } else { + token::Comment + }; + + tok + } + rustc_lexer::TokenKind::Whitespace => token::Whitespace, + rustc_lexer::TokenKind::Ident | rustc_lexer::TokenKind::RawIdent => { + let is_raw_ident = token == rustc_lexer::TokenKind::RawIdent; + let mut ident_start = start; + if is_raw_ident { + ident_start = ident_start + BytePos(2); + } + // FIXME: perform NFKC normalization here. (Issue #2253) + let sym = self.symbol_from(ident_start); + if is_raw_ident { + let span = self.mk_sp(start, self.pos); + if !sym.can_be_raw() { + self.err_span(span, &format!("`{}` cannot be a raw identifier", sym)); + } + self.sess.raw_identifier_spans.borrow_mut().push(span); + } + token::Ident(sym, is_raw_ident) + } + rustc_lexer::TokenKind::Literal { kind, suffix_start } => { + let suffix_start = start + BytePos(suffix_start as u32); + let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind); + let suffix = if suffix_start < self.pos { + let string = self.str_from(suffix_start); + if string == "_" { + self.sess.span_diagnostic + .struct_span_warn(self.mk_sp(suffix_start, self.pos), + "underscore literal suffix is not allowed") + .warn("this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!") + .note("for more information, see issue #42326 \ + ") + .emit(); + None + } else { + Some(Symbol::intern(string)) + } + } else { + None + }; + token::Literal(token::Lit { kind, symbol, suffix }) + } + rustc_lexer::TokenKind::Lifetime { starts_with_number } => { + // Include the leading `'` in the real identifier, for macro + // expansion purposes. See #12512 for the gory details of why + // this is necessary. + let lifetime_name = self.str_from(start); + if starts_with_number { + self.err_span_( + start, + self.pos, + "lifetimes cannot start with a number", + ); + } + let ident = Symbol::intern(lifetime_name); + token::Lifetime(ident) + } + rustc_lexer::TokenKind::Semi => token::Semi, + rustc_lexer::TokenKind::Comma => token::Comma, + rustc_lexer::TokenKind::Dot => token::Dot, + rustc_lexer::TokenKind::OpenParen => token::OpenDelim(token::Paren), + rustc_lexer::TokenKind::CloseParen => token::CloseDelim(token::Paren), + rustc_lexer::TokenKind::OpenBrace => token::OpenDelim(token::Brace), + rustc_lexer::TokenKind::CloseBrace => token::CloseDelim(token::Brace), + rustc_lexer::TokenKind::OpenBracket => token::OpenDelim(token::Bracket), + rustc_lexer::TokenKind::CloseBracket => token::CloseDelim(token::Bracket), + rustc_lexer::TokenKind::At => token::At, + rustc_lexer::TokenKind::Pound => token::Pound, + rustc_lexer::TokenKind::Tilde => token::Tilde, + rustc_lexer::TokenKind::Question => token::Question, + rustc_lexer::TokenKind::Colon => token::Colon, + rustc_lexer::TokenKind::Dollar => token::Dollar, + rustc_lexer::TokenKind::Eq => token::Eq, + rustc_lexer::TokenKind::Not => token::Not, + rustc_lexer::TokenKind::Lt => token::Lt, + rustc_lexer::TokenKind::Gt => token::Gt, + rustc_lexer::TokenKind::Minus => token::BinOp(token::Minus), + rustc_lexer::TokenKind::And => token::BinOp(token::And), + rustc_lexer::TokenKind::Or => token::BinOp(token::Or), + rustc_lexer::TokenKind::Plus => token::BinOp(token::Plus), + rustc_lexer::TokenKind::Star => token::BinOp(token::Star), + rustc_lexer::TokenKind::Slash => token::BinOp(token::Slash), + rustc_lexer::TokenKind::Caret => token::BinOp(token::Caret), + rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent), + + rustc_lexer::TokenKind::Unknown => { + let c = self.str_from(start).chars().next().unwrap(); + let mut err = self.struct_fatal_span_char(start, + self.pos, + "unknown start of token", + c); + // FIXME: the lexer could be used to turn the ASCII version of unicode homoglyphs, + // instead of keeping a table in `check_for_substitution`into the token. Ideally, + // this should be inside `rustc_lexer`. However, we should first remove compound + // tokens like `<<` from `rustc_lexer`, and then add fancier error recovery to it, + // as there will be less overall work to do this way. + let token = unicode_chars::check_for_substitution(self, start, c, &mut err) + .unwrap_or_else(|| token::Unknown(self.symbol_from(start))); + err.emit(); + token + } + } + } + + fn cook_lexer_literal( + &self, + start: BytePos, + suffix_start: BytePos, + kind: rustc_lexer::LiteralKind + ) -> (token::LitKind, Symbol) { + match kind { + rustc_lexer::LiteralKind::Char { terminated } => { + if !terminated { + self.fatal_span_(start, suffix_start, + "unterminated character literal".into()) + .raise() + } + let content_start = start + BytePos(1); + let content_end = suffix_start - BytePos(1); + self.validate_char_escape(content_start, content_end); + let id = self.symbol_from_to(content_start, content_end); + (token::Char, id) + }, + rustc_lexer::LiteralKind::Byte { terminated } => { + if !terminated { + self.fatal_span_(start + BytePos(1), suffix_start, + "unterminated byte constant".into()) + .raise() + } + let content_start = start + BytePos(2); + let content_end = suffix_start - BytePos(1); + self.validate_byte_escape(content_start, content_end); + let id = self.symbol_from_to(content_start, content_end); + (token::Byte, id) + }, + rustc_lexer::LiteralKind::Str { terminated } => { + if !terminated { + self.fatal_span_(start, suffix_start, + "unterminated double quote string".into()) + .raise() + } + let content_start = start + BytePos(1); + let content_end = suffix_start - BytePos(1); + self.validate_str_escape(content_start, content_end); + let id = self.symbol_from_to(content_start, content_end); + (token::Str, id) + } + rustc_lexer::LiteralKind::ByteStr { terminated } => { + if !terminated { + self.fatal_span_(start + BytePos(1), suffix_start, + "unterminated double quote byte string".into()) + .raise() + } + let content_start = start + BytePos(2); + let content_end = suffix_start - BytePos(1); + self.validate_byte_str_escape(content_start, content_end); + let id = self.symbol_from_to(content_start, content_end); + (token::ByteStr, id) + } + rustc_lexer::LiteralKind::RawStr { n_hashes, started, terminated } => { + if !started { + self.report_non_started_raw_string(start); + } + if !terminated { + self.report_unterminated_raw_string(start, n_hashes) + } + let n_hashes: u16 = self.restrict_n_hashes(start, n_hashes); + let n = u32::from(n_hashes); + let content_start = start + BytePos(2 + n); + let content_end = suffix_start - BytePos(1 + n); + self.validate_raw_str_escape(content_start, content_end); + let id = self.symbol_from_to(content_start, content_end); + (token::StrRaw(n_hashes), id) + } + rustc_lexer::LiteralKind::RawByteStr { n_hashes, started, terminated } => { + if !started { + self.report_non_started_raw_string(start); + } + if !terminated { + self.report_unterminated_raw_string(start, n_hashes) + } + let n_hashes: u16 = self.restrict_n_hashes(start, n_hashes); + let n = u32::from(n_hashes); + let content_start = start + BytePos(3 + n); + let content_end = suffix_start - BytePos(1 + n); + self.validate_raw_byte_str_escape(content_start, content_end); + let id = self.symbol_from_to(content_start, content_end); + (token::ByteStrRaw(n_hashes), id) + } + rustc_lexer::LiteralKind::Int { base, empty_int } => { + if empty_int { + self.err_span_(start, suffix_start, "no valid digits found for number"); + (token::Integer, sym::integer(0)) + } else { + self.validate_int_literal(base, start, suffix_start); + (token::Integer, self.symbol_from_to(start, suffix_start)) + } + }, + rustc_lexer::LiteralKind::Float { base, empty_exponent } => { + if empty_exponent { + let mut err = self.struct_span_fatal( + start, self.pos, + "expected at least one digit in exponent" + ); + err.emit(); + } + + match base { + Base::Hexadecimal => { + self.err_span_(start, suffix_start, + "hexadecimal float literal is not supported") + } + Base::Octal => { + self.err_span_(start, suffix_start, + "octal float literal is not supported") + } + Base::Binary => { + self.err_span_(start, suffix_start, + "binary float literal is not supported") + } + _ => () + } + + let id = self.symbol_from_to(start, suffix_start); + (token::Float, id) + }, + } + } + + #[inline] + fn src_index(&self, pos: BytePos) -> usize { + (pos - self.start_pos).to_usize() + } + + /// Slice of the source text from `start` up to but excluding `self.pos`, + /// meaning the slice does not include the character `self.ch`. + fn str_from(&self, start: BytePos) -> &str + { + self.str_from_to(start, self.pos) + } + + /// Creates a Symbol from a given offset to the current offset. + fn symbol_from(&self, start: BytePos) -> Symbol { + debug!("taking an ident from {:?} to {:?}", start, self.pos); + Symbol::intern(self.str_from(start)) + } + + /// As symbol_from, with an explicit endpoint. + fn symbol_from_to(&self, start: BytePos, end: BytePos) -> Symbol { + debug!("taking an ident from {:?} to {:?}", start, end); + Symbol::intern(self.str_from_to(start, end)) + } + + /// Slice of the source text spanning from `start` up to but excluding `end`. + fn str_from_to(&self, start: BytePos, end: BytePos) -> &str + { + &self.src[self.src_index(start)..self.src_index(end)] + } + + fn forbid_bare_cr(&self, start: BytePos, s: &str, errmsg: &str) { + let mut idx = 0; + loop { + idx = match s[idx..].find('\r') { + None => break, + Some(it) => idx + it + 1 + }; + self.err_span_(start + BytePos(idx as u32 - 1), + start + BytePos(idx as u32), + errmsg); + } + } + + fn report_non_started_raw_string(&self, start: BytePos) -> ! { + let bad_char = self.str_from(start).chars().last().unwrap(); + self + .struct_fatal_span_char( + start, + self.pos, + "found invalid character; only `#` is allowed \ + in raw string delimitation", + bad_char, + ) + .emit(); + FatalError.raise() + } + + fn report_unterminated_raw_string(&self, start: BytePos, n_hashes: usize) -> ! { + let mut err = self.struct_span_fatal( + start, start, + "unterminated raw string", + ); + err.span_label( + self.mk_sp(start, start), + "unterminated raw string", + ); + + if n_hashes > 0 { + err.note(&format!("this raw string should be terminated with `\"{}`", + "#".repeat(n_hashes as usize))); + } + + err.emit(); + FatalError.raise() + } + + fn restrict_n_hashes(&self, start: BytePos, n_hashes: usize) -> u16 { + match n_hashes.try_into() { + Ok(n_hashes) => n_hashes, + Err(_) => { + self.fatal_span_(start, + self.pos, + "too many `#` symbols: raw strings may be \ + delimited by up to 65535 `#` symbols").raise(); + } + } + } + + fn validate_char_escape(&self, content_start: BytePos, content_end: BytePos) { + let lit = self.str_from_to(content_start, content_end); + if let Err((off, err)) = unescape::unescape_char(lit) { + emit_unescape_error( + &self.sess.span_diagnostic, + lit, + self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)), + unescape::Mode::Char, + 0..off, + err, + ) + } + } + + fn validate_byte_escape(&self, content_start: BytePos, content_end: BytePos) { + let lit = self.str_from_to(content_start, content_end); + if let Err((off, err)) = unescape::unescape_byte(lit) { + emit_unescape_error( + &self.sess.span_diagnostic, + lit, + self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)), + unescape::Mode::Byte, + 0..off, + err, + ) + } + } + + fn validate_str_escape(&self, content_start: BytePos, content_end: BytePos) { + let lit = self.str_from_to(content_start, content_end); + unescape::unescape_str(lit, &mut |range, c| { + if let Err(err) = c { + emit_unescape_error( + &self.sess.span_diagnostic, + lit, + self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)), + unescape::Mode::Str, + range, + err, + ) + } + }) + } + + fn validate_raw_str_escape(&self, content_start: BytePos, content_end: BytePos) { + let lit = self.str_from_to(content_start, content_end); + unescape::unescape_raw_str(lit, &mut |range, c| { + if let Err(err) = c { + emit_unescape_error( + &self.sess.span_diagnostic, + lit, + self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)), + unescape::Mode::Str, + range, + err, + ) + } + }) + } + + fn validate_raw_byte_str_escape(&self, content_start: BytePos, content_end: BytePos) { + let lit = self.str_from_to(content_start, content_end); + unescape::unescape_raw_byte_str(lit, &mut |range, c| { + if let Err(err) = c { + emit_unescape_error( + &self.sess.span_diagnostic, + lit, + self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)), + unescape::Mode::ByteStr, + range, + err, + ) + } + }) + } + + fn validate_byte_str_escape(&self, content_start: BytePos, content_end: BytePos) { + let lit = self.str_from_to(content_start, content_end); + unescape::unescape_byte_str(lit, &mut |range, c| { + if let Err(err) = c { + emit_unescape_error( + &self.sess.span_diagnostic, + lit, + self.mk_sp(content_start - BytePos(1), content_end + BytePos(1)), + unescape::Mode::ByteStr, + range, + err, + ) + } + }) + } + + fn validate_int_literal(&self, base: Base, content_start: BytePos, content_end: BytePos) { + let base = match base { + Base::Binary => 2, + Base::Octal => 8, + _ => return, + }; + let s = self.str_from_to(content_start + BytePos(2), content_end); + for (idx, c) in s.char_indices() { + let idx = idx as u32; + if c != '_' && c.to_digit(base).is_none() { + let lo = content_start + BytePos(2 + idx); + let hi = content_start + BytePos(2 + idx + c.len_utf8() as u32); + self.err_span_(lo, hi, + &format!("invalid digit for a base {} literal", base)); + + } + } + } +} diff --git a/src/librustc_parse/lexer/tokentrees.rs b/src/librustc_parse/lexer/tokentrees.rs new file mode 100644 index 00000000000..1353591308b --- /dev/null +++ b/src/librustc_parse/lexer/tokentrees.rs @@ -0,0 +1,280 @@ +use rustc_data_structures::fx::FxHashMap; +use syntax_pos::Span; + +use super::{StringReader, UnmatchedBrace}; + +use syntax::print::pprust::token_to_string; +use syntax::token::{self, Token}; +use syntax::tokenstream::{DelimSpan, IsJoint::{self, *}, TokenStream, TokenTree, TreeAndJoint}; + +use errors::PResult; + +impl<'a> StringReader<'a> { + crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec) { + let mut tt_reader = TokenTreesReader { + string_reader: self, + token: Token::dummy(), + joint_to_prev: Joint, + open_braces: Vec::new(), + unmatched_braces: Vec::new(), + matching_delim_spans: Vec::new(), + last_unclosed_found_span: None, + last_delim_empty_block_spans: FxHashMap::default() + }; + let res = tt_reader.parse_all_token_trees(); + (res, tt_reader.unmatched_braces) + } +} + +struct TokenTreesReader<'a> { + string_reader: StringReader<'a>, + token: Token, + joint_to_prev: IsJoint, + /// Stack of open delimiters and their spans. Used for error message. + open_braces: Vec<(token::DelimToken, Span)>, + unmatched_braces: Vec, + /// The type and spans for all braces + /// + /// Used only for error recovery when arriving to EOF with mismatched braces. + matching_delim_spans: Vec<(token::DelimToken, Span, Span)>, + last_unclosed_found_span: Option, + last_delim_empty_block_spans: FxHashMap +} + +impl<'a> TokenTreesReader<'a> { + // Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`. + fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> { + let mut buf = TokenStreamBuilder::default(); + + self.real_token(); + while self.token != token::Eof { + buf.push(self.parse_token_tree()?); + } + + Ok(buf.into_token_stream()) + } + + // Parse a stream of tokens into a list of `TokenTree`s, up to a `CloseDelim`. + fn parse_token_trees_until_close_delim(&mut self) -> TokenStream { + let mut buf = TokenStreamBuilder::default(); + loop { + if let token::CloseDelim(..) = self.token.kind { + return buf.into_token_stream(); + } + + match self.parse_token_tree() { + Ok(tree) => buf.push(tree), + Err(mut e) => { + e.emit(); + return buf.into_token_stream(); + } + } + } + } + + fn parse_token_tree(&mut self) -> PResult<'a, TreeAndJoint> { + let sm = self.string_reader.sess.source_map(); + match self.token.kind { + token::Eof => { + let msg = "this file contains an un-closed delimiter"; + let mut err = self.string_reader.sess.span_diagnostic + .struct_span_err(self.token.span, msg); + for &(_, sp) in &self.open_braces { + err.span_label(sp, "un-closed delimiter"); + self.unmatched_braces.push(UnmatchedBrace { + expected_delim: token::DelimToken::Brace, + found_delim: None, + found_span: self.token.span, + unclosed_span: Some(sp), + candidate_span: None, + }); + } + + if let Some((delim, _)) = self.open_braces.last() { + if let Some((_, open_sp, close_sp)) = self.matching_delim_spans.iter() + .filter(|(d, open_sp, close_sp)| { + if let Some(close_padding) = sm.span_to_margin(*close_sp) { + if let Some(open_padding) = sm.span_to_margin(*open_sp) { + return delim == d && close_padding != open_padding; + } + } + false + }).next() // these are in reverse order as they get inserted on close, but + { // we want the last open/first close + err.span_label( + *open_sp, + "this delimiter might not be properly closed...", + ); + err.span_label( + *close_sp, + "...as it matches this but it has different indentation", + ); + } + } + Err(err) + }, + token::OpenDelim(delim) => { + // The span for beginning of the delimited section + let pre_span = self.token.span; + + // Parse the open delimiter. + self.open_braces.push((delim, self.token.span)); + self.real_token(); + + // Parse the token trees within the delimiters. + // We stop at any delimiter so we can try to recover if the user + // uses an incorrect delimiter. + let tts = self.parse_token_trees_until_close_delim(); + + // Expand to cover the entire delimited token tree + let delim_span = DelimSpan::from_pair(pre_span, self.token.span); + + match self.token.kind { + // Correct delimiter. + token::CloseDelim(d) if d == delim => { + let (open_brace, open_brace_span) = self.open_braces.pop().unwrap(); + let close_brace_span = self.token.span; + + if tts.is_empty() { + let empty_block_span = open_brace_span.to(close_brace_span); + self.last_delim_empty_block_spans.insert(delim, empty_block_span); + } + + if self.open_braces.len() == 0 { + // Clear up these spans to avoid suggesting them as we've found + // properly matched delimiters so far for an entire block. + self.matching_delim_spans.clear(); + } else { + self.matching_delim_spans.push( + (open_brace, open_brace_span, close_brace_span), + ); + } + // Parse the close delimiter. + self.real_token(); + } + // Incorrect delimiter. + token::CloseDelim(other) => { + let mut unclosed_delimiter = None; + let mut candidate = None; + if self.last_unclosed_found_span != Some(self.token.span) { + // do not complain about the same unclosed delimiter multiple times + self.last_unclosed_found_span = Some(self.token.span); + // This is a conservative error: only report the last unclosed + // delimiter. The previous unclosed delimiters could actually be + // closed! The parser just hasn't gotten to them yet. + if let Some(&(_, sp)) = self.open_braces.last() { + unclosed_delimiter = Some(sp); + }; + if let Some(current_padding) = sm.span_to_margin(self.token.span) { + for (brace, brace_span) in &self.open_braces { + if let Some(padding) = sm.span_to_margin(*brace_span) { + // high likelihood of these two corresponding + if current_padding == padding && brace == &other { + candidate = Some(*brace_span); + } + } + } + } + let (tok, _) = self.open_braces.pop().unwrap(); + self.unmatched_braces.push(UnmatchedBrace { + expected_delim: tok, + found_delim: Some(other), + found_span: self.token.span, + unclosed_span: unclosed_delimiter, + candidate_span: candidate, + }); + } else { + self.open_braces.pop(); + } + + // If the incorrect delimiter matches an earlier opening + // delimiter, then don't consume it (it can be used to + // close the earlier one). Otherwise, consume it. + // E.g., we try to recover from: + // fn foo() { + // bar(baz( + // } // Incorrect delimiter but matches the earlier `{` + if !self.open_braces.iter().any(|&(b, _)| b == other) { + self.real_token(); + } + } + token::Eof => { + // Silently recover, the EOF token will be seen again + // and an error emitted then. Thus we don't pop from + // self.open_braces here. + }, + _ => {} + } + + Ok(TokenTree::Delimited( + delim_span, + delim, + tts.into() + ).into()) + }, + token::CloseDelim(delim) => { + // An unexpected closing delimiter (i.e., there is no + // matching opening delimiter). + let token_str = token_to_string(&self.token); + let msg = format!("unexpected close delimiter: `{}`", token_str); + let mut err = self.string_reader.sess.span_diagnostic + .struct_span_err(self.token.span, &msg); + + if let Some(span) = self.last_delim_empty_block_spans.remove(&delim) { + err.span_label( + span, + "this block is empty, you might have not meant to close it" + ); + } + err.span_label(self.token.span, "unexpected close delimiter"); + Err(err) + }, + _ => { + let tt = TokenTree::Token(self.token.take()); + self.real_token(); + let is_joint = self.joint_to_prev == Joint && self.token.is_op(); + Ok((tt, if is_joint { Joint } else { NonJoint })) + } + } + } + + fn real_token(&mut self) { + self.joint_to_prev = Joint; + loop { + let token = self.string_reader.next_token(); + match token.kind { + token::Whitespace | token::Comment | token::Shebang(_) | token::Unknown(_) => { + self.joint_to_prev = NonJoint; + } + _ => { + self.token = token; + return; + } + } + } + } +} + +#[derive(Default)] +struct TokenStreamBuilder { + buf: Vec, +} + +impl TokenStreamBuilder { + fn push(&mut self, (tree, joint): TreeAndJoint) { + if let Some((TokenTree::Token(prev_token), Joint)) = self.buf.last() { + if let TokenTree::Token(token) = &tree { + if let Some(glued) = prev_token.glue(token) { + self.buf.pop(); + self.buf.push((TokenTree::Token(glued), joint)); + return; + } + } + } + self.buf.push((tree, joint)) + } + + fn into_token_stream(self) -> TokenStream { + TokenStream::new(self.buf) + } +} diff --git a/src/librustc_parse/lexer/unescape_error_reporting.rs b/src/librustc_parse/lexer/unescape_error_reporting.rs new file mode 100644 index 00000000000..a5749d07e62 --- /dev/null +++ b/src/librustc_parse/lexer/unescape_error_reporting.rs @@ -0,0 +1,215 @@ +//! Utilities for rendering escape sequence errors as diagnostics. + +use std::ops::Range; +use std::iter::once; + +use rustc_lexer::unescape::{EscapeError, Mode}; +use syntax_pos::{Span, BytePos}; + +use syntax::errors::{Handler, Applicability}; + +pub(crate) fn emit_unescape_error( + handler: &Handler, + // interior part of the literal, without quotes + lit: &str, + // full span of the literal, including quotes + span_with_quotes: Span, + mode: Mode, + // range of the error inside `lit` + range: Range, + error: EscapeError, +) { + log::debug!("emit_unescape_error: {:?}, {:?}, {:?}, {:?}, {:?}", + lit, span_with_quotes, mode, range, error); + let span = { + let Range { start, end } = range; + let (start, end) = (start as u32, end as u32); + let lo = span_with_quotes.lo() + BytePos(start + 1); + let hi = lo + BytePos(end - start); + span_with_quotes + .with_lo(lo) + .with_hi(hi) + }; + let last_char = || { + let c = lit[range.clone()].chars().rev().next().unwrap(); + let span = span.with_lo(span.hi() - BytePos(c.len_utf8() as u32)); + (c, span) + }; + match error { + EscapeError::LoneSurrogateUnicodeEscape => { + handler.struct_span_err(span, "invalid unicode character escape") + .help("unicode escape must not be a surrogate") + .emit(); + } + EscapeError::OutOfRangeUnicodeEscape => { + handler.struct_span_err(span, "invalid unicode character escape") + .help("unicode escape must be at most 10FFFF") + .emit(); + } + EscapeError::MoreThanOneChar => { + let msg = if mode.is_bytes() { + "if you meant to write a byte string literal, use double quotes" + } else { + "if you meant to write a `str` literal, use double quotes" + }; + + handler + .struct_span_err( + span_with_quotes, + "character literal may only contain one codepoint", + ) + .span_suggestion( + span_with_quotes, + msg, + format!("\"{}\"", lit), + Applicability::MachineApplicable, + ).emit() + } + EscapeError::EscapeOnlyChar => { + let (c, _span) = last_char(); + + let mut msg = if mode.is_bytes() { + "byte constant must be escaped: " + } else { + "character constant must be escaped: " + }.to_string(); + push_escaped_char(&mut msg, c); + + handler.span_err(span, msg.as_str()) + } + EscapeError::BareCarriageReturn => { + let msg = if mode.in_double_quotes() { + "bare CR not allowed in string, use \\r instead" + } else { + "character constant must be escaped: \\r" + }; + handler.span_err(span, msg); + } + EscapeError::BareCarriageReturnInRawString => { + assert!(mode.in_double_quotes()); + let msg = "bare CR not allowed in raw string"; + handler.span_err(span, msg); + } + EscapeError::InvalidEscape => { + let (c, span) = last_char(); + + let label = if mode.is_bytes() { + "unknown byte escape" + } else { + "unknown character escape" + }; + let mut msg = label.to_string(); + msg.push_str(": "); + push_escaped_char(&mut msg, c); + + let mut diag = handler.struct_span_err(span, msg.as_str()); + diag.span_label(span, label); + if c == '{' || c == '}' && !mode.is_bytes() { + diag.help("if used in a formatting string, \ + curly braces are escaped with `{{` and `}}`"); + } else if c == '\r' { + diag.help("this is an isolated carriage return; \ + consider checking your editor and version control settings"); + } + diag.emit(); + } + EscapeError::TooShortHexEscape => { + handler.span_err(span, "numeric character escape is too short") + } + EscapeError::InvalidCharInHexEscape | EscapeError::InvalidCharInUnicodeEscape => { + let (c, span) = last_char(); + + let mut msg = if error == EscapeError::InvalidCharInHexEscape { + "invalid character in numeric character escape: " + } else { + "invalid character in unicode escape: " + }.to_string(); + push_escaped_char(&mut msg, c); + + handler.span_err(span, msg.as_str()) + } + EscapeError::NonAsciiCharInByte => { + assert!(mode.is_bytes()); + let (_c, span) = last_char(); + handler.span_err(span, "byte constant must be ASCII. \ + Use a \\xHH escape for a non-ASCII byte") + } + EscapeError::NonAsciiCharInByteString => { + assert!(mode.is_bytes()); + let (_c, span) = last_char(); + handler.span_err(span, "raw byte string must be ASCII") + } + EscapeError::OutOfRangeHexEscape => { + handler.span_err(span, "this form of character escape may only be used \ + with characters in the range [\\x00-\\x7f]") + } + EscapeError::LeadingUnderscoreUnicodeEscape => { + let (_c, span) = last_char(); + handler.span_err(span, "invalid start of unicode escape") + } + EscapeError::OverlongUnicodeEscape => { + handler.span_err(span, "overlong unicode escape (must have at most 6 hex digits)") + } + EscapeError::UnclosedUnicodeEscape => { + handler.span_err(span, "unterminated unicode escape (needed a `}`)") + } + EscapeError::NoBraceInUnicodeEscape => { + let msg = "incorrect unicode escape sequence"; + let mut diag = handler.struct_span_err(span, msg); + + let mut suggestion = "\\u{".to_owned(); + let mut suggestion_len = 0; + let (c, char_span) = last_char(); + let chars = once(c).chain(lit[range.end..].chars()); + for c in chars.take(6).take_while(|c| c.is_digit(16)) { + suggestion.push(c); + suggestion_len += c.len_utf8(); + } + + if suggestion_len > 0 { + suggestion.push('}'); + let lo = char_span.lo(); + let hi = lo + BytePos(suggestion_len as u32); + diag.span_suggestion( + span.with_lo(lo).with_hi(hi), + "format of unicode escape sequences uses braces", + suggestion, + Applicability::MaybeIncorrect, + ); + } else { + diag.span_label(span, msg); + diag.help( + "format of unicode escape sequences is `\\u{...}`", + ); + } + + diag.emit(); + } + EscapeError::UnicodeEscapeInByte => { + handler.span_err(span, "unicode escape sequences cannot be used \ + as a byte or in a byte string") + } + EscapeError::EmptyUnicodeEscape => { + handler.span_err(span, "empty unicode escape (must have at least 1 hex digit)") + } + EscapeError::ZeroChars => { + handler.span_err(span, "empty character literal") + } + EscapeError::LoneSlash => { + handler.span_err(span, "invalid trailing slash in literal") + } + } +} + +/// Pushes a character to a message string for error reporting +pub(crate) fn push_escaped_char(msg: &mut String, c: char) { + match c { + '\u{20}'..='\u{7e}' => { + // Don't escape \, ' or " for user-facing messages + msg.push(c); + } + _ => { + msg.extend(c.escape_default()); + } + } +} diff --git a/src/librustc_parse/lexer/unicode_chars.rs b/src/librustc_parse/lexer/unicode_chars.rs new file mode 100644 index 00000000000..6eb995b61d3 --- /dev/null +++ b/src/librustc_parse/lexer/unicode_chars.rs @@ -0,0 +1,392 @@ +// Characters and their corresponding confusables were collected from +// http://www.unicode.org/Public/security/10.0.0/confusables.txt + +use super::StringReader; +use errors::{Applicability, DiagnosticBuilder}; +use syntax_pos::{BytePos, Pos, Span, symbol::kw}; +use crate::token; + +#[rustfmt::skip] // for line breaks +const UNICODE_ARRAY: &[(char, &str, char)] = &[ + ('
', "Line Separator", ' '), + ('
', "Paragraph Separator", ' '), + (' ', "Ogham Space mark", ' '), + (' ', "En Quad", ' '), + (' ', "Em Quad", ' '), + (' ', "En Space", ' '), + (' ', "Em Space", ' '), + (' ', "Three-Per-Em Space", ' '), + (' ', "Four-Per-Em Space", ' '), + (' ', "Six-Per-Em Space", ' '), + (' ', "Punctuation Space", ' '), + (' ', "Thin Space", ' '), + (' ', "Hair Space", ' '), + (' ', "Medium Mathematical Space", ' '), + (' ', "No-Break Space", ' '), + (' ', "Figure Space", ' '), + (' ', "Narrow No-Break Space", ' '), + (' ', "Ideographic Space", ' '), + + ('ߺ', "Nko Lajanyalan", '_'), + ('﹍', "Dashed Low Line", '_'), + ('﹎', "Centreline Low Line", '_'), + ('﹏', "Wavy Low Line", '_'), + ('_', "Fullwidth Low Line", '_'), + + ('‐', "Hyphen", '-'), + ('‑', "Non-Breaking Hyphen", '-'), + ('‒', "Figure Dash", '-'), + ('–', "En Dash", '-'), + ('—', "Em Dash", '-'), + ('﹘', "Small Em Dash", '-'), + ('۔', "Arabic Full Stop", '-'), + ('⁃', "Hyphen Bullet", '-'), + ('˗', "Modifier Letter Minus Sign", '-'), + ('−', "Minus Sign", '-'), + ('➖', "Heavy Minus Sign", '-'), + ('Ⲻ', "Coptic Letter Dialect-P Ni", '-'), + ('ー', "Katakana-Hiragana Prolonged Sound Mark", '-'), + ('-', "Fullwidth Hyphen-Minus", '-'), + ('―', "Horizontal Bar", '-'), + ('─', "Box Drawings Light Horizontal", '-'), + ('━', "Box Drawings Heavy Horizontal", '-'), + ('㇐', "CJK Stroke H", '-'), + ('ꟷ', "Latin Epigraphic Letter Sideways I", '-'), + ('ᅳ', "Hangul Jungseong Eu", '-'), + ('ㅡ', "Hangul Letter Eu", '-'), + ('一', "CJK Unified Ideograph-4E00", '-'), + ('⼀', "Kangxi Radical One", '-'), + + ('؍', "Arabic Date Separator", ','), + ('٫', "Arabic Decimal Separator", ','), + ('‚', "Single Low-9 Quotation Mark", ','), + ('¸', "Cedilla", ','), + ('ꓹ', "Lisu Letter Tone Na Po", ','), + (',', "Fullwidth Comma", ','), + + (';', "Greek Question Mark", ';'), + (';', "Fullwidth Semicolon", ';'), + ('︔', "Presentation Form For Vertical Semicolon", ';'), + + ('ः', "Devanagari Sign Visarga", ':'), + ('ઃ', "Gujarati Sign Visarga", ':'), + (':', "Fullwidth Colon", ':'), + ('։', "Armenian Full Stop", ':'), + ('܃', "Syriac Supralinear Colon", ':'), + ('܄', "Syriac Sublinear Colon", ':'), + ('᛬', "Runic Multiple Punctuation", ':'), + ('︰', "Presentation Form For Vertical Two Dot Leader", ':'), + ('᠃', "Mongolian Full Stop", ':'), + ('᠉', "Mongolian Manchu Full Stop", ':'), + ('⁚', "Two Dot Punctuation", ':'), + ('׃', "Hebrew Punctuation Sof Pasuq", ':'), + ('˸', "Modifier Letter Raised Colon", ':'), + ('꞉', "Modifier Letter Colon", ':'), + ('∶', "Ratio", ':'), + ('ː', "Modifier Letter Triangular Colon", ':'), + ('ꓽ', "Lisu Letter Tone Mya Jeu", ':'), + ('︓', "Presentation Form For Vertical Colon", ':'), + + ('!', "Fullwidth Exclamation Mark", '!'), + ('ǃ', "Latin Letter Retroflex Click", '!'), + ('ⵑ', "Tifinagh Letter Tuareg Yang", '!'), + ('︕', "Presentation Form For Vertical Exclamation Mark", '!'), + + ('ʔ', "Latin Letter Glottal Stop", '?'), + ('Ɂ', "Latin Capital Letter Glottal Stop", '?'), + ('ॽ', "Devanagari Letter Glottal Stop", '?'), + ('Ꭾ', "Cherokee Letter He", '?'), + ('ꛫ', "Bamum Letter Ntuu", '?'), + ('?', "Fullwidth Question Mark", '?'), + ('︖', "Presentation Form For Vertical Question Mark", '?'), + + ('𝅭', "Musical Symbol Combining Augmentation Dot", '.'), + ('․', "One Dot Leader", '.'), + ('܁', "Syriac Supralinear Full Stop", '.'), + ('܂', "Syriac Sublinear Full Stop", '.'), + ('꘎', "Vai Full Stop", '.'), + ('𐩐', "Kharoshthi Punctuation Dot", '.'), + ('٠', "Arabic-Indic Digit Zero", '.'), + ('۰', "Extended Arabic-Indic Digit Zero", '.'), + ('ꓸ', "Lisu Letter Tone Mya Ti", '.'), + ('·', "Middle Dot", '.'), + ('・', "Katakana Middle Dot", '.'), + ('・', "Halfwidth Katakana Middle Dot", '.'), + ('᛫', "Runic Single Punctuation", '.'), + ('·', "Greek Ano Teleia", '.'), + ('⸱', "Word Separator Middle Dot", '.'), + ('𐄁', "Aegean Word Separator Dot", '.'), + ('•', "Bullet", '.'), + ('‧', "Hyphenation Point", '.'), + ('∙', "Bullet Operator", '.'), + ('⋅', "Dot Operator", '.'), + ('ꞏ', "Latin Letter Sinological Dot", '.'), + ('ᐧ', "Canadian Syllabics Final Middle Dot", '.'), + ('ᐧ', "Canadian Syllabics Final Middle Dot", '.'), + ('.', "Fullwidth Full Stop", '.'), + ('。', "Ideographic Full Stop", '.'), + ('︒', "Presentation Form For Vertical Ideographic Full Stop", '.'), + + ('՝', "Armenian Comma", '\''), + (''', "Fullwidth Apostrophe", '\''), + ('‘', "Left Single Quotation Mark", '\''), + ('’', "Right Single Quotation Mark", '\''), + ('‛', "Single High-Reversed-9 Quotation Mark", '\''), + ('′', "Prime", '\''), + ('‵', "Reversed Prime", '\''), + ('՚', "Armenian Apostrophe", '\''), + ('׳', "Hebrew Punctuation Geresh", '\''), + ('`', "Grave Accent", '\''), + ('`', "Greek Varia", '\''), + ('`', "Fullwidth Grave Accent", '\''), + ('´', "Acute Accent", '\''), + ('΄', "Greek Tonos", '\''), + ('´', "Greek Oxia", '\''), + ('᾽', "Greek Koronis", '\''), + ('᾿', "Greek Psili", '\''), + ('῾', "Greek Dasia", '\''), + ('ʹ', "Modifier Letter Prime", '\''), + ('ʹ', "Greek Numeral Sign", '\''), + ('ˈ', "Modifier Letter Vertical Line", '\''), + ('ˊ', "Modifier Letter Acute Accent", '\''), + ('ˋ', "Modifier Letter Grave Accent", '\''), + ('˴', "Modifier Letter Middle Grave Accent", '\''), + ('ʻ', "Modifier Letter Turned Comma", '\''), + ('ʽ', "Modifier Letter Reversed Comma", '\''), + ('ʼ', "Modifier Letter Apostrophe", '\''), + ('ʾ', "Modifier Letter Right Half Ring", '\''), + ('ꞌ', "Latin Small Letter Saltillo", '\''), + ('י', "Hebrew Letter Yod", '\''), + ('ߴ', "Nko High Tone Apostrophe", '\''), + ('ߵ', "Nko Low Tone Apostrophe", '\''), + ('ᑊ', "Canadian Syllabics West-Cree P", '\''), + ('ᛌ', "Runic Letter Short-Twig-Sol S", '\''), + ('𖽑', "Miao Sign Aspiration", '\''), + ('𖽒', "Miao Sign Reformed Voicing", '\''), + + ('᳓', "Vedic Sign Nihshvasa", '"'), + ('"', "Fullwidth Quotation Mark", '"'), + ('“', "Left Double Quotation Mark", '"'), + ('”', "Right Double Quotation Mark", '"'), + ('‟', "Double High-Reversed-9 Quotation Mark", '"'), + ('″', "Double Prime", '"'), + ('‶', "Reversed Double Prime", '"'), + ('〃', "Ditto Mark", '"'), + ('״', "Hebrew Punctuation Gershayim", '"'), + ('˝', "Double Acute Accent", '"'), + ('ʺ', "Modifier Letter Double Prime", '"'), + ('˶', "Modifier Letter Middle Double Acute Accent", '"'), + ('˵', "Modifier Letter Middle Double Grave Accent", '"'), + ('ˮ', "Modifier Letter Double Apostrophe", '"'), + ('ײ', "Hebrew Ligature Yiddish Double Yod", '"'), + ('❞', "Heavy Double Comma Quotation Mark Ornament", '"'), + ('❝', "Heavy Double Turned Comma Quotation Mark Ornament", '"'), + + ('(', "Fullwidth Left Parenthesis", '('), + ('❨', "Medium Left Parenthesis Ornament", '('), + ('﴾', "Ornate Left Parenthesis", '('), + + (')', "Fullwidth Right Parenthesis", ')'), + ('❩', "Medium Right Parenthesis Ornament", ')'), + ('﴿', "Ornate Right Parenthesis", ')'), + + ('[', "Fullwidth Left Square Bracket", '['), + ('❲', "Light Left Tortoise Shell Bracket Ornament", '['), + ('「', "Left Corner Bracket", '['), + ('『', "Left White Corner Bracket", '['), + ('【', "Left Black Lenticular Bracket", '['), + ('〔', "Left Tortoise Shell Bracket", '['), + ('〖', "Left White Lenticular Bracket", '['), + ('〘', "Left White Tortoise Shell Bracket", '['), + ('〚', "Left White Square Bracket", '['), + + (']', "Fullwidth Right Square Bracket", ']'), + ('❳', "Light Right Tortoise Shell Bracket Ornament", ']'), + ('」', "Right Corner Bracket", ']'), + ('』', "Right White Corner Bracket", ']'), + ('】', "Right Black Lenticular Bracket", ']'), + ('〕', "Right Tortoise Shell Bracket", ']'), + ('〗', "Right White Lenticular Bracket", ']'), + ('〙', "Right White Tortoise Shell Bracket", ']'), + ('〛', "Right White Square Bracket", ']'), + + ('❴', "Medium Left Curly Bracket Ornament", '{'), + ('𝄔', "Musical Symbol Brace", '{'), + ('{', "Fullwidth Left Curly Bracket", '{'), + + ('❵', "Medium Right Curly Bracket Ornament", '}'), + ('}', "Fullwidth Right Curly Bracket", '}'), + + ('⁎', "Low Asterisk", '*'), + ('٭', "Arabic Five Pointed Star", '*'), + ('∗', "Asterisk Operator", '*'), + ('𐌟', "Old Italic Letter Ess", '*'), + ('*', "Fullwidth Asterisk", '*'), + + ('᜵', "Philippine Single Punctuation", '/'), + ('⁁', "Caret Insertion Point", '/'), + ('∕', "Division Slash", '/'), + ('⁄', "Fraction Slash", '/'), + ('╱', "Box Drawings Light Diagonal Upper Right To Lower Left", '/'), + ('⟋', "Mathematical Rising Diagonal", '/'), + ('⧸', "Big Solidus", '/'), + ('𝈺', "Greek Instrumental Notation Symbol-47", '/'), + ('㇓', "CJK Stroke Sp", '/'), + ('〳', "Vertical Kana Repeat Mark Upper Half", '/'), + ('Ⳇ', "Coptic Capital Letter Old Coptic Esh", '/'), + ('ノ', "Katakana Letter No", '/'), + ('丿', "CJK Unified Ideograph-4E3F", '/'), + ('⼃', "Kangxi Radical Slash", '/'), + ('/', "Fullwidth Solidus", '/'), + + ('\', "Fullwidth Reverse Solidus", '\\'), + ('﹨', "Small Reverse Solidus", '\\'), + ('∖', "Set Minus", '\\'), + ('⟍', "Mathematical Falling Diagonal", '\\'), + ('⧵', "Reverse Solidus Operator", '\\'), + ('⧹', "Big Reverse Solidus", '\\'), + ('⧹', "Greek Vocal Notation Symbol-16", '\\'), + ('⧹', "Greek Instrumental Symbol-48", '\\'), + ('㇔', "CJK Stroke D", '\\'), + ('丶', "CJK Unified Ideograph-4E36", '\\'), + ('⼂', "Kangxi Radical Dot", '\\'), + ('、', "Ideographic Comma", '\\'), + ('ヽ', "Katakana Iteration Mark", '\\'), + + ('ꝸ', "Latin Small Letter Um", '&'), + ('&', "Fullwidth Ampersand", '&'), + + ('᛭', "Runic Cross Punctuation", '+'), + ('➕', "Heavy Plus Sign", '+'), + ('𐊛', "Lycian Letter H", '+'), + ('﬩', "Hebrew Letter Alternative Plus Sign", '+'), + ('+', "Fullwidth Plus Sign", '+'), + + ('‹', "Single Left-Pointing Angle Quotation Mark", '<'), + ('❮', "Heavy Left-Pointing Angle Quotation Mark Ornament", '<'), + ('˂', "Modifier Letter Left Arrowhead", '<'), + ('𝈶', "Greek Instrumental Symbol-40", '<'), + ('ᐸ', "Canadian Syllabics Pa", '<'), + ('ᚲ', "Runic Letter Kauna", '<'), + ('❬', "Medium Left-Pointing Angle Bracket Ornament", '<'), + ('⟨', "Mathematical Left Angle Bracket", '<'), + ('〈', "Left-Pointing Angle Bracket", '<'), + ('〈', "Left Angle Bracket", '<'), + ('㇛', "CJK Stroke Pd", '<'), + ('く', "Hiragana Letter Ku", '<'), + ('𡿨', "CJK Unified Ideograph-21FE8", '<'), + ('《', "Left Double Angle Bracket", '<'), + ('<', "Fullwidth Less-Than Sign", '<'), + + ('᐀', "Canadian Syllabics Hyphen", '='), + ('⹀', "Double Hyphen", '='), + ('゠', "Katakana-Hiragana Double Hyphen", '='), + ('꓿', "Lisu Punctuation Full Stop", '='), + ('=', "Fullwidth Equals Sign", '='), + + ('›', "Single Right-Pointing Angle Quotation Mark", '>'), + ('❯', "Heavy Right-Pointing Angle Quotation Mark Ornament", '>'), + ('˃', "Modifier Letter Right Arrowhead", '>'), + ('𝈷', "Greek Instrumental Symbol-42", '>'), + ('ᐳ', "Canadian Syllabics Po", '>'), + ('𖼿', "Miao Letter Archaic Zza", '>'), + ('❭', "Medium Right-Pointing Angle Bracket Ornament", '>'), + ('⟩', "Mathematical Right Angle Bracket", '>'), + ('〉', "Right-Pointing Angle Bracket", '>'), + ('〉', "Right Angle Bracket", '>'), + ('》', "Right Double Angle Bracket", '>'), + ('>', "Fullwidth Greater-Than Sign", '>'), +]; + +// FIXME: the lexer could be used to turn the ASCII version of unicode homoglyphs, instead of +// keeping the substitution token in this table. Ideally, this should be inside `rustc_lexer`. +// However, we should first remove compound tokens like `<<` from `rustc_lexer`, and then add +// fancier error recovery to it, as there will be less overall work to do this way. +const ASCII_ARRAY: &[(char, &str, Option)] = &[ + (' ', "Space", Some(token::Whitespace)), + ('_', "Underscore", Some(token::Ident(kw::Underscore, false))), + ('-', "Minus/Hyphen", Some(token::BinOp(token::Minus))), + (',', "Comma", Some(token::Comma)), + (';', "Semicolon", Some(token::Semi)), + (':', "Colon", Some(token::Colon)), + ('!', "Exclamation Mark", Some(token::Not)), + ('?', "Question Mark", Some(token::Question)), + ('.', "Period", Some(token::Dot)), + ('(', "Left Parenthesis", Some(token::OpenDelim(token::Paren))), + (')', "Right Parenthesis", Some(token::CloseDelim(token::Paren))), + ('[', "Left Square Bracket", Some(token::OpenDelim(token::Bracket))), + (']', "Right Square Bracket", Some(token::CloseDelim(token::Bracket))), + ('{', "Left Curly Brace", Some(token::OpenDelim(token::Brace))), + ('}', "Right Curly Brace", Some(token::CloseDelim(token::Brace))), + ('*', "Asterisk", Some(token::BinOp(token::Star))), + ('/', "Slash", Some(token::BinOp(token::Slash))), + ('\\', "Backslash", None), + ('&', "Ampersand", Some(token::BinOp(token::And))), + ('+', "Plus Sign", Some(token::BinOp(token::Plus))), + ('<', "Less-Than Sign", Some(token::Lt)), + ('=', "Equals Sign", Some(token::Eq)), + ('>', "Greater-Than Sign", Some(token::Gt)), + // FIXME: Literals are already lexed by this point, so we can't recover gracefully just by + // spitting the correct token out. + ('\'', "Single Quote", None), + ('"', "Quotation Mark", None), +]; + +crate fn check_for_substitution<'a>( + reader: &StringReader<'a>, + pos: BytePos, + ch: char, + err: &mut DiagnosticBuilder<'a>, +) -> Option { + let (u_name, ascii_char) = match UNICODE_ARRAY.iter().find(|&&(c, _, _)| c == ch) { + Some(&(_u_char, u_name, ascii_char)) => (u_name, ascii_char), + None => return None, + }; + + let span = Span::with_root_ctxt(pos, pos + Pos::from_usize(ch.len_utf8())); + + let (ascii_name, token) = match ASCII_ARRAY.iter().find(|&&(c, _, _)| c == ascii_char) { + Some((_ascii_char, ascii_name, token)) => (ascii_name, token), + None => { + let msg = format!("substitution character not found for '{}'", ch); + reader.sess.span_diagnostic.span_bug_no_panic(span, &msg); + return None; + } + }; + + // special help suggestion for "directed" double quotes + if let Some(s) = peek_delimited(&reader.src[reader.src_index(pos)..], '“', '”') { + let msg = format!( + "Unicode characters '“' (Left Double Quotation Mark) and \ + '”' (Right Double Quotation Mark) look like '{}' ({}), but are not", + ascii_char, ascii_name + ); + err.span_suggestion( + Span::with_root_ctxt( + pos, + pos + Pos::from_usize('“'.len_utf8() + s.len() + '”'.len_utf8()), + ), + &msg, + format!("\"{}\"", s), + Applicability::MaybeIncorrect, + ); + } else { + let msg = format!( + "Unicode character '{}' ({}) looks like '{}' ({}), but it is not", + ch, u_name, ascii_char, ascii_name + ); + err.span_suggestion(span, &msg, ascii_char.to_string(), Applicability::MaybeIncorrect); + } + token.clone() +} + +/// Extract string if found at current position with given delimiters +fn peek_delimited(text: &str, from_ch: char, to_ch: char) -> Option<&str> { + let mut chars = text.chars(); + let first_char = chars.next()?; + if first_char != from_ch { + return None; + } + let last_char_idx = chars.as_str().find(to_ch)?; + Some(&chars.as_str()[..last_char_idx]) +} diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs new file mode 100644 index 00000000000..9f507d5319e --- /dev/null +++ b/src/librustc_parse/lib.rs @@ -0,0 +1,423 @@ +//! The main parser interface. + +#![feature(crate_visibility_modifier)] + +use syntax::ast; +use syntax::print::pprust; +use syntax::sess::ParseSess; +use syntax::token::{self, Nonterminal}; +use syntax::tokenstream::{self, TokenStream, TokenTree}; + +use errors::{PResult, FatalError, Level, Diagnostic}; +use rustc_data_structures::sync::Lrc; +use syntax_pos::{Span, SourceFile, FileName}; + +use std::borrow::Cow; +use std::path::Path; +use std::str; + +use log::info; + +pub const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments"); + +#[macro_use] +pub mod parser; +use parser::{Parser, emit_unclosed_delims, make_unclosed_delims_error}; +pub mod lexer; +pub mod validate_attr; +pub mod error_codes; + +#[derive(Clone)] +pub struct Directory<'a> { + pub path: Cow<'a, Path>, + pub ownership: DirectoryOwnership, +} + +#[derive(Copy, Clone)] +pub enum DirectoryOwnership { + Owned { + // None if `mod.rs`, `Some("foo")` if we're in `foo.rs`. + relative: Option, + }, + UnownedViaBlock, + UnownedViaMod, +} + +// A bunch of utility functions of the form `parse__from_` +// where includes crate, expr, item, stmt, tts, and one that +// uses a HOF to parse anything, and includes file and +// `source_str`. + +/// A variant of 'panictry!' that works on a Vec instead of a single DiagnosticBuilder. +macro_rules! panictry_buffer { + ($handler:expr, $e:expr) => ({ + use std::result::Result::{Ok, Err}; + use errors::FatalError; + match $e { + Ok(e) => e, + Err(errs) => { + for e in errs { + $handler.emit_diagnostic(&e); + } + FatalError.raise() + } + } + }) +} + +pub fn parse_crate_from_file<'a>(input: &Path, sess: &'a ParseSess) -> PResult<'a, ast::Crate> { + let mut parser = new_parser_from_file(sess, input); + parser.parse_crate_mod() +} + +pub fn parse_crate_attrs_from_file<'a>(input: &Path, sess: &'a ParseSess) + -> PResult<'a, Vec> { + let mut parser = new_parser_from_file(sess, input); + parser.parse_inner_attributes() +} + +pub fn parse_crate_from_source_str(name: FileName, source: String, sess: &ParseSess) + -> PResult<'_, ast::Crate> { + new_parser_from_source_str(sess, name, source).parse_crate_mod() +} + +pub fn parse_crate_attrs_from_source_str(name: FileName, source: String, sess: &ParseSess) + -> PResult<'_, Vec> { + new_parser_from_source_str(sess, name, source).parse_inner_attributes() +} + +pub fn parse_stream_from_source_str( + name: FileName, + source: String, + sess: &ParseSess, + override_span: Option, +) -> TokenStream { + let (stream, mut errors) = source_file_to_stream( + sess, + sess.source_map().new_source_file(name, source), + override_span, + ); + emit_unclosed_delims(&mut errors, &sess); + stream +} + +/// Creates a new parser from a source string. +pub fn new_parser_from_source_str(sess: &ParseSess, name: FileName, source: String) -> Parser<'_> { + panictry_buffer!(&sess.span_diagnostic, maybe_new_parser_from_source_str(sess, name, source)) +} + +/// Creates a new parser from a source string. Returns any buffered errors from lexing the initial +/// token stream. +pub fn maybe_new_parser_from_source_str(sess: &ParseSess, name: FileName, source: String) + -> Result, Vec> +{ + let mut parser = maybe_source_file_to_parser(sess, + sess.source_map().new_source_file(name, source))?; + parser.recurse_into_file_modules = false; + Ok(parser) +} + +/// Creates a new parser, handling errors as appropriate if the file doesn't exist. +pub fn new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path) -> Parser<'a> { + source_file_to_parser(sess, file_to_source_file(sess, path, None)) +} + +/// Creates a new parser, returning buffered diagnostics if the file doesn't exist, +/// or from lexing the initial token stream. +pub fn maybe_new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path) + -> Result, Vec> { + let file = try_file_to_source_file(sess, path, None).map_err(|db| vec![db])?; + maybe_source_file_to_parser(sess, file) +} + +/// Given a session, a crate config, a path, and a span, add +/// the file at the given path to the `source_map`, and returns a parser. +/// On an error, uses the given span as the source of the problem. +pub fn new_sub_parser_from_file<'a>(sess: &'a ParseSess, + path: &Path, + directory_ownership: DirectoryOwnership, + module_name: Option, + sp: Span) -> Parser<'a> { + let mut p = source_file_to_parser(sess, file_to_source_file(sess, path, Some(sp))); + p.directory.ownership = directory_ownership; + p.root_module_name = module_name; + p +} + +/// Given a `source_file` and config, returns a parser. +fn source_file_to_parser(sess: &ParseSess, source_file: Lrc) -> Parser<'_> { + panictry_buffer!(&sess.span_diagnostic, + maybe_source_file_to_parser(sess, source_file)) +} + +/// Given a `source_file` and config, return a parser. Returns any buffered errors from lexing the +/// initial token stream. +fn maybe_source_file_to_parser( + sess: &ParseSess, + source_file: Lrc, +) -> Result, Vec> { + let end_pos = source_file.end_pos; + let (stream, unclosed_delims) = maybe_file_to_stream(sess, source_file, None)?; + let mut parser = stream_to_parser(sess, stream, None); + parser.unclosed_delims = unclosed_delims; + if parser.token == token::Eof && parser.token.span.is_dummy() { + parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt()); + } + + Ok(parser) +} + +// Must preserve old name for now, because `quote!` from the *existing* +// compiler expands into it. +pub fn new_parser_from_tts(sess: &ParseSess, tts: Vec) -> Parser<'_> { + stream_to_parser(sess, tts.into_iter().collect(), crate::MACRO_ARGUMENTS) +} + + +// Base abstractions + +/// Given a session and a path and an optional span (for error reporting), +/// add the path to the session's source_map and return the new source_file or +/// error when a file can't be read. +fn try_file_to_source_file(sess: &ParseSess, path: &Path, spanopt: Option) + -> Result, Diagnostic> { + sess.source_map().load_file(path) + .map_err(|e| { + let msg = format!("couldn't read {}: {}", path.display(), e); + let mut diag = Diagnostic::new(Level::Fatal, &msg); + if let Some(sp) = spanopt { + diag.set_span(sp); + } + diag + }) +} + +/// Given a session and a path and an optional span (for error reporting), +/// adds the path to the session's `source_map` and returns the new `source_file`. +fn file_to_source_file(sess: &ParseSess, path: &Path, spanopt: Option) + -> Lrc { + match try_file_to_source_file(sess, path, spanopt) { + Ok(source_file) => source_file, + Err(d) => { + sess.span_diagnostic.emit_diagnostic(&d); + FatalError.raise(); + } + } +} + +/// Given a `source_file`, produces a sequence of token trees. +pub fn source_file_to_stream( + sess: &ParseSess, + source_file: Lrc, + override_span: Option, +) -> (TokenStream, Vec) { + panictry_buffer!(&sess.span_diagnostic, maybe_file_to_stream(sess, source_file, override_span)) +} + +/// Given a source file, produces a sequence of token trees. Returns any buffered errors from +/// parsing the token stream. +pub fn maybe_file_to_stream( + sess: &ParseSess, + source_file: Lrc, + override_span: Option, +) -> Result<(TokenStream, Vec), Vec> { + let srdr = lexer::StringReader::new(sess, source_file, override_span); + let (token_trees, unmatched_braces) = srdr.into_token_trees(); + + match token_trees { + Ok(stream) => Ok((stream, unmatched_braces)), + Err(err) => { + let mut buffer = Vec::with_capacity(1); + err.buffer(&mut buffer); + // Not using `emit_unclosed_delims` to use `db.buffer` + for unmatched in unmatched_braces { + if let Some(err) = make_unclosed_delims_error(unmatched, &sess) { + err.buffer(&mut buffer); + } + } + Err(buffer) + } + } +} + +/// Given a stream and the `ParseSess`, produces a parser. +pub fn stream_to_parser<'a>( + sess: &'a ParseSess, + stream: TokenStream, + subparser_name: Option<&'static str>, +) -> Parser<'a> { + Parser::new(sess, stream, None, true, false, subparser_name) +} + +/// Given a stream, the `ParseSess` and the base directory, produces a parser. +/// +/// Use this function when you are creating a parser from the token stream +/// and also care about the current working directory of the parser (e.g., +/// you are trying to resolve modules defined inside a macro invocation). +/// +/// # Note +/// +/// The main usage of this function is outside of rustc, for those who uses +/// libsyntax as a library. Please do not remove this function while refactoring +/// just because it is not used in rustc codebase! +pub fn stream_to_parser_with_base_dir<'a>( + sess: &'a ParseSess, + stream: TokenStream, + base_dir: Directory<'a>, +) -> Parser<'a> { + Parser::new(sess, stream, Some(base_dir), true, false, None) +} + +/// Runs the given subparser `f` on the tokens of the given `attr`'s item. +pub fn parse_in_attr<'a, T>( + sess: &'a ParseSess, + attr: &ast::Attribute, + mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, +) -> PResult<'a, T> { + let mut parser = Parser::new( + sess, + attr.get_normal_item().tokens.clone(), + None, + false, + false, + Some("attribute"), + ); + let result = f(&mut parser)?; + if parser.token != token::Eof { + parser.unexpected()?; + } + Ok(result) +} + +// NOTE(Centril): The following probably shouldn't be here but it acknowledges the +// fact that architecturally, we are using parsing (read on below to understand why). + +pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> TokenStream { + // A `Nonterminal` is often a parsed AST item. At this point we now + // need to convert the parsed AST to an actual token stream, e.g. + // un-parse it basically. + // + // Unfortunately there's not really a great way to do that in a + // guaranteed lossless fashion right now. The fallback here is to just + // stringify the AST node and reparse it, but this loses all span + // information. + // + // As a result, some AST nodes are annotated with the token stream they + // came from. Here we attempt to extract these lossless token streams + // before we fall back to the stringification. + let tokens = match *nt { + Nonterminal::NtItem(ref item) => { + prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) + } + Nonterminal::NtTraitItem(ref item) => { + prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) + } + Nonterminal::NtImplItem(ref item) => { + prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) + } + Nonterminal::NtIdent(ident, is_raw) => { + Some(tokenstream::TokenTree::token(token::Ident(ident.name, is_raw), ident.span).into()) + } + Nonterminal::NtLifetime(ident) => { + Some(tokenstream::TokenTree::token(token::Lifetime(ident.name), ident.span).into()) + } + Nonterminal::NtTT(ref tt) => { + Some(tt.clone().into()) + } + _ => None, + }; + + // FIXME(#43081): Avoid this pretty-print + reparse hack + let source = pprust::nonterminal_to_string(nt); + let filename = FileName::macro_expansion_source_code(&source); + let tokens_for_real = parse_stream_from_source_str(filename, source, sess, Some(span)); + + // During early phases of the compiler the AST could get modified + // directly (e.g., attributes added or removed) and the internal cache + // of tokens my not be invalidated or updated. Consequently if the + // "lossless" token stream disagrees with our actual stringification + // (which has historically been much more battle-tested) then we go + // with the lossy stream anyway (losing span information). + // + // Note that the comparison isn't `==` here to avoid comparing spans, + // but it *also* is a "probable" equality which is a pretty weird + // definition. We mostly want to catch actual changes to the AST + // like a `#[cfg]` being processed or some weird `macro_rules!` + // expansion. + // + // What we *don't* want to catch is the fact that a user-defined + // literal like `0xf` is stringified as `15`, causing the cached token + // stream to not be literal `==` token-wise (ignoring spans) to the + // token stream we got from stringification. + // + // Instead the "probably equal" check here is "does each token + // recursively have the same discriminant?" We basically don't look at + // the token values here and assume that such fine grained token stream + // modifications, including adding/removing typically non-semantic + // tokens such as extra braces and commas, don't happen. + if let Some(tokens) = tokens { + if tokens.probably_equal_for_proc_macro(&tokens_for_real) { + return tokens + } + info!("cached tokens found, but they're not \"probably equal\", \ + going with stringified version"); + } + return tokens_for_real +} + +fn prepend_attrs( + sess: &ParseSess, + attrs: &[ast::Attribute], + tokens: Option<&tokenstream::TokenStream>, + span: syntax_pos::Span +) -> Option { + let tokens = tokens?; + if attrs.len() == 0 { + return Some(tokens.clone()) + } + let mut builder = tokenstream::TokenStreamBuilder::new(); + for attr in attrs { + assert_eq!(attr.style, ast::AttrStyle::Outer, + "inner attributes should prevent cached tokens from existing"); + + let source = pprust::attribute_to_string(attr); + let macro_filename = FileName::macro_expansion_source_code(&source); + + let item = match attr.kind { + ast::AttrKind::Normal(ref item) => item, + ast::AttrKind::DocComment(_) => { + let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span)); + builder.push(stream); + continue + } + }; + + // synthesize # [ $path $tokens ] manually here + let mut brackets = tokenstream::TokenStreamBuilder::new(); + + // For simple paths, push the identifier directly + if item.path.segments.len() == 1 && item.path.segments[0].args.is_none() { + let ident = item.path.segments[0].ident; + let token = token::Ident(ident.name, ident.as_str().starts_with("r#")); + brackets.push(tokenstream::TokenTree::token(token, ident.span)); + + // ... and for more complicated paths, fall back to a reparse hack that + // should eventually be removed. + } else { + let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span)); + brackets.push(stream); + } + + brackets.push(item.tokens.clone()); + + // The span we list here for `#` and for `[ ... ]` are both wrong in + // that it encompasses more than each token, but it hopefully is "good + // enough" for now at least. + builder.push(tokenstream::TokenTree::token(token::Pound, attr.span)); + let delim_span = tokenstream::DelimSpan::from_single(attr.span); + builder.push(tokenstream::TokenTree::Delimited( + delim_span, token::DelimToken::Bracket, brackets.build().into())); + } + builder.push(tokens.clone()); + Some(builder.build()) +} diff --git a/src/librustc_parse/parser/attr.rs b/src/librustc_parse/parser/attr.rs new file mode 100644 index 00000000000..524b551e54c --- /dev/null +++ b/src/librustc_parse/parser/attr.rs @@ -0,0 +1,351 @@ +use super::{SeqSep, Parser, TokenType, PathStyle}; +use syntax::attr; +use syntax::ast; +use syntax::util::comments; +use syntax::token::{self, Nonterminal, DelimToken}; +use syntax::tokenstream::{TokenStream, TokenTree}; +use syntax_pos::{Span, Symbol}; +use errors::PResult; + +use log::debug; + +#[derive(Debug)] +enum InnerAttributeParsePolicy<'a> { + Permitted, + NotPermitted { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option }, +} + +const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \ + permitted in this context"; + +impl<'a> Parser<'a> { + /// Parses attributes that appear before an item. + pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec> { + let mut attrs: Vec = Vec::new(); + let mut just_parsed_doc_comment = false; + loop { + debug!("parse_outer_attributes: self.token={:?}", self.token); + match self.token.kind { + token::Pound => { + let inner_error_reason = if just_parsed_doc_comment { + "an inner attribute is not permitted following an outer doc comment" + } else if !attrs.is_empty() { + "an inner attribute is not permitted following an outer attribute" + } else { + DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG + }; + let inner_parse_policy = + InnerAttributeParsePolicy::NotPermitted { + reason: inner_error_reason, + saw_doc_comment: just_parsed_doc_comment, + prev_attr_sp: attrs.last().and_then(|a| Some(a.span)) + }; + let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?; + attrs.push(attr); + just_parsed_doc_comment = false; + } + token::DocComment(s) => { + let attr = self.mk_doc_comment(s); + if attr.style != ast::AttrStyle::Outer { + let mut err = self.fatal("expected outer doc comment"); + err.note("inner doc comments like this (starting with \ + `//!` or `/*!`) can only appear before items"); + return Err(err); + } + attrs.push(attr); + self.bump(); + just_parsed_doc_comment = true; + } + _ => break, + } + } + Ok(attrs) + } + + fn mk_doc_comment(&self, s: Symbol) -> ast::Attribute { + let style = comments::doc_comment_style(&s.as_str()); + attr::mk_doc_comment(style, s, self.token.span) + } + + /// Matches `attribute = # ! [ meta_item ]`. + /// + /// If `permit_inner` is `true`, then a leading `!` indicates an inner + /// attribute. + pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> { + debug!("parse_attribute: permit_inner={:?} self.token={:?}", + permit_inner, + self.token); + let inner_parse_policy = if permit_inner { + InnerAttributeParsePolicy::Permitted + } else { + InnerAttributeParsePolicy::NotPermitted { + reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG, + saw_doc_comment: false, + prev_attr_sp: None + } + }; + self.parse_attribute_with_inner_parse_policy(inner_parse_policy) + } + + /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy` + /// that prescribes how to handle inner attributes. + fn parse_attribute_with_inner_parse_policy( + &mut self, + inner_parse_policy: InnerAttributeParsePolicy<'_> + ) -> PResult<'a, ast::Attribute> { + debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}", + inner_parse_policy, + self.token); + let (span, item, style) = match self.token.kind { + token::Pound => { + let lo = self.token.span; + self.bump(); + + if let InnerAttributeParsePolicy::Permitted = inner_parse_policy { + self.expected_tokens.push(TokenType::Token(token::Not)); + } + + let style = if self.token == token::Not { + self.bump(); + ast::AttrStyle::Inner + } else { + ast::AttrStyle::Outer + }; + + self.expect(&token::OpenDelim(token::Bracket))?; + let item = self.parse_attr_item()?; + self.expect(&token::CloseDelim(token::Bracket))?; + let hi = self.prev_span; + + let attr_sp = lo.to(hi); + + // Emit error if inner attribute is encountered and not permitted + if style == ast::AttrStyle::Inner { + if let InnerAttributeParsePolicy::NotPermitted { reason, + saw_doc_comment, prev_attr_sp } = inner_parse_policy { + let prev_attr_note = if saw_doc_comment { + "previous doc comment" + } else { + "previous outer attribute" + }; + + let mut diagnostic = self + .diagnostic() + .struct_span_err(attr_sp, reason); + + if let Some(prev_attr_sp) = prev_attr_sp { + diagnostic + .span_label(attr_sp, "not permitted following an outer attibute") + .span_label(prev_attr_sp, prev_attr_note); + } + + diagnostic + .note("inner attributes, like `#![no_std]`, annotate the item \ + enclosing them, and are usually found at the beginning of \ + source files. Outer attributes, like `#[test]`, annotate the \ + item following them.") + .emit() + } + } + + (attr_sp, item, style) + } + _ => { + let token_str = self.this_token_to_string(); + return Err(self.fatal(&format!("expected `#`, found `{}`", token_str))); + } + }; + + Ok(attr::mk_attr_from_item(style, item, span)) + } + + /// Parses an inner part of an attribute (the path and following tokens). + /// The tokens must be either a delimited token stream, or empty token stream, + /// or the "legacy" key-value form. + /// PATH `(` TOKEN_STREAM `)` + /// PATH `[` TOKEN_STREAM `]` + /// PATH `{` TOKEN_STREAM `}` + /// PATH + /// PATH `=` UNSUFFIXED_LIT + /// The delimiters or `=` are still put into the resulting token stream. + pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> { + let item = match self.token.kind { + token::Interpolated(ref nt) => match **nt { + Nonterminal::NtMeta(ref item) => Some(item.clone()), + _ => None, + }, + _ => None, + }; + Ok(if let Some(item) = item { + self.bump(); + item + } else { + let path = self.parse_path(PathStyle::Mod)?; + let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) || + self.check(&token::OpenDelim(DelimToken::Bracket)) || + self.check(&token::OpenDelim(DelimToken::Brace)) { + self.parse_token_tree().into() + } else if self.eat(&token::Eq) { + let eq = TokenTree::token(token::Eq, self.prev_span); + let mut is_interpolated_expr = false; + if let token::Interpolated(nt) = &self.token.kind { + if let token::NtExpr(..) = **nt { + is_interpolated_expr = true; + } + } + let token_tree = if is_interpolated_expr { + // We need to accept arbitrary interpolated expressions to continue + // supporting things like `doc = $expr` that work on stable. + // Non-literal interpolated expressions are rejected after expansion. + self.parse_token_tree() + } else { + self.parse_unsuffixed_lit()?.token_tree() + }; + TokenStream::new(vec![eq.into(), token_tree.into()]) + } else { + TokenStream::default() + }; + ast::AttrItem { path, tokens } + }) + } + + /// Parses attributes that appear after the opening of an item. These should + /// be preceded by an exclamation mark, but we accept and warn about one + /// terminated by a semicolon. + /// + /// Matches `inner_attrs*`. + crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec> { + let mut attrs: Vec = vec![]; + loop { + match self.token.kind { + token::Pound => { + // Don't even try to parse if it's not an inner attribute. + if !self.look_ahead(1, |t| t == &token::Not) { + break; + } + + let attr = self.parse_attribute(true)?; + assert_eq!(attr.style, ast::AttrStyle::Inner); + attrs.push(attr); + } + token::DocComment(s) => { + // We need to get the position of this token before we bump. + let attr = self.mk_doc_comment(s); + if attr.style == ast::AttrStyle::Inner { + attrs.push(attr); + self.bump(); + } else { + break; + } + } + _ => break, + } + } + Ok(attrs) + } + + fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> { + let lit = self.parse_lit()?; + debug!("checking if {:?} is unusuffixed", lit); + + if !lit.kind.is_unsuffixed() { + let msg = "suffixed literals are not allowed in attributes"; + self.diagnostic().struct_span_err(lit.span, msg) + .help("instead of using a suffixed literal \ + (1u8, 1.0f32, etc.), use an unsuffixed version \ + (1, 1.0, etc.).") + .emit() + } + + Ok(lit) + } + + /// Parses `cfg_attr(pred, attr_item_list)` where `attr_item_list` is comma-delimited. + pub fn parse_cfg_attr(&mut self) -> PResult<'a, (ast::MetaItem, Vec<(ast::AttrItem, Span)>)> { + self.expect(&token::OpenDelim(token::Paren))?; + + let cfg_predicate = self.parse_meta_item()?; + self.expect(&token::Comma)?; + + // Presumably, the majority of the time there will only be one attr. + let mut expanded_attrs = Vec::with_capacity(1); + + while !self.check(&token::CloseDelim(token::Paren)) { + let lo = self.token.span.lo(); + let item = self.parse_attr_item()?; + expanded_attrs.push((item, self.prev_span.with_lo(lo))); + self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?; + } + + self.expect(&token::CloseDelim(token::Paren))?; + Ok((cfg_predicate, expanded_attrs)) + } + + /// Matches the following grammar (per RFC 1559). + /// + /// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ; + /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; + pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> { + let nt_meta = match self.token.kind { + token::Interpolated(ref nt) => match **nt { + token::NtMeta(ref e) => Some(e.clone()), + _ => None, + }, + _ => None, + }; + + if let Some(item) = nt_meta { + return match item.meta(item.path.span) { + Some(meta) => { + self.bump(); + Ok(meta) + } + None => self.unexpected(), + } + } + + let lo = self.token.span; + let path = self.parse_path(PathStyle::Mod)?; + let kind = self.parse_meta_item_kind()?; + let span = lo.to(self.prev_span); + Ok(ast::MetaItem { path, kind, span }) + } + + crate fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> { + Ok(if self.eat(&token::Eq) { + ast::MetaItemKind::NameValue(self.parse_unsuffixed_lit()?) + } else if self.eat(&token::OpenDelim(token::Paren)) { + ast::MetaItemKind::List(self.parse_meta_seq()?) + } else { + ast::MetaItemKind::Word + }) + } + + /// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`. + fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { + match self.parse_unsuffixed_lit() { + Ok(lit) => { + return Ok(ast::NestedMetaItem::Literal(lit)) + } + Err(ref mut err) => err.cancel(), + } + + match self.parse_meta_item() { + Ok(mi) => { + return Ok(ast::NestedMetaItem::MetaItem(mi)) + } + Err(ref mut err) => err.cancel(), + } + + let found = self.this_token_to_string(); + let msg = format!("expected unsuffixed literal or identifier, found `{}`", found); + Err(self.diagnostic().struct_span_err(self.token.span, &msg)) + } + + /// Matches `meta_seq = ( COMMASEP(meta_item_inner) )`. + fn parse_meta_seq(&mut self) -> PResult<'a, Vec> { + self.parse_seq_to_end(&token::CloseDelim(token::Paren), + SeqSep::trailing_allowed(token::Comma), + |p: &mut Parser<'a>| p.parse_meta_item_inner()) + } +} diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs new file mode 100644 index 00000000000..38eae008537 --- /dev/null +++ b/src/librustc_parse/parser/diagnostics.rs @@ -0,0 +1,1549 @@ +use super::{BlockMode, PathStyle, SemiColonMode, TokenType, TokenExpectType, SeqSep, Parser}; + +use syntax::ast::{ + self, Param, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Ident, Item, ItemKind, + Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind, +}; +use syntax::token::{self, TokenKind, token_can_begin_expr}; +use syntax::print::pprust; +use syntax::ptr::P; +use syntax::symbol::{kw, sym}; +use syntax::ThinVec; +use syntax::util::parser::AssocOp; +use syntax::struct_span_err; + +use errors::{PResult, Applicability, DiagnosticBuilder, DiagnosticId, pluralize}; +use rustc_data_structures::fx::FxHashSet; +use syntax_pos::{Span, DUMMY_SP, MultiSpan, SpanSnippetError}; +use log::{debug, trace}; +use std::mem; + +const TURBOFISH: &'static str = "use `::<...>` instead of `<...>` to specify type arguments"; + +/// Creates a placeholder argument. +pub(super) fn dummy_arg(ident: Ident) -> Param { + let pat = P(Pat { + id: ast::DUMMY_NODE_ID, + kind: PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None), + span: ident.span, + }); + let ty = Ty { + kind: TyKind::Err, + span: ident.span, + id: ast::DUMMY_NODE_ID + }; + Param { + attrs: ThinVec::default(), + id: ast::DUMMY_NODE_ID, + pat, + span: ident.span, + ty: P(ty), + is_placeholder: false, + } +} + +pub enum Error { + FileNotFoundForModule { + mod_name: String, + default_path: String, + secondary_path: String, + dir_path: String, + }, + DuplicatePaths { + mod_name: String, + default_path: String, + secondary_path: String, + }, + UselessDocComment, + InclusiveRangeWithNoEnd, +} + +impl Error { + fn span_err>( + self, + sp: S, + handler: &errors::Handler, + ) -> DiagnosticBuilder<'_> { + match self { + Error::FileNotFoundForModule { + ref mod_name, + ref default_path, + ref secondary_path, + ref dir_path, + } => { + let mut err = struct_span_err!( + handler, + sp, + E0583, + "file not found for module `{}`", + mod_name, + ); + err.help(&format!( + "name the file either {} or {} inside the directory \"{}\"", + default_path, + secondary_path, + dir_path, + )); + err + } + Error::DuplicatePaths { ref mod_name, ref default_path, ref secondary_path } => { + let mut err = struct_span_err!( + handler, + sp, + E0584, + "file for module `{}` found at both {} and {}", + mod_name, + default_path, + secondary_path, + ); + err.help("delete or rename one of them to remove the ambiguity"); + err + } + Error::UselessDocComment => { + let mut err = struct_span_err!( + handler, + sp, + E0585, + "found a documentation comment that doesn't document anything", + ); + err.help("doc comments must come before what they document, maybe a comment was \ + intended with `//`?"); + err + } + Error::InclusiveRangeWithNoEnd => { + let mut err = struct_span_err!( + handler, + sp, + E0586, + "inclusive range with no end", + ); + err.help("inclusive ranges must be bounded at the end (`..=b` or `a..=b`)"); + err + } + } + } +} + +pub(super) trait RecoverQPath: Sized + 'static { + const PATH_STYLE: PathStyle = PathStyle::Expr; + fn to_ty(&self) -> Option>; + fn recovered(qself: Option, path: ast::Path) -> Self; +} + +impl RecoverQPath for Ty { + const PATH_STYLE: PathStyle = PathStyle::Type; + fn to_ty(&self) -> Option> { + Some(P(self.clone())) + } + fn recovered(qself: Option, path: ast::Path) -> Self { + Self { + span: path.span, + kind: TyKind::Path(qself, path), + id: ast::DUMMY_NODE_ID, + } + } +} + +impl RecoverQPath for Pat { + fn to_ty(&self) -> Option> { + self.to_ty() + } + fn recovered(qself: Option, path: ast::Path) -> Self { + Self { + span: path.span, + kind: PatKind::Path(qself, path), + id: ast::DUMMY_NODE_ID, + } + } +} + +impl RecoverQPath for Expr { + fn to_ty(&self) -> Option> { + self.to_ty() + } + fn recovered(qself: Option, path: ast::Path) -> Self { + Self { + span: path.span, + kind: ExprKind::Path(qself, path), + attrs: ThinVec::new(), + id: ast::DUMMY_NODE_ID, + } + } +} + +/// Control whether the closing delimiter should be consumed when calling `Parser::consume_block`. +crate enum ConsumeClosingDelim { + Yes, + No, +} + +impl<'a> Parser<'a> { + pub fn fatal(&self, m: &str) -> DiagnosticBuilder<'a> { + self.span_fatal(self.token.span, m) + } + + crate fn span_fatal>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { + self.sess.span_diagnostic.struct_span_fatal(sp, m) + } + + pub(super) fn span_fatal_err>( + &self, + sp: S, + err: Error, + ) -> DiagnosticBuilder<'a> { + err.span_err(sp, self.diagnostic()) + } + + pub(super) fn bug(&self, m: &str) -> ! { + self.sess.span_diagnostic.span_bug(self.token.span, m) + } + + pub(super) fn span_err>(&self, sp: S, m: &str) { + self.sess.span_diagnostic.span_err(sp, m) + } + + pub fn struct_span_err>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { + self.sess.span_diagnostic.struct_span_err(sp, m) + } + + pub fn span_bug>(&self, sp: S, m: &str) -> ! { + self.sess.span_diagnostic.span_bug(sp, m) + } + + pub(super) fn diagnostic(&self) -> &'a errors::Handler { + &self.sess.span_diagnostic + } + + pub(super) fn span_to_snippet(&self, span: Span) -> Result { + self.sess.source_map().span_to_snippet(span) + } + + pub(super) fn expected_ident_found(&self) -> DiagnosticBuilder<'a> { + let mut err = self.struct_span_err( + self.token.span, + &format!("expected identifier, found {}", self.this_token_descr()), + ); + if let token::Ident(name, false) = self.token.kind { + if Ident::new(name, self.token.span).is_raw_guess() { + err.span_suggestion( + self.token.span, + "you can escape reserved keywords to use them as identifiers", + format!("r#{}", name), + Applicability::MaybeIncorrect, + ); + } + } + if let Some(token_descr) = self.token_descr() { + err.span_label(self.token.span, format!("expected identifier, found {}", token_descr)); + } else { + err.span_label(self.token.span, "expected identifier"); + if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) { + err.span_suggestion( + self.token.span, + "remove this comma", + String::new(), + Applicability::MachineApplicable, + ); + } + } + err + } + + pub(super) fn expected_one_of_not_found( + &mut self, + edible: &[TokenKind], + inedible: &[TokenKind], + ) -> PResult<'a, bool /* recovered */> { + fn tokens_to_string(tokens: &[TokenType]) -> String { + let mut i = tokens.iter(); + // This might be a sign we need a connect method on `Iterator`. + let b = i.next() + .map_or(String::new(), |t| t.to_string()); + i.enumerate().fold(b, |mut b, (i, a)| { + if tokens.len() > 2 && i == tokens.len() - 2 { + b.push_str(", or "); + } else if tokens.len() == 2 && i == tokens.len() - 2 { + b.push_str(" or "); + } else { + b.push_str(", "); + } + b.push_str(&a.to_string()); + b + }) + } + + let mut expected = edible.iter() + .map(|x| TokenType::Token(x.clone())) + .chain(inedible.iter().map(|x| TokenType::Token(x.clone()))) + .chain(self.expected_tokens.iter().cloned()) + .collect::>(); + expected.sort_by_cached_key(|x| x.to_string()); + expected.dedup(); + let expect = tokens_to_string(&expected[..]); + let actual = self.this_token_descr(); + let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 { + let short_expect = if expected.len() > 6 { + format!("{} possible tokens", expected.len()) + } else { + expect.clone() + }; + (format!("expected one of {}, found {}", expect, actual), + (self.sess.source_map().next_point(self.prev_span), + format!("expected one of {}", short_expect))) + } else if expected.is_empty() { + (format!("unexpected token: {}", actual), + (self.prev_span, "unexpected token after this".to_string())) + } else { + (format!("expected {}, found {}", expect, actual), + (self.sess.source_map().next_point(self.prev_span), + format!("expected {}", expect))) + }; + self.last_unexpected_token_span = Some(self.token.span); + let mut err = self.fatal(&msg_exp); + if self.token.is_ident_named(sym::and) { + err.span_suggestion_short( + self.token.span, + "use `&&` instead of `and` for the boolean operator", + "&&".to_string(), + Applicability::MaybeIncorrect, + ); + } + if self.token.is_ident_named(sym::or) { + err.span_suggestion_short( + self.token.span, + "use `||` instead of `or` for the boolean operator", + "||".to_string(), + Applicability::MaybeIncorrect, + ); + } + let sp = if self.token == token::Eof { + // This is EOF; don't want to point at the following char, but rather the last token. + self.prev_span + } else { + label_sp + }; + match self.recover_closing_delimiter(&expected.iter().filter_map(|tt| match tt { + TokenType::Token(t) => Some(t.clone()), + _ => None, + }).collect::>(), err) { + Err(e) => err = e, + Ok(recovered) => { + return Ok(recovered); + } + } + + let sm = self.sess.source_map(); + if self.prev_span == DUMMY_SP { + // Account for macro context where the previous span might not be + // available to avoid incorrect output (#54841). + err.span_label(self.token.span, label_exp); + } else if !sm.is_multiline(self.token.span.shrink_to_hi().until(sp.shrink_to_lo())) { + // When the spans are in the same line, it means that the only content between + // them is whitespace, point at the found token in that case: + // + // X | () => { syntax error }; + // | ^^^^^ expected one of 8 possible tokens here + // + // instead of having: + // + // X | () => { syntax error }; + // | -^^^^^ unexpected token + // | | + // | expected one of 8 possible tokens here + err.span_label(self.token.span, label_exp); + } else { + err.span_label(sp, label_exp); + err.span_label(self.token.span, "unexpected token"); + } + self.maybe_annotate_with_ascription(&mut err, false); + Err(err) + } + + pub fn maybe_annotate_with_ascription( + &mut self, + err: &mut DiagnosticBuilder<'_>, + maybe_expected_semicolon: bool, + ) { + if let Some((sp, likely_path)) = self.last_type_ascription.take() { + let sm = self.sess.source_map(); + let next_pos = sm.lookup_char_pos(self.token.span.lo()); + let op_pos = sm.lookup_char_pos(sp.hi()); + + let allow_unstable = self.sess.unstable_features.is_nightly_build(); + + if likely_path { + err.span_suggestion( + sp, + "maybe write a path separator here", + "::".to_string(), + if allow_unstable { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }, + ); + } else if op_pos.line != next_pos.line && maybe_expected_semicolon { + err.span_suggestion( + sp, + "try using a semicolon", + ";".to_string(), + Applicability::MaybeIncorrect, + ); + } else if allow_unstable { + err.span_label(sp, "tried to parse a type due to this type ascription"); + } else { + err.span_label(sp, "tried to parse a type due to this"); + } + if allow_unstable { + // Give extra information about type ascription only if it's a nightly compiler. + err.note("`#![feature(type_ascription)]` lets you annotate an expression with a \ + type: `: `"); + err.note("for more information, see \ + https://github.com/rust-lang/rust/issues/23416"); + } + } + } + + /// Eats and discards tokens until one of `kets` is encountered. Respects token trees, + /// passes through any errors encountered. Used for error recovery. + pub(super) fn eat_to_tokens(&mut self, kets: &[&TokenKind]) { + if let Err(ref mut err) = self.parse_seq_to_before_tokens( + kets, + SeqSep::none(), + TokenExpectType::Expect, + |p| Ok(p.parse_token_tree()), + ) { + err.cancel(); + } + } + + /// This function checks if there are trailing angle brackets and produces + /// a diagnostic to suggest removing them. + /// + /// ```ignore (diagnostic) + /// let _ = vec![1, 2, 3].into_iter().collect::>>>(); + /// ^^ help: remove extra angle brackets + /// ``` + pub(super) fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, end: TokenKind) { + // This function is intended to be invoked after parsing a path segment where there are two + // cases: + // + // 1. A specific token is expected after the path segment. + // eg. `x.foo(`, `x.foo::(` (parenthesis - method call), + // `Foo::`, or `Foo::::` (mod sep - continued path). + // 2. No specific token is expected after the path segment. + // eg. `x.foo` (field access) + // + // This function is called after parsing `.foo` and before parsing the token `end` (if + // present). This includes any angle bracket arguments, such as `.foo::` or + // `Foo::`. + + // We only care about trailing angle brackets if we previously parsed angle bracket + // arguments. This helps stop us incorrectly suggesting that extra angle brackets be + // removed in this case: + // + // `x.foo >> (3)` (where `x.foo` is a `u32` for example) + // + // This case is particularly tricky as we won't notice it just looking at the tokens - + // it will appear the same (in terms of upcoming tokens) as below (since the `::` will + // have already been parsed): + // + // `x.foo::>>(3)` + let parsed_angle_bracket_args = segment.args + .as_ref() + .map(|args| args.is_angle_bracketed()) + .unwrap_or(false); + + debug!( + "check_trailing_angle_brackets: parsed_angle_bracket_args={:?}", + parsed_angle_bracket_args, + ); + if !parsed_angle_bracket_args { + return; + } + + // Keep the span at the start so we can highlight the sequence of `>` characters to be + // removed. + let lo = self.token.span; + + // We need to look-ahead to see if we have `>` characters without moving the cursor forward + // (since we might have the field access case and the characters we're eating are + // actual operators and not trailing characters - ie `x.foo >> 3`). + let mut position = 0; + + // We can encounter `>` or `>>` tokens in any order, so we need to keep track of how + // many of each (so we can correctly pluralize our error messages) and continue to + // advance. + let mut number_of_shr = 0; + let mut number_of_gt = 0; + while self.look_ahead(position, |t| { + trace!("check_trailing_angle_brackets: t={:?}", t); + if *t == token::BinOp(token::BinOpToken::Shr) { + number_of_shr += 1; + true + } else if *t == token::Gt { + number_of_gt += 1; + true + } else { + false + } + }) { + position += 1; + } + + // If we didn't find any trailing `>` characters, then we have nothing to error about. + debug!( + "check_trailing_angle_brackets: number_of_gt={:?} number_of_shr={:?}", + number_of_gt, number_of_shr, + ); + if number_of_gt < 1 && number_of_shr < 1 { + return; + } + + // Finally, double check that we have our end token as otherwise this is the + // second case. + if self.look_ahead(position, |t| { + trace!("check_trailing_angle_brackets: t={:?}", t); + *t == end + }) { + // Eat from where we started until the end token so that parsing can continue + // as if we didn't have those extra angle brackets. + self.eat_to_tokens(&[&end]); + let span = lo.until(self.token.span); + + let total_num_of_gt = number_of_gt + number_of_shr * 2; + self.diagnostic() + .struct_span_err( + span, + &format!("unmatched angle bracket{}", pluralize!(total_num_of_gt)), + ) + .span_suggestion( + span, + &format!("remove extra angle bracket{}", pluralize!(total_num_of_gt)), + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + } + } + + /// Produces an error if comparison operators are chained (RFC #558). + /// We only need to check the LHS, not the RHS, because all comparison ops have same + /// precedence (see `fn precedence`) and are left-associative (see `fn fixity`). + /// + /// This can also be hit if someone incorrectly writes `foo()` when they should have used + /// the turbofish (`foo::()`) syntax. We attempt some heuristic recovery if that is the + /// case. + /// + /// Keep in mind that given that `outer_op.is_comparison()` holds and comparison ops are left + /// associative we can infer that we have: + /// + /// outer_op + /// / \ + /// inner_op r2 + /// / \ + /// l1 r1 + pub(super) fn check_no_chained_comparison( + &mut self, + lhs: &Expr, + outer_op: &AssocOp, + ) -> PResult<'a, Option>> { + debug_assert!( + outer_op.is_comparison(), + "check_no_chained_comparison: {:?} is not comparison", + outer_op, + ); + + let mk_err_expr = |this: &Self, span| { + Ok(Some(this.mk_expr(span, ExprKind::Err, ThinVec::new()))) + }; + + match lhs.kind { + ExprKind::Binary(op, _, _) if op.node.is_comparison() => { + // Respan to include both operators. + let op_span = op.span.to(self.prev_span); + let mut err = self.struct_span_err( + op_span, + "chained comparison operators require parentheses", + ); + + let suggest = |err: &mut DiagnosticBuilder<'_>| { + err.span_suggestion_verbose( + op_span.shrink_to_lo(), + TURBOFISH, + "::".to_string(), + Applicability::MaybeIncorrect, + ); + }; + + if op.node == BinOpKind::Lt && + *outer_op == AssocOp::Less || // Include `<` to provide this recommendation + *outer_op == AssocOp::Greater // even in a case like the following: + { // Foo>> + if *outer_op == AssocOp::Less { + let snapshot = self.clone(); + self.bump(); + // So far we have parsed `foo(` or `foo< bar >::`, so we rewind the + // parser and bail out. + mem::replace(self, snapshot.clone()); + } + } + return if token::ModSep == self.token.kind { + // We have some certainty that this was a bad turbofish at this point. + // `foo< bar >::` + suggest(&mut err); + + let snapshot = self.clone(); + self.bump(); // `::` + + // Consume the rest of the likely `foo::new()` or return at `foo`. + match self.parse_expr() { + Ok(_) => { + // 99% certain that the suggestion is correct, continue parsing. + err.emit(); + // FIXME: actually check that the two expressions in the binop are + // paths and resynthesize new fn call expression instead of using + // `ExprKind::Err` placeholder. + mk_err_expr(self, lhs.span.to(self.prev_span)) + } + Err(mut expr_err) => { + expr_err.cancel(); + // Not entirely sure now, but we bubble the error up with the + // suggestion. + mem::replace(self, snapshot); + Err(err) + } + } + } else if token::OpenDelim(token::Paren) == self.token.kind { + // We have high certainty that this was a bad turbofish at this point. + // `foo< bar >(` + suggest(&mut err); + // Consume the fn call arguments. + match self.consume_fn_args() { + Err(()) => Err(err), + Ok(()) => { + err.emit(); + // FIXME: actually check that the two expressions in the binop are + // paths and resynthesize new fn call expression instead of using + // `ExprKind::Err` placeholder. + mk_err_expr(self, lhs.span.to(self.prev_span)) + } + } + } else { + // All we know is that this is `foo < bar >` and *nothing* else. Try to + // be helpful, but don't attempt to recover. + err.help(TURBOFISH); + err.help("or use `(...)` if you meant to specify fn arguments"); + // These cases cause too many knock-down errors, bail out (#61329). + Err(err) + }; + } + err.emit(); + } + _ => {} + } + Ok(None) + } + + fn consume_fn_args(&mut self) -> Result<(), ()> { + let snapshot = self.clone(); + self.bump(); // `(` + + // Consume the fn call arguments. + let modifiers = [ + (token::OpenDelim(token::Paren), 1), + (token::CloseDelim(token::Paren), -1), + ]; + self.consume_tts(1, &modifiers[..]); + + if self.token.kind == token::Eof { + // Not entirely sure that what we consumed were fn arguments, rollback. + mem::replace(self, snapshot); + Err(()) + } else { + // 99% certain that the suggestion is correct, continue parsing. + Ok(()) + } + } + + pub(super) fn maybe_report_ambiguous_plus( + &mut self, + allow_plus: bool, + impl_dyn_multi: bool, + ty: &Ty, + ) { + if !allow_plus && impl_dyn_multi { + let sum_with_parens = format!("({})", pprust::ty_to_string(&ty)); + self.struct_span_err(ty.span, "ambiguous `+` in a type") + .span_suggestion( + ty.span, + "use parentheses to disambiguate", + sum_with_parens, + Applicability::MachineApplicable, + ) + .emit(); + } + } + + pub(super) fn maybe_recover_from_bad_type_plus( + &mut self, + allow_plus: bool, + ty: &Ty, + ) -> PResult<'a, ()> { + // Do not add `+` to expected tokens. + if !allow_plus || !self.token.is_like_plus() { + return Ok(()); + } + + self.bump(); // `+` + let bounds = self.parse_generic_bounds(None)?; + let sum_span = ty.span.to(self.prev_span); + + let mut err = struct_span_err!( + self.sess.span_diagnostic, + sum_span, + E0178, + "expected a path on the left-hand side of `+`, not `{}`", + pprust::ty_to_string(ty) + ); + + match ty.kind { + TyKind::Rptr(ref lifetime, ref mut_ty) => { + let sum_with_parens = pprust::to_string(|s| { + s.s.word("&"); + s.print_opt_lifetime(lifetime); + s.print_mutability(mut_ty.mutbl); + s.popen(); + s.print_type(&mut_ty.ty); + s.print_type_bounds(" +", &bounds); + s.pclose() + }); + err.span_suggestion( + sum_span, + "try adding parentheses", + sum_with_parens, + Applicability::MachineApplicable, + ); + } + TyKind::Ptr(..) | TyKind::BareFn(..) => { + err.span_label(sum_span, "perhaps you forgot parentheses?"); + } + _ => { + err.span_label(sum_span, "expected a path"); + } + } + err.emit(); + Ok(()) + } + + /// Tries to recover from associated item paths like `[T]::AssocItem` / `(T, U)::AssocItem`. + /// Attempts to convert the base expression/pattern/type into a type, parses the `::AssocItem` + /// tail, and combines them into a `::AssocItem` expression/pattern/type. + pub(super) fn maybe_recover_from_bad_qpath( + &mut self, + base: P, + allow_recovery: bool, + ) -> PResult<'a, P> { + // Do not add `::` to expected tokens. + if allow_recovery && self.token == token::ModSep { + if let Some(ty) = base.to_ty() { + return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty); + } + } + Ok(base) + } + + /// Given an already parsed `Ty`, parses the `::AssocItem` tail and + /// combines them into a `::AssocItem` expression/pattern/type. + pub(super) fn maybe_recover_from_bad_qpath_stage_2( + &mut self, + ty_span: Span, + ty: P, + ) -> PResult<'a, P> { + self.expect(&token::ModSep)?; + + let mut path = ast::Path { + segments: Vec::new(), + span: DUMMY_SP, + }; + self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?; + path.span = ty_span.to(self.prev_span); + + let ty_str = self + .span_to_snippet(ty_span) + .unwrap_or_else(|_| pprust::ty_to_string(&ty)); + self.diagnostic() + .struct_span_err(path.span, "missing angle brackets in associated item path") + .span_suggestion( + // This is a best-effort recovery. + path.span, + "try", + format!("<{}>::{}", ty_str, pprust::path_to_string(&path)), + Applicability::MaybeIncorrect, + ) + .emit(); + + let path_span = ty_span.shrink_to_hi(); // Use an empty path since `position == 0`. + Ok(P(T::recovered( + Some(QSelf { + ty, + path_span, + position: 0, + }), + path, + ))) + } + + pub(super) fn maybe_consume_incorrect_semicolon(&mut self, items: &[P]) -> bool { + if self.eat(&token::Semi) { + let mut err = self.struct_span_err(self.prev_span, "expected item, found `;`"); + err.span_suggestion_short( + self.prev_span, + "remove this semicolon", + String::new(), + Applicability::MachineApplicable, + ); + if !items.is_empty() { + let previous_item = &items[items.len() - 1]; + let previous_item_kind_name = match previous_item.kind { + // Say "braced struct" because tuple-structs and + // braceless-empty-struct declarations do take a semicolon. + ItemKind::Struct(..) => Some("braced struct"), + ItemKind::Enum(..) => Some("enum"), + ItemKind::Trait(..) => Some("trait"), + ItemKind::Union(..) => Some("union"), + _ => None, + }; + if let Some(name) = previous_item_kind_name { + err.help(&format!( + "{} declarations are not followed by a semicolon", + name + )); + } + } + err.emit(); + true + } else { + false + } + } + + /// Creates a `DiagnosticBuilder` for an unexpected token `t` and tries to recover if it is a + /// closing delimiter. + pub(super) fn unexpected_try_recover( + &mut self, + t: &TokenKind, + ) -> PResult<'a, bool /* recovered */> { + let token_str = pprust::token_kind_to_string(t); + let this_token_str = self.this_token_descr(); + let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) { + // Point at the end of the macro call when reaching end of macro arguments. + (token::Eof, Some(_)) => { + let sp = self.sess.source_map().next_point(self.token.span); + (sp, sp) + } + // We don't want to point at the following span after DUMMY_SP. + // This happens when the parser finds an empty TokenStream. + _ if self.prev_span == DUMMY_SP => (self.token.span, self.token.span), + // EOF, don't want to point at the following char, but rather the last token. + (token::Eof, None) => (self.prev_span, self.token.span), + _ => (self.sess.source_map().next_point(self.prev_span), self.token.span), + }; + let msg = format!( + "expected `{}`, found {}", + token_str, + match (&self.token.kind, self.subparser_name) { + (token::Eof, Some(origin)) => format!("end of {}", origin), + _ => this_token_str, + }, + ); + let mut err = self.struct_span_err(sp, &msg); + let label_exp = format!("expected `{}`", token_str); + match self.recover_closing_delimiter(&[t.clone()], err) { + Err(e) => err = e, + Ok(recovered) => { + return Ok(recovered); + } + } + let sm = self.sess.source_map(); + if !sm.is_multiline(prev_sp.until(sp)) { + // When the spans are in the same line, it means that the only content + // between them is whitespace, point only at the found token. + err.span_label(sp, label_exp); + } else { + err.span_label(prev_sp, label_exp); + err.span_label(sp, "unexpected token"); + } + Err(err) + } + + pub(super) fn expect_semi(&mut self) -> PResult<'a, ()> { + if self.eat(&token::Semi) { + return Ok(()); + } + let sm = self.sess.source_map(); + let msg = format!("expected `;`, found `{}`", self.this_token_descr()); + let appl = Applicability::MachineApplicable; + if self.token.span == DUMMY_SP || self.prev_span == DUMMY_SP { + // Likely inside a macro, can't provide meaninful suggestions. + return self.expect(&token::Semi).map(|_| ()); + } else if !sm.is_multiline(self.prev_span.until(self.token.span)) { + // The current token is in the same line as the prior token, not recoverable. + } else if self.look_ahead(1, |t| t == &token::CloseDelim(token::Brace) + || token_can_begin_expr(t) && t.kind != token::Colon + ) && [token::Comma, token::Colon].contains(&self.token.kind) { + // Likely typo: `,` → `;` or `:` → `;`. This is triggered if the current token is + // either `,` or `:`, and the next token could either start a new statement or is a + // block close. For example: + // + // let x = 32: + // let y = 42; + self.bump(); + let sp = self.prev_span; + self.struct_span_err(sp, &msg) + .span_suggestion(sp, "change this to `;`", ";".to_string(), appl) + .emit(); + return Ok(()) + } else if self.look_ahead(0, |t| t == &token::CloseDelim(token::Brace) || ( + token_can_begin_expr(t) + && t != &token::Semi + && t != &token::Pound // Avoid triggering with too many trailing `#` in raw string. + )) { + // Missing semicolon typo. This is triggered if the next token could either start a + // new statement or is a block close. For example: + // + // let x = 32 + // let y = 42; + let sp = self.prev_span.shrink_to_hi(); + self.struct_span_err(sp, &msg) + .span_label(self.token.span, "unexpected token") + .span_suggestion_short(sp, "add `;` here", ";".to_string(), appl) + .emit(); + return Ok(()) + } + self.expect(&token::Semi).map(|_| ()) // Error unconditionally + } + + pub(super) fn parse_semi_or_incorrect_foreign_fn_body( + &mut self, + ident: &Ident, + extern_sp: Span, + ) -> PResult<'a, ()> { + if self.token != token::Semi { + // This might be an incorrect fn definition (#62109). + let parser_snapshot = self.clone(); + match self.parse_inner_attrs_and_block() { + Ok((_, body)) => { + self.struct_span_err(ident.span, "incorrect `fn` inside `extern` block") + .span_label(ident.span, "can't have a body") + .span_label(body.span, "this body is invalid here") + .span_label( + extern_sp, + "`extern` blocks define existing foreign functions and `fn`s \ + inside of them cannot have a body") + .help("you might have meant to write a function accessible through ffi, \ + which can be done by writing `extern fn` outside of the \ + `extern` block") + .note("for more information, visit \ + https://doc.rust-lang.org/std/keyword.extern.html") + .emit(); + } + Err(mut err) => { + err.cancel(); + mem::replace(self, parser_snapshot); + self.expect_semi()?; + } + } + } else { + self.bump(); + } + Ok(()) + } + + /// Consumes alternative await syntaxes like `await!()`, `await `, + /// `await? `, `await()`, and `await { }`. + pub(super) fn parse_incorrect_await_syntax( + &mut self, + lo: Span, + await_sp: Span, + ) -> PResult<'a, (Span, ExprKind)> { + if self.token == token::Not { + // Handle `await!()`. + self.expect(&token::Not)?; + self.expect(&token::OpenDelim(token::Paren))?; + let expr = self.parse_expr()?; + self.expect(&token::CloseDelim(token::Paren))?; + let sp = self.error_on_incorrect_await(lo, self.prev_span, &expr, false); + return Ok((sp, ExprKind::Await(expr))) + } + + let is_question = self.eat(&token::Question); // Handle `await? `. + let expr = if self.token == token::OpenDelim(token::Brace) { + // Handle `await { }`. + // This needs to be handled separatedly from the next arm to avoid + // interpreting `await { }?` as `?.await`. + self.parse_block_expr( + None, + self.token.span, + BlockCheckMode::Default, + ThinVec::new(), + ) + } else { + self.parse_expr() + }.map_err(|mut err| { + err.span_label(await_sp, "while parsing this incorrect await expression"); + err + })?; + let sp = self.error_on_incorrect_await(lo, expr.span, &expr, is_question); + Ok((sp, ExprKind::Await(expr))) + } + + fn error_on_incorrect_await(&self, lo: Span, hi: Span, expr: &Expr, is_question: bool) -> Span { + let expr_str = self.span_to_snippet(expr.span) + .unwrap_or_else(|_| pprust::expr_to_string(&expr)); + let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" }); + let sp = lo.to(hi); + let app = match expr.kind { + ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await ?` + _ => Applicability::MachineApplicable, + }; + self.struct_span_err(sp, "incorrect use of `await`") + .span_suggestion(sp, "`await` is a postfix operation", suggestion, app) + .emit(); + sp + } + + /// If encountering `future.await()`, consumes and emits an error. + pub(super) fn recover_from_await_method_call(&mut self) { + if self.token == token::OpenDelim(token::Paren) && + self.look_ahead(1, |t| t == &token::CloseDelim(token::Paren)) + { + // future.await() + let lo = self.token.span; + self.bump(); // ( + let sp = lo.to(self.token.span); + self.bump(); // ) + self.struct_span_err(sp, "incorrect use of `await`") + .span_suggestion( + sp, + "`await` is not a method call, remove the parentheses", + String::new(), + Applicability::MachineApplicable, + ).emit() + } + } + + /// Recovers a situation like `for ( $pat in $expr )` + /// and suggest writing `for $pat in $expr` instead. + /// + /// This should be called before parsing the `$block`. + pub(super) fn recover_parens_around_for_head( + &mut self, + pat: P, + expr: &Expr, + begin_paren: Option, + ) -> P { + match (&self.token.kind, begin_paren) { + (token::CloseDelim(token::Paren), Some(begin_par_sp)) => { + self.bump(); + + let pat_str = self + // Remove the `(` from the span of the pattern: + .span_to_snippet(pat.span.trim_start(begin_par_sp).unwrap()) + .unwrap_or_else(|_| pprust::pat_to_string(&pat)); + + self.struct_span_err(self.prev_span, "unexpected closing `)`") + .span_label(begin_par_sp, "opening `(`") + .span_suggestion( + begin_par_sp.to(self.prev_span), + "remove parenthesis in `for` loop", + format!("{} in {}", pat_str, pprust::expr_to_string(&expr)), + // With e.g. `for (x) in y)` this would replace `(x) in y)` + // with `x) in y)` which is syntactically invalid. + // However, this is prevented before we get here. + Applicability::MachineApplicable, + ) + .emit(); + + // Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint. + pat.and_then(|pat| match pat.kind { + PatKind::Paren(pat) => pat, + _ => P(pat), + }) + } + _ => pat, + } + } + + pub(super) fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool { + (self.token == token::Lt && // `foo: true, + _ => false, + } && + !self.token.is_reserved_ident() && // v `foo:bar(baz)` + self.look_ahead(1, |t| t == &token::OpenDelim(token::Paren)) || + self.look_ahead(1, |t| t == &token::Lt) && // `foo:bar` + } + + pub(super) fn recover_seq_parse_error( + &mut self, + delim: token::DelimToken, + lo: Span, + result: PResult<'a, P>, + ) -> P { + match result { + Ok(x) => x, + Err(mut err) => { + err.emit(); + // Recover from parse error, callers expect the closing delim to be consumed. + self.consume_block(delim, ConsumeClosingDelim::Yes); + self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new()) + } + } + } + + pub(super) fn recover_closing_delimiter( + &mut self, + tokens: &[TokenKind], + mut err: DiagnosticBuilder<'a>, + ) -> PResult<'a, bool> { + let mut pos = None; + // We want to use the last closing delim that would apply. + for (i, unmatched) in self.unclosed_delims.iter().enumerate().rev() { + if tokens.contains(&token::CloseDelim(unmatched.expected_delim)) + && Some(self.token.span) > unmatched.unclosed_span + { + pos = Some(i); + } + } + match pos { + Some(pos) => { + // Recover and assume that the detected unclosed delimiter was meant for + // this location. Emit the diagnostic and act as if the delimiter was + // present for the parser's sake. + + // Don't attempt to recover from this unclosed delimiter more than once. + let unmatched = self.unclosed_delims.remove(pos); + let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim)); + if unmatched.found_delim.is_none() { + // We encountered `Eof`, set this fact here to avoid complaining about missing + // `fn main()` when we found place to suggest the closing brace. + *self.sess.reached_eof.borrow_mut() = true; + } + + // We want to suggest the inclusion of the closing delimiter where it makes + // the most sense, which is immediately after the last token: + // + // {foo(bar {}} + // - ^ + // | | + // | help: `)` may belong here + // | + // unclosed delimiter + if let Some(sp) = unmatched.unclosed_span { + err.span_label(sp, "unclosed delimiter"); + } + err.span_suggestion_short( + self.sess.source_map().next_point(self.prev_span), + &format!("{} may belong here", delim.to_string()), + delim.to_string(), + Applicability::MaybeIncorrect, + ); + if unmatched.found_delim.is_none() { + // Encountered `Eof` when lexing blocks. Do not recover here to avoid knockdown + // errors which would be emitted elsewhere in the parser and let other error + // recovery consume the rest of the file. + Err(err) + } else { + err.emit(); + self.expected_tokens.clear(); // Reduce the number of errors. + Ok(true) + } + } + _ => Err(err), + } + } + + /// Recovers from `pub` keyword in places where it seems _reasonable_ but isn't valid. + pub(super) fn eat_bad_pub(&mut self) { + // When `unclosed_delims` is populated, it means that the code being parsed is already + // quite malformed, which might mean that, for example, a pub struct definition could be + // parsed as being a trait item, which is invalid and this error would trigger + // unconditionally, resulting in misleading diagnostics. Because of this, we only attempt + // this nice to have recovery for code that is otherwise well formed. + if self.token.is_keyword(kw::Pub) && self.unclosed_delims.is_empty() { + match self.parse_visibility(false) { + Ok(vis) => { + self.diagnostic() + .struct_span_err(vis.span, "unnecessary visibility qualifier") + .span_label(vis.span, "`pub` not permitted here") + .emit(); + } + Err(mut err) => err.emit(), + } + } + } + + /// Eats tokens until we can be relatively sure we reached the end of the + /// statement. This is something of a best-effort heuristic. + /// + /// We terminate when we find an unmatched `}` (without consuming it). + pub(super) fn recover_stmt(&mut self) { + self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore) + } + + /// If `break_on_semi` is `Break`, then we will stop consuming tokens after + /// finding (and consuming) a `;` outside of `{}` or `[]` (note that this is + /// approximate -- it can mean we break too early due to macros, but that + /// should only lead to sub-optimal recovery, not inaccurate parsing). + /// + /// If `break_on_block` is `Break`, then we will stop consuming tokens + /// after finding (and consuming) a brace-delimited block. + pub(super) fn recover_stmt_( + &mut self, + break_on_semi: SemiColonMode, + break_on_block: BlockMode, + ) { + let mut brace_depth = 0; + let mut bracket_depth = 0; + let mut in_block = false; + debug!("recover_stmt_ enter loop (semi={:?}, block={:?})", + break_on_semi, break_on_block); + loop { + debug!("recover_stmt_ loop {:?}", self.token); + match self.token.kind { + token::OpenDelim(token::DelimToken::Brace) => { + brace_depth += 1; + self.bump(); + if break_on_block == BlockMode::Break && + brace_depth == 1 && + bracket_depth == 0 { + in_block = true; + } + } + token::OpenDelim(token::DelimToken::Bracket) => { + bracket_depth += 1; + self.bump(); + } + token::CloseDelim(token::DelimToken::Brace) => { + if brace_depth == 0 { + debug!("recover_stmt_ return - close delim {:?}", self.token); + break; + } + brace_depth -= 1; + self.bump(); + if in_block && bracket_depth == 0 && brace_depth == 0 { + debug!("recover_stmt_ return - block end {:?}", self.token); + break; + } + } + token::CloseDelim(token::DelimToken::Bracket) => { + bracket_depth -= 1; + if bracket_depth < 0 { + bracket_depth = 0; + } + self.bump(); + } + token::Eof => { + debug!("recover_stmt_ return - Eof"); + break; + } + token::Semi => { + self.bump(); + if break_on_semi == SemiColonMode::Break && + brace_depth == 0 && + bracket_depth == 0 { + debug!("recover_stmt_ return - Semi"); + break; + } + } + token::Comma if break_on_semi == SemiColonMode::Comma && + brace_depth == 0 && + bracket_depth == 0 => + { + debug!("recover_stmt_ return - Semi"); + break; + } + _ => { + self.bump() + } + } + } + } + + pub(super) fn check_for_for_in_in_typo(&mut self, in_span: Span) { + if self.eat_keyword(kw::In) { + // a common typo: `for _ in in bar {}` + self.struct_span_err(self.prev_span, "expected iterable, found keyword `in`") + .span_suggestion_short( + in_span.until(self.prev_span), + "remove the duplicated `in`", + String::new(), + Applicability::MachineApplicable, + ) + .emit(); + } + } + + pub(super) fn expected_semi_or_open_brace(&mut self) -> PResult<'a, T> { + let token_str = self.this_token_descr(); + let mut err = self.fatal(&format!("expected `;` or `{{`, found {}", token_str)); + err.span_label(self.token.span, "expected `;` or `{`"); + Err(err) + } + + pub(super) fn eat_incorrect_doc_comment_for_param_type(&mut self) { + if let token::DocComment(_) = self.token.kind { + self.struct_span_err( + self.token.span, + "documentation comments cannot be applied to a function parameter's type", + ) + .span_label(self.token.span, "doc comments are not allowed here") + .emit(); + self.bump(); + } else if self.token == token::Pound && self.look_ahead(1, |t| { + *t == token::OpenDelim(token::Bracket) + }) { + let lo = self.token.span; + // Skip every token until next possible arg. + while self.token != token::CloseDelim(token::Bracket) { + self.bump(); + } + let sp = lo.to(self.token.span); + self.bump(); + self.struct_span_err( + sp, + "attributes cannot be applied to a function parameter's type", + ) + .span_label(sp, "attributes are not allowed here") + .emit(); + } + } + + pub(super) fn parameter_without_type( + &mut self, + err: &mut DiagnosticBuilder<'_>, + pat: P, + require_name: bool, + is_self_allowed: bool, + is_trait_item: bool, + ) -> Option { + // If we find a pattern followed by an identifier, it could be an (incorrect) + // C-style parameter declaration. + if self.check_ident() && self.look_ahead(1, |t| { + *t == token::Comma || *t == token::CloseDelim(token::Paren) + }) { // `fn foo(String s) {}` + let ident = self.parse_ident().unwrap(); + let span = pat.span.with_hi(ident.span.hi()); + + err.span_suggestion( + span, + "declare the type after the parameter binding", + String::from(": "), + Applicability::HasPlaceholders, + ); + return Some(ident); + } else if let PatKind::Ident(_, ident, _) = pat.kind { + if require_name && ( + is_trait_item || + self.token == token::Comma || + self.token == token::Lt || + self.token == token::CloseDelim(token::Paren) + ) { // `fn foo(a, b) {}`, `fn foo(a, b) {}` or `fn foo(usize, usize) {}` + if is_self_allowed { + err.span_suggestion( + pat.span, + "if this is a `self` type, give it a parameter name", + format!("self: {}", ident), + Applicability::MaybeIncorrect, + ); + } + // Avoid suggesting that `fn foo(HashMap)` is fixed with a change to + // `fn foo(HashMap: TypeName)`. + if self.token != token::Lt { + err.span_suggestion( + pat.span, + "if this was a parameter name, give it a type", + format!("{}: TypeName", ident), + Applicability::HasPlaceholders, + ); + } + err.span_suggestion( + pat.span, + "if this is a type, explicitly ignore the parameter name", + format!("_: {}", ident), + Applicability::MachineApplicable, + ); + err.note("anonymous parameters are removed in the 2018 edition (see RFC 1685)"); + + // Don't attempt to recover by using the `X` in `X` as the parameter name. + return if self.token == token::Lt { None } else { Some(ident) }; + } + } + None + } + + pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (P, P)> { + let pat = self.parse_pat(Some("argument name"))?; + self.expect(&token::Colon)?; + let ty = self.parse_ty()?; + + self.diagnostic() + .struct_span_err_with_code( + pat.span, + "patterns aren't allowed in methods without bodies", + DiagnosticId::Error("E0642".into()), + ) + .span_suggestion_short( + pat.span, + "give this argument a name or use an underscore to ignore it", + "_".to_owned(), + Applicability::MachineApplicable, + ) + .emit(); + + // Pretend the pattern is `_`, to avoid duplicate errors from AST validation. + let pat = P(Pat { + kind: PatKind::Wild, + span: pat.span, + id: ast::DUMMY_NODE_ID + }); + Ok((pat, ty)) + } + + pub(super) fn recover_bad_self_param( + &mut self, + mut param: ast::Param, + is_trait_item: bool, + ) -> PResult<'a, ast::Param> { + let sp = param.pat.span; + param.ty.kind = TyKind::Err; + let mut err = self.struct_span_err(sp, "unexpected `self` parameter in function"); + if is_trait_item { + err.span_label(sp, "must be the first associated function parameter"); + } else { + err.span_label(sp, "not valid as function parameter"); + err.note("`self` is only valid as the first parameter of an associated function"); + } + err.emit(); + Ok(param) + } + + pub(super) fn consume_block( + &mut self, + delim: token::DelimToken, + consume_close: ConsumeClosingDelim, + ) { + let mut brace_depth = 0; + loop { + if self.eat(&token::OpenDelim(delim)) { + brace_depth += 1; + } else if self.check(&token::CloseDelim(delim)) { + if brace_depth == 0 { + if let ConsumeClosingDelim::Yes = consume_close { + // Some of the callers of this method expect to be able to parse the + // closing delimiter themselves, so we leave it alone. Otherwise we advance + // the parser. + self.bump(); + } + return; + } else { + self.bump(); + brace_depth -= 1; + continue; + } + } else if self.token == token::Eof || self.eat(&token::CloseDelim(token::NoDelim)) { + return; + } else { + self.bump(); + } + } + } + + pub(super) fn expected_expression_found(&self) -> DiagnosticBuilder<'a> { + let (span, msg) = match (&self.token.kind, self.subparser_name) { + (&token::Eof, Some(origin)) => { + let sp = self.sess.source_map().next_point(self.token.span); + (sp, format!("expected expression, found end of {}", origin)) + } + _ => (self.token.span, format!( + "expected expression, found {}", + self.this_token_descr(), + )), + }; + let mut err = self.struct_span_err(span, &msg); + let sp = self.sess.source_map().start_point(self.token.span); + if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) { + self.sess.expr_parentheses_needed(&mut err, *sp, None); + } + err.span_label(span, "expected expression"); + err + } + + fn consume_tts( + &mut self, + mut acc: i64, // `i64` because malformed code can have more closing delims than opening. + // Not using `FxHashMap` due to `token::TokenKind: !Eq + !Hash`. + modifier: &[(token::TokenKind, i64)], + ) { + while acc > 0 { + if let Some((_, val)) = modifier.iter().find(|(t, _)| *t == self.token.kind) { + acc += *val; + } + if self.token.kind == token::Eof { + break; + } + self.bump(); + } + } + + /// Replace duplicated recovered parameters with `_` pattern to avoid unecessary errors. + /// + /// This is necessary because at this point we don't know whether we parsed a function with + /// anonymous parameters or a function with names but no types. In order to minimize + /// unecessary errors, we assume the parameters are in the shape of `fn foo(a, b, c)` where + /// the parameters are *names* (so we don't emit errors about not being able to find `b` in + /// the local scope), but if we find the same name multiple times, like in `fn foo(i8, i8)`, + /// we deduplicate them to not complain about duplicated parameter names. + pub(super) fn deduplicate_recovered_params_names(&self, fn_inputs: &mut Vec) { + let mut seen_inputs = FxHashSet::default(); + for input in fn_inputs.iter_mut() { + let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err) = ( + &input.pat.kind, &input.ty.kind, + ) { + Some(*ident) + } else { + None + }; + if let Some(ident) = opt_ident { + if seen_inputs.contains(&ident) { + input.pat.kind = PatKind::Wild; + } + seen_inputs.insert(ident); + } + } + } +} diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs new file mode 100644 index 00000000000..dadb91f8b3c --- /dev/null +++ b/src/librustc_parse/parser/expr.rs @@ -0,0 +1,1963 @@ +use super::{Parser, Restrictions, PrevTokenKind, TokenType, PathStyle, BlockMode}; +use super::{SemiColonMode, SeqSep, TokenExpectType}; +use super::pat::{GateOr, PARAM_EXPECTED}; +use super::diagnostics::Error; +use crate::maybe_recover_from_interpolated_ty_qpath; + +use syntax::ast::{ + self, DUMMY_NODE_ID, Attribute, AttrStyle, Ident, CaptureBy, BlockCheckMode, + Expr, ExprKind, RangeLimits, Label, Movability, IsAsync, Arm, Ty, TyKind, + FunctionRetTy, Param, FnDecl, BinOpKind, BinOp, UnOp, Mac, AnonConst, Field, Lit, +}; +use syntax::token::{self, Token, TokenKind}; +use syntax::print::pprust; +use syntax::ptr::P; +use syntax::source_map::{self, Span}; +use syntax::util::classify; +use syntax::util::literal::LitError; +use syntax::util::parser::{AssocOp, Fixity, prec_let_scrutinee_needs_par}; +use syntax_pos::symbol::{kw, sym}; +use syntax_pos::Symbol; +use errors::{PResult, Applicability}; +use std::mem; +use rustc_data_structures::thin_vec::ThinVec; + +/// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression +/// dropped into the token stream, which happens while parsing the result of +/// macro expansion). Placement of these is not as complex as I feared it would +/// be. The important thing is to make sure that lookahead doesn't balk at +/// `token::Interpolated` tokens. +macro_rules! maybe_whole_expr { + ($p:expr) => { + if let token::Interpolated(nt) = &$p.token.kind { + match &**nt { + token::NtExpr(e) | token::NtLiteral(e) => { + let e = e.clone(); + $p.bump(); + return Ok(e); + } + token::NtPath(path) => { + let path = path.clone(); + $p.bump(); + return Ok($p.mk_expr( + $p.token.span, ExprKind::Path(None, path), ThinVec::new() + )); + } + token::NtBlock(block) => { + let block = block.clone(); + $p.bump(); + return Ok($p.mk_expr( + $p.token.span, ExprKind::Block(block, None), ThinVec::new() + )); + } + // N.B., `NtIdent(ident)` is normalized to `Ident` in `fn bump`. + _ => {}, + }; + } + } +} + +#[derive(Debug)] +pub(super) enum LhsExpr { + NotYetParsed, + AttributesParsed(ThinVec), + AlreadyParsed(P), +} + +impl From>> for LhsExpr { + /// Converts `Some(attrs)` into `LhsExpr::AttributesParsed(attrs)` + /// and `None` into `LhsExpr::NotYetParsed`. + /// + /// This conversion does not allocate. + fn from(o: Option>) -> Self { + if let Some(attrs) = o { + LhsExpr::AttributesParsed(attrs) + } else { + LhsExpr::NotYetParsed + } + } +} + +impl From> for LhsExpr { + /// Converts the `expr: P` into `LhsExpr::AlreadyParsed(expr)`. + /// + /// This conversion does not allocate. + fn from(expr: P) -> Self { + LhsExpr::AlreadyParsed(expr) + } +} + +impl<'a> Parser<'a> { + /// Parses an expression. + #[inline] + pub fn parse_expr(&mut self) -> PResult<'a, P> { + self.parse_expr_res(Restrictions::empty(), None) + } + + fn parse_paren_expr_seq(&mut self) -> PResult<'a, Vec>> { + self.parse_paren_comma_seq(|p| { + match p.parse_expr() { + Ok(expr) => Ok(expr), + Err(mut err) => match p.token.kind { + token::Ident(name, false) + if name == kw::Underscore && p.look_ahead(1, |t| { + t == &token::Comma + }) => { + // Special-case handling of `foo(_, _, _)` + err.emit(); + let sp = p.token.span; + p.bump(); + Ok(p.mk_expr(sp, ExprKind::Err, ThinVec::new())) + } + _ => Err(err), + }, + } + }).map(|(r, _)| r) + } + + /// Parses an expression, subject to the given restrictions. + #[inline] + pub(super) fn parse_expr_res( + &mut self, + r: Restrictions, + already_parsed_attrs: Option> + ) -> PResult<'a, P> { + self.with_res(r, |this| this.parse_assoc_expr(already_parsed_attrs)) + } + + /// Parses an associative expression. + /// + /// This parses an expression accounting for associativity and precedence of the operators in + /// the expression. + #[inline] + fn parse_assoc_expr( + &mut self, + already_parsed_attrs: Option>, + ) -> PResult<'a, P> { + self.parse_assoc_expr_with(0, already_parsed_attrs.into()) + } + + /// Parses an associative expression with operators of at least `min_prec` precedence. + pub(super) fn parse_assoc_expr_with( + &mut self, + min_prec: usize, + lhs: LhsExpr, + ) -> PResult<'a, P> { + let mut lhs = if let LhsExpr::AlreadyParsed(expr) = lhs { + expr + } else { + let attrs = match lhs { + LhsExpr::AttributesParsed(attrs) => Some(attrs), + _ => None, + }; + if [token::DotDot, token::DotDotDot, token::DotDotEq].contains(&self.token.kind) { + return self.parse_prefix_range_expr(attrs); + } else { + self.parse_prefix_expr(attrs)? + } + }; + let last_type_ascription_set = self.last_type_ascription.is_some(); + + match (self.expr_is_complete(&lhs), AssocOp::from_token(&self.token)) { + (true, None) => { + self.last_type_ascription = None; + // Semi-statement forms are odd. See https://github.com/rust-lang/rust/issues/29071 + return Ok(lhs); + } + (false, _) => {} // continue parsing the expression + // An exhaustive check is done in the following block, but these are checked first + // because they *are* ambiguous but also reasonable looking incorrect syntax, so we + // want to keep their span info to improve diagnostics in these cases in a later stage. + (true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3` + (true, Some(AssocOp::Subtract)) | // `{ 42 } -5` + (true, Some(AssocOp::LAnd)) | // `{ 42 } &&x` (#61475) + (true, Some(AssocOp::Add)) // `{ 42 } + 42 + // If the next token is a keyword, then the tokens above *are* unambiguously incorrect: + // `if x { a } else { b } && if y { c } else { d }` + if !self.look_ahead(1, |t| t.is_reserved_ident()) => { + self.last_type_ascription = None; + // These cases are ambiguous and can't be identified in the parser alone + let sp = self.sess.source_map().start_point(self.token.span); + self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span); + return Ok(lhs); + } + (true, Some(ref op)) if !op.can_continue_expr_unambiguously() => { + self.last_type_ascription = None; + return Ok(lhs); + } + (true, Some(_)) => { + // We've found an expression that would be parsed as a statement, but the next + // token implies this should be parsed as an expression. + // For example: `if let Some(x) = x { x } else { 0 } / 2` + let mut err = self.struct_span_err(self.token.span, &format!( + "expected expression, found `{}`", + pprust::token_to_string(&self.token), + )); + err.span_label(self.token.span, "expected expression"); + self.sess.expr_parentheses_needed( + &mut err, + lhs.span, + Some(pprust::expr_to_string(&lhs), + )); + err.emit(); + } + } + self.expected_tokens.push(TokenType::Operator); + while let Some(op) = AssocOp::from_token(&self.token) { + + // Adjust the span for interpolated LHS to point to the `$lhs` token and not to what + // it refers to. Interpolated identifiers are unwrapped early and never show up here + // as `PrevTokenKind::Interpolated` so if LHS is a single identifier we always process + // it as "interpolated", it doesn't change the answer for non-interpolated idents. + let lhs_span = match (self.prev_token_kind, &lhs.kind) { + (PrevTokenKind::Interpolated, _) => self.prev_span, + (PrevTokenKind::Ident, &ExprKind::Path(None, ref path)) + if path.segments.len() == 1 => self.prev_span, + _ => lhs.span, + }; + + let cur_op_span = self.token.span; + let restrictions = if op.is_assign_like() { + self.restrictions & Restrictions::NO_STRUCT_LITERAL + } else { + self.restrictions + }; + let prec = op.precedence(); + if prec < min_prec { + break; + } + // Check for deprecated `...` syntax + if self.token == token::DotDotDot && op == AssocOp::DotDotEq { + self.err_dotdotdot_syntax(self.token.span); + } + + if self.token == token::LArrow { + self.err_larrow_operator(self.token.span); + } + + self.bump(); + if op.is_comparison() { + if let Some(expr) = self.check_no_chained_comparison(&lhs, &op)? { + return Ok(expr); + } + } + // Special cases: + if op == AssocOp::As { + lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Cast)?; + continue + } else if op == AssocOp::Colon { + let maybe_path = self.could_ascription_be_path(&lhs.kind); + self.last_type_ascription = Some((self.prev_span, maybe_path)); + + lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Type)?; + self.sess.gated_spans.gate(sym::type_ascription, lhs.span); + continue + } else if op == AssocOp::DotDot || op == AssocOp::DotDotEq { + // If we didn’t have to handle `x..`/`x..=`, it would be pretty easy to + // generalise it to the Fixity::None code. + // + // We have 2 alternatives here: `x..y`/`x..=y` and `x..`/`x..=` The other + // two variants are handled with `parse_prefix_range_expr` call above. + let rhs = if self.is_at_start_of_range_notation_rhs() { + Some(self.parse_assoc_expr_with(prec + 1, LhsExpr::NotYetParsed)?) + } else { + None + }; + let (lhs_span, rhs_span) = (lhs.span, if let Some(ref x) = rhs { + x.span + } else { + cur_op_span + }); + let limits = if op == AssocOp::DotDot { + RangeLimits::HalfOpen + } else { + RangeLimits::Closed + }; + + let r = self.mk_range(Some(lhs), rhs, limits)?; + lhs = self.mk_expr(lhs_span.to(rhs_span), r, ThinVec::new()); + break + } + + let fixity = op.fixity(); + let prec_adjustment = match fixity { + Fixity::Right => 0, + Fixity::Left => 1, + // We currently have no non-associative operators that are not handled above by + // the special cases. The code is here only for future convenience. + Fixity::None => 1, + }; + let rhs = self.with_res( + restrictions - Restrictions::STMT_EXPR, + |this| this.parse_assoc_expr_with(prec + prec_adjustment, LhsExpr::NotYetParsed) + )?; + + // Make sure that the span of the parent node is larger than the span of lhs and rhs, + // including the attributes. + let lhs_span = lhs + .attrs + .iter() + .filter(|a| a.style == AttrStyle::Outer) + .next() + .map_or(lhs_span, |a| a.span); + let span = lhs_span.to(rhs.span); + lhs = match op { + AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | + AssocOp::Modulus | AssocOp::LAnd | AssocOp::LOr | AssocOp::BitXor | + AssocOp::BitAnd | AssocOp::BitOr | AssocOp::ShiftLeft | AssocOp::ShiftRight | + AssocOp::Equal | AssocOp::Less | AssocOp::LessEqual | AssocOp::NotEqual | + AssocOp::Greater | AssocOp::GreaterEqual => { + let ast_op = op.to_ast_binop().unwrap(); + let binary = self.mk_binary(source_map::respan(cur_op_span, ast_op), lhs, rhs); + self.mk_expr(span, binary, ThinVec::new()) + } + AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()), + AssocOp::AssignOp(k) => { + let aop = match k { + token::Plus => BinOpKind::Add, + token::Minus => BinOpKind::Sub, + token::Star => BinOpKind::Mul, + token::Slash => BinOpKind::Div, + token::Percent => BinOpKind::Rem, + token::Caret => BinOpKind::BitXor, + token::And => BinOpKind::BitAnd, + token::Or => BinOpKind::BitOr, + token::Shl => BinOpKind::Shl, + token::Shr => BinOpKind::Shr, + }; + let aopexpr = self.mk_assign_op(source_map::respan(cur_op_span, aop), lhs, rhs); + self.mk_expr(span, aopexpr, ThinVec::new()) + } + AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotEq => { + self.bug("AssocOp should have been handled by special case") + } + }; + + if let Fixity::None = fixity { break } + } + if last_type_ascription_set { + self.last_type_ascription = None; + } + Ok(lhs) + } + + /// Checks if this expression is a successfully parsed statement. + fn expr_is_complete(&self, e: &Expr) -> bool { + self.restrictions.contains(Restrictions::STMT_EXPR) && + !classify::expr_requires_semi_to_be_stmt(e) + } + + fn is_at_start_of_range_notation_rhs(&self) -> bool { + if self.token.can_begin_expr() { + // Parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`. + if self.token == token::OpenDelim(token::Brace) { + return !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL); + } + true + } else { + false + } + } + + /// Parses prefix-forms of range notation: `..expr`, `..`, `..=expr`. + fn parse_prefix_range_expr( + &mut self, + already_parsed_attrs: Option> + ) -> PResult<'a, P> { + // Check for deprecated `...` syntax. + if self.token == token::DotDotDot { + self.err_dotdotdot_syntax(self.token.span); + } + + debug_assert!([token::DotDot, token::DotDotDot, token::DotDotEq].contains(&self.token.kind), + "parse_prefix_range_expr: token {:?} is not DotDot/DotDotEq", + self.token); + let tok = self.token.clone(); + let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; + let lo = self.token.span; + let mut hi = self.token.span; + self.bump(); + let opt_end = if self.is_at_start_of_range_notation_rhs() { + // RHS must be parsed with more associativity than the dots. + let next_prec = AssocOp::from_token(&tok).unwrap().precedence() + 1; + Some(self.parse_assoc_expr_with(next_prec, LhsExpr::NotYetParsed) + .map(|x| { + hi = x.span; + x + })?) + } else { + None + }; + let limits = if tok == token::DotDot { + RangeLimits::HalfOpen + } else { + RangeLimits::Closed + }; + + let r = self.mk_range(None, opt_end, limits)?; + Ok(self.mk_expr(lo.to(hi), r, attrs)) + } + + /// Parses a prefix-unary-operator expr. + fn parse_prefix_expr( + &mut self, + already_parsed_attrs: Option> + ) -> PResult<'a, P> { + let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; + let lo = self.token.span; + // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr() + let (hi, ex) = match self.token.kind { + token::Not => { + self.bump(); + let e = self.parse_prefix_expr(None); + let (span, e) = self.interpolated_or_expr_span(e)?; + (lo.to(span), self.mk_unary(UnOp::Not, e)) + } + // Suggest `!` for bitwise negation when encountering a `~` + token::Tilde => { + self.bump(); + let e = self.parse_prefix_expr(None); + let (span, e) = self.interpolated_or_expr_span(e)?; + let span_of_tilde = lo; + self.struct_span_err(span_of_tilde, "`~` cannot be used as a unary operator") + .span_suggestion_short( + span_of_tilde, + "use `!` to perform bitwise not", + "!".to_owned(), + Applicability::MachineApplicable + ) + .emit(); + (lo.to(span), self.mk_unary(UnOp::Not, e)) + } + token::BinOp(token::Minus) => { + self.bump(); + let e = self.parse_prefix_expr(None); + let (span, e) = self.interpolated_or_expr_span(e)?; + (lo.to(span), self.mk_unary(UnOp::Neg, e)) + } + token::BinOp(token::Star) => { + self.bump(); + let e = self.parse_prefix_expr(None); + let (span, e) = self.interpolated_or_expr_span(e)?; + (lo.to(span), self.mk_unary(UnOp::Deref, e)) + } + token::BinOp(token::And) | token::AndAnd => { + self.expect_and()?; + let m = self.parse_mutability(); + let e = self.parse_prefix_expr(None); + let (span, e) = self.interpolated_or_expr_span(e)?; + (lo.to(span), ExprKind::AddrOf(m, e)) + } + token::Ident(..) if self.token.is_keyword(kw::Box) => { + self.bump(); + let e = self.parse_prefix_expr(None); + let (span, e) = self.interpolated_or_expr_span(e)?; + let span = lo.to(span); + self.sess.gated_spans.gate(sym::box_syntax, span); + (span, ExprKind::Box(e)) + } + token::Ident(..) if self.token.is_ident_named(sym::not) => { + // `not` is just an ordinary identifier in Rust-the-language, + // but as `rustc`-the-compiler, we can issue clever diagnostics + // for confused users who really want to say `!` + let token_cannot_continue_expr = |t: &Token| match t.kind { + // These tokens can start an expression after `!`, but + // can't continue an expression after an ident + token::Ident(name, is_raw) => token::ident_can_begin_expr(name, t.span, is_raw), + token::Literal(..) | token::Pound => true, + _ => t.is_whole_expr(), + }; + let cannot_continue_expr = self.look_ahead(1, token_cannot_continue_expr); + if cannot_continue_expr { + self.bump(); + // Emit the error ... + self.struct_span_err( + self.token.span, + &format!("unexpected {} after identifier",self.this_token_descr()) + ) + .span_suggestion_short( + // Span the `not` plus trailing whitespace to avoid + // trailing whitespace after the `!` in our suggestion + self.sess.source_map() + .span_until_non_whitespace(lo.to(self.token.span)), + "use `!` to perform logical negation", + "!".to_owned(), + Applicability::MachineApplicable + ) + .emit(); + // —and recover! (just as if we were in the block + // for the `token::Not` arm) + let e = self.parse_prefix_expr(None); + let (span, e) = self.interpolated_or_expr_span(e)?; + (lo.to(span), self.mk_unary(UnOp::Not, e)) + } else { + return self.parse_dot_or_call_expr(Some(attrs)); + } + } + _ => { return self.parse_dot_or_call_expr(Some(attrs)); } + }; + return Ok(self.mk_expr(lo.to(hi), ex, attrs)); + } + + /// Returns the span of expr, if it was not interpolated or the span of the interpolated token. + fn interpolated_or_expr_span( + &self, + expr: PResult<'a, P>, + ) -> PResult<'a, (Span, P)> { + expr.map(|e| { + if self.prev_token_kind == PrevTokenKind::Interpolated { + (self.prev_span, e) + } else { + (e.span, e) + } + }) + } + + fn parse_assoc_op_cast(&mut self, lhs: P, lhs_span: Span, + expr_kind: fn(P, P) -> ExprKind) + -> PResult<'a, P> { + let mk_expr = |this: &mut Self, rhs: P| { + this.mk_expr(lhs_span.to(rhs.span), expr_kind(lhs, rhs), ThinVec::new()) + }; + + // Save the state of the parser before parsing type normally, in case there is a + // LessThan comparison after this cast. + let parser_snapshot_before_type = self.clone(); + match self.parse_ty_no_plus() { + Ok(rhs) => { + Ok(mk_expr(self, rhs)) + } + Err(mut type_err) => { + // Rewind to before attempting to parse the type with generics, to recover + // from situations like `x as usize < y` in which we first tried to parse + // `usize < y` as a type with generic arguments. + let parser_snapshot_after_type = self.clone(); + mem::replace(self, parser_snapshot_before_type); + + match self.parse_path(PathStyle::Expr) { + Ok(path) => { + let (op_noun, op_verb) = match self.token.kind { + token::Lt => ("comparison", "comparing"), + token::BinOp(token::Shl) => ("shift", "shifting"), + _ => { + // We can end up here even without `<` being the next token, for + // example because `parse_ty_no_plus` returns `Err` on keywords, + // but `parse_path` returns `Ok` on them due to error recovery. + // Return original error and parser state. + mem::replace(self, parser_snapshot_after_type); + return Err(type_err); + } + }; + + // Successfully parsed the type path leaving a `<` yet to parse. + type_err.cancel(); + + // Report non-fatal diagnostics, keep `x as usize` as an expression + // in AST and continue parsing. + let msg = format!( + "`<` is interpreted as a start of generic arguments for `{}`, not a {}", + pprust::path_to_string(&path), + op_noun, + ); + let span_after_type = parser_snapshot_after_type.token.span; + let expr = mk_expr(self, P(Ty { + span: path.span, + kind: TyKind::Path(None, path), + id: DUMMY_NODE_ID, + })); + + let expr_str = self.span_to_snippet(expr.span) + .unwrap_or_else(|_| pprust::expr_to_string(&expr)); + + self.struct_span_err(self.token.span, &msg) + .span_label( + self.look_ahead(1, |t| t.span).to(span_after_type), + "interpreted as generic arguments" + ) + .span_label(self.token.span, format!("not interpreted as {}", op_noun)) + .span_suggestion( + expr.span, + &format!("try {} the cast value", op_verb), + format!("({})", expr_str), + Applicability::MachineApplicable, + ) + .emit(); + + Ok(expr) + } + Err(mut path_err) => { + // Couldn't parse as a path, return original error and parser state. + path_err.cancel(); + mem::replace(self, parser_snapshot_after_type); + Err(type_err) + } + } + } + } + } + + /// Parses `a.b` or `a(13)` or `a[4]` or just `a`. + fn parse_dot_or_call_expr( + &mut self, + already_parsed_attrs: Option>, + ) -> PResult<'a, P> { + let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; + + let b = self.parse_bottom_expr(); + let (span, b) = self.interpolated_or_expr_span(b)?; + self.parse_dot_or_call_expr_with(b, span, attrs) + } + + pub(super) fn parse_dot_or_call_expr_with( + &mut self, + e0: P, + lo: Span, + mut attrs: ThinVec, + ) -> PResult<'a, P> { + // Stitch the list of outer attributes onto the return value. + // A little bit ugly, but the best way given the current code + // structure + self.parse_dot_or_call_expr_with_(e0, lo).map(|expr| + expr.map(|mut expr| { + attrs.extend::>(expr.attrs.into()); + expr.attrs = attrs; + match expr.kind { + ExprKind::If(..) if !expr.attrs.is_empty() => { + // Just point to the first attribute in there... + let span = expr.attrs[0].span; + self.span_err(span, "attributes are not yet allowed on `if` expressions"); + } + _ => {} + } + expr + }) + ) + } + + fn parse_dot_or_call_expr_with_(&mut self, e0: P, lo: Span) -> PResult<'a, P> { + let mut e = e0; + let mut hi; + loop { + // expr? + while self.eat(&token::Question) { + let hi = self.prev_span; + e = self.mk_expr(lo.to(hi), ExprKind::Try(e), ThinVec::new()); + } + + // expr.f + if self.eat(&token::Dot) { + match self.token.kind { + token::Ident(..) => { + e = self.parse_dot_suffix(e, lo)?; + } + token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => { + let span = self.token.span; + self.bump(); + let field = ExprKind::Field(e, Ident::new(symbol, span)); + e = self.mk_expr(lo.to(span), field, ThinVec::new()); + + self.expect_no_suffix(span, "a tuple index", suffix); + } + token::Literal(token::Lit { kind: token::Float, symbol, .. }) => { + self.bump(); + let fstr = symbol.as_str(); + let msg = format!("unexpected token: `{}`", symbol); + let mut err = self.diagnostic().struct_span_err(self.prev_span, &msg); + err.span_label(self.prev_span, "unexpected token"); + if fstr.chars().all(|x| "0123456789.".contains(x)) { + let float = match fstr.parse::().ok() { + Some(f) => f, + None => continue, + }; + let sugg = pprust::to_string(|s| { + s.popen(); + s.print_expr(&e); + s.s.word( "."); + s.print_usize(float.trunc() as usize); + s.pclose(); + s.s.word("."); + s.s.word(fstr.splitn(2, ".").last().unwrap().to_string()) + }); + err.span_suggestion( + lo.to(self.prev_span), + "try parenthesizing the first index", + sugg, + Applicability::MachineApplicable + ); + } + return Err(err); + + } + _ => { + // FIXME Could factor this out into non_fatal_unexpected or something. + let actual = self.this_token_to_string(); + self.span_err(self.token.span, &format!("unexpected token: `{}`", actual)); + } + } + continue; + } + if self.expr_is_complete(&e) { break; } + match self.token.kind { + // expr(...) + token::OpenDelim(token::Paren) => { + let seq = self.parse_paren_expr_seq().map(|es| { + let nd = self.mk_call(e, es); + let hi = self.prev_span; + self.mk_expr(lo.to(hi), nd, ThinVec::new()) + }); + e = self.recover_seq_parse_error(token::Paren, lo, seq); + } + + // expr[...] + // Could be either an index expression or a slicing expression. + token::OpenDelim(token::Bracket) => { + self.bump(); + let ix = self.parse_expr()?; + hi = self.token.span; + self.expect(&token::CloseDelim(token::Bracket))?; + let index = self.mk_index(e, ix); + e = self.mk_expr(lo.to(hi), index, ThinVec::new()) + } + _ => return Ok(e) + } + } + return Ok(e); + } + + /// Assuming we have just parsed `.`, continue parsing into an expression. + fn parse_dot_suffix(&mut self, self_arg: P, lo: Span) -> PResult<'a, P> { + if self.token.span.rust_2018() && self.eat_keyword(kw::Await) { + return self.mk_await_expr(self_arg, lo); + } + + let segment = self.parse_path_segment(PathStyle::Expr)?; + self.check_trailing_angle_brackets(&segment, token::OpenDelim(token::Paren)); + + Ok(match self.token.kind { + token::OpenDelim(token::Paren) => { + // Method call `expr.f()` + let mut args = self.parse_paren_expr_seq()?; + args.insert(0, self_arg); + + let span = lo.to(self.prev_span); + self.mk_expr(span, ExprKind::MethodCall(segment, args), ThinVec::new()) + } + _ => { + // Field access `expr.f` + if let Some(args) = segment.args { + self.span_err(args.span(), + "field expressions may not have generic arguments"); + } + + let span = lo.to(self.prev_span); + self.mk_expr(span, ExprKind::Field(self_arg, segment.ident), ThinVec::new()) + } + }) + } + + /// At the bottom (top?) of the precedence hierarchy, + /// Parses things like parenthesized exprs, macros, `return`, etc. + /// + /// N.B., this does not parse outer attributes, and is private because it only works + /// correctly if called from `parse_dot_or_call_expr()`. + fn parse_bottom_expr(&mut self) -> PResult<'a, P> { + maybe_recover_from_interpolated_ty_qpath!(self, true); + maybe_whole_expr!(self); + + // Outer attributes are already parsed and will be + // added to the return value after the fact. + // + // Therefore, prevent sub-parser from parsing + // attributes by giving them a empty "already-parsed" list. + let mut attrs = ThinVec::new(); + + let lo = self.token.span; + let mut hi = self.token.span; + + let ex: ExprKind; + + macro_rules! parse_lit { + () => { + match self.parse_lit() { + Ok(literal) => { + hi = self.prev_span; + ex = ExprKind::Lit(literal); + } + Err(mut err) => { + err.cancel(); + return Err(self.expected_expression_found()); + } + } + } + } + + // Note: when adding new syntax here, don't forget to adjust `TokenKind::can_begin_expr()`. + match self.token.kind { + // This match arm is a special-case of the `_` match arm below and + // could be removed without changing functionality, but it's faster + // to have it here, especially for programs with large constants. + token::Literal(_) => { + parse_lit!() + } + token::OpenDelim(token::Paren) => { + self.bump(); + + attrs.extend(self.parse_inner_attributes()?); + + // `(e)` is parenthesized `e`. + // `(e,)` is a tuple with only one field, `e`. + let mut es = vec![]; + let mut trailing_comma = false; + let mut recovered = false; + while self.token != token::CloseDelim(token::Paren) { + es.push(match self.parse_expr() { + Ok(es) => es, + Err(mut err) => { + // Recover from parse error in tuple list. + match self.token.kind { + token::Ident(name, false) + if name == kw::Underscore && self.look_ahead(1, |t| { + t == &token::Comma + }) => { + // Special-case handling of `Foo<(_, _, _)>` + err.emit(); + let sp = self.token.span; + self.bump(); + self.mk_expr(sp, ExprKind::Err, ThinVec::new()) + } + _ => return Ok( + self.recover_seq_parse_error(token::Paren, lo, Err(err)), + ), + } + } + }); + recovered = self.expect_one_of( + &[], + &[token::Comma, token::CloseDelim(token::Paren)], + )?; + if self.eat(&token::Comma) { + trailing_comma = true; + } else { + trailing_comma = false; + break; + } + } + if !recovered { + self.bump(); + } + + hi = self.prev_span; + ex = if es.len() == 1 && !trailing_comma { + ExprKind::Paren(es.into_iter().nth(0).unwrap()) + } else { + ExprKind::Tup(es) + }; + } + token::OpenDelim(token::Brace) => { + return self.parse_block_expr(None, lo, BlockCheckMode::Default, attrs); + } + token::BinOp(token::Or) | token::OrOr => { + return self.parse_closure_expr(attrs); + } + token::OpenDelim(token::Bracket) => { + self.bump(); + + attrs.extend(self.parse_inner_attributes()?); + + if self.eat(&token::CloseDelim(token::Bracket)) { + // Empty vector + ex = ExprKind::Array(Vec::new()); + } else { + // Non-empty vector + let first_expr = self.parse_expr()?; + if self.eat(&token::Semi) { + // Repeating array syntax: `[ 0; 512 ]` + let count = AnonConst { + id: DUMMY_NODE_ID, + value: self.parse_expr()?, + }; + self.expect(&token::CloseDelim(token::Bracket))?; + ex = ExprKind::Repeat(first_expr, count); + } else if self.eat(&token::Comma) { + // Vector with two or more elements + let remaining_exprs = self.parse_seq_to_end( + &token::CloseDelim(token::Bracket), + SeqSep::trailing_allowed(token::Comma), + |p| Ok(p.parse_expr()?) + )?; + let mut exprs = vec![first_expr]; + exprs.extend(remaining_exprs); + ex = ExprKind::Array(exprs); + } else { + // Vector with one element + self.expect(&token::CloseDelim(token::Bracket))?; + ex = ExprKind::Array(vec![first_expr]); + } + } + hi = self.prev_span; + } + _ => { + if self.eat_lt() { + let (qself, path) = self.parse_qpath(PathStyle::Expr)?; + hi = path.span; + return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs)); + } + if self.token.is_path_start() { + let path = self.parse_path(PathStyle::Expr)?; + + // `!`, as an operator, is prefix, so we know this isn't that. + if self.eat(&token::Not) { + // MACRO INVOCATION expression + let (delim, tts) = self.expect_delimited_token_tree()?; + hi = self.prev_span; + ex = ExprKind::Mac(Mac { + path, + tts, + delim, + span: lo.to(hi), + prior_type_ascription: self.last_type_ascription, + }); + } else if self.check(&token::OpenDelim(token::Brace)) { + if let Some(expr) = self.maybe_parse_struct_expr(lo, &path, &attrs) { + return expr; + } else { + hi = path.span; + ex = ExprKind::Path(None, path); + } + } else { + hi = path.span; + ex = ExprKind::Path(None, path); + } + + let expr = self.mk_expr(lo.to(hi), ex, attrs); + return self.maybe_recover_from_bad_qpath(expr, true); + } + if self.check_keyword(kw::Move) || self.check_keyword(kw::Static) { + return self.parse_closure_expr(attrs); + } + if self.eat_keyword(kw::If) { + return self.parse_if_expr(attrs); + } + if self.eat_keyword(kw::For) { + let lo = self.prev_span; + return self.parse_for_expr(None, lo, attrs); + } + if self.eat_keyword(kw::While) { + let lo = self.prev_span; + return self.parse_while_expr(None, lo, attrs); + } + if let Some(label) = self.eat_label() { + let lo = label.ident.span; + self.expect(&token::Colon)?; + if self.eat_keyword(kw::While) { + return self.parse_while_expr(Some(label), lo, attrs) + } + if self.eat_keyword(kw::For) { + return self.parse_for_expr(Some(label), lo, attrs) + } + if self.eat_keyword(kw::Loop) { + return self.parse_loop_expr(Some(label), lo, attrs) + } + if self.token == token::OpenDelim(token::Brace) { + return self.parse_block_expr(Some(label), + lo, + BlockCheckMode::Default, + attrs); + } + let msg = "expected `while`, `for`, `loop` or `{` after a label"; + let mut err = self.fatal(msg); + err.span_label(self.token.span, msg); + return Err(err); + } + if self.eat_keyword(kw::Loop) { + let lo = self.prev_span; + return self.parse_loop_expr(None, lo, attrs); + } + if self.eat_keyword(kw::Continue) { + let label = self.eat_label(); + let ex = ExprKind::Continue(label); + let hi = self.prev_span; + return Ok(self.mk_expr(lo.to(hi), ex, attrs)); + } + if self.eat_keyword(kw::Match) { + let match_sp = self.prev_span; + return self.parse_match_expr(attrs).map_err(|mut err| { + err.span_label(match_sp, "while parsing this match expression"); + err + }); + } + if self.eat_keyword(kw::Unsafe) { + return self.parse_block_expr( + None, + lo, + BlockCheckMode::Unsafe(ast::UserProvided), + attrs); + } + if self.is_do_catch_block() { + let mut db = self.fatal("found removed `do catch` syntax"); + db.help("following RFC #2388, the new non-placeholder syntax is `try`"); + return Err(db); + } + if self.is_try_block() { + let lo = self.token.span; + assert!(self.eat_keyword(kw::Try)); + return self.parse_try_block(lo, attrs); + } + + // `Span::rust_2018()` is somewhat expensive; don't get it repeatedly. + let is_span_rust_2018 = self.token.span.rust_2018(); + if is_span_rust_2018 && self.check_keyword(kw::Async) { + return if self.is_async_block() { // Check for `async {` and `async move {`. + self.parse_async_block(attrs) + } else { + self.parse_closure_expr(attrs) + }; + } + if self.eat_keyword(kw::Return) { + if self.token.can_begin_expr() { + let e = self.parse_expr()?; + hi = e.span; + ex = ExprKind::Ret(Some(e)); + } else { + ex = ExprKind::Ret(None); + } + } else if self.eat_keyword(kw::Break) { + let label = self.eat_label(); + let e = if self.token.can_begin_expr() + && !(self.token == token::OpenDelim(token::Brace) + && self.restrictions.contains( + Restrictions::NO_STRUCT_LITERAL)) { + Some(self.parse_expr()?) + } else { + None + }; + ex = ExprKind::Break(label, e); + hi = self.prev_span; + } else if self.eat_keyword(kw::Yield) { + if self.token.can_begin_expr() { + let e = self.parse_expr()?; + hi = e.span; + ex = ExprKind::Yield(Some(e)); + } else { + ex = ExprKind::Yield(None); + } + + let span = lo.to(hi); + self.sess.gated_spans.gate(sym::generators, span); + } else if self.eat_keyword(kw::Let) { + return self.parse_let_expr(attrs); + } else if is_span_rust_2018 && self.eat_keyword(kw::Await) { + let (await_hi, e_kind) = self.parse_incorrect_await_syntax(lo, self.prev_span)?; + hi = await_hi; + ex = e_kind; + } else { + if !self.unclosed_delims.is_empty() && self.check(&token::Semi) { + // Don't complain about bare semicolons after unclosed braces + // recovery in order to keep the error count down. Fixing the + // delimiters will possibly also fix the bare semicolon found in + // expression context. For example, silence the following error: + // + // error: expected expression, found `;` + // --> file.rs:2:13 + // | + // 2 | foo(bar(; + // | ^ expected expression + self.bump(); + return Ok(self.mk_expr(self.token.span, ExprKind::Err, ThinVec::new())); + } + parse_lit!() + } + } + } + + let expr = self.mk_expr(lo.to(hi), ex, attrs); + self.maybe_recover_from_bad_qpath(expr, true) + } + + /// Matches `lit = true | false | token_lit`. + pub(super) fn parse_lit(&mut self) -> PResult<'a, Lit> { + let mut recovered = None; + if self.token == token::Dot { + // Attempt to recover `.4` as `0.4`. + recovered = self.look_ahead(1, |next_token| { + if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) + = next_token.kind { + if self.token.span.hi() == next_token.span.lo() { + let s = String::from("0.") + &symbol.as_str(); + let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix); + return Some(Token::new(kind, self.token.span.to(next_token.span))); + } + } + None + }); + if let Some(token) = &recovered { + self.bump(); + self.struct_span_err(token.span, "float literals must have an integer part") + .span_suggestion( + token.span, + "must have an integer part", + pprust::token_to_string(token), + Applicability::MachineApplicable, + ) + .emit(); + } + } + + let token = recovered.as_ref().unwrap_or(&self.token); + match Lit::from_token(token) { + Ok(lit) => { + self.bump(); + Ok(lit) + } + Err(LitError::NotLiteral) => { + let msg = format!("unexpected token: {}", self.this_token_descr()); + Err(self.span_fatal(token.span, &msg)) + } + Err(err) => { + let span = token.span; + let lit = match token.kind { + token::Literal(lit) => lit, + _ => unreachable!(), + }; + self.bump(); + self.error_literal_from_token(err, lit, span); + // Pack possible quotes and prefixes from the original literal into + // the error literal's symbol so they can be pretty-printed faithfully. + let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None); + let symbol = Symbol::intern(&suffixless_lit.to_string()); + let lit = token::Lit::new(token::Err, symbol, lit.suffix); + Lit::from_lit_token(lit, span).map_err(|_| unreachable!()) + } + } + } + + fn error_literal_from_token(&self, err: LitError, lit: token::Lit, span: Span) { + // Checks if `s` looks like i32 or u1234 etc. + fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { + s.len() > 1 + && s.starts_with(first_chars) + && s[1..].chars().all(|c| c.is_ascii_digit()) + } + + let token::Lit { kind, suffix, .. } = lit; + match err { + // `NotLiteral` is not an error by itself, so we don't report + // it and give the parser opportunity to try something else. + LitError::NotLiteral => {} + // `LexerError` *is* an error, but it was already reported + // by lexer, so here we don't report it the second time. + LitError::LexerError => {} + LitError::InvalidSuffix => { + self.expect_no_suffix( + span, + &format!("{} {} literal", kind.article(), kind.descr()), + suffix, + ); + } + LitError::InvalidIntSuffix => { + let suf = suffix.expect("suffix error with no suffix").as_str(); + if looks_like_width_suffix(&['i', 'u'], &suf) { + // If it looks like a width, try to be helpful. + let msg = format!("invalid width `{}` for integer literal", &suf[1..]); + self.struct_span_err(span, &msg) + .help("valid widths are 8, 16, 32, 64 and 128") + .emit(); + } else { + let msg = format!("invalid suffix `{}` for integer literal", suf); + self.struct_span_err(span, &msg) + .span_label(span, format!("invalid suffix `{}`", suf)) + .help("the suffix must be one of the integral types (`u32`, `isize`, etc)") + .emit(); + } + } + LitError::InvalidFloatSuffix => { + let suf = suffix.expect("suffix error with no suffix").as_str(); + if looks_like_width_suffix(&['f'], &suf) { + // If it looks like a width, try to be helpful. + let msg = format!("invalid width `{}` for float literal", &suf[1..]); + self.struct_span_err(span, &msg) + .help("valid widths are 32 and 64") + .emit(); + } else { + let msg = format!("invalid suffix `{}` for float literal", suf); + self.struct_span_err(span, &msg) + .span_label(span, format!("invalid suffix `{}`", suf)) + .help("valid suffixes are `f32` and `f64`") + .emit(); + } + } + LitError::NonDecimalFloat(base) => { + let descr = match base { + 16 => "hexadecimal", + 8 => "octal", + 2 => "binary", + _ => unreachable!(), + }; + self.struct_span_err(span, &format!("{} float literal is not supported", descr)) + .span_label(span, "not supported") + .emit(); + } + LitError::IntTooLarge => { + self.struct_span_err(span, "integer literal is too large") + .emit(); + } + } + } + + pub(super) fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option) { + if let Some(suf) = suffix { + let mut err = if kind == "a tuple index" + && [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suf) + { + // #59553: warn instead of reject out of hand to allow the fix to percolate + // through the ecosystem when people fix their macros + let mut err = self.sess.span_diagnostic.struct_span_warn( + sp, + &format!("suffixes on {} are invalid", kind), + ); + err.note(&format!( + "`{}` is *temporarily* accepted on tuple index fields as it was \ + incorrectly accepted on stable for a few releases", + suf, + )); + err.help( + "on proc macros, you'll want to use `syn::Index::from` or \ + `proc_macro::Literal::*_unsuffixed` for code that will desugar \ + to tuple field access", + ); + err.note( + "for more context, see https://github.com/rust-lang/rust/issues/60210", + ); + err + } else { + self.struct_span_err(sp, &format!("suffixes on {} are invalid", kind)) + }; + err.span_label(sp, format!("invalid suffix `{}`", suf)); + err.emit(); + } + } + + /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`). + pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P> { + maybe_whole_expr!(self); + + let minus_lo = self.token.span; + let minus_present = self.eat(&token::BinOp(token::Minus)); + let lo = self.token.span; + let literal = self.parse_lit()?; + let hi = self.prev_span; + let expr = self.mk_expr(lo.to(hi), ExprKind::Lit(literal), ThinVec::new()); + + if minus_present { + let minus_hi = self.prev_span; + let unary = self.mk_unary(UnOp::Neg, expr); + Ok(self.mk_expr(minus_lo.to(minus_hi), unary, ThinVec::new())) + } else { + Ok(expr) + } + } + + /// Parses a block or unsafe block. + pub(super) fn parse_block_expr( + &mut self, + opt_label: Option