From 5410ac1155737da9625f0941b7947cca09683377 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 29 Oct 2022 11:37:28 -0400 Subject: [PATCH 01/12] Adjust stabilization version to 1.65.0 for wasi fds See https://github.com/rust-lang/rust/pull/103308#issuecomment-1292277645 for this ask. --- library/std/src/os/wasi/io/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/os/wasi/io/mod.rs b/library/std/src/os/wasi/io/mod.rs index 57bd842a50ce0..4e123a1eec8ae 100644 --- a/library/std/src/os/wasi/io/mod.rs +++ b/library/std/src/os/wasi/io/mod.rs @@ -1,6 +1,6 @@ //! WASI-specific extensions to general I/O primitives. -#![stable(feature = "io_safety", since = "1.63.0")] +#![stable(feature = "io_safety_wasi", since = "1.65.0")] -#[stable(feature = "io_safety", since = "1.63.0")] +#[stable(feature = "io_safety_wasi", since = "1.65.0")] pub use crate::os::fd::*; From 5ef85bbd7cd02df6389db6b3160ec7ef153091f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 8 Nov 2022 13:43:03 +0100 Subject: [PATCH 02/12] Visit attributes of trait impl items during AST validation --- compiler/rustc_ast_passes/src/ast_validation.rs | 3 ++- src/test/ui/on-unimplemented/issue-104140.rs | 8 ++++++++ src/test/ui/on-unimplemented/issue-104140.stderr | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/on-unimplemented/issue-104140.rs create mode 100644 src/test/ui/on-unimplemented/issue-104140.stderr diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 0366432440445..712fb5ac71f97 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1051,6 +1051,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl); }); + walk_list!(self, visit_attribute, &item.attrs); return; // Avoid visiting again. } ItemKind::Impl(box Impl { @@ -1168,7 +1169,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }); walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait); walk_list!(self, visit_attribute, &item.attrs); - return; + return; // Avoid visiting again } ItemKind::Mod(unsafety, ref mod_kind) => { if let Unsafe::Yes(span) = unsafety { diff --git a/src/test/ui/on-unimplemented/issue-104140.rs b/src/test/ui/on-unimplemented/issue-104140.rs new file mode 100644 index 0000000000000..ade3f727004ab --- /dev/null +++ b/src/test/ui/on-unimplemented/issue-104140.rs @@ -0,0 +1,8 @@ +#![feature(rustc_attrs)] + +trait Foo {} + +#[rustc_on_unimplemented] //~ ERROR malformed `rustc_on_unimplemented` attribute input +impl Foo for u32 {} + +fn main() {} diff --git a/src/test/ui/on-unimplemented/issue-104140.stderr b/src/test/ui/on-unimplemented/issue-104140.stderr new file mode 100644 index 0000000000000..ddb1f50f0bb45 --- /dev/null +++ b/src/test/ui/on-unimplemented/issue-104140.stderr @@ -0,0 +1,15 @@ +error: malformed `rustc_on_unimplemented` attribute input + --> $DIR/issue-104140.rs:5:1 + | +LL | #[rustc_on_unimplemented] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: the following are the possible correct uses + | +LL | #[rustc_on_unimplemented = "message"] + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")] + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +error: aborting due to previous error + From 033cf9880d00cb1632c152888a8a96e26021c047 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 10 Nov 2022 19:36:04 +0000 Subject: [PATCH 03/12] Support DoubleEndedIterator for subst_iter and subst_iter_copied --- compiler/rustc_middle/src/ty/subst.rs | 78 +++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 0660e9b79a700..ec7cb97116878 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -6,7 +6,6 @@ use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts}; use crate::ty::visit::{TypeVisitable, TypeVisitor}; use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt}; -use rustc_data_structures::captures::Captures; use rustc_data_structures::intern::{Interned, WithStableHash}; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; @@ -19,7 +18,7 @@ use std::fmt; use std::marker::PhantomData; use std::mem; use std::num::NonZeroUsize; -use std::ops::ControlFlow; +use std::ops::{ControlFlow, Deref}; use std::slice; /// An entity in the Rust type system, which can be one of @@ -559,25 +558,86 @@ impl EarlyBinder<(T, U)> { } } -impl<'tcx, 's, T: IntoIterator, I: TypeFoldable<'tcx>> EarlyBinder { +impl<'tcx, 's, I: IntoIterator> EarlyBinder +where + I::Item: TypeFoldable<'tcx>, +{ pub fn subst_iter( self, tcx: TyCtxt<'tcx>, substs: &'s [GenericArg<'tcx>], - ) -> impl Iterator + Captures<'s> + Captures<'tcx> { - self.0.into_iter().map(move |t| EarlyBinder(t).subst(tcx, substs)) + ) -> SubstIter<'s, 'tcx, I> { + SubstIter { it: self.0.into_iter(), tcx, substs } + } +} + +pub struct SubstIter<'s, 'tcx, I: IntoIterator> { + it: I::IntoIter, + tcx: TyCtxt<'tcx>, + substs: &'s [GenericArg<'tcx>], +} + +impl<'tcx, I: IntoIterator> Iterator for SubstIter<'_, 'tcx, I> +where + I::Item: TypeFoldable<'tcx>, +{ + type Item = I::Item; + + fn next(&mut self) -> Option { + Some(EarlyBinder(self.it.next()?).subst(self.tcx, self.substs)) + } +} + +impl<'tcx, I: IntoIterator> DoubleEndedIterator for SubstIter<'_, 'tcx, I> +where + I::IntoIter: DoubleEndedIterator, + I::Item: TypeFoldable<'tcx>, +{ + fn next_back(&mut self) -> Option { + Some(EarlyBinder(self.it.next_back()?).subst(self.tcx, self.substs)) } } -impl<'tcx, 's, 'a, T: IntoIterator, I: Copy + TypeFoldable<'tcx> + 'a> - EarlyBinder +impl<'tcx, 's, I: IntoIterator> EarlyBinder +where + I::Item: Deref, + ::Target: Copy + TypeFoldable<'tcx>, { pub fn subst_iter_copied( self, tcx: TyCtxt<'tcx>, substs: &'s [GenericArg<'tcx>], - ) -> impl Iterator + Captures<'s> + Captures<'tcx> + Captures<'a> { - self.0.into_iter().map(move |t| EarlyBinder(*t).subst(tcx, substs)) + ) -> SubstIterCopied<'s, 'tcx, I> { + SubstIterCopied { it: self.0.into_iter(), tcx, substs } + } +} + +pub struct SubstIterCopied<'a, 'tcx, I: IntoIterator> { + it: I::IntoIter, + tcx: TyCtxt<'tcx>, + substs: &'a [GenericArg<'tcx>], +} + +impl<'tcx, I: IntoIterator> Iterator for SubstIterCopied<'_, 'tcx, I> +where + I::Item: Deref, + ::Target: Copy + TypeFoldable<'tcx>, +{ + type Item = ::Target; + + fn next(&mut self) -> Option { + Some(EarlyBinder(*self.it.next()?).subst(self.tcx, self.substs)) + } +} + +impl<'tcx, I: IntoIterator> DoubleEndedIterator for SubstIterCopied<'_, 'tcx, I> +where + I::IntoIter: DoubleEndedIterator, + I::Item: Deref, + ::Target: Copy + TypeFoldable<'tcx>, +{ + fn next_back(&mut self) -> Option { + Some(EarlyBinder(*self.it.next_back()?).subst(self.tcx, self.substs)) } } From 9c8037c43070ab93bb66d1351901d717319e79c2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 10 Nov 2022 19:53:29 +0000 Subject: [PATCH 04/12] Deduce closure signature from TAIT supertraits --- compiler/rustc_hir_typeck/src/closure.rs | 43 +++++-------------- .../deduce-signature-from-supertrait.rs | 15 +++++++ 2 files changed, 25 insertions(+), 33 deletions(-) create mode 100644 src/test/ui/impl-trait/deduce-signature-from-supertrait.rs diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 3001e79947672..42a8102c8e0ed 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -173,34 +173,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty: Ty<'tcx>, ) -> (Option>, Option) { match *expected_ty.kind() { - ty::Opaque(def_id, substs) => { - let bounds = self.tcx.bound_explicit_item_bounds(def_id); - let sig = - bounds.subst_iter_copied(self.tcx, substs).find_map(|(pred, span)| match pred - .kind() - .skip_binder() - { - ty::PredicateKind::Projection(proj_predicate) => self - .deduce_sig_from_projection( - Some(span), - pred.kind().rebind(proj_predicate), - ), - _ => None, - }); - - let kind = bounds - .0 - .iter() - .filter_map(|(pred, _)| match pred.kind().skip_binder() { - ty::PredicateKind::Trait(tp) => { - self.tcx.fn_trait_kind_from_lang_item(tp.def_id()) - } - _ => None, - }) - .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur)))); - trace!(?sig, ?kind); - (sig, kind) - } + ty::Opaque(def_id, substs) => self.deduce_signature_from_predicates( + self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs), + ), ty::Dynamic(ref object_type, ..) => { let sig = object_type.projection_bounds().find_map(|pb| { let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self); @@ -211,7 +186,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .and_then(|did| self.tcx.fn_trait_kind_from_lang_item(did)); (sig, kind) } - ty::Infer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid), + ty::Infer(ty::TyVar(vid)) => self.deduce_signature_from_predicates( + self.obligations_for_self_ty(vid).map(|obl| (obl.predicate, obl.cause.span)), + ), ty::FnPtr(sig) => { let expected_sig = ExpectedSig { cause_span: None, sig }; (Some(expected_sig), Some(ty::ClosureKind::Fn)) @@ -220,19 +197,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn deduce_expectations_from_obligations( + fn deduce_signature_from_predicates( &self, - expected_vid: ty::TyVid, + predicates: impl DoubleEndedIterator, Span)>, ) -> (Option>, Option) { let mut expected_sig = None; let mut expected_kind = None; - for obligation in traits::elaborate_obligations( + for obligation in traits::elaborate_predicates_with_span( self.tcx, // Reverse the obligations here, since `elaborate_*` uses a stack, // and we want to keep inference generally in the same order of // the registered obligations. - self.obligations_for_self_ty(expected_vid).rev().collect(), + predicates.rev(), ) { debug!(?obligation.predicate); let bound_predicate = obligation.predicate.kind(); diff --git a/src/test/ui/impl-trait/deduce-signature-from-supertrait.rs b/src/test/ui/impl-trait/deduce-signature-from-supertrait.rs new file mode 100644 index 0000000000000..d2c3479203573 --- /dev/null +++ b/src/test/ui/impl-trait/deduce-signature-from-supertrait.rs @@ -0,0 +1,15 @@ +// check-pass + +#![feature(type_alias_impl_trait)] + +trait SuperExpectation: Fn(i32) {} + +impl SuperExpectation for T {} + +type Foo = impl SuperExpectation; + +fn main() { + let _: Foo = |x| { + let _ = x.to_string(); + }; +} From 3a05db66e2a7f5db2e292f683b36505a493190b9 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 2 Oct 2022 10:15:02 +0200 Subject: [PATCH 05/12] Simplify suggestions for errors in generators. --- .../src/traits/error_reporting/suggestions.rs | 93 +++++++++---------- 1 file changed, 42 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 540b1fa2b0fb7..8375d11d6be38 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -44,7 +44,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; #[derive(Debug)] pub enum GeneratorInteriorOrUpvar { // span of interior type - Interior(Span), + Interior(Span, Option<(Option, Span, Option, Option)>), // span of upvar Upvar(Span), } @@ -283,7 +283,6 @@ pub trait TypeErrCtxtExt<'tcx> { &self, err: &mut Diagnostic, interior_or_upvar_span: GeneratorInteriorOrUpvar, - interior_extra_info: Option<(Option, Span, Option, Option)>, is_async: bool, outer_generator: Option, trait_pred: ty::TraitPredicate<'tcx>, @@ -2003,17 +2002,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .as_local() .and_then(|def_id| hir.maybe_body_owned_by(def_id)) .map(|body_id| hir.body(body_id)); - let is_async = match generator_did.as_local() { - Some(_) => generator_body - .and_then(|body| body.generator_kind()) - .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..))) - .unwrap_or(false), - None => self - .tcx - .generator_kind(generator_did) - .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..))) - .unwrap_or(false), - }; + let is_async = self + .tcx + .generator_kind(generator_did) + .map(|generator_kind| matches!(generator_kind, hir::GeneratorKind::Async(..))) + .unwrap_or(false); let mut visitor = AwaitsVisitor::default(); if let Some(body) = generator_body { visitor.visit_body(body); @@ -2043,61 +2036,60 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { eq }; - let mut interior_or_upvar_span = None; - let mut interior_extra_info = None; - // Get the typeck results from the infcx if the generator is the function we are currently // type-checking; otherwise, get them by performing a query. This is needed to avoid // cycles. If we can't use resolved types because the generator comes from another crate, // we still provide a targeted error but without all the relevant spans. - let generator_data: Option> = match &self.typeck_results { - Some(t) if t.hir_owner.to_def_id() == generator_did_root => { - Some(GeneratorData::Local(&t)) - } + let generator_data = match &self.typeck_results { + Some(t) if t.hir_owner.to_def_id() == generator_did_root => GeneratorData::Local(&t), _ if generator_did.is_local() => { - Some(GeneratorData::Local(self.tcx.typeck(generator_did.expect_local()))) + GeneratorData::Local(self.tcx.typeck(generator_did.expect_local())) } - _ => self - .tcx - .generator_diagnostic_data(generator_did) - .as_ref() - .map(|generator_diag_data| GeneratorData::Foreign(generator_diag_data)), + _ if let Some(generator_diag_data) = self.tcx.generator_diagnostic_data(generator_did) => { + GeneratorData::Foreign(generator_diag_data) + } + _ => return false, }; - if let Some(generator_data) = generator_data.as_ref() { - interior_or_upvar_span = - generator_data.try_get_upvar_span(&self, generator_did, ty_matches); + let mut interior_or_upvar_span = None; - // The generator interior types share the same binders - if let Some(cause) = - generator_data.get_generator_interior_types().skip_binder().iter().find( - |ty::GeneratorInteriorTypeCause { ty, .. }| { - ty_matches(generator_data.get_generator_interior_types().rebind(*ty)) - }, - ) - { - let from_awaited_ty = generator_data.get_from_await_ty(visitor, hir, ty_matches); - let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = - cause; + let from_awaited_ty = generator_data.get_from_await_ty(visitor, hir, ty_matches); + debug!(?from_awaited_ty); - interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span)); - interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty)); - } + // The generator interior types share the same binders + if let Some(cause) = + generator_data.get_generator_interior_types().skip_binder().iter().find( + |ty::GeneratorInteriorTypeCause { ty, .. }| { + ty_matches(generator_data.get_generator_interior_types().rebind(*ty)) + }, + ) + { + let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = cause; - if interior_or_upvar_span.is_none() && generator_data.is_foreign() { - interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span)); - } + interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior( + *span, + Some((*scope_span, *yield_span, *expr, from_awaited_ty)), + )); } + if interior_or_upvar_span.is_none() { + interior_or_upvar_span = + generator_data.try_get_upvar_span(&self, generator_did, ty_matches); + } + + if interior_or_upvar_span.is_none() && generator_data.is_foreign() { + interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span, None)); + } + + debug!(?interior_or_upvar_span); if let Some(interior_or_upvar_span) = interior_or_upvar_span { - let typeck_results = generator_data.and_then(|generator_data| match generator_data { + let typeck_results = match generator_data { GeneratorData::Local(typeck_results) => Some(typeck_results), GeneratorData::Foreign(_) => None, - }); + }; self.note_obligation_cause_for_async_await( err, interior_or_upvar_span, - interior_extra_info, is_async, outer_generator, trait_ref, @@ -2119,7 +2111,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { &self, err: &mut Diagnostic, interior_or_upvar_span: GeneratorInteriorOrUpvar, - interior_extra_info: Option<(Option, Span, Option, Option)>, is_async: bool, outer_generator: Option, trait_pred: ty::TraitPredicate<'tcx>, @@ -2241,7 +2232,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } }; match interior_or_upvar_span { - GeneratorInteriorOrUpvar::Interior(interior_span) => { + GeneratorInteriorOrUpvar::Interior(interior_span, interior_extra_info) => { if let Some((scope_span, yield_span, expr, from_awaited_ty)) = interior_extra_info { if let Some(await_span) = from_awaited_ty { // The type causing this obligation is one being awaited at await_span. From b5b64678108f6c5460d9dcf8a415b3b8dc4d1a52 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 12 Nov 2022 23:37:52 +0000 Subject: [PATCH 06/12] Add rustc_deny_explicit_impl --- .../src/error_codes/E0322.md | 3 +- compiler/rustc_feature/src/builtin_attrs.rs | 4 ++ .../rustc_hir_analysis/src/coherence/mod.rs | 66 +++++-------------- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/marker.rs | 5 ++ library/core/src/ptr/metadata.rs | 1 + 6 files changed, 29 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0322.md b/compiler/rustc_error_codes/src/error_codes/E0322.md index ccef8681dd601..194bbd83b0f74 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0322.md +++ b/compiler/rustc_error_codes/src/error_codes/E0322.md @@ -1,4 +1,5 @@ -The `Sized` trait was implemented explicitly. +A built-in trait was implemented explicitly. All implementations of the trait +are provided automatically by the compiler. Erroneous code example: diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index dc3a74956843e..db40c15a7cd3d 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -691,6 +691,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: true, "#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl." ), + rustc_attr!( + rustc_deny_explicit_impl, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: false, + "#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls" + ), rustc_attr!( rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word), ErrorFollowing, "#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \ diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index ae9ebe5909144..1bf3768fead36 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -5,10 +5,11 @@ // done by the orphan and overlap modules. Then we build up various // mappings. That mapping code resides here. -use rustc_errors::struct_span_err; +use rustc_errors::{error_code, struct_span_err}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; +use rustc_span::sym; use rustc_trait_selection::traits; mod builtin; @@ -39,61 +40,26 @@ fn enforce_trait_manually_implementable( impl_def_id: LocalDefId, trait_def_id: DefId, ) { - let did = Some(trait_def_id); - let li = tcx.lang_items(); let impl_header_span = tcx.def_span(impl_def_id); - // Disallow *all* explicit impls of `Pointee`, `DiscriminantKind`, `Sized` and `Unsize` for now. - if did == li.pointee_trait() { - struct_span_err!( + // Disallow *all* explicit impls of traits marked `#[rustc_deny_explicit_impl]` + if tcx.has_attr(trait_def_id, sym::rustc_deny_explicit_impl) { + let trait_name = tcx.item_name(trait_def_id); + let mut err = struct_span_err!( tcx.sess, impl_header_span, E0322, - "explicit impls for the `Pointee` trait are not permitted" - ) - .span_label(impl_header_span, "impl of `Pointee` not allowed") - .emit(); - return; - } - - if did == li.discriminant_kind_trait() { - struct_span_err!( - tcx.sess, - impl_header_span, - E0322, - "explicit impls for the `DiscriminantKind` trait are not permitted" - ) - .span_label(impl_header_span, "impl of `DiscriminantKind` not allowed") - .emit(); - return; - } - - if did == li.sized_trait() { - struct_span_err!( - tcx.sess, - impl_header_span, - E0322, - "explicit impls for the `Sized` trait are not permitted" - ) - .span_label(impl_header_span, "impl of `Sized` not allowed") - .emit(); - return; - } - - if did == li.unsize_trait() { - struct_span_err!( - tcx.sess, - impl_header_span, - E0328, - "explicit impls for the `Unsize` trait are not permitted" - ) - .span_label(impl_header_span, "impl of `Unsize` not allowed") - .emit(); - return; - } + "explicit impls for the `{trait_name}` trait are not permitted" + ); + err.span_label(impl_header_span, format!("impl of `{trait_name}` not allowed")); + + // Maintain explicit error code for `Unsize`, since it has a useful + // explanation about using `CoerceUnsized` instead. + if Some(trait_def_id) == tcx.lang_items().unsize_trait() { + err.code(error_code!(E0328)); + } - if tcx.features().unboxed_closures { - // the feature gate allows all Fn traits + err.emit(); return; } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 54a61483a11a3..908257c92535f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1251,6 +1251,7 @@ symbols! { rustc_deallocator, rustc_def_path, rustc_default_body_unstable, + rustc_deny_explicit_impl, rustc_diagnostic_item, rustc_diagnostic_macros, rustc_dirty, diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index ae4ebf4444295..3eff6033f8da9 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -96,6 +96,7 @@ unsafe impl Send for &T {} )] #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable #[rustc_specialization_trait] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] pub trait Sized { // Empty. } @@ -127,6 +128,7 @@ pub trait Sized { /// [nomicon-coerce]: ../../nomicon/coercions.html #[unstable(feature = "unsize", issue = "27732")] #[lang = "unsize"] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] pub trait Unsize { // Empty. } @@ -693,6 +695,7 @@ impl StructuralEq for PhantomData {} reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead" )] #[lang = "discriminant_kind"] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] pub trait DiscriminantKind { /// The type of the discriminant, which must satisfy the trait /// bounds required by `mem::Discriminant`. @@ -793,6 +796,7 @@ impl Unpin for *mut T {} #[lang = "destruct"] #[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)] #[const_trait] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] pub trait Destruct {} /// A marker for tuple types. @@ -802,6 +806,7 @@ pub trait Destruct {} #[unstable(feature = "tuple_trait", issue = "none")] #[lang = "tuple_trait"] #[rustc_on_unimplemented(message = "`{Self}` is not a tuple")] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] pub trait Tuple {} /// Implementations of `Copy` for primitive types. diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index caa10f1818b4d..a8604843e9631 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -50,6 +50,7 @@ use crate::hash::{Hash, Hasher}; /// /// [`to_raw_parts`]: *const::to_raw_parts #[lang = "pointee_trait"] +#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)] pub trait Pointee { /// The type for metadata in pointers and references to `Self`. #[lang = "metadata_type"] From 53852ee4eb1fed3a616cd2f99ac77fc3d5bd296b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 10 Nov 2022 12:17:31 +0000 Subject: [PATCH 07/12] Move most of unwind's build script to lib.rs Only the android libunwind detection remains in the build script * Reduces dependence on build scripts for building the standard library * Reduces dependence on exact target names in favor of using semantic cfg(target_*) usage. * Keeps almost all code related to linking of the unwinder in one file --- library/unwind/build.rs | 24 ------------------------ library/unwind/src/lib.rs | 24 ++++++++++++++++++++++++ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/library/unwind/build.rs b/library/unwind/build.rs index 31af390253b6f..5c3c02fb6adac 100644 --- a/library/unwind/build.rs +++ b/library/unwind/build.rs @@ -21,29 +21,5 @@ fn main() { if has_unwind { println!("cargo:rustc-cfg=feature=\"system-llvm-libunwind\""); } - } else if target.contains("freebsd") { - println!("cargo:rustc-link-lib=gcc_s"); - } else if target.contains("netbsd") { - println!("cargo:rustc-link-lib=gcc_s"); - } else if target.contains("openbsd") { - if target.contains("sparc64") { - println!("cargo:rustc-link-lib=gcc"); - } else { - println!("cargo:rustc-link-lib=c++abi"); - } - } else if target.contains("solaris") { - println!("cargo:rustc-link-lib=gcc_s"); - } else if target.contains("illumos") { - println!("cargo:rustc-link-lib=gcc_s"); - } else if target.contains("dragonfly") { - println!("cargo:rustc-link-lib=gcc_pic"); - } else if target.ends_with("pc-windows-gnu") { - // This is handled in the target spec with late_link_args_[static|dynamic] - } else if target.contains("uwp-windows-gnu") { - println!("cargo:rustc-link-lib=unwind"); - } else if target.contains("haiku") { - println!("cargo:rustc-link-lib=gcc_s"); - } else if target.contains("redox") { - // redox is handled in lib.rs } } diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 2efd2d5dd4aa4..3753071d5f0c1 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -103,3 +103,27 @@ extern "C" {} #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] #[link(name = "unwind", kind = "static", modifiers = "-bundle")] extern "C" {} + +#[cfg(any(target_os = "freebsd", target_os = "netbsd"))] +#[link(name = "gcc_s")] +extern "C" {} + +#[cfg(all(target_os = "openbsd", target_arch = "sparc64"))] +#[link(name = "gcc")] +extern "C" {} + +#[cfg(all(target_os = "openbsd", not(target_arch = "sparc64")))] +#[link(name = "c++abi")] +extern "C" {} + +#[cfg(any(target_os = "solaris", target_os = "illumos"))] +#[link(name = "gcc_s")] +extern "C" {} + +#[cfg(target_os = "dragonfly")] +#[link(name = "gcc_pic")] +extern "C" {} + +#[cfg(target_os = "haiku")] +#[link(name = "gcc_s")] +extern "C" {} From 7e7c11cf560527c4a7c70da63455cc23f4c51235 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sat, 12 Nov 2022 23:18:32 +0100 Subject: [PATCH 08/12] Show a note where a macro failed to match This shows a small note on what the macro matcher was currently processing to aid with "no rules expected the token X" errors. --- compiler/rustc_expand/src/mbe/macro_parser.rs | 48 ++++++++++++++++- compiler/rustc_expand/src/mbe/macro_rules.rs | 39 ++++++++++---- .../vec-macro-with-comma-only.stderr | 2 + .../min_const_generics/macro-fail.stderr | 6 +++ .../edition-keywords-2015-2015-parsing.stderr | 12 +++++ .../edition-keywords-2015-2018-parsing.stderr | 12 +++++ .../edition-keywords-2018-2015-parsing.stderr | 12 +++++ .../edition-keywords-2018-2018-parsing.stderr | 12 +++++ src/test/ui/empty/empty-comment.stderr | 6 +++ src/test/ui/fail-simple.stderr | 2 + src/test/ui/issues/issue-7970a.stderr | 6 +++ ...rt-trailing-junk.with-generic-asset.stderr | 4 ++ ...trailing-junk.without-generic-asset.stderr | 4 ++ .../macros/macro-at-most-once-rep-2015.stderr | 54 +++++++++++++++++++ .../macros/macro-at-most-once-rep-2018.stderr | 54 +++++++++++++++++++ src/test/ui/macros/macro-non-lifetime.stderr | 6 +++ src/test/ui/macros/missing-comma.stderr | 36 +++++++++++++ .../ui/macros/nonterminal-matching.stderr | 8 +++ src/test/ui/macros/trace_faulty_macros.stderr | 1 + .../or-patterns-syntactic-fail-2018.stderr | 12 +++++ .../parser/macro/macro-doc-comments-1.stderr | 6 +++ .../parser/macro/macro-doc-comments-2.stderr | 6 +++ .../rfc-2294-if-let-guard/feature-gate.stderr | 6 +++ .../feature-gate.stderr | 6 +++ src/test/ui/underscore-ident-matcher.stderr | 6 +++ 25 files changed, 355 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 95cec8d7ae299..d161868edce77 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -76,6 +76,7 @@ pub(crate) use ParseResult::*; use crate::mbe::{macro_rules::Tracker, KleeneOp, TokenTree}; use rustc_ast::token::{self, DocComment, Nonterminal, NonterminalKind, Token}; +use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorGuaranteed; @@ -86,6 +87,7 @@ use rustc_span::symbol::MacroRulesNormalizedIdent; use rustc_span::Span; use std::borrow::Cow; use std::collections::hash_map::Entry::{Occupied, Vacant}; +use std::fmt::Display; /// A unit within a matcher that a `MatcherPos` can refer to. Similar to (and derived from) /// `mbe::TokenTree`, but designed specifically for fast and easy traversal during matching. @@ -96,7 +98,7 @@ use std::collections::hash_map::Entry::{Occupied, Vacant}; /// /// This means a matcher can be represented by `&[MatcherLoc]`, and traversal mostly involves /// simply incrementing the current matcher position index by one. -#[derive(Debug)] +#[derive(Debug, PartialEq, Clone)] pub(crate) enum MatcherLoc { Token { token: Token, @@ -129,6 +131,46 @@ pub(crate) enum MatcherLoc { Eof, } +impl MatcherLoc { + pub(super) fn span(&self) -> Option { + match self { + MatcherLoc::Token { token } => Some(token.span), + MatcherLoc::Delimited => None, + MatcherLoc::Sequence { .. } => None, + MatcherLoc::SequenceKleeneOpNoSep { .. } => None, + MatcherLoc::SequenceSep { .. } => None, + MatcherLoc::SequenceKleeneOpAfterSep { .. } => None, + MatcherLoc::MetaVarDecl { span, .. } => Some(*span), + MatcherLoc::Eof => None, + } + } +} + +impl Display for MatcherLoc { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + MatcherLoc::Token { token } | MatcherLoc::SequenceSep { separator: token } => { + write!(f, "`{}`", pprust::token_to_string(token)) + } + MatcherLoc::MetaVarDecl { bind, kind, .. } => { + write!(f, "meta-variable `${bind}")?; + if let Some(kind) = kind { + write!(f, ":{}", kind)?; + } + write!(f, "`")?; + Ok(()) + } + MatcherLoc::Eof => f.write_str("end of macro"), + + // These are not printed in the diagnostic + MatcherLoc::Delimited => f.write_str("delimiter"), + MatcherLoc::Sequence { .. } => f.write_str("sequence start"), + MatcherLoc::SequenceKleeneOpNoSep { .. } => f.write_str("sequence end"), + MatcherLoc::SequenceKleeneOpAfterSep { .. } => f.write_str("sequence end"), + } + } +} + pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec { fn inner( tts: &[TokenTree], @@ -398,6 +440,10 @@ impl TtParser { } } + pub(super) fn has_no_remaining_items_for_step(&self) -> bool { + self.cur_mps.is_empty() + } + /// Process the matcher positions of `cur_mps` until it is empty. In the process, this will /// produce more mps in `next_mps` and `bb_mps`. /// diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 99af91072882e..80c2db030fc57 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -337,7 +337,7 @@ fn expand_macro<'cx>( return result; } - let Some((token, label)) = tracker.best_failure else { + let Some((token, label, remaining_matcher)) = tracker.best_failure else { return tracker.result.expect("must have encountered Error or ErrorReported"); }; @@ -351,6 +351,12 @@ fn expand_macro<'cx>( annotate_doc_comment(&mut err, sess.source_map(), span); + if let Some(span) = remaining_matcher.span() { + err.span_note(span, format!("while trying to match {remaining_matcher}")); + } else { + err.note(format!("while trying to match {remaining_matcher}")); + } + // Check whether there's a missing comma in this macro call, like `println!("{}" a);` if let Some((arg, comma_span)) = arg.add_comma() { for lhs in lhses { @@ -379,17 +385,22 @@ fn expand_macro<'cx>( } /// The tracker used for the slow error path that collects useful info for diagnostics. -struct CollectTrackerAndEmitter<'a, 'cx> { +struct CollectTrackerAndEmitter<'a, 'cx, 'matcher> { cx: &'a mut ExtCtxt<'cx>, + remaining_matcher: Option<&'matcher MatcherLoc>, /// Which arm's failure should we report? (the one furthest along) - best_failure: Option<(Token, &'static str)>, + best_failure: Option<(Token, &'static str, MatcherLoc)>, root_span: Span, result: Option>, } -impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx> { - fn before_match_loc(&mut self, _parser: &TtParser, _matcher: &'matcher MatcherLoc) { - // Empty for now. +impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, 'matcher> { + fn before_match_loc(&mut self, parser: &TtParser, matcher: &'matcher MatcherLoc) { + if self.remaining_matcher.is_none() + || (parser.has_no_remaining_items_for_step() && *matcher != MatcherLoc::Eof) + { + self.remaining_matcher = Some(matcher); + } } fn after_arm(&mut self, result: &NamedParseResult) { @@ -398,8 +409,16 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx> unreachable!("should not collect detailed info for successful macro match"); } Failure(token, msg) => match self.best_failure { - Some((ref best_token, _)) if best_token.span.lo() >= token.span.lo() => {} - _ => self.best_failure = Some((token.clone(), msg)), + Some((ref best_token, _, _)) if best_token.span.lo() >= token.span.lo() => {} + _ => { + self.best_failure = Some(( + token.clone(), + msg, + self.remaining_matcher + .expect("must have collected matcher already") + .clone(), + )) + } }, Error(err_sp, msg) => { let span = err_sp.substitute_dummy(self.root_span); @@ -415,9 +434,9 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx> } } -impl<'a, 'cx> CollectTrackerAndEmitter<'a, 'cx> { +impl<'a, 'cx> CollectTrackerAndEmitter<'a, 'cx, '_> { fn new(cx: &'a mut ExtCtxt<'cx>, root_span: Span) -> Self { - Self { cx, best_failure: None, root_span, result: None } + Self { cx, remaining_matcher: None, best_failure: None, root_span, result: None } } } diff --git a/src/test/ui/array-slice-vec/vec-macro-with-comma-only.stderr b/src/test/ui/array-slice-vec/vec-macro-with-comma-only.stderr index abbee347c00bc..ec4a001f4d01a 100644 --- a/src/test/ui/array-slice-vec/vec-macro-with-comma-only.stderr +++ b/src/test/ui/array-slice-vec/vec-macro-with-comma-only.stderr @@ -3,6 +3,8 @@ error: no rules expected the token `,` | LL | vec![,]; | ^ no rules expected this token in macro call + | + = note: while trying to match end of macro error: aborting due to previous error diff --git a/src/test/ui/const-generics/min_const_generics/macro-fail.stderr b/src/test/ui/const-generics/min_const_generics/macro-fail.stderr index 2b75c19774842..9f73b91aabebf 100644 --- a/src/test/ui/const-generics/min_const_generics/macro-fail.stderr +++ b/src/test/ui/const-generics/min_const_generics/macro-fail.stderr @@ -53,6 +53,12 @@ LL | macro_rules! gimme_a_const { ... LL | let _fail = Example::; | ^^^^^^^^^^^^^^^^ missing tokens in macro arguments + | +note: while trying to match meta-variable `$rusty:ident` + --> $DIR/macro-fail.rs:28:8 + | +LL | ($rusty: ident) => {{ let $rusty = 3; *&$rusty }} + | ^^^^^^^^^^^^^ error[E0747]: type provided when a constant was expected --> $DIR/macro-fail.rs:14:33 diff --git a/src/test/ui/editions/edition-keywords-2015-2015-parsing.stderr b/src/test/ui/editions/edition-keywords-2015-2015-parsing.stderr index 3435fdfd72570..39944622d07b9 100644 --- a/src/test/ui/editions/edition-keywords-2015-2015-parsing.stderr +++ b/src/test/ui/editions/edition-keywords-2015-2015-parsing.stderr @@ -3,12 +3,24 @@ error: no rules expected the token `r#async` | LL | r#async = consumes_async!(r#async); | ^^^^^^^ no rules expected this token in macro call + | +note: while trying to match `async` + --> $DIR/auxiliary/edition-kw-macro-2015.rs:17:6 + | +LL | (async) => (1) + | ^^^^^ error: no rules expected the token `async` --> $DIR/edition-keywords-2015-2015-parsing.rs:17:35 | LL | r#async = consumes_async_raw!(async); | ^^^^^ no rules expected this token in macro call + | +note: while trying to match `r#async` + --> $DIR/auxiliary/edition-kw-macro-2015.rs:22:6 + | +LL | (r#async) => (1) + | ^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/editions/edition-keywords-2015-2018-parsing.stderr b/src/test/ui/editions/edition-keywords-2015-2018-parsing.stderr index 6e86d746f5442..fa83908e6666e 100644 --- a/src/test/ui/editions/edition-keywords-2015-2018-parsing.stderr +++ b/src/test/ui/editions/edition-keywords-2015-2018-parsing.stderr @@ -3,12 +3,24 @@ error: no rules expected the token `r#async` | LL | r#async = consumes_async!(r#async); | ^^^^^^^ no rules expected this token in macro call + | +note: while trying to match `async` + --> $DIR/auxiliary/edition-kw-macro-2018.rs:17:6 + | +LL | (async) => (1) + | ^^^^^ error: no rules expected the token `async` --> $DIR/edition-keywords-2015-2018-parsing.rs:17:35 | LL | r#async = consumes_async_raw!(async); | ^^^^^ no rules expected this token in macro call + | +note: while trying to match `r#async` + --> $DIR/auxiliary/edition-kw-macro-2018.rs:22:6 + | +LL | (r#async) => (1) + | ^^^^^^^ error: aborting due to 2 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 e1eea725bb0b0..1a4a94e973327 100644 --- a/src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr +++ b/src/test/ui/editions/edition-keywords-2018-2015-parsing.stderr @@ -25,12 +25,24 @@ error: no rules expected the token `r#async` | LL | r#async = consumes_async!(r#async); | ^^^^^^^ no rules expected this token in macro call + | +note: while trying to match `async` + --> $DIR/auxiliary/edition-kw-macro-2015.rs:17:6 + | +LL | (async) => (1) + | ^^^^^ error: no rules expected the token `async` --> $DIR/edition-keywords-2018-2015-parsing.rs:21:35 | LL | r#async = consumes_async_raw!(async); | ^^^^^ no rules expected this token in macro call + | +note: while trying to match `r#async` + --> $DIR/auxiliary/edition-kw-macro-2015.rs:22:6 + | +LL | (r#async) => (1) + | ^^^^^^^ error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` --> $DIR/auxiliary/edition-kw-macro-2015.rs:27:23 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 0af4da09c19e3..19eb7ac98239e 100644 --- a/src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr +++ b/src/test/ui/editions/edition-keywords-2018-2018-parsing.stderr @@ -25,12 +25,24 @@ error: no rules expected the token `r#async` | LL | r#async = consumes_async!(r#async); | ^^^^^^^ no rules expected this token in macro call + | +note: while trying to match `async` + --> $DIR/auxiliary/edition-kw-macro-2018.rs:17:6 + | +LL | (async) => (1) + | ^^^^^ error: no rules expected the token `async` --> $DIR/edition-keywords-2018-2018-parsing.rs:21:35 | LL | r#async = consumes_async_raw!(async); | ^^^^^ no rules expected this token in macro call + | +note: while trying to match `r#async` + --> $DIR/auxiliary/edition-kw-macro-2018.rs:22:6 + | +LL | (r#async) => (1) + | ^^^^^^^ error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||` --> $DIR/auxiliary/edition-kw-macro-2018.rs:27:23 diff --git a/src/test/ui/empty/empty-comment.stderr b/src/test/ui/empty/empty-comment.stderr index f583dbbdc64f8..7cc8d8fe9229a 100644 --- a/src/test/ui/empty/empty-comment.stderr +++ b/src/test/ui/empty/empty-comment.stderr @@ -6,6 +6,12 @@ LL | macro_rules! one_arg_macro { ... LL | one_arg_macro!(/**/); | ^^^^^^^^^^^^^^^^^^^^ missing tokens in macro arguments + | +note: while trying to match meta-variable `$fmt:expr` + --> $DIR/empty-comment.rs:6:6 + | +LL | ($fmt:expr) => (print!(concat!($fmt, "\n"))); + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/fail-simple.stderr b/src/test/ui/fail-simple.stderr index 26ed918e94d91..af8f54291ff47 100644 --- a/src/test/ui/fail-simple.stderr +++ b/src/test/ui/fail-simple.stderr @@ -3,6 +3,8 @@ error: no rules expected the token `@` | LL | panic!(@); | ^ no rules expected this token in macro call + | + = note: while trying to match end of macro error: aborting due to previous error diff --git a/src/test/ui/issues/issue-7970a.stderr b/src/test/ui/issues/issue-7970a.stderr index ea400d7e1917e..b04a0eef37139 100644 --- a/src/test/ui/issues/issue-7970a.stderr +++ b/src/test/ui/issues/issue-7970a.stderr @@ -6,6 +6,12 @@ LL | macro_rules! one_arg_macro { ... LL | one_arg_macro!(); | ^^^^^^^^^^^^^^^^ missing tokens in macro arguments + | +note: while trying to match meta-variable `$fmt:expr` + --> $DIR/issue-7970a.rs:2:6 + | +LL | ($fmt:expr) => (print!(concat!($fmt, "\n"))); + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/macros/assert-trailing-junk.with-generic-asset.stderr b/src/test/ui/macros/assert-trailing-junk.with-generic-asset.stderr index 09dd16a0b0d89..1e73320e43912 100644 --- a/src/test/ui/macros/assert-trailing-junk.with-generic-asset.stderr +++ b/src/test/ui/macros/assert-trailing-junk.with-generic-asset.stderr @@ -17,6 +17,8 @@ LL | assert!(true, "whatever" blah); | -^^^^ no rules expected this token in macro call | | | help: missing comma here + | + = note: while trying to match sequence start error: unexpected string literal --> $DIR/assert-trailing-junk.rs:18:18 @@ -33,6 +35,8 @@ LL | assert!(true "whatever" blah); | -^^^^ no rules expected this token in macro call | | | help: missing comma here + | + = note: while trying to match sequence start error: macro requires an expression as an argument --> $DIR/assert-trailing-junk.rs:22:5 diff --git a/src/test/ui/macros/assert-trailing-junk.without-generic-asset.stderr b/src/test/ui/macros/assert-trailing-junk.without-generic-asset.stderr index 09dd16a0b0d89..1e73320e43912 100644 --- a/src/test/ui/macros/assert-trailing-junk.without-generic-asset.stderr +++ b/src/test/ui/macros/assert-trailing-junk.without-generic-asset.stderr @@ -17,6 +17,8 @@ LL | assert!(true, "whatever" blah); | -^^^^ no rules expected this token in macro call | | | help: missing comma here + | + = note: while trying to match sequence start error: unexpected string literal --> $DIR/assert-trailing-junk.rs:18:18 @@ -33,6 +35,8 @@ LL | assert!(true "whatever" blah); | -^^^^ no rules expected this token in macro call | | | help: missing comma here + | + = note: while trying to match sequence start error: macro requires an expression as an argument --> $DIR/assert-trailing-junk.rs:22:5 diff --git a/src/test/ui/macros/macro-at-most-once-rep-2015.stderr b/src/test/ui/macros/macro-at-most-once-rep-2015.stderr index 9a3df858e515f..7c45b85bc8d4e 100644 --- a/src/test/ui/macros/macro-at-most-once-rep-2015.stderr +++ b/src/test/ui/macros/macro-at-most-once-rep-2015.stderr @@ -12,6 +12,8 @@ LL | macro_rules! foo { ... LL | foo!(a?); | ^ no rules expected this token in macro call + | + = note: while trying to match sequence end error: no rules expected the token `?` --> $DIR/macro-at-most-once-rep-2015.rs:26:11 @@ -21,6 +23,8 @@ LL | macro_rules! foo { ... LL | foo!(a?a); | ^ no rules expected this token in macro call + | + = note: while trying to match sequence end error: no rules expected the token `?` --> $DIR/macro-at-most-once-rep-2015.rs:27:11 @@ -30,6 +34,8 @@ LL | macro_rules! foo { ... LL | foo!(a?a?a); | ^ no rules expected this token in macro call + | + = note: while trying to match sequence end error: unexpected end of macro invocation --> $DIR/macro-at-most-once-rep-2015.rs:29:5 @@ -39,6 +45,12 @@ LL | macro_rules! barplus { ... LL | barplus!(); | ^^^^^^^^^^ missing tokens in macro arguments + | +note: while trying to match `+` + --> $DIR/macro-at-most-once-rep-2015.rs:15:11 + | +LL | ($(a)?+) => {}; // ok. matches "a+" and "+" + | ^ error: unexpected end of macro invocation --> $DIR/macro-at-most-once-rep-2015.rs:30:15 @@ -48,6 +60,12 @@ LL | macro_rules! barplus { ... LL | barplus!(a); | ^ missing tokens in macro arguments + | +note: while trying to match `+` + --> $DIR/macro-at-most-once-rep-2015.rs:15:11 + | +LL | ($(a)?+) => {}; // ok. matches "a+" and "+" + | ^ error: no rules expected the token `?` --> $DIR/macro-at-most-once-rep-2015.rs:31:15 @@ -57,6 +75,12 @@ LL | macro_rules! barplus { ... LL | barplus!(a?); | ^ no rules expected this token in macro call + | +note: while trying to match `+` + --> $DIR/macro-at-most-once-rep-2015.rs:15:11 + | +LL | ($(a)?+) => {}; // ok. matches "a+" and "+" + | ^ error: no rules expected the token `?` --> $DIR/macro-at-most-once-rep-2015.rs:32:15 @@ -66,6 +90,12 @@ LL | macro_rules! barplus { ... LL | barplus!(a?a); | ^ no rules expected this token in macro call + | +note: while trying to match `+` + --> $DIR/macro-at-most-once-rep-2015.rs:15:11 + | +LL | ($(a)?+) => {}; // ok. matches "a+" and "+" + | ^ error: unexpected end of macro invocation --> $DIR/macro-at-most-once-rep-2015.rs:36:5 @@ -75,6 +105,12 @@ LL | macro_rules! barstar { ... LL | barstar!(); | ^^^^^^^^^^ missing tokens in macro arguments + | +note: while trying to match `*` + --> $DIR/macro-at-most-once-rep-2015.rs:19:11 + | +LL | ($(a)?*) => {}; // ok. matches "a*" and "*" + | ^ error: unexpected end of macro invocation --> $DIR/macro-at-most-once-rep-2015.rs:37:15 @@ -84,6 +120,12 @@ LL | macro_rules! barstar { ... LL | barstar!(a); | ^ missing tokens in macro arguments + | +note: while trying to match `*` + --> $DIR/macro-at-most-once-rep-2015.rs:19:11 + | +LL | ($(a)?*) => {}; // ok. matches "a*" and "*" + | ^ error: no rules expected the token `?` --> $DIR/macro-at-most-once-rep-2015.rs:38:15 @@ -93,6 +135,12 @@ LL | macro_rules! barstar { ... LL | barstar!(a?); | ^ no rules expected this token in macro call + | +note: while trying to match `*` + --> $DIR/macro-at-most-once-rep-2015.rs:19:11 + | +LL | ($(a)?*) => {}; // ok. matches "a*" and "*" + | ^ error: no rules expected the token `?` --> $DIR/macro-at-most-once-rep-2015.rs:39:15 @@ -102,6 +150,12 @@ LL | macro_rules! barstar { ... LL | barstar!(a?a); | ^ no rules expected this token in macro call + | +note: while trying to match `*` + --> $DIR/macro-at-most-once-rep-2015.rs:19:11 + | +LL | ($(a)?*) => {}; // ok. matches "a*" and "*" + | ^ error: aborting due to 12 previous errors diff --git a/src/test/ui/macros/macro-at-most-once-rep-2018.stderr b/src/test/ui/macros/macro-at-most-once-rep-2018.stderr index 013fabe13e5f6..696520b28268a 100644 --- a/src/test/ui/macros/macro-at-most-once-rep-2018.stderr +++ b/src/test/ui/macros/macro-at-most-once-rep-2018.stderr @@ -12,6 +12,8 @@ LL | macro_rules! foo { ... LL | foo!(a?); | ^ no rules expected this token in macro call + | + = note: while trying to match sequence end error: no rules expected the token `?` --> $DIR/macro-at-most-once-rep-2018.rs:26:11 @@ -21,6 +23,8 @@ LL | macro_rules! foo { ... LL | foo!(a?a); | ^ no rules expected this token in macro call + | + = note: while trying to match sequence end error: no rules expected the token `?` --> $DIR/macro-at-most-once-rep-2018.rs:27:11 @@ -30,6 +34,8 @@ LL | macro_rules! foo { ... LL | foo!(a?a?a); | ^ no rules expected this token in macro call + | + = note: while trying to match sequence end error: unexpected end of macro invocation --> $DIR/macro-at-most-once-rep-2018.rs:29:5 @@ -39,6 +45,12 @@ LL | macro_rules! barplus { ... LL | barplus!(); | ^^^^^^^^^^ missing tokens in macro arguments + | +note: while trying to match `+` + --> $DIR/macro-at-most-once-rep-2018.rs:15:11 + | +LL | ($(a)?+) => {}; // ok. matches "a+" and "+" + | ^ error: unexpected end of macro invocation --> $DIR/macro-at-most-once-rep-2018.rs:30:15 @@ -48,6 +60,12 @@ LL | macro_rules! barplus { ... LL | barplus!(a); | ^ missing tokens in macro arguments + | +note: while trying to match `+` + --> $DIR/macro-at-most-once-rep-2018.rs:15:11 + | +LL | ($(a)?+) => {}; // ok. matches "a+" and "+" + | ^ error: no rules expected the token `?` --> $DIR/macro-at-most-once-rep-2018.rs:31:15 @@ -57,6 +75,12 @@ LL | macro_rules! barplus { ... LL | barplus!(a?); | ^ no rules expected this token in macro call + | +note: while trying to match `+` + --> $DIR/macro-at-most-once-rep-2018.rs:15:11 + | +LL | ($(a)?+) => {}; // ok. matches "a+" and "+" + | ^ error: no rules expected the token `?` --> $DIR/macro-at-most-once-rep-2018.rs:32:15 @@ -66,6 +90,12 @@ LL | macro_rules! barplus { ... LL | barplus!(a?a); | ^ no rules expected this token in macro call + | +note: while trying to match `+` + --> $DIR/macro-at-most-once-rep-2018.rs:15:11 + | +LL | ($(a)?+) => {}; // ok. matches "a+" and "+" + | ^ error: unexpected end of macro invocation --> $DIR/macro-at-most-once-rep-2018.rs:36:5 @@ -75,6 +105,12 @@ LL | macro_rules! barstar { ... LL | barstar!(); | ^^^^^^^^^^ missing tokens in macro arguments + | +note: while trying to match `*` + --> $DIR/macro-at-most-once-rep-2018.rs:19:11 + | +LL | ($(a)?*) => {}; // ok. matches "a*" and "*" + | ^ error: unexpected end of macro invocation --> $DIR/macro-at-most-once-rep-2018.rs:37:15 @@ -84,6 +120,12 @@ LL | macro_rules! barstar { ... LL | barstar!(a); | ^ missing tokens in macro arguments + | +note: while trying to match `*` + --> $DIR/macro-at-most-once-rep-2018.rs:19:11 + | +LL | ($(a)?*) => {}; // ok. matches "a*" and "*" + | ^ error: no rules expected the token `?` --> $DIR/macro-at-most-once-rep-2018.rs:38:15 @@ -93,6 +135,12 @@ LL | macro_rules! barstar { ... LL | barstar!(a?); | ^ no rules expected this token in macro call + | +note: while trying to match `*` + --> $DIR/macro-at-most-once-rep-2018.rs:19:11 + | +LL | ($(a)?*) => {}; // ok. matches "a*" and "*" + | ^ error: no rules expected the token `?` --> $DIR/macro-at-most-once-rep-2018.rs:39:15 @@ -102,6 +150,12 @@ LL | macro_rules! barstar { ... LL | barstar!(a?a); | ^ no rules expected this token in macro call + | +note: while trying to match `*` + --> $DIR/macro-at-most-once-rep-2018.rs:19:11 + | +LL | ($(a)?*) => {}; // ok. matches "a*" and "*" + | ^ error: aborting due to 12 previous errors diff --git a/src/test/ui/macros/macro-non-lifetime.stderr b/src/test/ui/macros/macro-non-lifetime.stderr index 6234735dfc8a4..e1ed87f943551 100644 --- a/src/test/ui/macros/macro-non-lifetime.stderr +++ b/src/test/ui/macros/macro-non-lifetime.stderr @@ -6,6 +6,12 @@ LL | macro_rules! m { ($x:lifetime) => { } } ... LL | m!(a); | ^ no rules expected this token in macro call + | +note: while trying to match meta-variable `$x:lifetime` + --> $DIR/macro-non-lifetime.rs:3:19 + | +LL | macro_rules! m { ($x:lifetime) => { } } + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/macros/missing-comma.stderr b/src/test/ui/macros/missing-comma.stderr index 6da92bdea19e0..81877a29ed8ae 100644 --- a/src/test/ui/macros/missing-comma.stderr +++ b/src/test/ui/macros/missing-comma.stderr @@ -14,6 +14,12 @@ LL | foo!(a b); | -^ no rules expected this token in macro call | | | help: missing comma here + | +note: while trying to match meta-variable `$a:ident` + --> $DIR/missing-comma.rs:2:6 + | +LL | ($a:ident) => (); + | ^^^^^^^^ error: no rules expected the token `e` --> $DIR/missing-comma.rs:23:21 @@ -25,6 +31,12 @@ LL | foo!(a, b, c, d e); | -^ no rules expected this token in macro call | | | help: missing comma here + | +note: while trying to match meta-variable `$d:ident` + --> $DIR/missing-comma.rs:5:36 + | +LL | ($a:ident, $b:ident, $c:ident, $d:ident) => (); + | ^^^^^^^^ error: no rules expected the token `d` --> $DIR/missing-comma.rs:25:18 @@ -36,6 +48,12 @@ LL | foo!(a, b, c d, e); | -^ no rules expected this token in macro call | | | help: missing comma here + | +note: while trying to match meta-variable `$c:ident` + --> $DIR/missing-comma.rs:4:26 + | +LL | ($a:ident, $b:ident, $c:ident) => (); + | ^^^^^^^^ error: no rules expected the token `d` --> $DIR/missing-comma.rs:27:18 @@ -45,6 +63,12 @@ LL | macro_rules! foo { ... LL | foo!(a, b, c d e); | ^ no rules expected this token in macro call + | +note: while trying to match meta-variable `$c:ident` + --> $DIR/missing-comma.rs:4:26 + | +LL | ($a:ident, $b:ident, $c:ident) => (); + | ^^^^^^^^ error: unexpected end of macro invocation --> $DIR/missing-comma.rs:29:23 @@ -54,6 +78,12 @@ LL | macro_rules! bar { ... LL | bar!(Level::Error, ); | ^ missing tokens in macro arguments + | +note: while trying to match meta-variable `$arg:tt` + --> $DIR/missing-comma.rs:10:19 + | +LL | ($lvl:expr, $($arg:tt)+) => {} + | ^^^^^^^ error: no rules expected the token `,` --> $DIR/missing-comma.rs:32:38 @@ -63,6 +93,12 @@ LL | macro_rules! check { ... LL | check!(::fmt, "fmt",); | ^ no rules expected this token in macro call + | +note: while trying to match meta-variable `$expected:expr` + --> $DIR/missing-comma.rs:14:14 + | +LL | ($ty:ty, $expected:expr) => {}; + | ^^^^^^^^^^^^^^ error: aborting due to 7 previous errors diff --git a/src/test/ui/macros/nonterminal-matching.stderr b/src/test/ui/macros/nonterminal-matching.stderr index 585f2355321f5..5bbd543909833 100644 --- a/src/test/ui/macros/nonterminal-matching.stderr +++ b/src/test/ui/macros/nonterminal-matching.stderr @@ -10,6 +10,14 @@ LL | n!(a $nt_item b); LL | complex_nonterminal!(enum E {}); | ------------------------------- in this macro invocation | +note: while trying to match `enum E {}` + --> $DIR/nonterminal-matching.rs:15:15 + | +LL | macro n(a $nt_item b) { + | ^^^^^^^^ +... +LL | complex_nonterminal!(enum E {}); + | ------------------------------- in this macro invocation = note: this error originates in the macro `complex_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/macros/trace_faulty_macros.stderr b/src/test/ui/macros/trace_faulty_macros.stderr index d6fc694021448..21e47da075716 100644 --- a/src/test/ui/macros/trace_faulty_macros.stderr +++ b/src/test/ui/macros/trace_faulty_macros.stderr @@ -10,6 +10,7 @@ LL | my_faulty_macro!(bcd); LL | my_faulty_macro!(); | ------------------ in this macro invocation | + = note: while trying to match end of macro = note: this error originates in the macro `my_faulty_macro` (in Nightly builds, run with -Z macro-backtrace for more info) note: trace_macro diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr index 001c68a977473..acc2099bbc6a8 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail-2018.stderr @@ -6,6 +6,12 @@ LL | macro_rules! accept_pat { ... LL | accept_pat!(p | q); | ^ no rules expected this token in macro call + | +note: while trying to match meta-variable `$p:pat` + --> $DIR/or-patterns-syntactic-fail-2018.rs:9:6 + | +LL | ($p:pat) => {}; + | ^^^^^^ error: no rules expected the token `|` --> $DIR/or-patterns-syntactic-fail-2018.rs:13:13 @@ -15,6 +21,12 @@ LL | macro_rules! accept_pat { ... LL | accept_pat!(|p| q); | ^ no rules expected this token in macro call + | +note: while trying to match meta-variable `$p:pat` + --> $DIR/or-patterns-syntactic-fail-2018.rs:9:6 + | +LL | ($p:pat) => {}; + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/macro/macro-doc-comments-1.stderr b/src/test/ui/parser/macro/macro-doc-comments-1.stderr index 0ebf3d52b6372..eaeb62d2cfd98 100644 --- a/src/test/ui/parser/macro/macro-doc-comments-1.stderr +++ b/src/test/ui/parser/macro/macro-doc-comments-1.stderr @@ -9,6 +9,12 @@ LL | //! Inner | | | no rules expected this token in macro call | inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match + | +note: while trying to match `[` + --> $DIR/macro-doc-comments-1.rs:2:7 + | +LL | (#[$outer:meta]) => () + | ^ error: aborting due to previous error 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 346d865868d99..1dcd95f6fad4f 100644 --- a/src/test/ui/parser/macro/macro-doc-comments-2.stderr +++ b/src/test/ui/parser/macro/macro-doc-comments-2.stderr @@ -9,6 +9,12 @@ LL | /// Outer | | | no rules expected this token in macro call | outer doc comments expand to `#[doc = "..."]`, which is what this macro attempted to match + | +note: while trying to match `!` + --> $DIR/macro-doc-comments-2.rs:2:7 + | +LL | (#![$inner:meta]) => () + | ^ error: aborting due to previous error diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr index e017d04a5c933..96fe11911b7a0 100644 --- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr +++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr @@ -72,6 +72,12 @@ LL | macro_rules! use_expr { ... LL | use_expr!(let 0 = 1); | ^^^ no rules expected this token in macro call + | +note: while trying to match meta-variable `$e:expr` + --> $DIR/feature-gate.rs:61:10 + | +LL | ($e:expr) => { + | ^^^^^^^ error[E0658]: `if let` guards are experimental --> $DIR/feature-gate.rs:7:12 diff --git a/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr index feea1c254d8da..7a43b71fc8b89 100644 --- a/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr @@ -18,6 +18,12 @@ LL | macro_rules! use_expr { ... LL | use_expr!(let 0 = 1); | ^^^ no rules expected this token in macro call + | +note: while trying to match meta-variable `$e:expr` + --> $DIR/feature-gate.rs:50:10 + | +LL | ($e:expr) => { + | ^^^^^^^ error[E0658]: `let` expressions in this position are unstable --> $DIR/feature-gate.rs:14:16 diff --git a/src/test/ui/underscore-ident-matcher.stderr b/src/test/ui/underscore-ident-matcher.stderr index 241c3d3d8ce61..b0e4d88f67186 100644 --- a/src/test/ui/underscore-ident-matcher.stderr +++ b/src/test/ui/underscore-ident-matcher.stderr @@ -6,6 +6,12 @@ LL | macro_rules! identity { ... LL | let identity!(_) = 10; | ^ no rules expected this token in macro call + | +note: while trying to match meta-variable `$i:ident` + --> $DIR/underscore-ident-matcher.rs:2:6 + | +LL | ($i: ident) => ( + | ^^^^^^^^^ error: aborting due to previous error From 9db8e183dc17896ce5f307f6de19c261d746a9bc Mon Sep 17 00:00:00 2001 From: yukang Date: Sat, 12 Nov 2022 04:22:47 +0800 Subject: [PATCH 09/12] fix #104088, Slightly improve error message for invalid identifier --- .../locales/en-US/parser.ftl | 3 ++ compiler/rustc_parse/src/errors.rs | 8 +++++ compiler/rustc_parse/src/parser/stmt.rs | 17 +++++++++-- src/test/ui/parser/issues/issue-104088.rs | 26 +++++++++++++++++ src/test/ui/parser/issues/issue-104088.stderr | 29 +++++++++++++++++++ 5 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/parser/issues/issue-104088.rs create mode 100644 src/test/ui/parser/issues/issue-104088.stderr diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl index 815e8f4d3567e..4c7ce30097c95 100644 --- a/compiler/rustc_error_messages/locales/en-US/parser.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl @@ -384,3 +384,6 @@ parser_fn_ptr_with_generics = function pointer types may not have generic parame [true] the *[false] a } `for` parameter list + +parser_invalid_identifier_with_leading_number = expected identifier, found number literal + .label = identifiers cannot start with a number diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index a39398950a533..2b17cea97949a 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1205,6 +1205,14 @@ pub(crate) struct SelfParamNotFirst { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parser_invalid_identifier_with_leading_number)] +pub(crate) struct InvalidIdentiferStartsWithNumber { + #[primary_span] + #[label] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(parser_const_generic_without_braces)] pub(crate) struct ConstGenericWithoutBraces { diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 9684145ad9948..c2c3ff64ec701 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -10,8 +10,8 @@ use super::{ use crate::errors::{ AssignmentElseNotAllowed, CompoundAssignmentExpressionInLet, ConstLetMutuallyExclusive, DocCommentDoesNotDocumentAnything, ExpectedStatementAfterOuterAttr, InvalidCurlyInLetElse, - InvalidExpressionInLetElse, InvalidVariableDeclaration, InvalidVariableDeclarationSub, - WrapExpressionInParentheses, + InvalidExpressionInLetElse, InvalidIdentiferStartsWithNumber, InvalidVariableDeclaration, + InvalidVariableDeclarationSub, WrapExpressionInParentheses, }; use crate::maybe_whole; @@ -264,6 +264,7 @@ impl<'a> Parser<'a> { self.bump(); } + self.report_invalid_identifier_error()?; let (pat, colon) = self.parse_pat_before_ty(None, RecoverComma::Yes, "`let` bindings")?; let (err, ty) = if colon { @@ -355,6 +356,18 @@ impl<'a> Parser<'a> { Ok(P(ast::Local { ty, pat, kind, id: DUMMY_NODE_ID, span: lo.to(hi), attrs, tokens: None })) } + /// report error for `let 1x = 123` + pub fn report_invalid_identifier_error(&mut self) -> PResult<'a, ()> { + if let token::Literal(lit) = self.token.uninterpolate().kind && + let Err(_) = rustc_ast::Lit::from_token(&self.token) && + (lit.kind == token::LitKind::Integer || lit.kind == token::LitKind::Float) && + self.look_ahead(1, |t| matches!(t.kind, token::Eq) || matches!(t.kind, token::Colon ) ) { + let err = self.sess.create_err(InvalidIdentiferStartsWithNumber { span: self.token.span }); + return Err(err); + } + Ok(()) + } + fn check_let_else_init_bool_expr(&self, init: &ast::Expr) { if let ast::ExprKind::Binary(op, ..) = init.kind { if op.node.lazy() { diff --git a/src/test/ui/parser/issues/issue-104088.rs b/src/test/ui/parser/issues/issue-104088.rs new file mode 100644 index 0000000000000..5f794fe2dc924 --- /dev/null +++ b/src/test/ui/parser/issues/issue-104088.rs @@ -0,0 +1,26 @@ +fn test() { + if let 123 = 123 { println!("yes"); } +} + +fn test_2() { + let 1x = 123; + //~^ ERROR expected identifier, found number literal +} + +fn test_3() { + let 2x: i32 = 123; + //~^ ERROR expected identifier, found number literal +} + +fn test_4() { + if let 2e1 = 123 { + //~^ ERROR mismatched types + } +} + +fn test_5() { + let 23name = 123; + //~^ ERROR expected identifier, found number literal +} + +fn main() {} diff --git a/src/test/ui/parser/issues/issue-104088.stderr b/src/test/ui/parser/issues/issue-104088.stderr new file mode 100644 index 0000000000000..ff4b4bdb6953e --- /dev/null +++ b/src/test/ui/parser/issues/issue-104088.stderr @@ -0,0 +1,29 @@ +error: expected identifier, found number literal + --> $DIR/issue-104088.rs:6:9 + | +LL | let 1x = 123; + | ^^ identifiers cannot start with a number + +error: expected identifier, found number literal + --> $DIR/issue-104088.rs:11:9 + | +LL | let 2x: i32 = 123; + | ^^ identifiers cannot start with a number + +error: expected identifier, found number literal + --> $DIR/issue-104088.rs:22:9 + | +LL | let 23name = 123; + | ^^^^^^ identifiers cannot start with a number + +error[E0308]: mismatched types + --> $DIR/issue-104088.rs:16:12 + | +LL | if let 2e1 = 123 { + | ^^^ --- this expression has type `{integer}` + | | + | expected integer, found floating-point number + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. From ff18c73065d25f20b393af52f4edecce04f6bd44 Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 14 Nov 2022 22:13:49 +0800 Subject: [PATCH 10/12] comment feedback --- compiler/rustc_parse/src/parser/stmt.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index c2c3ff64ec701..18b661034e070 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -362,8 +362,7 @@ impl<'a> Parser<'a> { let Err(_) = rustc_ast::Lit::from_token(&self.token) && (lit.kind == token::LitKind::Integer || lit.kind == token::LitKind::Float) && self.look_ahead(1, |t| matches!(t.kind, token::Eq) || matches!(t.kind, token::Colon ) ) { - let err = self.sess.create_err(InvalidIdentiferStartsWithNumber { span: self.token.span }); - return Err(err); + return Err(self.sess.create_err(InvalidIdentiferStartsWithNumber { span: self.token.span })); } Ok(()) } From b2b509491d55072d31935c4c3f267d3d46f61f03 Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 15 Nov 2022 09:00:27 +0800 Subject: [PATCH 11/12] move testcase for tidy --- src/test/ui/{ => parser}/slowparse-bstring.rs | 0 src/test/ui/{ => parser}/slowparse-string.rs | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{ => parser}/slowparse-bstring.rs (100%) rename src/test/ui/{ => parser}/slowparse-string.rs (100%) diff --git a/src/test/ui/slowparse-bstring.rs b/src/test/ui/parser/slowparse-bstring.rs similarity index 100% rename from src/test/ui/slowparse-bstring.rs rename to src/test/ui/parser/slowparse-bstring.rs diff --git a/src/test/ui/slowparse-string.rs b/src/test/ui/parser/slowparse-string.rs similarity index 100% rename from src/test/ui/slowparse-string.rs rename to src/test/ui/parser/slowparse-string.rs From d8bd153ba54ce2ad2d7f1a431f471504690e33b1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 15 Nov 2022 03:44:45 +0000 Subject: [PATCH 12/12] Normalize types before looking for opaques --- compiler/rustc_lint/src/types.rs | 39 ++++++++---------- .../lint/opaque-ty-ffi-normalization-cycle.rs | 41 +++++++++++++++++++ .../opaque-ty-ffi-normalization-cycle.stderr | 15 +++++++ 3 files changed, 73 insertions(+), 22 deletions(-) create mode 100644 src/test/ui/lint/opaque-ty-ffi-normalization-cycle.rs create mode 100644 src/test/ui/lint/opaque-ty-ffi-normalization-cycle.stderr diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 37caab2da0f5b..22e5be3762df5 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1195,35 +1195,30 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { - struct ProhibitOpaqueTypes<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - } - - impl<'a, 'tcx> ty::visit::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { + struct ProhibitOpaqueTypes; + impl<'tcx> ty::visit::TypeVisitor<'tcx> for ProhibitOpaqueTypes { type BreakTy = Ty<'tcx>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - match ty.kind() { - ty::Opaque(..) => ControlFlow::Break(ty), - // Consider opaque types within projections FFI-safe if they do not normalize - // to more opaque types. - ty::Projection(..) => { - let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty); - - // If `ty` is an opaque type directly then `super_visit_with` won't invoke - // this function again. - if ty.has_opaque_types() { - self.visit_ty(ty) - } else { - ControlFlow::CONTINUE - } - } - _ => ty.super_visit_with(self), + if !ty.has_opaque_types() { + return ControlFlow::CONTINUE; + } + + if let ty::Opaque(..) = ty.kind() { + ControlFlow::Break(ty) + } else { + ty.super_visit_with(self) } } } - if let Some(ty) = ty.visit_with(&mut ProhibitOpaqueTypes { cx: self.cx }).break_value() { + if let Some(ty) = self + .cx + .tcx + .normalize_erasing_regions(self.cx.param_env, ty) + .visit_with(&mut ProhibitOpaqueTypes) + .break_value() + { self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint_improper_ctypes_opaque, None); true } else { diff --git a/src/test/ui/lint/opaque-ty-ffi-normalization-cycle.rs b/src/test/ui/lint/opaque-ty-ffi-normalization-cycle.rs new file mode 100644 index 0000000000000..c83bca4a4c570 --- /dev/null +++ b/src/test/ui/lint/opaque-ty-ffi-normalization-cycle.rs @@ -0,0 +1,41 @@ +#![feature(type_alias_impl_trait)] +#![allow(unused)] +#![deny(improper_ctypes)] + +pub trait TraitA { + type Assoc; +} + +impl TraitA for u32 { + type Assoc = u32; +} + +pub trait TraitB { + type Assoc; +} + +impl TraitB for T +where + T: TraitA, +{ + type Assoc = ::Assoc; +} + +type AliasA = impl TraitA; + +type AliasB = impl TraitB; + +fn use_of_a() -> AliasA { + 3 +} + +fn use_of_b() -> AliasB { + 3 +} + +extern "C" { + fn lint_me() -> ::Assoc; + //~^ ERROR `extern` block uses type `AliasB`, which is not FFI-safe +} + +fn main() {} diff --git a/src/test/ui/lint/opaque-ty-ffi-normalization-cycle.stderr b/src/test/ui/lint/opaque-ty-ffi-normalization-cycle.stderr new file mode 100644 index 0000000000000..e8d696477ada1 --- /dev/null +++ b/src/test/ui/lint/opaque-ty-ffi-normalization-cycle.stderr @@ -0,0 +1,15 @@ +error: `extern` block uses type `AliasB`, which is not FFI-safe + --> $DIR/opaque-ty-ffi-normalization-cycle.rs:37:21 + | +LL | fn lint_me() -> ::Assoc; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = note: opaque types have no C equivalent +note: the lint level is defined here + --> $DIR/opaque-ty-ffi-normalization-cycle.rs:3:9 + | +LL | #![deny(improper_ctypes)] + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error +