diff --git a/Cargo.lock b/Cargo.lock index d4c1a02c018af..bfc075a77e382 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4451,6 +4451,7 @@ dependencies = [ "thin-vec", "tracing", "unicode-normalization", + "unicode-properties", "unicode-width 0.2.2", ] diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index f8968639f98c2..099a75e11f3af 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -1,10 +1,12 @@ use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit}; +use rustc_errors::msg; use rustc_feature::template; use rustc_hir::Target; use rustc_hir::attrs::{ AttributeKind, CfgEntry, CfgHideShow, CfgInfo, DocAttribute, DocInline, HideOrShow, }; use rustc_hir::lints::AttributeLintKind; +use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, edition, sym}; use thin_vec::ThinVec; @@ -481,15 +483,19 @@ impl DocParser { } macro_rules! no_args_and_crate_level { ($ident: ident) => {{ + no_args_and_crate_level!($ident, |span| {}); + }}; + ($ident: ident, |$span:ident| $extra_validation:block) => {{ if let Err(span) = args.no_args() { expected_no_args(cx, span); return; } - let span = path.span(); - if !check_attr_crate_level(cx, span) { + let $span = path.span(); + if !check_attr_crate_level(cx, $span) { return; } - self.attribute.$ident = Some(span); + $extra_validation + self.attribute.$ident = Some($span); }}; } macro_rules! string_arg_and_crate_level { @@ -553,7 +559,17 @@ impl DocParser { ), Some(sym::fake_variadic) => no_args_and_not_crate_level!(fake_variadic), Some(sym::search_unbox) => no_args_and_not_crate_level!(search_unbox), - Some(sym::rust_logo) => no_args_and_crate_level!(rust_logo), + Some(sym::rust_logo) => no_args_and_crate_level!(rust_logo, |span| { + if !cx.features().rustdoc_internals() { + feature_err( + cx.sess(), + sym::rustdoc_internals, + span, + msg!("the `#[doc(rust_logo)]` attribute is used for Rust branding"), + ) + .emit(); + } + }), Some(sym::auto_cfg) => self.parse_auto_cfg(cx, path, args), Some(sym::test) => { let Some(list) = args.list() else { diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 557b00b911aa9..3269fc5c9c1d5 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -199,6 +199,14 @@ fn exported_non_generic_symbols_provider_local<'tcx>( })) } + symbols.extend(sorted.iter().flat_map(|&(&def_id, &info)| { + tcx.codegen_fn_attrs(def_id).foreign_item_symbol_aliases.iter().map( + move |&(foreign_item, _linkage, _visibility)| { + (ExportedSymbol::NonGeneric(foreign_item), info) + }, + ) + })); + if tcx.entry_fn(()).is_some() { let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, tcx.sess.target.entry_name.as_ref())); diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index dc6e3b1f358dc..fea8980103cce 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -140,7 +140,7 @@ pub enum TokenKind { /// A lifetime, e.g. `'a`. Lifetime { - starts_with_number: bool, + invalid: bool, }, /// `;` @@ -584,7 +584,7 @@ impl<'a> Cursor<'a> { let kind = RawStr { n_hashes: res.ok() }; Literal { kind, suffix_start } } - _ => self.ident_or_unknown_prefix(), + _ => self.ident_or_unknown_prefix(false), }, // Byte literal, byte string literal, raw byte string literal or identifier. @@ -603,7 +603,7 @@ impl<'a> Cursor<'a> { // Identifier (this should be checked after other variant that can // start as identifier). - c if is_id_start(c) => self.ident_or_unknown_prefix(), + c if is_id_start(c) => self.ident_or_unknown_prefix(false), // Numeric literal. c @ '0'..='9' => { @@ -661,7 +661,7 @@ impl<'a> Cursor<'a> { Literal { kind, suffix_start } } // Identifier starting with an emoji. Only lexed for graceful error recovery. - c if !c.is_ascii() && c.is_emoji_char() => self.invalid_ident(), + c if is_emoji(c) => self.invalid_ident(), _ => Unknown, }; if matches!(self.frontmatter_allowed, FrontmatterAllowed::Yes) @@ -832,25 +832,22 @@ impl<'a> Cursor<'a> { RawIdent } - fn ident_or_unknown_prefix(&mut self) -> TokenKind { - debug_assert!(is_id_start(self.prev())); + fn ident_or_unknown_prefix(&mut self, already_invalid: bool) -> TokenKind { + debug_assert!(is_id_start(self.prev()) || already_invalid); // Start is already eaten, eat the rest of identifier. self.eat_while(is_id_continue); // Known prefixes must have been handled earlier. So if // we see a prefix here, it is definitely an unknown prefix. match self.first() { '#' | '"' | '\'' => UnknownPrefix, - c if !c.is_ascii() && c.is_emoji_char() => self.invalid_ident(), + c if is_emoji(c) => self.invalid_ident(), _ => Ident, } } fn invalid_ident(&mut self) -> TokenKind { // Start is already eaten, eat the rest of identifier. - self.eat_while(|c| { - const ZERO_WIDTH_JOINER: char = '\u{200d}'; - is_id_continue(c) || (!c.is_ascii() && c.is_emoji_char()) || c == ZERO_WIDTH_JOINER - }); + self.eat_while(|c| is_id_continue(c) || is_emoji(c)); // An invalid identifier followed by '#' or '"' or '\'' could be // interpreted as an invalid literal prefix. We don't bother doing that // because the treatment of invalid identifiers and invalid prefixes @@ -895,7 +892,7 @@ impl<'a> Cursor<'a> { let kind = mk_kind_raw(res.ok()); Literal { kind, suffix_start } } - _ => self.ident_or_unknown_prefix(), + _ => self.ident_or_unknown_prefix(false), } } @@ -975,6 +972,7 @@ impl<'a> Cursor<'a> { fn lifetime_or_char(&mut self) -> TokenKind { debug_assert!(self.prev() == '\''); + let mut invalid = false; let can_be_a_lifetime = if self.second() == '\'' { // It's surely not a lifetime. false @@ -982,7 +980,10 @@ impl<'a> Cursor<'a> { // If the first symbol is valid for identifier, it can be a lifetime. // Also check if it's a number for a better error reporting (so '0 will // be reported as invalid lifetime and not as unterminated char literal). - is_id_start(self.first()) || self.first().is_ascii_digit() + let c = self.first(); + invalid |= c.is_ascii_digit(); + invalid |= is_emoji(c); + is_id_start(c) || invalid }; if !can_be_a_lifetime { @@ -1012,7 +1013,7 @@ impl<'a> Cursor<'a> { // First symbol can be a number (which isn't a valid identifier start), // so skip it without any checks. self.bump(); - self.eat_while(is_id_continue); + invalid |= matches!(self.ident_or_unknown_prefix(invalid), InvalidIdent); match self.first() { // Check if after skipping literal contents we've met a closing @@ -1024,7 +1025,7 @@ impl<'a> Cursor<'a> { Literal { kind, suffix_start: self.pos_within_token() } } '#' if !starts_with_number => UnknownPrefixLifetime, - _ => Lifetime { starts_with_number }, + _ => Lifetime { invalid }, } } @@ -1277,3 +1278,7 @@ impl<'a> Cursor<'a> { self.eat_while(is_id_continue); } } + +fn is_emoji(c: char) -> bool { + !c.is_ascii() && c.is_emoji_char() +} diff --git a/compiler/rustc_lexer/src/tests.rs b/compiler/rustc_lexer/src/tests.rs index a7357ba38c8e4..f74ba7f532a68 100644 --- a/compiler/rustc_lexer/src/tests.rs +++ b/compiler/rustc_lexer/src/tests.rs @@ -231,7 +231,7 @@ fn lifetime() { "'abc", FrontmatterAllowed::No, expect![[r#" - Token { kind: Lifetime { starts_with_number: false }, len: 4 } + Token { kind: Lifetime { invalid: false }, len: 4 } "#]], ); } diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 28a67ae12126b..2c9c4f54d1034 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -20,6 +20,7 @@ rustc_span = { path = "../rustc_span" } thin-vec = "0.2.12" tracing = "0.1" unicode-normalization = "0.1.25" +unicode-properties = { version = "0.1.4", default-features = false, features = ["emoji"] } unicode-width = "0.2.2" # tidy-alphabetical-end diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 5766d25bc86ce..4569230de0f98 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -16,6 +16,7 @@ use rustc_session::lint::builtin::{ use rustc_session::parse::ParseSess; use rustc_span::{BytePos, Pos, Span, Symbol, sym}; use tracing::debug; +use unicode_properties::emoji::UnicodeEmoji; use crate::errors; use crate::lexer::diagnostics::TokenTreeDiagInfo; @@ -315,18 +316,42 @@ impl<'psess, 'src> Lexer<'psess, 'src> { self.lint_literal_unicode_text_flow(symbol, kind, self.mk_sp(start, self.pos), "literal"); token::Literal(token::Lit { kind, symbol, suffix }) } - rustc_lexer::TokenKind::Lifetime { starts_with_number } => { + rustc_lexer::TokenKind::Lifetime { invalid } => { // 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 = nfc_normalize(self.str_from(start)); self.last_lifetime = Some(self.mk_sp(start, start + BytePos(1))); - if starts_with_number { - let span = self.mk_sp(start, self.pos); - self.dcx() - .struct_err("lifetimes cannot start with a number") - .with_span(span) - .stash(span, StashKey::LifetimeIsChar); + let span = self.mk_sp(start, self.pos); + if invalid { + let name = lifetime_name.as_str(); + // skip(1) to skip the `'` + let starts_with_number = matches!( + name.chars().skip(1).next(), + Some(c) if c.is_ascii_digit() + ); + if name.chars().any(|c| !c.is_ascii() && c.is_emoji_char()) { + self.psess + .bad_unicode_identifiers + .borrow_mut() + .entry(lifetime_name) + .or_default() + .push(span); + } + if starts_with_number { + let mut err = self.dcx() + .struct_err(format!( + "lifetimes cannot start with a number: `{name}`" + )) + .with_span(span); + if name.len() > 2 { + // Point at the first lifetime name character. + let start_span = self.mk_sp(start + BytePos(1), start + BytePos(2)); + err.span(start_span); + err.span_label(span, ""); + } + err.stash(span, StashKey::LifetimeIsChar); + } } token::Lifetime(lifetime_name, IdentIsRaw::No) } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 26ba2b0e8f42d..6aeb0ae57e752 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1188,7 +1188,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { html_no_source: _, // already checked in attr_parsing issue_tracker_base_url: _, - rust_logo, + // already checked in attr_parsing + rust_logo: _, // allowed anywhere test_attrs: _, // already checked in attr_parsing @@ -1217,18 +1218,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_doc_inline(hir_id, target, inline); - if let Some(span) = rust_logo - && !self.tcx.features().rustdoc_internals() - { - feature_err( - &self.tcx.sess, - sym::rustdoc_internals, - *span, - msg!("the `#[doc(rust_logo)]` attribute is used for Rust branding"), - ) - .emit(); - } - if let Some(span) = masked { self.check_doc_masked(*span, hir_id, target); } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index d6cfc993c8b83..d0358b03af197 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -2878,6 +2878,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_predicate: ty::PolyTraitPredicate<'tcx>, root_obligation: &PredicateObligation<'tcx>, ) -> (PredicateObligation<'tcx>, ty::PolyTraitPredicate<'tcx>) { + if obligation.predicate.has_non_region_param() || obligation.has_non_region_infer() { + return (obligation.clone(), trait_predicate); + } + let ocx = ObligationCtxt::new(self); let normalized_predicate = self.tcx.erase_and_anonymize_regions( self.tcx.instantiate_bound_regions_with_erased(trait_predicate), diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index b486e64499107..2d9574ea8c546 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -545,8 +545,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .all(|obligation| self.predicate_may_hold(obligation)) }) && steps > 0 { + if span.in_external_macro(self.tcx.sess.source_map()) { + return false; + } let derefs = "*".repeat(steps); let msg = "consider dereferencing here"; + let call_node = self.tcx.hir_node(*call_hir_id); let is_receiver = matches!( call_node, @@ -593,7 +597,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) { // Suggest dereferencing the LHS, RHS, or both terms of a binop if possible - let trait_pred = predicate.unwrap_or(trait_pred); let lhs_ty = self.tcx.instantiate_bound_regions_with_erased(trait_pred.self_ty()); let lhs_autoderef = (self.autoderef_steps)(lhs_ty); @@ -644,6 +647,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) { let make_sugg = |mut expr: &Expr<'_>, mut steps| { + if expr.span.in_external_macro(self.tcx.sess.source_map()) { + return None; + } let mut prefix_span = expr.span.shrink_to_lo(); let mut msg = "consider dereferencing here"; if let hir::ExprKind::AddrOf(_, _, inner) = expr.kind { @@ -661,10 +667,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } // Empty suggestions with empty spans ICE with debug assertions if steps == 0 { - return ( + return Some(( msg.trim_end_matches(" and dereferencing instead"), vec![(prefix_span, String::new())], - ); + )); } let derefs = "*".repeat(steps); let needs_parens = steps > 0 && expr_needs_parens(expr); @@ -686,7 +692,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if !prefix_span.is_empty() { suggestion.push((prefix_span, String::new())); } - (msg, suggestion) + Some((msg, suggestion)) }; if let Some(lsteps) = lsteps @@ -694,8 +700,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && lsteps > 0 && rsteps > 0 { - let mut suggestion = make_sugg(lhs, lsteps).1; - suggestion.append(&mut make_sugg(rhs, rsteps).1); + let Some((_, mut suggestion)) = make_sugg(lhs, lsteps) else { + return false; + }; + let Some((_, mut rhs_suggestion)) = make_sugg(rhs, rsteps) else { + return false; + }; + suggestion.append(&mut rhs_suggestion); err.multipart_suggestion( "consider dereferencing both sides of the expression", suggestion, @@ -705,13 +716,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } else if let Some(lsteps) = lsteps && lsteps > 0 { - let (msg, suggestion) = make_sugg(lhs, lsteps); + let Some((msg, suggestion)) = make_sugg(lhs, lsteps) else { + return false; + }; err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable); return true; } else if let Some(rsteps) = rsteps && rsteps > 0 { - let (msg, suggestion) = make_sugg(rhs, rsteps); + let Some((msg, suggestion)) = make_sugg(rhs, rsteps) else { + return false; + }; err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable); return true; } @@ -4824,6 +4839,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { candidate_impls: &[ImplCandidate<'tcx>], span: Span, ) { + if span.in_external_macro(self.tcx.sess.source_map()) { + return; + } // We can only suggest the slice coercion for function and binary operation arguments, // since the suggestion would make no sense in turbofish or call let (ObligationCauseCode::BinOp { .. } | ObligationCauseCode::FunctionArg { .. }) = diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 1fde7e5d43b76..bdad1b259b733 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -300,19 +300,14 @@ fn do_normalize_predicates<'tcx>( Ok(predicates) => Ok(predicates), Err(fixup_err) => { // If we encounter a fixup error, it means that some type - // variable wound up unconstrained. I actually don't know - // if this can happen, and I certainly don't expect it to - // happen often, but if it did happen it probably - // represents a legitimate failure due to some kind of - // unconstrained variable. - // - // @lcnr: Let's still ICE here for now. I want a test case - // for that. - span_bug!( + // variable wound up unconstrained. That can happen for + // ill-formed impls, so we delay a bug here instead of + // immediately ICEing and let type checking report the + // actual user-facing errors. + Err(tcx.dcx().span_delayed_bug( span, - "inference variables in normalized parameter environment: {}", - fixup_err - ); + format!("inference variables in normalized parameter environment: {fixup_err}"), + )) } } } diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 541257b6cda6e..b32e5e991cc74 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -16,7 +16,7 @@ bench = false [dependencies] core = { path = "../core", public = true } -compiler_builtins = { path = "../compiler-builtins/compiler-builtins", features = ["rustc-dep-of-std"] } +compiler_builtins = { path = "../compiler-builtins/compiler-builtins", features = ["compiler-builtins"] } [features] compiler-builtins-mem = ['compiler_builtins/mem'] diff --git a/library/compiler-builtins/builtins-shim/Cargo.toml b/library/compiler-builtins/builtins-shim/Cargo.toml index 37d3407e9f668..32b0308a7b3c9 100644 --- a/library/compiler-builtins/builtins-shim/Cargo.toml +++ b/library/compiler-builtins/builtins-shim/Cargo.toml @@ -39,7 +39,7 @@ test = false cc = { version = "1.2", optional = true } [features] -default = ["compiler-builtins"] +default = [] # Enable compilation of C code in compiler-rt, filling in some more optimized # implementations and also filling in unimplemented intrinsics @@ -50,7 +50,8 @@ c = ["dep:cc"] # the generic versions on all platforms. no-asm = [] -# Flag this library as the unstable compiler-builtins lib +# Flag this library as the unstable compiler-builtins lib. This must be enabled +# when using as `std`'s dependency.' compiler-builtins = [] # Generate memory-related intrinsics like memcpy @@ -60,9 +61,6 @@ mem = [] # compiler-rt implementations. Also used for testing mangled-names = [] -# Only used in the compiler's build system -rustc-dep-of-std = ["compiler-builtins"] - # This makes certain traits and function specializations public that # are not normally public but are required by the `builtins-test` unstable-public-internals = [] diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index a8b8920421b3e..d9acb8341d483 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -34,7 +34,7 @@ core = { path = "../../core", optional = true } cc = { version = "1.2", optional = true } [features] -default = ["compiler-builtins"] +default = [] # Enable compilation of C code in compiler-rt, filling in some more optimized # implementations and also filling in unimplemented intrinsics @@ -45,8 +45,9 @@ c = ["dep:cc"] # the generic versions on all platforms. no-asm = [] -# Flag this library as the unstable compiler-builtins lib -compiler-builtins = [] +# Flag this library as the unstable compiler-builtins lib. This must be enabled +# when using as `std`'s dependency.' +compiler-builtins = ["dep:core"] # Generate memory-related intrinsics like memcpy mem = [] @@ -55,9 +56,6 @@ mem = [] # compiler-rt implementations. Also used for testing mangled-names = [] -# Only used in the compiler's build system -rustc-dep-of-std = ["compiler-builtins", "dep:core"] - # This makes certain traits and function specializations public that # are not normally public but are required by the `builtins-test` unstable-public-internals = [] diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs index d7eec6cde8c01..df7bef5843da8 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs @@ -255,9 +255,9 @@ impl<'a> Converter<'a> { return; } - rustc_lexer::TokenKind::Lifetime { starts_with_number } => { - if *starts_with_number { - errors.push("Lifetime name cannot start with a number".into()); + rustc_lexer::TokenKind::Lifetime { invalid } => { + if *invalid { + errors.push("Lifetime name contains invalid characters".into()); } LIFETIME_IDENT } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.rast index e919bf2a4aef2..b2bf087e749f3 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.rast @@ -1,4 +1,4 @@ -LIFETIME_IDENT "'1" error: Lifetime name cannot start with a number +LIFETIME_IDENT "'1" error: Lifetime name contains invalid characters WHITESPACE "\n" -LIFETIME_IDENT "'1lifetime" error: Lifetime name cannot start with a number +LIFETIME_IDENT "'1lifetime" error: Lifetime name contains invalid characters WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.txt index e919bf2a4aef2..b2bf087e749f3 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.txt +++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.txt @@ -1,4 +1,4 @@ -LIFETIME_IDENT "'1" error: Lifetime name cannot start with a number +LIFETIME_IDENT "'1" error: Lifetime name contains invalid characters WHITESPACE "\n" -LIFETIME_IDENT "'1lifetime" error: Lifetime name cannot start with a number +LIFETIME_IDENT "'1lifetime" error: Lifetime name contains invalid characters WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.rast index 56f19cce0784e..6ace31f434ef2 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.rast @@ -1 +1 @@ -CHAR "'๐Ÿฆ€" error: Missing trailing `'` symbol to terminate the character literal +LIFETIME_IDENT "'๐Ÿฆ€" error: Lifetime name contains invalid characters diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/token_stream.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/token_stream.rs index 2358f6963c79e..d6773153ed988 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/token_stream.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/token_stream.rs @@ -302,9 +302,9 @@ impl TokenStream { span: span.derive_ranged(range), })) } - rustc_lexer::TokenKind::Lifetime { starts_with_number } => { - if starts_with_number { - return Err("Lifetime cannot start with a number".to_owned()); + rustc_lexer::TokenKind::Lifetime { invalid } => { + if invalid { + return Err(format!("Invalid lifetime identifier: `{}`", &s[range])); } let range = range.start + 1..range.end; tokenstream.push(TokenTree::Punct(Punct { diff --git a/tests/crashes/120033.rs b/tests/crashes/120033.rs deleted file mode 100644 index 7584f98ec9060..0000000000000 --- a/tests/crashes/120033.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ known-bug: #120033 -#![feature(non_lifetime_binders)] -#![allow(sized_hierarchy_migration)] -#![feature(sized_hierarchy)] // added to keep parameters unconstrained - -pub trait Foo { - type Bar; -} - -pub struct Bar {} - -pub fn f() -where - T1: for Foo>, - T2: for Foo = T1::Bar>, -{} diff --git a/tests/ui/lexer/emoji-in-lifetime.rs b/tests/ui/lexer/emoji-in-lifetime.rs new file mode 100644 index 0000000000000..e4a12f332ae70 --- /dev/null +++ b/tests/ui/lexer/emoji-in-lifetime.rs @@ -0,0 +1,16 @@ +// #141081 +fn bad_lifetime_name< + '๐Ÿ›๐Ÿ›๐Ÿ›family๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ,//~ ERROR: identifiers cannot contain emoji + '12, //~ ERROR: lifetimes cannot start with a number + 'a๐Ÿ›, //~ ERROR: identifiers cannot contain emoji + '1๐Ÿ›, //~ ERROR: identifiers cannot contain emoji + //~^ ERROR: lifetimes cannot start with a number + '1, //~ ERROR: lifetimes cannot start with a number + 'aโ€Œb // bare zero-width-joiners are accepted as XID_Continue +>() {} + +fn main() { + 'a๐Ÿ›: { // pointed at on the error from line 5 + todo!(); + }; +} diff --git a/tests/ui/lexer/emoji-in-lifetime.stderr b/tests/ui/lexer/emoji-in-lifetime.stderr new file mode 100644 index 0000000000000..7e205639a9a3c --- /dev/null +++ b/tests/ui/lexer/emoji-in-lifetime.stderr @@ -0,0 +1,41 @@ +error: identifiers cannot contain emoji: `'๐Ÿ›๐Ÿ›๐Ÿ›family๐Ÿ‘จ๐Ÿ‘ฉ๐Ÿ‘ง๐Ÿ‘ฆ` + --> $DIR/emoji-in-lifetime.rs:3:5 + | +LL | '๐Ÿ›๐Ÿ›๐Ÿ›family๐Ÿ‘จ๐Ÿ‘ฉ๐Ÿ‘ง๐Ÿ‘ฆ, + | ^^^^^^^^^^^^^^^^^^^^^ + +error: identifiers cannot contain emoji: `'a๐Ÿ›` + --> $DIR/emoji-in-lifetime.rs:5:5 + | +LL | 'a๐Ÿ›, + | ^^^^ +... +LL | 'a๐Ÿ›: { // pointed at on the error from line 5 + | ^^^^ + +error: identifiers cannot contain emoji: `'1๐Ÿ›` + --> $DIR/emoji-in-lifetime.rs:6:5 + | +LL | '1๐Ÿ›, + | ^^^^ + +error: lifetimes cannot start with a number: `'12` + --> $DIR/emoji-in-lifetime.rs:4:6 + | +LL | '12, + | -^- + +error: lifetimes cannot start with a number: `'1๐Ÿ›` + --> $DIR/emoji-in-lifetime.rs:6:6 + | +LL | '1๐Ÿ›, + | -^-- + +error: lifetimes cannot start with a number: `'1` + --> $DIR/emoji-in-lifetime.rs:8:5 + | +LL | '1, + | ^^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr index 81ee697802b9c..7503774cd686f 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-1.stderr @@ -10,7 +10,7 @@ LL - println!('1 + 1'); LL + println!("1 + 1"); | -error: lifetimes cannot start with a number +error: lifetimes cannot start with a number: `'1` --> $DIR/lex-bad-str-literal-as-char-1.rs:3:14 | LL | println!('1 + 1'); diff --git a/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.rs b/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.rs new file mode 100644 index 0000000000000..5a6ef0421e2fa --- /dev/null +++ b/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.rs @@ -0,0 +1,23 @@ +macro_rules! local_assert_ne { + ($left:expr, $right:expr $(,)?) => { + match (&$left, &$right) { + (left_val, right_val) => { + if *left_val == *right_val { + //~^ ERROR can't compare `[u8; 4]` with `&[u8; 4]` + panic!(); + } + } + } + }; +} + +fn main() { + let buf = [0_u8; 4]; + assert_ne!(buf, b"----"); + //~^ ERROR can't compare `[u8; 4]` with `&[u8; 4]` + + assert_eq!(buf, b"----"); + //~^ ERROR can't compare `[u8; 4]` with `&[u8; 4]` + + local_assert_ne!(buf, b"----"); +} diff --git a/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.stderr b/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.stderr new file mode 100644 index 0000000000000..359deee7bee4b --- /dev/null +++ b/tests/ui/macros/assert-ne-no-invalid-help-issue-146204.stderr @@ -0,0 +1,55 @@ +error[E0277]: can't compare `[u8; 4]` with `&[u8; 4]` + --> $DIR/assert-ne-no-invalid-help-issue-146204.rs:16:5 + | +LL | assert_ne!(buf, b"----"); + | ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `[u8; 4] == &[u8; 4]` + | + = help: the trait `PartialEq<&[u8; 4]>` is not implemented for `[u8; 4]` + = help: the following other types implement trait `PartialEq`: + `&[T]` implements `PartialEq>` + `&[T]` implements `PartialEq<[U; N]>` + `&[u8; N]` implements `PartialEq` + `&[u8; N]` implements `PartialEq` + `&[u8]` implements `PartialEq` + `&[u8]` implements `PartialEq` + `&mut [T]` implements `PartialEq>` + `&mut [T]` implements `PartialEq<[U; N]>` + and 11 others + +error[E0277]: can't compare `[u8; 4]` with `&[u8; 4]` + --> $DIR/assert-ne-no-invalid-help-issue-146204.rs:19:5 + | +LL | assert_eq!(buf, b"----"); + | ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `[u8; 4] == &[u8; 4]` + | + = help: the trait `PartialEq<&[u8; 4]>` is not implemented for `[u8; 4]` + = help: the following other types implement trait `PartialEq`: + `&[T]` implements `PartialEq>` + `&[T]` implements `PartialEq<[U; N]>` + `&[u8; N]` implements `PartialEq` + `&[u8; N]` implements `PartialEq` + `&[u8]` implements `PartialEq` + `&[u8]` implements `PartialEq` + `&mut [T]` implements `PartialEq>` + `&mut [T]` implements `PartialEq<[U; N]>` + and 11 others + +error[E0277]: can't compare `[u8; 4]` with `&[u8; 4]` + --> $DIR/assert-ne-no-invalid-help-issue-146204.rs:5:30 + | +LL | if *left_val == *right_val { + | ^^ no implementation for `[u8; 4] == &[u8; 4]` +... +LL | local_assert_ne!(buf, b"----"); + | ------------------------------ in this macro invocation + | + = help: the trait `PartialEq<&[u8; 4]>` is not implemented for `[u8; 4]` + = note: this error originates in the macro `local_assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider dereferencing here + | +LL | if *left_val == **right_val { + | + + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/parser/numeric-lifetime.stderr b/tests/ui/parser/numeric-lifetime.stderr index 7c1bcb7263171..46b06ae7dc3cb 100644 --- a/tests/ui/parser/numeric-lifetime.stderr +++ b/tests/ui/parser/numeric-lifetime.stderr @@ -6,13 +6,13 @@ LL | let x: usize = ""; | | | expected due to this -error: lifetimes cannot start with a number +error: lifetimes cannot start with a number: `'1` --> $DIR/numeric-lifetime.rs:1:10 | LL | struct S<'1> { s: &'1 usize } | ^^ -error: lifetimes cannot start with a number +error: lifetimes cannot start with a number: `'1` --> $DIR/numeric-lifetime.rs:1:20 | LL | struct S<'1> { s: &'1 usize } diff --git a/tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.rs b/tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.rs new file mode 100644 index 0000000000000..52f83966c6bd1 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.rs @@ -0,0 +1,22 @@ +//@ compile-flags: --crate-type=lib + +// Regression test for + +#![feature(rustc_attrs)] +#![feature(non_lifetime_binders)] +#![allow(incomplete_features)] +#![rustc_no_implicit_bounds] + +pub trait Foo { + type Bar; +} + +pub struct Bar {} //~ ERROR cannot find trait `AutoTrait` + +pub fn f() +where + T1: for Foo>, //~ ERROR missing generics for associated type `Foo::Bar` + //~| ERROR missing generics for associated type `Foo::Bar` + T2: for Foo = T1::Bar>, +{ +} diff --git a/tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.stderr b/tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.stderr new file mode 100644 index 0000000000000..c95e6c68fc6a1 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/normalized-param-env-unconstrained-type-120033.stderr @@ -0,0 +1,43 @@ +error[E0405]: cannot find trait `AutoTrait` in this scope + --> $DIR/normalized-param-env-unconstrained-type-120033.rs:14:20 + | +LL | pub struct Bar {} + | ^^^^^^^^^ not found in this scope + +error[E0107]: missing generics for associated type `Foo::Bar` + --> $DIR/normalized-param-env-unconstrained-type-120033.rs:18:27 + | +LL | T1: for Foo>, + | ^^^ expected 1 generic argument + | +note: associated type defined here, with 1 generic parameter: `K` + --> $DIR/normalized-param-env-unconstrained-type-120033.rs:11:10 + | +LL | type Bar; + | ^^^ - +help: add missing generic argument + | +LL | T1: for Foo = Bar>, + | +++ + +error[E0107]: missing generics for associated type `Foo::Bar` + --> $DIR/normalized-param-env-unconstrained-type-120033.rs:18:27 + | +LL | T1: for Foo>, + | ^^^ expected 1 generic argument + | +note: associated type defined here, with 1 generic parameter: `K` + --> $DIR/normalized-param-env-unconstrained-type-120033.rs:11:10 + | +LL | type Bar; + | ^^^ - + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add missing generic argument + | +LL | T1: for Foo = Bar>, + | +++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0107, E0405. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/traits/self-referential-param-env-normalization.rs b/tests/ui/traits/self-referential-param-env-normalization.rs new file mode 100644 index 0000000000000..a40c8cc26bd94 --- /dev/null +++ b/tests/ui/traits/self-referential-param-env-normalization.rs @@ -0,0 +1,18 @@ +//~ ERROR overflow evaluating the requirement `Self: StreamingIterator<'_>` [E0275] +// Regression test for . + +trait StreamingIterator<'a> { + type Item: 'a; +} + +impl<'b, I, T> StreamingIterator<'b> for I +//~^ ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates [E0207] +where + I: IntoIterator, + T: FnMut(Self::Item, I::Item), +{ + type Item = T; + //~^ ERROR overflow evaluating the requirement `I: IntoIterator` [E0275] +} + +fn main() {} diff --git a/tests/ui/traits/self-referential-param-env-normalization.stderr b/tests/ui/traits/self-referential-param-env-normalization.stderr new file mode 100644 index 0000000000000..5e9c2c92eaac6 --- /dev/null +++ b/tests/ui/traits/self-referential-param-env-normalization.stderr @@ -0,0 +1,42 @@ +error[E0275]: overflow evaluating the requirement `Self: StreamingIterator<'_>` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`self_referential_param_env_normalization`) +note: required for `Self` to implement `StreamingIterator<'_>` + --> $DIR/self-referential-param-env-normalization.rs:8:16 + | +LL | impl<'b, I, T> StreamingIterator<'b> for I + | ^^^^^^^^^^^^^^^^^^^^^ ^ +... +LL | T: FnMut(Self::Item, I::Item), + | -------------------------- unsatisfied trait bound introduced here + = note: 127 redundant requirements hidden + = note: required for `Self` to implement `StreamingIterator<'a>` + +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/self-referential-param-env-normalization.rs:8:13 + | +LL | impl<'b, I, T> StreamingIterator<'b> for I + | ^ unconstrained type parameter + +error[E0275]: overflow evaluating the requirement `I: IntoIterator` + --> $DIR/self-referential-param-env-normalization.rs:14:17 + | +LL | type Item = T; + | ^ + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`self_referential_param_env_normalization`) +note: required for `I` to implement `StreamingIterator<'_>` + --> $DIR/self-referential-param-env-normalization.rs:8:16 + | +LL | impl<'b, I, T> StreamingIterator<'b> for I + | ^^^^^^^^^^^^^^^^^^^^^ ^ +... +LL | T: FnMut(Self::Item, I::Item), + | -------------------------- unsatisfied trait bound introduced here + = note: 127 redundant requirements hidden + = note: required for `I` to implement `StreamingIterator<'b>` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0207, E0275. +For more information about an error, try `rustc --explain E0207`. diff --git a/tests/ui/transmutability/generic-transmute-from-regression.rs b/tests/ui/transmutability/generic-transmute-from-regression.rs new file mode 100644 index 0000000000000..38568243ed9d0 --- /dev/null +++ b/tests/ui/transmutability/generic-transmute-from-regression.rs @@ -0,0 +1,11 @@ +//! Regression test for: +#![feature(transmutability)] + +fn foo(x: T) -> U { + unsafe { + std::mem::TransmuteFrom::transmute(x) + //~^ ERROR: the trait bound `U: TransmuteFrom` is not satisfied [E0277] + } +} + +fn main() {} diff --git a/tests/ui/transmutability/generic-transmute-from-regression.stderr b/tests/ui/transmutability/generic-transmute-from-regression.stderr new file mode 100644 index 0000000000000..3912aec0a9c84 --- /dev/null +++ b/tests/ui/transmutability/generic-transmute-from-regression.stderr @@ -0,0 +1,11 @@ +error[E0277]: the trait bound `U: TransmuteFrom` is not satisfied + --> $DIR/generic-transmute-from-regression.rs:6:44 + | +LL | std::mem::TransmuteFrom::transmute(x) + | ---------------------------------- ^ the nightly-only, unstable trait `TransmuteFrom` is not implemented for `U` + | | + | required by a bound introduced by this call + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.