diff options
Diffstat (limited to 'compiler')
98 files changed, 889 insertions, 552 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 098e2606a3b..3fdb2a2225a 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1846,7 +1846,7 @@ pub enum LitKind { /// A boolean literal (`true`, `false`). Bool(bool), /// Placeholder for a literal that wasn't well-formed in some way. - Err, + Err(ErrorGuaranteed), } impl LitKind { @@ -1893,7 +1893,7 @@ impl LitKind { | LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed) | LitKind::Bool(..) - | LitKind::Err => false, + | LitKind::Err(_) => false, } } } @@ -2136,10 +2136,12 @@ pub enum TyKind { ImplicitSelf, /// A macro in the type position. MacCall(P<MacCall>), - /// Placeholder for a kind that has failed to be defined. - Err, /// Placeholder for a `va_list`. CVarArgs, + /// Sometimes we need a dummy value when no error has occurred. + Dummy, + /// Placeholder for a kind that has failed to be defined. + Err(ErrorGuaranteed), } impl TyKind { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index d482ada170e..c42c4199973 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -481,7 +481,12 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) { let Ty { id, kind, span, tokens } = ty.deref_mut(); vis.visit_id(id); match kind { - TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err | TyKind::Never | TyKind::CVarArgs => {} + TyKind::Infer + | TyKind::ImplicitSelf + | TyKind::Err(_) + | TyKind::Dummy + | TyKind::Never + | TyKind::CVarArgs => {} TyKind::Slice(ty) => vis.visit_ty(ty), TyKind::Ptr(mt) => vis.visit_mt(mt), TyKind::Ref(lt, mt) => { @@ -1649,7 +1654,7 @@ impl DummyAstNode for Ty { fn dummy() -> Self { Ty { id: DUMMY_NODE_ID, - kind: TyKind::Err, + kind: TyKind::Dummy, span: Default::default(), tokens: Default::default(), } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index d62462b1ae3..50fe37dcdb6 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -13,7 +13,7 @@ use rustc_macros::HashStable_Generic; use rustc_span::symbol::{kw, sym}; #[allow(hidden_glob_reexports)] use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{edition::Edition, Span, DUMMY_SP}; +use rustc_span::{edition::Edition, ErrorGuaranteed, Span, DUMMY_SP}; use std::borrow::Cow; use std::fmt; @@ -75,7 +75,7 @@ pub enum LitKind { ByteStrRaw(u8), // raw byte string delimited by `n` hash symbols CStr, CStrRaw(u8), - Err, + Err(ErrorGuaranteed), } /// A literal token. @@ -144,7 +144,7 @@ impl fmt::Display for Lit { CStrRaw(n) => { write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize))? } - Integer | Float | Bool | Err => write!(f, "{symbol}")?, + Integer | Float | Bool | Err(_) => write!(f, "{symbol}")?, } if let Some(suffix) = suffix { @@ -159,7 +159,7 @@ impl LitKind { /// An English article for the literal token kind. pub fn article(self) -> &'static str { match self { - Integer | Err => "an", + Integer | Err(_) => "an", _ => "a", } } @@ -174,12 +174,12 @@ impl LitKind { Str | StrRaw(..) => "string", ByteStr | ByteStrRaw(..) => "byte string", CStr | CStrRaw(..) => "C string", - Err => "error", + Err(_) => "error", } } pub(crate) fn may_have_suffix(self) -> bool { - matches!(self, Integer | Float | Err) + matches!(self, Integer | Float | Err(_)) } } diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index aaeb1bb9bff..5ed2762b726 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -31,20 +31,21 @@ pub fn escape_byte_str_symbol(bytes: &[u8]) -> Symbol { #[derive(Debug)] pub enum LitError { - LexerError, - InvalidSuffix, - InvalidIntSuffix, - InvalidFloatSuffix, - NonDecimalFloat(u32), - IntTooLarge(u32), + InvalidSuffix(Symbol), + InvalidIntSuffix(Symbol), + InvalidFloatSuffix(Symbol), + NonDecimalFloat(u32), // u32 is the base + IntTooLarge(u32), // u32 is the base } impl LitKind { /// Converts literal token into a semantic literal. pub fn from_token_lit(lit: token::Lit) -> Result<LitKind, LitError> { let token::Lit { kind, symbol, suffix } = lit; - if suffix.is_some() && !kind.may_have_suffix() { - return Err(LitError::InvalidSuffix); + if let Some(suffix) = suffix + && !kind.may_have_suffix() + { + return Err(LitError::InvalidSuffix(suffix)); } // For byte/char/string literals, chars and escapes have already been @@ -145,7 +146,7 @@ impl LitKind { buf.push(0); LitKind::CStr(buf.into(), StrStyle::Raw(n)) } - token::Err => LitKind::Err, + token::Err(guar) => LitKind::Err(guar), }) } } @@ -202,7 +203,7 @@ impl fmt::Display for LitKind { } } LitKind::Bool(b) => write!(f, "{}", if b { "true" } else { "false" })?, - LitKind::Err => { + LitKind::Err(_) => { // This only shows up in places like `-Zunpretty=hir` output, so we // don't bother to produce something useful. write!(f, "<bad-literal>")?; @@ -238,7 +239,7 @@ impl MetaItemLit { LitKind::Char(_) => token::Char, LitKind::Int(..) => token::Integer, LitKind::Float(..) => token::Float, - LitKind::Err => token::Err, + LitKind::Err(guar) => token::Err(guar), }; token::Lit::new(kind, self.symbol, self.suffix) @@ -272,12 +273,12 @@ fn filtered_float_lit( return Err(LitError::NonDecimalFloat(base)); } Ok(match suffix { - Some(suf) => LitKind::Float( + Some(suffix) => LitKind::Float( symbol, - ast::LitFloatType::Suffixed(match suf { + ast::LitFloatType::Suffixed(match suffix { sym::f32 => ast::FloatTy::F32, sym::f64 => ast::FloatTy::F64, - _ => return Err(LitError::InvalidFloatSuffix), + _ => return Err(LitError::InvalidFloatSuffix(suffix)), }), ), None => LitKind::Float(symbol, ast::LitFloatType::Unsuffixed), @@ -318,17 +319,13 @@ fn integer_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitErr // `1f64` and `2f32` etc. are valid float literals, and // `fxxx` looks more like an invalid float literal than invalid integer literal. _ if suf.as_str().starts_with('f') => return filtered_float_lit(symbol, suffix, base), - _ => return Err(LitError::InvalidIntSuffix), + _ => return Err(LitError::InvalidIntSuffix(suf)), }, _ => ast::LitIntType::Unsuffixed, }; let s = &s[if base != 10 { 2 } else { 0 }..]; - u128::from_str_radix(s, base).map(|i| LitKind::Int(i.into(), ty)).map_err(|_| { - // Small bases are lexed as if they were base 10, e.g, the string - // might be `0b10201`. This will cause the conversion above to fail, - // but these kinds of errors are already reported by the lexer. - let from_lexer = base < 10 && s.chars().any(|c| c.to_digit(10).is_some_and(|d| d >= base)); - if from_lexer { LitError::LexerError } else { LitError::IntTooLarge(base) } - }) + u128::from_str_radix(s, base) + .map(|i| LitKind::Int(i.into(), ty)) + .map_err(|_| LitError::IntTooLarge(base)) } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 4aaaa0ba424..83f6746bdeb 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -447,7 +447,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { walk_list!(visitor, visit_param_bound, bounds, BoundKind::Impl); } TyKind::Typeof(expression) => visitor.visit_anon_const(expression), - TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {} + TyKind::Infer | TyKind::ImplicitSelf | TyKind::Dummy | TyKind::Err(_) => {} TyKind::MacCall(mac) => visitor.visit_mac_call(mac), TyKind::Never | TyKind::CVarArgs => {} TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => { diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 942aae3d536..aafa99b3aa6 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -124,8 +124,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let lit_kind = match LitKind::from_token_lit(*token_lit) { Ok(lit_kind) => lit_kind, Err(err) => { - report_lit_error(&self.tcx.sess.parse_sess, err, *token_lit, e.span); - LitKind::Err + let guar = report_lit_error( + &self.tcx.sess.parse_sess, + err, + *token_lit, + e.span, + ); + LitKind::Err(guar) } }; let lit = self.arena.alloc(respan(self.lower_span(e.span), lit_kind)); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 6b5fc014240..e9e1095a4ae 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -966,10 +966,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { { lit } else { + let guar = self.dcx().has_errors().unwrap(); MetaItemLit { symbol: kw::Empty, suffix: None, - kind: LitKind::Err, + kind: LitKind::Err(guar), span: DUMMY_SP, } }; @@ -1285,7 +1286,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> { let kind = match &t.kind { TyKind::Infer => hir::TyKind::Infer, - TyKind::Err => hir::TyKind::Err(self.dcx().has_errors().unwrap()), + TyKind::Err(guar) => hir::TyKind::Err(*guar), // Lower the anonymous structs or unions in a nested lowering context. // // ``` @@ -1503,6 +1504,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ); hir::TyKind::Err(guar) } + TyKind::Dummy => panic!("`TyKind::Dummy` should never be lowered"), }; hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index ebc5c17a4c4..fa0f5326196 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -881,7 +881,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { &item.vis, errors::VisibilityNotPermittedNote::TraitImpl, ); - if let TyKind::Err = self_ty.kind { + // njn: use Dummy here + if let TyKind::Err(_) = self_ty.kind { this.dcx().emit_err(errors::ObsoleteAuto { span: item.span }); } if let (&Unsafe::Yes(span), &ImplPolarity::Negative(sp)) = (unsafety, polarity) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index cda746894e8..7ea0078ea3b 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -254,7 +254,7 @@ fn literal_to_string(lit: token::Lit) -> String { token::CStrRaw(n) => { format!("cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize)) } - token::Integer | token::Float | token::Bool | token::Err => symbol.to_string(), + token::Integer | token::Float | token::Bool | token::Err(_) => symbol.to_string(), }; if let Some(suffix) = suffix { @@ -1048,11 +1048,16 @@ impl<'a> State<'a> { ast::TyKind::Infer => { self.word("_"); } - ast::TyKind::Err => { + ast::TyKind::Err(_) => { self.popen(); self.word("/*ERROR*/"); self.pclose(); } + ast::TyKind::Dummy => { + self.popen(); + self.word("/*DUMMY*/"); + self.pclose(); + } ast::TyKind::ImplicitSelf => { self.word("Self"); } diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index a7bdfa4eae7..90e8f1b93b2 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -15,7 +15,7 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Diagnostic; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::lang_items::LangItem; @@ -180,7 +180,7 @@ struct UniversalRegionIndices<'tcx> { /// basically equivalent to an `GenericArgs`, except that it also /// contains an entry for `ReStatic` -- it might be nice to just /// use an args, and then handle `ReStatic` another way. - indices: FxHashMap<ty::Region<'tcx>, RegionVid>, + indices: FxIndexMap<ty::Region<'tcx>, RegionVid>, /// The vid assigned to `'static`. Used only for diagnostics. pub fr_static: RegionVid, @@ -325,9 +325,6 @@ impl<'tcx> UniversalRegions<'tcx> { } /// Gets an iterator over all the early-bound regions that have names. - /// Iteration order may be unstable, so this should only be used when - /// iteration order doesn't affect anything - #[allow(rustc::potential_query_instability)] pub fn named_universal_regions<'s>( &'s self, ) -> impl Iterator<Item = (ty::Region<'tcx>, ty::RegionVid)> + 's { diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index dade29593af..795161e65d8 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -40,7 +40,7 @@ pub fn expand_concat( cx.dcx().emit_err(errors::ConcatBytestr { span: e.span }); has_errors = true; } - Ok(ast::LitKind::Err) => { + Ok(ast::LitKind::Err(_)) => { has_errors = true; } Err(err) => { diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index a01bbeac824..3ef8cb7bffe 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -44,7 +44,7 @@ fn invalid_type_err( Ok(ast::LitKind::Bool(_)) => { dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None }); } - Ok(ast::LitKind::Err) => {} + Ok(ast::LitKind::Err(_)) => {} Ok(ast::LitKind::Int(_, _)) if !is_nested => { let sugg = snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span: span, snippet }); diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 42bd8687042..06a681c24e6 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -21,6 +21,7 @@ use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; use rustc_session::config::{self, CrateType, Lto}; +use std::collections::BTreeMap; use std::ffi::{CStr, CString}; use std::fs::File; use std::io; @@ -787,7 +788,7 @@ pub unsafe fn optimize_thin_module( #[derive(Debug, Default)] pub struct ThinLTOKeysMap { // key = llvm name of importing module, value = LLVM cache key - keys: FxHashMap<String, String>, + keys: BTreeMap<String, String>, } impl ThinLTOKeysMap { @@ -797,7 +798,6 @@ impl ThinLTOKeysMap { let mut writer = io::BufWriter::new(file); // The entries are loaded back into a hash map in `load_from_file()`, so // the order in which we write them to file here does not matter. - #[allow(rustc::potential_query_instability)] for (module, key) in &self.keys { writeln!(writer, "{module} {key}")?; } @@ -806,7 +806,7 @@ impl ThinLTOKeysMap { fn load_from_file(path: &Path) -> io::Result<Self> { use std::io::BufRead; - let mut keys = FxHashMap::default(); + let mut keys = BTreeMap::default(); let file = File::open(path)?; for line in io::BufReader::new(file).lines() { let line = line?; diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index b1ceb1d4dd5..6116a6fd222 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -403,7 +403,6 @@ fn codegenned_and_inlined_items(tcx: TyCtxt<'_>) -> DefIdSet { let mut result = items.clone(); for cgu in cgus { - #[allow(rustc::potential_query_instability)] for item in cgu.items().keys() { if let mir::mono::MonoItem::Fn(ref instance) = item { let did = instance.def_id(); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index e48479c8da2..54e8ed85e32 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -266,6 +266,10 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> { ("riscv32" | "riscv64", "fast-unaligned-access") if get_version().0 <= 17 => { LLVMFeature::new("unaligned-scalar-mem") } + // For LLVM 18, enable the evex512 target feature if a avx512 target feature is enabled. + ("x86", s) if get_version().0 >= 18 && s.starts_with("avx512") => { + LLVMFeature::with_dependency(s, TargetFeatureFoldStrength::EnableOnly("evex512")) + } (_, s) => LLVMFeature::new(s), } } diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs index 3e5a43c6e73..344e7dbdf03 100644 --- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs +++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs @@ -25,7 +25,7 @@ use crate::errors; use rustc_ast as ast; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::unord::UnordMap; use rustc_data_structures::unord::UnordSet; use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir::def_id::LOCAL_CRATE; @@ -218,8 +218,8 @@ pub enum ComparisonKind { } struct TrackerData { - actual_reuse: FxHashMap<String, CguReuse>, - expected_reuse: FxHashMap<String, (String, Span, CguReuse, ComparisonKind)>, + actual_reuse: UnordMap<String, CguReuse>, + expected_reuse: UnordMap<String, (String, Span, CguReuse, ComparisonKind)>, } pub struct CguReuseTracker { @@ -267,9 +267,7 @@ impl CguReuseTracker { fn check_expected_reuse(&self, sess: &Session) { if let Some(ref data) = self.data { - #[allow(rustc::potential_query_instability)] - let mut keys = data.expected_reuse.keys().collect::<Vec<_>>(); - keys.sort_unstable(); + let keys = data.expected_reuse.keys().into_sorted_stable_ord(); for cgu_name in keys { let &(ref cgu_user_name, ref error_span, expected_reuse, comparison_kind) = data.expected_reuse.get(cgu_name).unwrap(); diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 8d7ad24b446..0dadd047c9a 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::memmap::Mmap; use rustc_session::cstore::DllImport; use rustc_session::Session; @@ -41,7 +41,7 @@ pub trait ArchiveBuilderBuilder { &'a self, rlib: &'a Path, outdir: &Path, - bundled_lib_file_names: &FxHashSet<Symbol>, + bundled_lib_file_names: &FxIndexSet<Symbol>, ) -> Result<(), ExtractBundledLibsError<'_>> { let archive_map = unsafe { Mmap::map( diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index b29f71bfb95..435b517e602 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1,7 +1,6 @@ use rustc_arena::TypedArena; use rustc_ast::CRATE_NODE_ID; -use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::{DiagCtxt, ErrorGuaranteed}; @@ -534,9 +533,9 @@ fn link_staticlib<'a>( let native_libs = codegen_results.crate_info.native_libraries[&cnum].iter(); let relevant = native_libs.clone().filter(|lib| relevant_lib(sess, lib)); - let relevant_libs: FxHashSet<_> = relevant.filter_map(|lib| lib.filename).collect(); + let relevant_libs: FxIndexSet<_> = relevant.filter_map(|lib| lib.filename).collect(); - let bundled_libs: FxHashSet<_> = native_libs.filter_map(|lib| lib.filename).collect(); + let bundled_libs: FxIndexSet<_> = native_libs.filter_map(|lib| lib.filename).collect(); ab.add_archive( path, Box::new(move |fname: &str| { @@ -564,11 +563,7 @@ fn link_staticlib<'a>( .extract_bundled_libs(path, tempdir.as_ref(), &relevant_libs) .unwrap_or_else(|e| sess.dcx().emit_fatal(e)); - // We sort the libraries below - #[allow(rustc::potential_query_instability)] - let mut relevant_libs: Vec<Symbol> = relevant_libs.into_iter().collect(); - relevant_libs.sort_unstable(); - for filename in relevant_libs { + for filename in relevant_libs.iter() { let joined = tempdir.as_ref().join(filename.as_str()); let path = joined.as_path(); ab.add_archive(path, Box::new(|_| false)).unwrap(); @@ -682,13 +677,14 @@ fn link_dwarf_object<'a>( } // Input rlibs contain .o/.dwo files from dependencies. - #[allow(rustc::potential_query_instability)] let input_rlibs = cg_results .crate_info .used_crate_source - .values() - .filter_map(|csource| csource.rlib.as_ref()) - .map(|(path, _)| path); + .items() + .filter_map(|(_, csource)| csource.rlib.as_ref()) + .map(|(path, _)| path) + .into_sorted_stable_ord(); + for input_rlib in input_rlibs { debug!(?input_rlib); package.add_input_object(input_rlib)?; @@ -2456,7 +2452,7 @@ fn add_native_libs_from_crate( codegen_results: &CodegenResults, tmpdir: &Path, search_paths: &SearchPaths, - bundled_libs: &FxHashSet<Symbol>, + bundled_libs: &FxIndexSet<Symbol>, cnum: CrateNum, link_static: bool, link_dynamic: bool, @@ -2777,7 +2773,7 @@ fn add_static_crate<'a>( codegen_results: &CodegenResults, tmpdir: &Path, cnum: CrateNum, - bundled_lib_file_names: &FxHashSet<Symbol>, + bundled_lib_file_names: &FxIndexSet<Symbol>, ) { let src = &codegen_results.crate_info.used_crate_source[&cnum]; let cratepath = &src.rlib.as_ref().unwrap().0; diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index a63642d76b9..24fdd013509 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1001,7 +1001,7 @@ pub struct CguMessage; struct Diagnostic { msgs: Vec<(DiagnosticMessage, Style)>, - args: FxHashMap<DiagnosticArgName, DiagnosticArgValue>, + args: FxIndexMap<DiagnosticArgName, DiagnosticArgValue>, code: Option<ErrCode>, lvl: Level, } @@ -1813,7 +1813,7 @@ impl Translate for SharedEmitter { impl Emitter for SharedEmitter { fn emit_diagnostic(&mut self, diag: rustc_errors::Diagnostic) { - let args: FxHashMap<DiagnosticArgName, DiagnosticArgValue> = + let args: FxIndexMap<DiagnosticArgName, DiagnosticArgValue> = diag.args().map(|(name, arg)| (name.clone(), arg.clone())).collect(); drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { msgs: diag.messages.clone(), diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 098ea1b793c..760b3f30ee5 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -16,9 +16,10 @@ use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, MemFlags, ModuleCode use rustc_ast::expand::allocator::{global_fn_name, AllocatorKind, ALLOCATOR_METHODS}; use rustc_attr as attr; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::par_map; +use rustc_data_structures::unord::UnordMap; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; @@ -851,6 +852,8 @@ impl CrateInfo { // `compiler_builtins` are always placed last to ensure that they're linked correctly. used_crates.extend(compiler_builtins); + let crates = tcx.crates(()); + let n_crates = crates.len(); let mut info = CrateInfo { target_cpu, crate_types, @@ -862,19 +865,15 @@ impl CrateInfo { is_no_builtins: Default::default(), native_libraries: Default::default(), used_libraries: tcx.native_libraries(LOCAL_CRATE).iter().map(Into::into).collect(), - crate_name: Default::default(), + crate_name: UnordMap::with_capacity(n_crates), used_crates, - used_crate_source: Default::default(), + used_crate_source: UnordMap::with_capacity(n_crates), dependency_formats: tcx.dependency_formats(()).clone(), windows_subsystem, natvis_debugger_visualizers: Default::default(), }; - let crates = tcx.crates(()); - let n_crates = crates.len(); info.native_libraries.reserve(n_crates); - info.crate_name.reserve(n_crates); - info.used_crate_source.reserve(n_crates); for &cnum in crates.iter() { info.native_libraries @@ -901,7 +900,7 @@ impl CrateInfo { // by the compiler, but that's ok because all this stuff is unstable anyway. let target = &tcx.sess.target; if !are_upstream_rust_objects_already_included(tcx.sess) { - let missing_weak_lang_items: FxHashSet<Symbol> = info + let missing_weak_lang_items: FxIndexSet<Symbol> = info .used_crates .iter() .flat_map(|&cnum| tcx.missing_lang_items(cnum)) diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 1afc597a7ef..92f0be541c0 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -24,8 +24,10 @@ extern crate tracing; extern crate rustc_middle; use rustc_ast as ast; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::Lrc; +use rustc_data_structures::unord::UnordMap; use rustc_hir::def_id::CrateNum; use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; @@ -152,16 +154,16 @@ impl From<&cstore::NativeLib> for NativeLib { pub struct CrateInfo { pub target_cpu: String, pub crate_types: Vec<CrateType>, - pub exported_symbols: FxHashMap<CrateType, Vec<String>>, - pub linked_symbols: FxHashMap<CrateType, Vec<(String, SymbolExportKind)>>, + pub exported_symbols: UnordMap<CrateType, Vec<String>>, + pub linked_symbols: FxIndexMap<CrateType, Vec<(String, SymbolExportKind)>>, pub local_crate_name: Symbol, pub compiler_builtins: Option<CrateNum>, pub profiler_runtime: Option<CrateNum>, pub is_no_builtins: FxHashSet<CrateNum>, - pub native_libraries: FxHashMap<CrateNum, Vec<NativeLib>>, - pub crate_name: FxHashMap<CrateNum, Symbol>, + pub native_libraries: FxIndexMap<CrateNum, Vec<NativeLib>>, + pub crate_name: UnordMap<CrateNum, Symbol>, pub used_libraries: Vec<NativeLib>, - pub used_crate_source: FxHashMap<CrateNum, Lrc<CrateSource>>, + pub used_crate_source: UnordMap<CrateNum, Lrc<CrateSource>>, pub used_crates: Vec<CrateNum>, pub dependency_formats: Lrc<Dependencies>, pub windows_subsystem: Option<String>, diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 85ebbb00c5f..4a6d4fe930c 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -313,6 +313,8 @@ const_eval_realloc_or_alloc_with_offset = *[other] {""} } {$ptr} which does not point to the beginning of an object +const_eval_recursive_static = encountered static that tried to initialize itself with itself + const_eval_remainder_by_zero = calculating the remainder with a divisor of zero const_eval_remainder_overflow = diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 80d02589900..935329f1189 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -19,6 +19,7 @@ use crate::interpret::{ErrorHandled, InterpError, InterpErrorInfo, MachineStopTy pub enum ConstEvalErrKind { ConstAccessesMutGlobal, ModifiedGlobal, + RecursiveStatic, AssertFailure(AssertKind<ConstInt>), Panic { msg: Symbol, line: u32, col: u32, file: Symbol }, } @@ -31,13 +32,14 @@ impl MachineStopType for ConstEvalErrKind { ConstAccessesMutGlobal => const_eval_const_accesses_mut_global, ModifiedGlobal => const_eval_modified_global, Panic { .. } => const_eval_panic, + RecursiveStatic => const_eval_recursive_static, AssertFailure(x) => x.diagnostic_message(), } } fn add_args(self: Box<Self>, adder: &mut dyn FnMut(DiagnosticArgName, DiagnosticArgValue)) { use ConstEvalErrKind::*; match *self { - ConstAccessesMutGlobal | ModifiedGlobal => {} + RecursiveStatic | ConstAccessesMutGlobal | ModifiedGlobal => {} AssertFailure(kind) => kind.add_args(adder), Panic { msg, line, col, file } => { adder("msg".into(), msg.into_diagnostic_arg()); diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index c55d899e4d5..7099cdd5a75 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -2,12 +2,12 @@ use either::{Left, Right}; use rustc_hir::def::DefKind; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo}; -use rustc_middle::mir::pretty::write_allocation_bytes; use rustc_middle::mir::{self, ConstAlloc, ConstValue}; use rustc_middle::traits::Reveal; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::def_id::LocalDefId; use rustc_span::Span; use rustc_target::abi::{self, Abi}; @@ -17,8 +17,9 @@ use crate::errors; use crate::errors::ConstEvalError; use crate::interpret::eval_nullary_intrinsic; use crate::interpret::{ - intern_const_alloc_recursive, CtfeValidationMode, GlobalId, Immediate, InternKind, InterpCx, - InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, StackPopCleanup, + create_static_alloc, intern_const_alloc_recursive, take_static_root_alloc, CtfeValidationMode, + GlobalId, Immediate, InternKind, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, + OpTy, RefTracking, StackPopCleanup, }; // Returns a pointer to where the result lives @@ -46,7 +47,21 @@ fn eval_body_using_ecx<'mir, 'tcx>( ); let layout = ecx.layout_of(body.bound_return_ty().instantiate(tcx, cid.instance.args))?; assert!(layout.is_sized()); - let ret = ecx.allocate(layout, MemoryKind::Stack)?; + + let intern_kind = if cid.promoted.is_some() { + InternKind::Promoted + } else { + match tcx.static_mutability(cid.instance.def_id()) { + Some(m) => InternKind::Static(m), + None => InternKind::Constant, + } + }; + + let ret = if let InternKind::Static(_) = intern_kind { + create_static_alloc(ecx, cid.instance.def_id(), layout)? + } else { + ecx.allocate(layout, MemoryKind::Stack)? + }; trace!( "eval_body_using_ecx: pushing stack frame for global: {}{}", @@ -66,14 +81,6 @@ fn eval_body_using_ecx<'mir, 'tcx>( while ecx.step()? {} // Intern the result - let intern_kind = if cid.promoted.is_some() { - InternKind::Promoted - } else { - match tcx.static_mutability(cid.instance.def_id()) { - Some(m) => InternKind::Static(m), - None => InternKind::Constant, - } - }; intern_const_alloc_recursive(ecx, intern_kind, &ret)?; Ok(ret) @@ -250,10 +257,36 @@ pub fn eval_to_const_value_raw_provider<'tcx>( } #[instrument(skip(tcx), level = "debug")] +pub fn eval_static_initializer_provider<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> ::rustc_middle::mir::interpret::EvalStaticInitializerRawResult<'tcx> { + assert!(tcx.is_static(def_id.to_def_id())); + + let instance = ty::Instance::mono(tcx, def_id.to_def_id()); + let cid = rustc_middle::mir::interpret::GlobalId { instance, promoted: None }; + let mut ecx = InterpCx::new( + tcx, + tcx.def_span(def_id), + ty::ParamEnv::reveal_all(), + // Statics (and promoteds inside statics) may access other statics, because unlike consts + // they do not have to behave "as if" they were evaluated at runtime. + CompileTimeInterpreter::new(CanAccessMutGlobal::Yes, CheckAlignment::Error), + ); + let alloc_id = eval_in_interpreter(&mut ecx, cid, true)?.alloc_id; + let alloc = take_static_root_alloc(&mut ecx, alloc_id); + let alloc = tcx.mk_const_alloc(alloc); + Ok(alloc) +} + +#[instrument(skip(tcx), level = "debug")] pub fn eval_to_allocation_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, ) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { + // This shouldn't be used for statics, since statics are conceptually places, + // not values -- so what we do here could break pointer identity. + assert!(key.value.promoted.is_some() || !tcx.is_static(key.value.instance.def_id())); // Const eval always happens in Reveal::All mode in order to be able to use the hidden types of // opaque types. This is needed for trivial things like `size_of`, but also for using associated // types that are not specified in the opaque type. @@ -273,7 +306,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>( let def = cid.instance.def.def_id(); let is_static = tcx.is_static(def); - let ecx = InterpCx::new( + let mut ecx = InterpCx::new( tcx, tcx.def_span(def), key.param_env, @@ -283,11 +316,11 @@ pub fn eval_to_allocation_raw_provider<'tcx>( // so we have to reject reading mutable global memory. CompileTimeInterpreter::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error), ); - eval_in_interpreter(ecx, cid, is_static) + eval_in_interpreter(&mut ecx, cid, is_static) } pub fn eval_in_interpreter<'mir, 'tcx>( - mut ecx: InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, + ecx: &mut InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, cid: GlobalId<'tcx>, is_static: bool, ) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> { @@ -295,7 +328,7 @@ pub fn eval_in_interpreter<'mir, 'tcx>( debug_assert_eq!(is_static, ecx.tcx.static_mutability(cid.instance.def_id()).is_some()); let res = ecx.load_mir(cid.instance.def, cid.promoted); - match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)) { + match res.and_then(|body| eval_body_using_ecx(ecx, cid, body)) { Err(error) => { let (error, backtrace) = error.into_parts(); backtrace.print_backtrace(); @@ -330,8 +363,11 @@ pub fn eval_in_interpreter<'mir, 'tcx>( } Ok(mplace) => { // Since evaluation had no errors, validate the resulting constant. - // This is a separate `try` block to provide more targeted error reporting. + + // Temporarily allow access to the static_root_alloc_id for the purpose of validation. + let static_root_alloc_id = ecx.machine.static_root_alloc_id.take(); let validation = const_validate_mplace(&ecx, &mplace, cid); + ecx.machine.static_root_alloc_id = static_root_alloc_id; let alloc_id = mplace.ptr().provenance.unwrap().alloc_id(); @@ -383,15 +419,9 @@ pub fn const_report_error<'mir, 'tcx>( let ub_note = matches!(error, InterpError::UndefinedBehavior(_)).then(|| {}); - let alloc = ecx.tcx.global_alloc(alloc_id).unwrap_memory().inner(); - let mut bytes = String::new(); - if alloc.size() != abi::Size::ZERO { - bytes = "\n".into(); - // FIXME(translation) there might be pieces that are translatable. - write_allocation_bytes(*ecx.tcx, alloc, &mut bytes, " ").unwrap(); - } - let raw_bytes = - errors::RawBytesNote { size: alloc.size().bytes(), align: alloc.align.bytes(), bytes }; + let bytes = ecx.print_alloc_bytes_for_diagnostics(alloc_id); + let (size, align, _) = ecx.get_alloc_info(alloc_id); + let raw_bytes = errors::RawBytesNote { size: size.bytes(), align: align.bytes(), bytes }; crate::const_eval::report( *ecx.tcx, diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 5019bec388c..2c60ede7975 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -58,6 +58,9 @@ pub struct CompileTimeInterpreter<'mir, 'tcx> { /// Whether to check alignment during evaluation. pub(super) check_alignment: CheckAlignment, + + /// Used to prevent reads from a static's base allocation, as that may allow for self-initialization. + pub(crate) static_root_alloc_id: Option<AllocId>, } #[derive(Copy, Clone)] @@ -91,6 +94,7 @@ impl<'mir, 'tcx> CompileTimeInterpreter<'mir, 'tcx> { stack: Vec::new(), can_access_mut_global, check_alignment, + static_root_alloc_id: None, } } } @@ -746,6 +750,17 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, // Everything else is fine. Ok(()) } + + fn before_alloc_read( + ecx: &InterpCx<'mir, 'tcx, Self>, + alloc_id: AllocId, + ) -> InterpResult<'tcx> { + if Some(alloc_id) == ecx.machine.static_root_alloc_id { + Err(ConstEvalErrKind::RecursiveStatic.into()) + } else { + Ok(()) + } + } } // Please do not add any code below the above `Machine` trait impl. I (oli-obk) plan more cleanups diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 6d470ff162e..a88e130cd4b 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -153,7 +153,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ); } - self.copy_op(src, dest, /*allow_transmute*/ true)?; + self.copy_op_allow_transmute(src, dest)?; } } Ok(()) @@ -441,7 +441,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if src_field.layout.is_1zst() && cast_ty_field.is_1zst() { // Skip 1-ZST fields. } else if src_field.layout.ty == cast_ty_field.ty { - self.copy_op(&src_field, &dst_field, /*allow_transmute*/ false)?; + self.copy_op(&src_field, &dst_field)?; } else { if found_cast_field { span_bug!(self.cur_span(), "unsize_into: more than one field to cast"); diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 8af69220e03..517994d4741 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -899,7 +899,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .local_to_op(self.frame(), mir::RETURN_PLACE, None) .expect("return place should always be live"); let dest = self.frame().return_place.clone(); - let err = self.copy_op(&op, &dest, /*allow_transmute*/ true); + let err = if self.stack().len() == 1 { + // The initializer of constants and statics will get validated separately + // after the constant has been fully evaluated. While we could fall back to the default + // code path, that will cause -Zenforce-validity to cycle on static initializers. + // Reading from a static's memory is not allowed during its evaluation, and will always + // trigger a cycle error. Validation must read from the memory of the current item. + // For Miri this means we do not validate the root frame return value, + // but Miri anyway calls `read_target_isize` on that so separate validation + // is not needed. + self.copy_op_no_dest_validation(&op, &dest) + } else { + self.copy_op_allow_transmute(&op, &dest) + }; trace!("return value: {:?}", self.dump_place(&dest)); // We delay actually short-circuiting on this error until *after* the stack frame is // popped, since we want this error to be attributed to the caller, whose type defines diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 7feac6156bc..959ec2ca865 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -85,6 +85,8 @@ pub enum InternKind { /// /// This *cannot raise an interpreter error*. Doing so is left to validation, which /// tracks where in the value we are and thus can show much better error messages. +/// +/// For `InternKind::Static` the root allocation will not be interned, but must be handled by the caller. #[instrument(level = "debug", skip(ecx))] pub fn intern_const_alloc_recursive< 'mir, @@ -97,12 +99,12 @@ pub fn intern_const_alloc_recursive< ) -> Result<(), ErrorGuaranteed> { // We are interning recursively, and for mutability we are distinguishing the "root" allocation // that we are starting in, and all other allocations that we are encountering recursively. - let (base_mutability, inner_mutability) = match intern_kind { + let (base_mutability, inner_mutability, is_static) = match intern_kind { InternKind::Constant | InternKind::Promoted => { // Completely immutable. Interning anything mutably here can only lead to unsoundness, // since all consts are conceptually independent values but share the same underlying // memory. - (Mutability::Not, Mutability::Not) + (Mutability::Not, Mutability::Not, false) } InternKind::Static(Mutability::Not) => { ( @@ -115,22 +117,31 @@ pub fn intern_const_alloc_recursive< // Inner allocations are never mutable. They can only arise via the "tail // expression" / "outer scope" rule, and we treat them consistently with `const`. Mutability::Not, + true, ) } InternKind::Static(Mutability::Mut) => { // Just make everything mutable. We accept code like // `static mut X = &mut [42]`, so even inner allocations need to be mutable. - (Mutability::Mut, Mutability::Mut) + (Mutability::Mut, Mutability::Mut, true) } }; // Intern the base allocation, and initialize todo list for recursive interning. let base_alloc_id = ret.ptr().provenance.unwrap().alloc_id(); + trace!(?base_alloc_id, ?base_mutability); // First we intern the base allocation, as it requires a different mutability. // This gives us the initial set of nested allocations, which will then all be processed // recursively in the loop below. - let mut todo: Vec<_> = - intern_shallow(ecx, base_alloc_id, base_mutability).unwrap().map(|prov| prov).collect(); + let mut todo: Vec<_> = if is_static { + // Do not steal the root allocation, we need it later for `take_static_root_alloc` + // But still change its mutability to match the requested one. + let alloc = ecx.memory.alloc_map.get_mut(&base_alloc_id).unwrap(); + alloc.1.mutability = base_mutability; + alloc.1.provenance().ptrs().iter().map(|&(_, prov)| prov).collect() + } else { + intern_shallow(ecx, base_alloc_id, base_mutability).unwrap().map(|prov| prov).collect() + }; // We need to distinguish "has just been interned" from "was already in `tcx`", // so we track this in a separate set. let mut just_interned: FxHashSet<_> = std::iter::once(base_alloc_id).collect(); @@ -148,7 +159,17 @@ pub fn intern_const_alloc_recursive< // before validation, and interning doesn't know the type of anything, this means we can't show // better errors. Maybe we should consider doing validation before interning in the future. while let Some(prov) = todo.pop() { + trace!(?prov); let alloc_id = prov.alloc_id(); + + if base_alloc_id == alloc_id && is_static { + // This is a pointer to the static itself. It's ok for a static to refer to itself, + // even mutably. Whether that mutable pointer is legal at all is checked in validation. + // See tests/ui/statics/recursive_interior_mut.rs for how such a situation can occur. + // We also already collected all the nested allocations, so there's no need to do that again. + continue; + } + // Crucially, we check this *before* checking whether the `alloc_id` // has already been interned. The point of this check is to ensure that when // there are multiple pointers to the same allocation, they are *all* immutable. @@ -176,6 +197,7 @@ pub fn intern_const_alloc_recursive< // `&None::<Cell<i32>>` lead to promotion that can produce mutable pointers. We rely // on the promotion analysis not screwing up to ensure that it is sound to intern // promoteds as immutable. + trace!("found bad mutable pointer"); found_bad_mutable_pointer = true; } if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 7991f90b815..f020616f6d8 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -120,7 +120,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let val = self.tcx.span_as_caller_location(span); let val = self.const_val_to_op(val, self.tcx.caller_location_ty(), Some(dest.layout))?; - self.copy_op(&val, dest, /* allow_transmute */ false)?; + self.copy_op(&val, dest)?; } sym::min_align_of_val | sym::size_of_val => { @@ -157,7 +157,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { tcx.const_eval_global_id(self.param_env, gid, Some(tcx.span)) })?; let val = self.const_val_to_op(val, ty, Some(dest.layout))?; - self.copy_op(&val, dest, /*allow_transmute*/ false)?; + self.copy_op(&val, dest)?; } sym::ctpop @@ -391,7 +391,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } else { self.project_index(&input, i)?.into() }; - self.copy_op(&value, &place, /*allow_transmute*/ false)?; + self.copy_op(&value, &place)?; } } sym::simd_extract => { @@ -401,15 +401,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { index < input_len, "index `{index}` must be in bounds of vector with length {input_len}" ); - self.copy_op( - &self.project_index(&input, index)?, - dest, - /*allow_transmute*/ false, - )?; + self.copy_op(&self.project_index(&input, index)?, dest)?; } sym::likely | sym::unlikely | sym::black_box => { // These just return their argument - self.copy_op(&args[0], dest, /*allow_transmute*/ false)?; + self.copy_op(&args[0], dest)?; } sym::raw_eq => { let result = self.raw_eq_intrinsic(&args[0], &args[1])?; diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index b981a1ee2ca..0106ec425bc 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -388,6 +388,8 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { /// Takes read-only access to the allocation so we can keep all the memory read /// operations take `&self`. Use a `RefCell` in `AllocExtra` if you /// need to mutate. + /// + /// This is not invoked for ZST accesses, as no read actually happens. #[inline(always)] fn before_memory_read( _tcx: TyCtxtAt<'tcx>, @@ -399,7 +401,20 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized { Ok(()) } + /// Hook for performing extra checks on any memory read access, + /// that involves an allocation, even ZST reads. + /// + /// Used to prevent statics from self-initializing by reading from their own memory + /// as it is being initialized. + fn before_alloc_read( + _ecx: &InterpCx<'mir, 'tcx, Self>, + _alloc_id: AllocId, + ) -> InterpResult<'tcx> { + Ok(()) + } + /// Hook for performing extra checks on a memory write access. + /// This is not invoked for ZST accesses, as no write actually happens. #[inline(always)] fn before_memory_write( _tcx: TyCtxtAt<'tcx>, diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 4acf4ed893c..3b2208b8caa 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -13,7 +13,7 @@ use std::fmt; use std::ptr; use rustc_ast::Mutability; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_middle::mir::display_allocation; use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; use rustc_target::abi::{Align, HasDataLayout, Size}; @@ -104,13 +104,13 @@ pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> { pub(super) alloc_map: M::MemoryMap, /// Map for "extra" function pointers. - extra_fn_ptr_map: FxHashMap<AllocId, M::ExtraFnVal>, + extra_fn_ptr_map: FxIndexMap<AllocId, M::ExtraFnVal>, /// To be able to compare pointers with null, and to check alignment for accesses /// to ZSTs (where pointers may dangle), we keep track of the size even for allocations /// that do not exist any more. // FIXME: this should not be public, but interning currently needs access to it - pub(super) dead_alloc_map: FxHashMap<AllocId, (Size, Align)>, + pub(super) dead_alloc_map: FxIndexMap<AllocId, (Size, Align)>, } /// A reference to some allocation that was already bounds-checked for the given region @@ -135,8 +135,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { pub fn new() -> Self { Memory { alloc_map: M::MemoryMap::default(), - extra_fn_ptr_map: FxHashMap::default(), - dead_alloc_map: FxHashMap::default(), + extra_fn_ptr_map: FxIndexMap::default(), + dead_alloc_map: FxIndexMap::default(), } } @@ -624,19 +624,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { size, CheckInAllocMsg::MemoryAccessTest, |alloc_id, offset, prov| { + // We want to call the hook on *all* accesses that involve an AllocId, + // including zero-sized accesses. That means we have to do it here + // rather than below in the `Some` branch. + M::before_alloc_read(self, alloc_id)?; let alloc = self.get_alloc_raw(alloc_id)?; Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc))) }, )?; + if let Some((alloc_id, offset, prov, alloc)) = ptr_and_alloc { let range = alloc_range(offset, size); M::before_memory_read(self.tcx, &self.machine, &alloc.extra, (alloc_id, prov), range)?; Ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id })) } else { - // Even in this branch we have to be sure that we actually access the allocation, in - // order to ensure that `static FOO: Type = FOO;` causes a cycle error instead of - // magically pulling *any* ZST value from the ether. However, the `get_raw` above is - // always called when `ptr` has an `AllocId`. Ok(None) } } @@ -855,6 +856,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { DumpAllocs { ecx: self, allocs } } + /// Print the allocation's bytes, without any nested allocations. + pub fn print_alloc_bytes_for_diagnostics(&self, id: AllocId) -> String { + // Using the "raw" access to avoid the `before_alloc_read` hook, we specifically + // want to be able to read all memory for diagnostics, even if that is cyclic. + let alloc = self.get_alloc_raw(id).unwrap(); + let mut bytes = String::new(); + if alloc.size() != Size::ZERO { + bytes = "\n".into(); + // FIXME(translation) there might be pieces that are translatable. + rustc_middle::mir::pretty::write_allocation_bytes(*self.tcx, alloc, &mut bytes, " ") + .unwrap(); + } + bytes + } + /// Find leaked allocations. Allocations reachable from `static_roots` or a `Global` allocation /// are not considered leaked, as well as leaks whose kind's `may_leak()` returns true. pub fn find_leaked_allocations( diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index c1b6ce4eb4e..a15e52d07e6 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -39,4 +39,5 @@ use self::{ }; pub(crate) use self::intrinsics::eval_nullary_intrinsic; +pub(crate) use self::util::{create_static_alloc, take_static_root_alloc}; use eval_context::{from_known_layout, mir_assign_valid_types}; diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 03d1dc9fd3d..6e987784ff9 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -759,14 +759,57 @@ where } /// Copies the data from an operand to a place. + /// The layouts of the `src` and `dest` may disagree. + /// Does not perform validation of the destination. + /// The only known use case for this function is checking the return + /// value of a static during stack frame popping. + #[inline(always)] + pub(super) fn copy_op_no_dest_validation( + &mut self, + src: &impl Readable<'tcx, M::Provenance>, + dest: &impl Writeable<'tcx, M::Provenance>, + ) -> InterpResult<'tcx> { + self.copy_op_inner( + src, dest, /* allow_transmute */ true, /* validate_dest */ false, + ) + } + + /// Copies the data from an operand to a place. + /// The layouts of the `src` and `dest` may disagree. + #[inline(always)] + pub fn copy_op_allow_transmute( + &mut self, + src: &impl Readable<'tcx, M::Provenance>, + dest: &impl Writeable<'tcx, M::Provenance>, + ) -> InterpResult<'tcx> { + self.copy_op_inner( + src, dest, /* allow_transmute */ true, /* validate_dest */ true, + ) + } + + /// Copies the data from an operand to a place. + /// `src` and `dest` must have the same layout and the copied value will be validated. + #[inline(always)] + pub fn copy_op( + &mut self, + src: &impl Readable<'tcx, M::Provenance>, + dest: &impl Writeable<'tcx, M::Provenance>, + ) -> InterpResult<'tcx> { + self.copy_op_inner( + src, dest, /* allow_transmute */ false, /* validate_dest */ true, + ) + } + + /// Copies the data from an operand to a place. /// `allow_transmute` indicates whether the layouts may disagree. #[inline(always)] #[instrument(skip(self), level = "debug")] - pub fn copy_op( + fn copy_op_inner( &mut self, src: &impl Readable<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>, allow_transmute: bool, + validate_dest: bool, ) -> InterpResult<'tcx> { // Generally for transmutation, data must be valid both at the old and new type. // But if the types are the same, the 2nd validation below suffices. @@ -777,7 +820,7 @@ where // Do the actual copy. self.copy_op_no_validate(src, dest, allow_transmute)?; - if M::enforce_validity(self, dest.layout()) { + if validate_dest && M::enforce_validity(self, dest.layout()) { // Data got changed, better make sure it matches the type! self.validate_operand(&dest.to_op(self)?)?; } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 23f3d7eb67d..d4c96f4573d 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -151,12 +151,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Use(ref operand) => { // Avoid recomputing the layout let op = self.eval_operand(operand, Some(dest.layout))?; - self.copy_op(&op, &dest, /*allow_transmute*/ false)?; + self.copy_op(&op, &dest)?; } CopyForDeref(place) => { let op = self.eval_place_to_op(place, Some(dest.layout))?; - self.copy_op(&op, &dest, /* allow_transmute*/ false)?; + self.copy_op(&op, &dest)?; } BinaryOp(bin_op, box (ref left, ref right)) => { @@ -316,7 +316,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let field_index = active_field_index.unwrap_or(field_index); let field_dest = self.project_field(&variant_dest, field_index.as_usize())?; let op = self.eval_operand(operand, Some(field_dest.layout))?; - self.copy_op(&op, &field_dest, /*allow_transmute*/ false)?; + self.copy_op(&op, &field_dest)?; } self.write_discriminant(variant_index, dest) } @@ -339,7 +339,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } else { // Write the src to the first element. let first = self.project_index(&dest, 0)?; - self.copy_op(&src, &first, /*allow_transmute*/ false)?; + self.copy_op(&src, &first)?; // This is performance-sensitive code for big static/const arrays! So we // avoid writing each operand individually and instead just make many copies diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 4037220e5ed..b2207c3d310 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -481,7 +481,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // FIXME: Depending on the PassMode, this should reset some padding to uninitialized. (This // is true for all `copy_op`, but there are a lot of special cases for argument passing // specifically.) - self.copy_op(&caller_arg_copy, &callee_arg, /*allow_transmute*/ true)?; + self.copy_op_allow_transmute(&caller_arg_copy, &callee_arg)?; // If this was an in-place pass, protect the place it comes from for the duration of the call. if let FnArg::InPlace(place) = caller_arg { M::protect_in_place_function_argument(self, place)?; diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 3a9ee904734..2a13671a829 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -1,9 +1,15 @@ -use rustc_middle::mir::interpret::InterpResult; +use crate::const_eval::CompileTimeEvalContext; +use crate::interpret::{MemPlaceMeta, MemoryKind}; +use rustc_middle::mir::interpret::{AllocId, Allocation, InterpResult, Pointer}; +use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; +use rustc_span::def_id::DefId; use std::ops::ControlFlow; +use super::MPlaceTy; + /// Checks whether a type contains generic parameters which must be instantiated. /// /// In case it does, returns a `TooGeneric` const eval error. Note that due to polymorphization @@ -73,3 +79,23 @@ where Ok(()) } } + +pub(crate) fn take_static_root_alloc<'mir, 'tcx: 'mir>( + ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, + alloc_id: AllocId, +) -> Allocation { + ecx.memory.alloc_map.swap_remove(&alloc_id).unwrap().1 +} + +pub(crate) fn create_static_alloc<'mir, 'tcx: 'mir>( + ecx: &mut CompileTimeEvalContext<'mir, 'tcx>, + static_def_id: DefId, + layout: TyAndLayout<'tcx>, +) -> InterpResult<'tcx, MPlaceTy<'tcx>> { + let alloc = Allocation::try_uninit(layout.size, layout.align.abi)?; + let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id); + assert_eq!(ecx.machine.static_root_alloc_id, None); + ecx.machine.static_root_alloc_id = Some(alloc_id); + assert!(ecx.memory.alloc_map.insert(alloc_id, (MemoryKind::Stack, alloc)).is_none()); + Ok(ecx.ptr_with_meta_to_mplace(Pointer::from(alloc_id).into(), MemPlaceMeta::None, layout)) +} diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index eb9f3fee165..08a2e38bfa1 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -27,9 +27,9 @@ use rustc_target::abi::{ use std::hash::Hash; use super::{ - format_interp_error, AllocId, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, - InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Pointer, Projectable, Scalar, - ValueVisitor, + format_interp_error, machine::AllocMap, AllocId, CheckInAllocMsg, GlobalAlloc, ImmTy, + Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Pointer, Projectable, + Scalar, ValueVisitor, }; // for the validation errors @@ -712,11 +712,14 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' fn in_mutable_memory(&self, op: &OpTy<'tcx, M::Provenance>) -> bool { if let Some(mplace) = op.as_mplace_or_imm().left() { if let Some(alloc_id) = mplace.ptr().provenance.and_then(|p| p.get_alloc_id()) { - if self.ecx.tcx.global_alloc(alloc_id).unwrap_memory().inner().mutability - == Mutability::Mut - { - return true; - } + let mutability = match self.ecx.tcx.global_alloc(alloc_id) { + GlobalAlloc::Static(_) => { + self.ecx.memory.alloc_map.get(alloc_id).unwrap().1.mutability + } + GlobalAlloc::Memory(alloc) => alloc.inner().mutability, + _ => span_bug!(self.ecx.tcx.span, "not a memory allocation"), + }; + return mutability == Mutability::Mut; } } false diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 839cfd8d85a..e33f374c359 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -40,6 +40,7 @@ pub fn provide(providers: &mut Providers) { const_eval::provide(providers); providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider; providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider; + providers.eval_static_initializer = const_eval::eval_static_initializer_provider; providers.hooks.const_caller_location = util::caller_location::const_caller_location_provider; providers.eval_to_valtree = |tcx, param_env_and_value| { let (param_env, raw) = param_env_and_value.into_parts(); diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index 907c866b3ed..a99e2062039 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -524,6 +524,11 @@ impl<K: Eq + Hash, V> UnordMap<K, V> { UnordItems(self.inner.into_iter()) } + #[inline] + pub fn keys(&self) -> UnordItems<&K, impl Iterator<Item = &K>> { + UnordItems(self.inner.keys()) + } + /// Returns the entries of this map in stable sort order (as defined by `ToStableHashKey`). /// /// The `cache_sort_key` parameter controls if [slice::sort_by_cached_key] or diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index b14a12175c7..91a8ec3b794 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -3,7 +3,7 @@ use crate::{ CodeSuggestion, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, ErrCode, Level, MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle, }; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; +use rustc_data_structures::fx::FxIndexMap; use rustc_error_messages::fluent_value_from_str_list_sep_by_and; use rustc_error_messages::FluentValue; use rustc_lint_defs::{Applicability, LintExpectationId}; @@ -105,7 +105,7 @@ pub struct Diagnostic { pub span: MultiSpan, pub children: Vec<SubDiagnostic>, pub suggestions: Result<Vec<CodeSuggestion>, SuggestionsDisabled>, - args: FxHashMap<DiagnosticArgName, DiagnosticArgValue>, + args: FxIndexMap<DiagnosticArgName, DiagnosticArgValue>, /// This is not used for highlighting or rendering any error message. Rather, it can be used /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of @@ -898,9 +898,6 @@ impl Diagnostic { self } - // Exact iteration order of diagnostic arguments shouldn't make a difference to output because - // they're only used in interpolation. - #[allow(rustc::potential_query_instability)] pub fn args(&self) -> impl Iterator<Item = DiagnosticArg<'_>> { self.args.iter() } @@ -914,7 +911,7 @@ impl Diagnostic { self } - pub fn replace_args(&mut self, args: FxHashMap<DiagnosticArgName, DiagnosticArgValue>) { + pub fn replace_args(&mut self, args: FxIndexMap<DiagnosticArgName, DiagnosticArgValue>) { self.args = args; } diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 38c6661377b..afb1b854e72 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1743,9 +1743,17 @@ impl HumanEmitter { buffer.append(0, level.to_str(), Style::Level(*level)); buffer.append(0, ": ", Style::HeaderMsg); + let mut msg = vec![(suggestion.msg.to_owned(), Style::NoStyle)]; + if suggestions + .iter() + .take(MAX_SUGGESTIONS) + .any(|(_, _, _, only_capitalization)| *only_capitalization) + { + msg.push((" (notice the capitalization difference)".into(), Style::NoStyle)); + } self.msgs_to_buffer( &mut buffer, - &[(suggestion.msg.to_owned(), Style::NoStyle)], + &msg, args, max_line_num_len, "suggestion", @@ -1754,12 +1762,8 @@ impl HumanEmitter { let mut row_num = 2; draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1); - let mut notice_capitalization = false; - for (complete, parts, highlights, only_capitalization) in - suggestions.iter().take(MAX_SUGGESTIONS) - { + for (complete, parts, highlights, _) in suggestions.iter().take(MAX_SUGGESTIONS) { debug!(?complete, ?parts, ?highlights); - notice_capitalization |= only_capitalization; let has_deletion = parts.iter().any(|p| p.is_deletion(sm)); let is_multiline = complete.lines().count() > 1; @@ -2058,9 +2062,6 @@ impl HumanEmitter { let others = suggestions.len() - MAX_SUGGESTIONS; let msg = format!("and {} other candidate{}", others, pluralize!(others)); buffer.puts(row_num, max_line_num_len + 3, &msg, Style::NoStyle); - } else if notice_capitalization { - let msg = "notice the capitalization difference"; - buffer.puts(row_num, max_line_num_len + 3, msg, Style::NoStyle); } emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?; Ok(()) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index d876f28040d..b0db3545ae7 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -320,7 +320,9 @@ impl CodeSuggestion { // We need to keep track of the difference between the existing code and the added // or deleted code in order to point at the correct column *after* substitution. let mut acc = 0; + let mut only_capitalization = false; for part in &substitution.parts { + only_capitalization |= is_case_difference(sm, &part.snippet, part.span); let cur_lo = sm.lookup_char_pos(part.span.lo()); if prev_hi.line == cur_lo.line { let mut count = @@ -393,7 +395,6 @@ impl CodeSuggestion { } } highlights.push(std::mem::take(&mut line_highlight)); - let only_capitalization = is_case_difference(sm, &buf, bounding_span); // if the replacement already ends with a newline, don't print the next line if !buf.ends_with('\n') { push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None); diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index cfeb31fc4c8..09144523658 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -567,10 +567,13 @@ impl DummyResult { } /// A plain dummy type. - pub fn raw_ty(sp: Span, is_error: bool) -> P<ast::Ty> { + pub fn raw_ty(sp: Span) -> P<ast::Ty> { + // FIXME(nnethercote): you might expect `ast::TyKind::Dummy` to be used here, but some + // values produced here end up being lowered to HIR, which `ast::TyKind::Dummy` does not + // support, so we use an empty tuple instead. P(ast::Ty { id: ast::DUMMY_NODE_ID, - kind: if is_error { ast::TyKind::Err } else { ast::TyKind::Tup(ThinVec::new()) }, + kind: ast::TyKind::Tup(ThinVec::new()), span: sp, tokens: None, }) @@ -611,7 +614,7 @@ impl MacResult for DummyResult { } fn make_ty(self: Box<DummyResult>) -> Option<P<ast::Ty>> { - Some(DummyResult::raw_ty(self.span, self.is_error)) + Some(DummyResult::raw_ty(self.span)) } fn make_arms(self: Box<DummyResult>) -> Option<SmallVec<[ast::Arm; 1]>> { @@ -1266,7 +1269,7 @@ pub fn expr_to_spanned_string<'a>( ); Some((err, true)) } - Ok(ast::LitKind::Err) => None, + Ok(ast::LitKind::Err(_)) => None, Err(err) => { report_lit_error(&cx.sess.parse_sess, err, token_lit, expr.span); None diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 3a78bd94505..8f31b5801da 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -10,7 +10,7 @@ use rustc_ast::util::literal::escape_byte_str_symbol; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; -use rustc_errors::{MultiSpan, PResult}; +use rustc_errors::{ErrorGuaranteed, MultiSpan, PResult}; use rustc_parse::lexer::nfc_normalize; use rustc_parse::parse_stream_from_source_str; use rustc_session::parse::ParseSess; @@ -63,7 +63,12 @@ impl FromInternal<token::LitKind> for LitKind { token::ByteStrRaw(n) => LitKind::ByteStrRaw(n), token::CStr => LitKind::CStr, token::CStrRaw(n) => LitKind::CStrRaw(n), - token::Err => LitKind::Err, + token::Err(_guar) => { + // This is the only place a `pm::bridge::LitKind::ErrWithGuar` + // is constructed. Note that an `ErrorGuaranteed` is available, + // as required. See the comment in `to_internal`. + LitKind::ErrWithGuar + } token::Bool => unreachable!(), } } @@ -82,7 +87,16 @@ impl ToInternal<token::LitKind> for LitKind { LitKind::ByteStrRaw(n) => token::ByteStrRaw(n), LitKind::CStr => token::CStr, LitKind::CStrRaw(n) => token::CStrRaw(n), - LitKind::Err => token::Err, + LitKind::ErrWithGuar => { + // This is annoying but valid. `LitKind::ErrWithGuar` would + // have an `ErrorGuaranteed` except that type isn't available + // in that crate. So we have to fake one. And we don't want to + // use a delayed bug because there might be lots of these, + // which would be expensive. + #[allow(deprecated)] + let guar = ErrorGuaranteed::unchecked_error_guaranteed(); + token::Err(guar) + } } } } @@ -477,7 +491,7 @@ impl server::FreeFunctions for Rustc<'_, '_> { | token::LitKind::ByteStrRaw(_) | token::LitKind::CStr | token::LitKind::CStrRaw(_) - | token::LitKind::Err => return Err(()), + | token::LitKind::Err(_) => return Err(()), token::LitKind::Integer | token::LitKind::Float => {} } diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs index 7157382c883..dab1e2d5253 100644 --- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs +++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -241,7 +241,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ { binding: &ConvertedBinding<'_, 'tcx>, bounds: &mut Bounds<'tcx>, speculative: bool, - dup_bindings: &mut FxHashMap<DefId, Span>, + dup_bindings: &mut FxIndexMap<DefId, Span>, path_span: Span, only_self_bounds: OnlySelfBounds, ) -> Result<(), ErrorGuaranteed> { diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index 3c64b102bae..ea8d364bba6 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -5,7 +5,7 @@ use crate::errors::{ }; use crate::fluent_generated as fluent; use crate::traits::error_reporting::report_object_safety_error; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordMap; use rustc_errors::{ @@ -806,7 +806,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if suggestions.len() != 1 || already_has_generics_args_suggestion { // We don't need this label if there's an inline suggestion, show otherwise. for (span, assoc_items) in &associated_types { - let mut names: FxHashMap<_, usize> = FxHashMap::default(); + let mut names: FxIndexMap<_, usize> = FxIndexMap::default(); for item in assoc_items { types_count += 1; *names.entry(item.name).or_insert(0) += 1; diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 98a27c5ed20..94c49453cdc 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -16,7 +16,7 @@ use crate::errors::AmbiguousLifetimeBound; use crate::middle::resolve_bound_vars as rbv; use crate::require_c_abi_if_c_variadic; use rustc_ast::TraitObjectSyntax; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::{ codes::*, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan, @@ -752,7 +752,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!(?poly_trait_ref, ?assoc_bindings); bounds.push_trait_bound(tcx, poly_trait_ref, span, polarity); - let mut dup_bindings = FxHashMap::default(); + let mut dup_bindings = FxIndexMap::default(); for binding in &assoc_bindings { // Don't register additional associated type bounds for negative bounds, // since we should have emitten an error for them earlier, and they will diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index b693d7201c1..488d16f18da 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1367,7 +1367,7 @@ fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalD // `Sized` bounds. If they came last for example, this would break `Trait + /*elab*/Sized` // since it would overwrite the span of the user-written bound. This could be fixed by // folding the spans with `Span::to` which requires a bit of effort I think. - .collect::<FxHashMap<_, _>>() + .collect::<FxIndexMap<_, _>>() }); let mut params_used = BitSet::new_empty(generics.params.len()); diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 69a02b73a79..1dd27f0cc53 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -1,7 +1,7 @@ use super::potentially_plural_count; use crate::errors::{LifetimesOrBoundsMismatchOnTrait, MethodShouldReturnFuture}; use hir::def_id::{DefId, DefIdMap, LocalDefId}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -392,7 +392,7 @@ fn compare_method_predicate_entailment<'tcx>( struct RemapLateBound<'a, 'tcx> { tcx: TyCtxt<'tcx>, - mapping: &'a FxHashMap<ty::BoundRegionKind, ty::BoundRegionKind>, + mapping: &'a FxIndexMap<ty::BoundRegionKind, ty::BoundRegionKind>, } impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RemapLateBound<'_, 'tcx> { @@ -553,7 +553,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // prove below that the hidden types are well formed. let universe = infcx.create_next_universe(); let mut idx = 0; - let mapping: FxHashMap<_, _> = collector + let mapping: FxIndexMap<_, _> = collector .types .iter() .map(|(_, &(ty, _))| { @@ -690,7 +690,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // contains `def_id`'s early-bound regions. let id_args = GenericArgs::identity_for_item(tcx, def_id); debug!(?id_args, ?args); - let map: FxHashMap<_, _> = std::iter::zip(args, id_args) + let map: FxIndexMap<_, _> = std::iter::zip(args, id_args) .skip(tcx.generics_of(trait_m.def_id).count()) .filter_map(|(a, b)| Some((a.as_region()?, b.as_region()?))) .collect(); @@ -766,7 +766,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( struct ImplTraitInTraitCollector<'a, 'tcx> { ocx: &'a ObligationCtxt<'a, 'tcx>, - types: FxHashMap<DefId, (Ty<'tcx>, ty::GenericArgsRef<'tcx>)>, + types: FxIndexMap<DefId, (Ty<'tcx>, ty::GenericArgsRef<'tcx>)>, span: Span, param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, @@ -779,7 +779,7 @@ impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> { param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, ) -> Self { - ImplTraitInTraitCollector { ocx, types: FxHashMap::default(), span, param_env, body_id } + ImplTraitInTraitCollector { ocx, types: FxIndexMap::default(), span, param_env, body_id } } } @@ -838,7 +838,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> { struct RemapHiddenTyRegions<'tcx> { tcx: TyCtxt<'tcx>, - map: FxHashMap<ty::Region<'tcx>, ty::Region<'tcx>>, + map: FxIndexMap<ty::Region<'tcx>, ty::Region<'tcx>>, num_trait_args: usize, num_impl_args: usize, def_id: DefId, diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 2f8e065df33..8884c218d05 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -76,7 +76,7 @@ pub use check::check_abi; use std::num::NonZeroU32; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::ErrorGuaranteed; use rustc_errors::{pluralize, struct_span_code_err, Diagnostic, DiagnosticBuilder}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -307,7 +307,7 @@ fn bounds_from_generic_predicates<'tcx>( tcx: TyCtxt<'tcx>, predicates: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>, ) -> (String, String) { - let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default(); + let mut types: FxIndexMap<Ty<'tcx>, Vec<DefId>> = FxIndexMap::default(); let mut projections = vec![]; for (predicate, _) in predicates { debug!("predicate {:?}", predicate); diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index 951440d6a2d..9e1e884d976 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -1,4 +1,5 @@ -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::IndexEntry; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -9,7 +10,6 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{ErrorGuaranteed, Symbol}; use rustc_trait_selection::traits::{self, SkipLeakCheck}; use smallvec::SmallVec; -use std::collections::hash_map::Entry; pub fn crate_inherent_impls_overlap_check(tcx: TyCtxt<'_>, (): ()) -> Result<(), ErrorGuaranteed> { let mut inherent_overlap_checker = InherentOverlapChecker { tcx }; @@ -63,7 +63,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { fn check_for_duplicate_items_in_impl(&self, impl_: DefId) -> Result<(), ErrorGuaranteed> { let impl_items = self.tcx.associated_items(impl_); - let mut seen_items = FxHashMap::default(); + let mut seen_items = FxIndexMap::default(); let mut res = Ok(()); for impl_item in impl_items.in_definition_order() { let span = self.tcx.def_span(impl_item.def_id); @@ -71,7 +71,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { let norm_ident = ident.normalize_to_macros_2_0(); match seen_items.entry(norm_ident) { - Entry::Occupied(entry) => { + IndexEntry::Occupied(entry) => { let former = entry.get(); res = Err(struct_span_code_err!( self.tcx.dcx(), @@ -84,7 +84,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { .with_span_label(*former, format!("other definition for `{ident}`")) .emit()); } - Entry::Vacant(entry) => { + IndexEntry::Vacant(entry) => { entry.insert(span); } } @@ -216,7 +216,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { } let mut connected_regions: IndexVec<RegionId, _> = Default::default(); // Reverse map from the Symbol to the connected region id. - let mut connected_region_ids = FxHashMap::default(); + let mut connected_region_ids = FxIndexMap::default(); for (i, &(&_impl_def_id, impl_items)) in impls_items.iter().enumerate() { if impl_items.len() == 0 { @@ -228,7 +228,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { .in_definition_order() .filter_map(|item| { let entry = connected_region_ids.entry(item.name); - if let Entry::Occupied(e) = &entry { + if let IndexEntry::Occupied(e) = &entry { Some(*e.get()) } else { idents_to_add.push(item.name); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 4891dae47c6..41420b9caec 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -15,7 +15,7 @@ //! crate as a kind of pass. This should eventually be factored away. use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::UnordMap; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey}; use rustc_hir as hir; @@ -834,12 +834,12 @@ impl From<NestedSpan> for FieldDeclSpan { struct FieldUniquenessCheckContext<'tcx> { tcx: TyCtxt<'tcx>, - seen_fields: FxHashMap<Ident, FieldDeclSpan>, + seen_fields: FxIndexMap<Ident, FieldDeclSpan>, } impl<'tcx> FieldUniquenessCheckContext<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> Self { - Self { tcx, seen_fields: FxHashMap::default() } + Self { tcx, seen_fields: FxIndexMap::default() } } /// Check if a given field `ident` declared at `field_decl` has been declared elsewhere before. diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 1cd77050217..33092825e89 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -178,8 +178,9 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { let _ = tcx.ensure().coherent_trait(trait_def_id); } // these queries are executed for side-effects (error reporting): - res.and(tcx.ensure().crate_inherent_impls(())) - .and(tcx.ensure().crate_inherent_impls_overlap_check(())) + let _ = tcx.ensure().crate_inherent_impls(()); + let _ = tcx.ensure().crate_inherent_impls_overlap_check(()); + res })?; if tcx.features().rustc_attrs { diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index a7fca41f86a..1de7a0f7bc7 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, OutlivesPredicate, TyCtxt}; @@ -6,12 +6,12 @@ use super::utils::*; #[derive(Debug)] pub struct ExplicitPredicatesMap<'tcx> { - map: FxHashMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>, + map: FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>, } impl<'tcx> ExplicitPredicatesMap<'tcx> { pub fn new() -> ExplicitPredicatesMap<'tcx> { - ExplicitPredicatesMap { map: FxHashMap::default() } + ExplicitPredicatesMap { map: FxIndexMap::default() } } pub(crate) fn explicit_predicates_of( diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs index 0c0dbbe7ad9..e6c582667ba 100644 --- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs +++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -15,12 +15,12 @@ use super::utils::*; /// now be filled with inferred predicates. pub(super) fn infer_predicates( tcx: TyCtxt<'_>, -) -> FxHashMap<DefId, ty::EarlyBinder<RequiredPredicates<'_>>> { +) -> FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'_>>> { debug!("infer_predicates"); let mut explicit_map = ExplicitPredicatesMap::new(); - let mut global_inferred_outlives = FxHashMap::default(); + let mut global_inferred_outlives = FxIndexMap::default(); // If new predicates were added then we need to re-calculate // all crates since there could be new implied predicates. @@ -101,7 +101,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, - global_inferred_outlives: &FxHashMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>, + global_inferred_outlives: &FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>, required_predicates: &mut RequiredPredicates<'tcx>, explicit_map: &mut ExplicitPredicatesMap<'tcx>, ) { @@ -322,7 +322,7 @@ fn check_inferred_predicates<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, args: ty::GenericArgsRef<'tcx>, - global_inferred_outlives: &FxHashMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>, + global_inferred_outlives: &FxIndexMap<DefId, ty::EarlyBinder<RequiredPredicates<'tcx>>>, required_predicates: &mut RequiredPredicates<'tcx>, ) { // Load the current set of inferred and explicit predicates from `global_inferred_outlives` diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 19bdeab409b..949fbb65dbd 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -24,6 +24,7 @@ use crate::{ use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_data_structures::unord::UnordMap; use rustc_errors::{ codes::*, pluralize, struct_span_code_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrCode, ErrorGuaranteed, StashKey, @@ -1709,7 +1710,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .fields .iter_enumerated() .map(|(i, field)| (field.ident(tcx).normalize_to_macros_2_0(), (i, field))) - .collect::<FxHashMap<_, _>>(); + .collect::<UnordMap<_, _>>(); let mut seen_fields = FxHashMap::default(); @@ -1954,18 +1955,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, adt_ty: Ty<'tcx>, span: Span, - remaining_fields: FxHashMap<Ident, (FieldIdx, &ty::FieldDef)>, + remaining_fields: UnordMap<Ident, (FieldIdx, &ty::FieldDef)>, variant: &'tcx ty::VariantDef, ast_fields: &'tcx [hir::ExprField<'tcx>], args: GenericArgsRef<'tcx>, ) { let len = remaining_fields.len(); - #[allow(rustc::potential_query_instability)] - let mut displayable_field_names: Vec<&str> = - remaining_fields.keys().map(|ident| ident.as_str()).collect(); - // sorting &str primitives here, sort_unstable is ok - displayable_field_names.sort_unstable(); + let displayable_field_names: Vec<&str> = + remaining_fields.items().map(|(ident, _)| ident.as_str()).into_sorted_stable_ord(); let mut truncated_fields_error = String::new(); let remaining_fields_names = match &displayable_field_names[..] { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 65b8505c090..3bce8a1dd45 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1319,7 +1319,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, Some(lit.span))) .skip_binder(), ), - ast::LitKind::Err => Ty::new_misc_error(tcx), + ast::LitKind::Err(guar) => Ty::new_error(tcx, guar), } } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 50b2bf7da15..60d13f02ad7 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -306,11 +306,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { // Gate identifiers containing invalid Unicode codepoints that were recovered during lexing. sess.parse_sess.bad_unicode_identifiers.with_lock(|identifiers| { - // We will soon sort, so the initial order does not matter. - #[allow(rustc::potential_query_instability)] - let mut identifiers: Vec<_> = identifiers.drain().collect(); - identifiers.sort_by_key(|&(key, _)| key); - for (ident, mut spans) in identifiers.into_iter() { + for (ident, mut spans) in identifiers.drain(..) { spans.sort(); if ident == sym::ferris { let first_span = spans[0]; diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 30f05444d21..5e27a0ed818 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -18,8 +18,9 @@ use self::TargetLint::*; use crate::levels::LintLevelsBuilder; use crate::passes::{EarlyLintPassObject, LateLintPassObject}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync; +use rustc_data_structures::unord::UnordMap; use rustc_errors::{DecorateLint, DiagnosticBuilder, DiagnosticMessage, MultiSpan}; use rustc_feature::Features; use rustc_hir as hir; @@ -69,10 +70,10 @@ pub struct LintStore { pub late_module_passes: Vec<Box<LateLintPassFactory>>, /// Lints indexed by name. - by_name: FxHashMap<String, TargetLint>, + by_name: UnordMap<String, TargetLint>, /// Map of registered lint groups to what lints they expand to. - lint_groups: FxHashMap<&'static str, LintGroup>, + lint_groups: FxIndexMap<&'static str, LintGroup>, } impl LintStoreMarker for LintStore {} @@ -152,8 +153,6 @@ impl LintStore { pub fn get_lint_groups<'t>( &'t self, ) -> impl Iterator<Item = (&'static str, Vec<LintId>, bool)> + 't { - // This function is not used in a way which observes the order of lints. - #[allow(rustc::potential_query_instability)] self.lint_groups .iter() .filter(|(_, LintGroup { depr, .. })| { @@ -326,9 +325,11 @@ impl LintStore { /// True if this symbol represents a lint group name. pub fn is_lint_group(&self, lint_name: Symbol) -> bool { - #[allow(rustc::potential_query_instability)] - let lint_groups = self.lint_groups.keys().collect::<Vec<_>>(); - debug!("is_lint_group(lint_name={:?}, lint_groups={:?})", lint_name, lint_groups); + debug!( + "is_lint_group(lint_name={:?}, lint_groups={:?})", + lint_name, + self.lint_groups.keys().collect::<Vec<_>>() + ); let lint_name_str = lint_name.as_str(); self.lint_groups.contains_key(lint_name_str) || { let warnings_name_str = crate::WARNINGS.name_lower(); @@ -372,12 +373,9 @@ impl LintStore { None => { // 1. The tool is currently running, so this lint really doesn't exist. // FIXME: should this handle tools that never register a lint, like rustfmt? - #[allow(rustc::potential_query_instability)] - let lints = self.by_name.keys().collect::<Vec<_>>(); - debug!("lints={:?}", lints); + debug!("lints={:?}", self.by_name); let tool_prefix = format!("{tool_name}::"); - #[allow(rustc::potential_query_instability)] return if self.by_name.keys().any(|lint| lint.starts_with(&tool_prefix)) { self.no_lint_suggestion(&complete_name, tool_name.as_str()) } else { diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index f78b32ce5e7..e112cd6915c 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -179,7 +179,6 @@ impl EarlyLintPass for NonAsciiIdents { #[allow(rustc::potential_query_instability)] let mut symbols: Vec<_> = symbols.iter().collect(); symbols.sort_by_key(|k| k.1); - for (symbol, &sp) in symbols.iter() { let symbol_str = symbol.as_str(); if symbol_str.is_ascii() { diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index 519ab8bd50f..f386db9d8db 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -207,6 +207,13 @@ fn is_cast_to_bigger_memory_layout<'tcx>( } let from_layout = cx.layout_of(*inner_start_ty).ok()?; + + // if the type isn't sized, we bail out, instead of potentially giving + // the user a meaningless warning. + if from_layout.is_unsized() { + return None; + } + let alloc_layout = cx.layout_of(alloc_ty).ok()?; let to_layout = cx.layout_of(*inner_end_ty).ok()?; diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index d79d4b226a5..178bfc3a380 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -250,6 +250,15 @@ provide! { tcx, def_id, other, cdata, fn_arg_names => { table } coroutine_kind => { table_direct } coroutine_for_closure => { table } + eval_static_initializer => { + Ok(cdata + .root + .tables + .eval_static_initializer + .get(cdata, def_id.index) + .map(|lazy| lazy.decode((cdata, tcx))) + .unwrap_or_else(|| panic!("{def_id:?} does not have eval_static_initializer"))) + } trait_def => { table } deduced_param_attrs => { table } is_type_alias_impl_trait => { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 4a24c038f7a..6f908f7752a 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1045,11 +1045,9 @@ fn should_encode_mir( (true, mir_opt_base) } // Constants - DefKind::AnonConst - | DefKind::InlineConst - | DefKind::AssocConst - | DefKind::Static(..) - | DefKind::Const => (true, false), + DefKind::AnonConst | DefKind::InlineConst | DefKind::AssocConst | DefKind::Const => { + (true, false) + } // Coroutines require optimized MIR to compute layout. DefKind::Closure if tcx.is_coroutine(def_id.to_def_id()) => (false, true), // Full-fledged functions + closures @@ -1454,6 +1452,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { .coroutine_for_closure .set_some(def_id.index, self.tcx.coroutine_for_closure(def_id).into()); } + if let DefKind::Static(_) = def_kind { + if !self.tcx.is_foreign_item(def_id) { + let data = self.tcx.eval_static_initializer(def_id).unwrap(); + record!(self.tables.eval_static_initializer[def_id] <- data); + } + } if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind { self.encode_info_for_adt(local_id); } diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 4d0a6cb60ee..eac78a3cd7c 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -443,6 +443,7 @@ define_tables! { fn_arg_names: Table<DefIndex, LazyArray<Ident>>, coroutine_kind: Table<DefIndex, hir::CoroutineKind>, coroutine_for_closure: Table<DefIndex, RawDefId>, + eval_static_initializer: Table<DefIndex, LazyValue<mir::interpret::ConstAllocation<'static>>>, trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>, trait_item_def_id: Table<DefIndex, RawDefId>, expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>, diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index a1cdc794749..9d4ec7d25bb 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,4 +1,4 @@ -use super::{AllocId, AllocRange, Pointer, Scalar}; +use super::{AllocId, AllocRange, ConstAllocation, Pointer, Scalar}; use crate::error; use crate::mir::{ConstAlloc, ConstValue}; @@ -83,6 +83,7 @@ impl Into<ErrorGuaranteed> for ReportedErrorInfo { TrivialTypeTraversalImpls! { ErrorHandled } pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>; +pub type EvalStaticInitializerRawResult<'tcx> = Result<ConstAllocation<'tcx>, ErrorHandled>; pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>; /// `Ok(None)` indicates the constant was fine, but the valtree couldn't be constructed. /// This is needed in `thir::pattern::lower_inline_const`. diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 0da3524e055..ec2af393639 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -142,11 +142,12 @@ use crate::ty::GenericArgKind; use crate::ty::{self, Instance, Ty, TyCtxt}; pub use self::error::{ - BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, - EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, InterpError, InterpErrorInfo, - InterpResult, InvalidMetaKind, InvalidProgramInfo, MachineStopType, Misalignment, PointerKind, - ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, - UnsupportedOpInfo, ValidationErrorInfo, ValidationErrorKind, + BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalStaticInitializerRawResult, + EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, ExpectedKind, + InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, InvalidProgramInfo, + MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo, + ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, + ValidationErrorKind, }; pub use self::value::Scalar; diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index e8aca5f2e7d..643b61c1de3 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -1,7 +1,7 @@ use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId}; use crate::mir; -use crate::query::{TyCtxtAt, TyCtxtEnsure}; +use crate::query::TyCtxtEnsure; use crate::ty::visit::TypeVisitableExt; use crate::ty::GenericArgs; use crate::ty::{self, TyCtxt}; @@ -173,44 +173,6 @@ impl<'tcx> TyCtxt<'tcx> { self.eval_to_valtree(inputs) } } - - /// Evaluate a static's initializer, returning the allocation of the initializer's memory. - #[inline(always)] - pub fn eval_static_initializer( - self, - def_id: DefId, - ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> { - self.at(DUMMY_SP).eval_static_initializer(def_id) - } -} - -impl<'tcx> TyCtxtAt<'tcx> { - /// Evaluate a static's initializer, returning the allocation of the initializer's memory. - /// - /// The span is entirely ignored here, but still helpful for better query cycle errors. - pub fn eval_static_initializer( - self, - def_id: DefId, - ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> { - trace!("eval_static_initializer: Need to compute {:?}", def_id); - assert!(self.is_static(def_id)); - let instance = ty::Instance::mono(*self, def_id); - let gid = GlobalId { instance, promoted: None }; - self.eval_to_allocation(gid, ty::ParamEnv::reveal_all()) - } - - /// Evaluate anything constant-like, returning the allocation of the final memory. - /// - /// The span is entirely ignored here, but still helpful for better query cycle errors. - fn eval_to_allocation( - self, - gid: GlobalId<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Result<mir::ConstAllocation<'tcx>, ErrorHandled> { - trace!("eval_to_allocation: Need to compute {:?}", gid); - let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?; - Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory()) - } } impl<'tcx> TyCtxtEnsure<'tcx> { @@ -232,15 +194,4 @@ impl<'tcx> TyCtxtEnsure<'tcx> { let inputs = self.tcx.erase_regions(param_env.and(cid)); self.eval_to_const_value_raw(inputs) } - - /// Evaluate a static's initializer, returning the allocation of the initializer's memory. - pub fn eval_static_initializer(self, def_id: DefId) { - trace!("eval_static_initializer: Need to compute {:?}", def_id); - assert!(self.tcx.is_static(def_id)); - let instance = ty::Instance::mono(self.tcx, def_id); - let gid = GlobalId { instance, promoted: None }; - let param_env = ty::ParamEnv::reveal_all(); - trace!("eval_to_allocation: Need to compute {:?}", gid); - self.eval_to_allocation_raw(param_env.and(gid)) - } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index e22d5228628..3017f912ef0 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2,7 +2,7 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html -use crate::mir::interpret::{AllocRange, ConstAllocation, Scalar}; +use crate::mir::interpret::{AllocRange, Scalar}; use crate::mir::visit::MirVisitable; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable}; diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 3cd251caf5e..43e1318a75a 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -4,6 +4,7 @@ use rustc_attr::InlineAttr; use rustc_data_structures::base_n; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::ItemId; @@ -241,7 +242,7 @@ pub struct CodegenUnit<'tcx> { /// contain something unique to this crate (e.g., a module path) /// as well as the crate name and disambiguator. name: Symbol, - items: FxHashMap<MonoItem<'tcx>, MonoItemData>, + items: FxIndexMap<MonoItem<'tcx>, MonoItemData>, size_estimate: usize, primary: bool, /// True if this is CGU is used to hold code coverage information for dead code, @@ -316,13 +317,11 @@ impl<'tcx> CodegenUnit<'tcx> { self.primary = true; } - /// The order of these items is non-determinstic. - pub fn items(&self) -> &FxHashMap<MonoItem<'tcx>, MonoItemData> { + pub fn items(&self) -> &FxIndexMap<MonoItem<'tcx>, MonoItemData> { &self.items } - /// The order of these items is non-determinstic. - pub fn items_mut(&mut self) -> &mut FxHashMap<MonoItem<'tcx>, MonoItemData> { + pub fn items_mut(&mut self) -> &mut FxIndexMap<MonoItem<'tcx>, MonoItemData> { &mut self.items } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index a011f6114de..5638b575b31 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -4,6 +4,8 @@ use std::fs; use std::io::{self, Write as _}; use std::path::{Path, PathBuf}; +use crate::mir::interpret::ConstAllocation; + use super::graphviz::write_mir_fn_graphviz; use rustc_ast::InlineAsmTemplatePiece; use rustc_middle::mir::interpret::{ diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 5666a59e38e..7ac7fa0ac33 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -337,6 +337,7 @@ tcx_lifetime! { rustc_middle::mir::ConstValue, rustc_middle::mir::interpret::GlobalId, rustc_middle::mir::interpret::LitToConstInput, + rustc_middle::mir::interpret::EvalStaticInitializerRawResult, rustc_middle::traits::query::MethodAutoderefStepsResult, rustc_middle::traits::query::type_op::AscribeUserType, rustc_middle::traits::query::type_op::Eq, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 60d195e4d3e..a7f4e75e214 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -20,7 +20,8 @@ use crate::middle::stability::{self, DeprecationEntry}; use crate::mir; use crate::mir::interpret::GlobalId; use crate::mir::interpret::{ - EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, + EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult, + EvalToValTreeResult, }; use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; @@ -1061,7 +1062,7 @@ rustc_queries! { /// Evaluates a constant and returns the computed allocation. /// - /// **Do not use this** directly, use the `tcx.eval_static_initializer` wrapper. + /// **Do not use this** directly, use the `eval_to_const_value` or `eval_to_valtree` instead. query eval_to_allocation_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> EvalToAllocationRawResult<'tcx> { desc { |tcx| @@ -1071,6 +1072,16 @@ rustc_queries! { cache_on_disk_if { true } } + /// Evaluate a static's initializer, returning the allocation of the initializer's memory. + query eval_static_initializer(key: DefId) -> EvalStaticInitializerRawResult<'tcx> { + desc { |tcx| + "evaluating initializer of static `{}`", + tcx.def_path_str(key) + } + cache_on_disk_if { key.is_local() } + separate_provide_extern + } + /// Evaluates const items or anonymous constants /// (such as enum variant explicit discriminants or array lengths) /// into a representation suitable for the type system and const generics. diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 045856dd9cd..22f0574d614 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -126,6 +126,7 @@ parameterized_over_tcx! { crate::middle::exported_symbols::ExportedSymbol, crate::mir::Body, crate::mir::CoroutineLayout, + crate::mir::interpret::ConstAllocation, ty::Ty, ty::FnSig, ty::GenericPredicates, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 66086ac87f1..a5817125267 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2363,28 +2363,42 @@ impl<'tcx> Ty<'tcx> { } /// When we create a closure, we record its kind (i.e., what trait - /// it implements) into its `ClosureArgs` using a type + /// it implements, constrained by how it uses its borrows) into its + /// [`ty::ClosureArgs`] or [`ty::CoroutineClosureArgs`] using a type /// parameter. This is kind of a phantom type, except that the /// most convenient thing for us to are the integral types. This /// function converts such a special type into the closure - /// kind. To go the other way, use `closure_kind.to_ty(tcx)`. + /// kind. To go the other way, use [`Ty::from_closure_kind`]. /// /// Note that during type checking, we use an inference variable /// to represent the closure kind, because it has not yet been /// inferred. Once upvar inference (in `rustc_hir_analysis/src/check/upvar.rs`) - /// is complete, that type variable will be unified. + /// is complete, that type variable will be unified with one of + /// the integral types. /// - /// To be noted that you can use [`ClosureArgs::kind()`] or [`CoroutineClosureArgs::kind()`] - /// to get the same information, which you can get by calling [`GenericArgs::as_closure()`] - /// or [`GenericArgs::as_coroutine_closure()`], depending on the type of the closure. + /// ```rust,ignore (snippet of compiler code) + /// if let TyKind::Closure(def_id, args) = closure_ty.kind() + /// && let Some(closure_kind) = args.as_closure().kind_ty().to_opt_closure_kind() + /// { + /// println!("{closure_kind:?}"); + /// } else if let TyKind::CoroutineClosure(def_id, args) = closure_ty.kind() + /// && let Some(closure_kind) = args.as_coroutine_closure().kind_ty().to_opt_closure_kind() + /// { + /// println!("{closure_kind:?}"); + /// } + /// ``` /// - /// Otherwise, this method can be used as follows: + /// After upvar analysis, you should instead use [`ClosureArgs::kind()`] + /// or [`CoroutineClosureArgs::kind()`] to assert that the `ClosureKind` + /// has been constrained instead of manually calling this method. /// /// ```rust,ignore (snippet of compiler code) - /// let TyKind::Closure(def_id, [closure_fn_kind_ty, ..]) = closure_ty.kind() - /// && let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() + /// if let TyKind::Closure(def_id, args) = closure_ty.kind() + /// { + /// println!("{:?}", args.as_closure().kind()); + /// } else if let TyKind::CoroutineClosure(def_id, args) = closure_ty.kind() /// { - /// // your code + /// println!("{:?}", args.as_coroutine_closure().kind()); /// } /// ``` pub fn to_opt_closure_kind(self) -> Option<ty::ClosureKind> { @@ -2406,7 +2420,8 @@ impl<'tcx> Ty<'tcx> { } } - /// Inverse of [`Ty::to_opt_closure_kind`]. + /// Inverse of [`Ty::to_opt_closure_kind`]. See docs on that method + /// for explanation of the relationship between `Ty` and [`ty::ClosureKind`]. pub fn from_closure_kind(tcx: TyCtxt<'tcx>, kind: ty::ClosureKind) -> Ty<'tcx> { match kind { ty::ClosureKind::Fn => tcx.types.i8, diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 6636f75d998..7c3d2671d59 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -164,11 +164,7 @@ fn lit_to_mir_constant<'tcx>( })?, (ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)), (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)), - (ast::LitKind::Err, _) => { - return Err(LitToConstError::Reported( - tcx.dcx().delayed_bug("encountered LitKind::Err during mir build"), - )); - } + (ast::LitKind::Err(guar), _) => return Err(LitToConstError::Reported(*guar)), _ => return Err(LitToConstError::TypeError), }; diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 71aebd13003..d444de8b28e 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -71,11 +71,7 @@ pub(crate) fn lit_to_const<'tcx>( ty::ValTree::from_scalar_int(bits) } (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()), - (ast::LitKind::Err, _) => { - return Err(LitToConstError::Reported( - tcx.dcx().delayed_bug("encountered LitKind::Err during mir build"), - )); - } + (ast::LitKind::Err(guar), _) => return Err(LitToConstError::Reported(*guar)), _ => return Err(LitToConstError::TypeError), }; diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 99952e1c178..62762168cf4 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -897,12 +897,14 @@ impl<'tcx> Cx<'tcx> { let hir_id = self.tcx.local_def_id_to_hir_id(def_id.expect_local()); let generics = self.tcx.generics_of(hir_id.owner); let Some(&index) = generics.param_def_id_to_index.get(&def_id) else { - self.tcx.dcx().has_errors().unwrap(); + let guar = self.tcx.dcx().has_errors().unwrap(); // We already errored about a late bound const - return ExprKind::Literal { - lit: &Spanned { span: DUMMY_SP, node: LitKind::Err }, - neg: false, - }; + + let lit = self + .tcx + .hir_arena + .alloc(Spanned { span: DUMMY_SP, node: LitKind::Err(guar) }); + return ExprKind::Literal { lit, neg: false }; }; let name = self.tcx.hir().name(hir_id); let param = ty::ParamConst::new(index, name); diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 370f0db72cb..a080e2423d4 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -399,7 +399,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { }; for (field_index, op) in fields.into_iter().enumerate() { let field_dest = self.ecx.project_field(&variant_dest, field_index).ok()?; - self.ecx.copy_op(op, &field_dest, /*allow_transmute*/ false).ok()?; + self.ecx.copy_op(op, &field_dest).ok()?; } self.ecx.write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest).ok()?; self.ecx @@ -1181,8 +1181,7 @@ fn op_to_prop_const<'tcx>( } // Everything failed: create a new allocation to hold the data. - let alloc_id = - ecx.intern_with_temp_alloc(op.layout, |ecx, dest| ecx.copy_op(op, dest, false)).ok()?; + let alloc_id = ecx.intern_with_temp_alloc(op.layout, |ecx, dest| ecx.copy_op(op, dest)).ok()?; let value = ConstValue::Indirect { alloc_id, offset: Size::ZERO }; // Check that we do not leak a pointer. diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 78ba166ba43..ad8f21ffbda 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -68,6 +68,12 @@ impl<'tcx> MirPass<'tcx> for JumpThreading { let def_id = body.source.def_id(); debug!(?def_id); + // Optimizing coroutines creates query cycles. + if tcx.is_coroutine(def_id) { + trace!("Skipped for coroutine {:?}", def_id); + return; + } + let param_env = tcx.param_env_reveal_all_normalized(def_id); let map = Map::new(tcx, body, Some(MAX_PLACES)); let loop_headers = loop_headers(body); diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 5cfebcaa5a5..8bebc30e435 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -368,7 +368,7 @@ fn merge_codegen_units<'tcx>( // Move the items from `cgu_src` to `cgu_dst`. Some of them may be // duplicate inlined items, in which case the destination CGU is // unaffected. Recalculate size estimates afterwards. - cgu_dst.items_mut().extend(cgu_src.items_mut().drain()); + cgu_dst.items_mut().extend(cgu_src.items_mut().drain(..)); cgu_dst.compute_size_estimate(); // Record that `cgu_dst` now contains all the stuff that was in @@ -407,7 +407,7 @@ fn merge_codegen_units<'tcx>( // Move the items from `smallest` to `second_smallest`. Some of them // may be duplicate inlined items, in which case the destination CGU is // unaffected. Recalculate size estimates afterwards. - second_smallest.items_mut().extend(smallest.items_mut().drain()); + second_smallest.items_mut().extend(smallest.items_mut().drain(..)); second_smallest.compute_size_estimate(); // Don't update `cgu_contents`, that's only for incremental builds. diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 31552452676..c768ea93b5f 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -16,7 +16,7 @@ use rustc_session::lint::builtin::{ }; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::ParseSess; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::Symbol; use rustc_span::{edition::Edition, BytePos, Pos, Span}; mod diagnostics; @@ -478,26 +478,27 @@ impl<'sess, 'src> StringReader<'sess, 'src> { } } rustc_lexer::LiteralKind::Int { base, empty_int } => { + let mut kind = token::Integer; if empty_int { let span = self.mk_sp(start, end); - self.dcx().emit_err(errors::NoDigitsLiteral { span }); - (token::Integer, sym::integer(0)) - } else { - if matches!(base, Base::Binary | Base::Octal) { - let base = base as u32; - let s = self.str_from_to(start + BytePos(2), end); - for (idx, c) in s.char_indices() { - let span = self.mk_sp( - start + BytePos::from_usize(2 + idx), - start + BytePos::from_usize(2 + idx + c.len_utf8()), - ); - if c != '_' && c.to_digit(base).is_none() { + let guar = self.dcx().emit_err(errors::NoDigitsLiteral { span }); + kind = token::Err(guar); + } else if matches!(base, Base::Binary | Base::Octal) { + let base = base as u32; + let s = self.str_from_to(start + BytePos(2), end); + for (idx, c) in s.char_indices() { + let span = self.mk_sp( + start + BytePos::from_usize(2 + idx), + start + BytePos::from_usize(2 + idx + c.len_utf8()), + ); + if c != '_' && c.to_digit(base).is_none() { + let guar = self.dcx().emit_err(errors::InvalidDigitLiteral { span, base }); - } + kind = token::Err(guar); } } - (token::Integer, self.symbol_from_to(start, end)) } + (kind, self.symbol_from_to(start, end)) } rustc_lexer::LiteralKind::Float { base, empty_exponent } => { if empty_exponent { @@ -691,7 +692,7 @@ impl<'sess, 'src> StringReader<'sess, 'src> { fn cook_common( &self, - kind: token::LitKind, + mut kind: token::LitKind, mode: Mode, start: BytePos, end: BytePos, @@ -699,7 +700,6 @@ impl<'sess, 'src> StringReader<'sess, 'src> { postfix_len: u32, unescape: fn(&str, Mode, &mut dyn FnMut(Range<usize>, Result<(), EscapeError>)), ) -> (token::LitKind, Symbol) { - let mut has_fatal_err = false; let content_start = start + BytePos(prefix_len); let content_end = end - BytePos(postfix_len); let lit_content = self.str_from_to(content_start, content_end); @@ -711,10 +711,8 @@ impl<'sess, 'src> StringReader<'sess, 'src> { let lo = content_start + BytePos(start); let hi = lo + BytePos(end - start); let span = self.mk_sp(lo, hi); - if err.is_fatal() { - has_fatal_err = true; - } - emit_unescape_error( + let is_fatal = err.is_fatal(); + if let Some(guar) = emit_unescape_error( self.dcx(), lit_content, span_with_quotes, @@ -722,17 +720,21 @@ impl<'sess, 'src> StringReader<'sess, 'src> { mode, range, err, - ); + ) { + assert!(is_fatal); + kind = token::Err(guar); + } } }); // We normally exclude the quotes for the symbol, but for errors we // include it because it results in clearer error messages. - if !has_fatal_err { - (kind, Symbol::intern(lit_content)) + let sym = if !matches!(kind, token::Err(_)) { + Symbol::intern(lit_content) } else { - (token::Err, self.symbol_from_to(start, end)) - } + self.symbol_from_to(start, end) + }; + (kind, sym) } fn cook_unicode( diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 3238f8e23bb..3ebad6a9fd7 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -3,7 +3,7 @@ use std::iter::once; use std::ops::Range; -use rustc_errors::{Applicability, DiagCtxt}; +use rustc_errors::{Applicability, DiagCtxt, ErrorGuaranteed}; use rustc_lexer::unescape::{EscapeError, Mode}; use rustc_span::{BytePos, Span}; @@ -21,7 +21,7 @@ pub(crate) fn emit_unescape_error( // range of the error inside `lit` range: Range<usize>, error: EscapeError, -) { +) -> Option<ErrorGuaranteed> { debug!( "emit_unescape_error: {:?}, {:?}, {:?}, {:?}, {:?}", lit, full_lit_span, mode, range, error @@ -31,12 +31,12 @@ pub(crate) fn emit_unescape_error( let span = err_span.with_lo(err_span.hi() - BytePos(c.len_utf8() as u32)); (c, span) }; - match error { + Some(match error { EscapeError::LoneSurrogateUnicodeEscape => { - dcx.emit_err(UnescapeError::InvalidUnicodeEscape { span: err_span, surrogate: true }); + dcx.emit_err(UnescapeError::InvalidUnicodeEscape { span: err_span, surrogate: true }) } EscapeError::OutOfRangeUnicodeEscape => { - dcx.emit_err(UnescapeError::InvalidUnicodeEscape { span: err_span, surrogate: false }); + dcx.emit_err(UnescapeError::InvalidUnicodeEscape { span: err_span, surrogate: false }) } EscapeError::MoreThanOneChar => { use unicode_normalization::{char::is_combining_mark, UnicodeNormalization}; @@ -106,7 +106,7 @@ pub(crate) fn emit_unescape_error( span: full_lit_span, note, suggestion: sugg, - }); + }) } EscapeError::EscapeOnlyChar => { let (c, char_span) = last_char(); @@ -116,15 +116,15 @@ pub(crate) fn emit_unescape_error( escaped_sugg: c.escape_default().to_string(), escaped_msg: escaped_char(c), byte: mode == Mode::Byte, - }); + }) } EscapeError::BareCarriageReturn => { let double_quotes = mode.in_double_quotes(); - dcx.emit_err(UnescapeError::BareCr { span: err_span, double_quotes }); + dcx.emit_err(UnescapeError::BareCr { span: err_span, double_quotes }) } EscapeError::BareCarriageReturnInRawString => { assert!(mode.in_double_quotes()); - dcx.emit_err(UnescapeError::BareCrRawString(err_span)); + dcx.emit_err(UnescapeError::BareCrRawString(err_span)) } EscapeError::InvalidEscape => { let (c, span) = last_char(); @@ -161,16 +161,14 @@ pub(crate) fn emit_unescape_error( <https://doc.rust-lang.org/reference/tokens.html#literals>", ); } - diag.emit(); - } - EscapeError::TooShortHexEscape => { - dcx.emit_err(UnescapeError::TooShortHexEscape(err_span)); + diag.emit() } + EscapeError::TooShortHexEscape => dcx.emit_err(UnescapeError::TooShortHexEscape(err_span)), EscapeError::InvalidCharInHexEscape | EscapeError::InvalidCharInUnicodeEscape => { let (c, span) = last_char(); let is_hex = error == EscapeError::InvalidCharInHexEscape; let ch = escaped_char(c); - dcx.emit_err(UnescapeError::InvalidCharInEscape { span, is_hex, ch }); + dcx.emit_err(UnescapeError::InvalidCharInEscape { span, is_hex, ch }) } EscapeError::NonAsciiCharInByte => { let (c, span) = last_char(); @@ -213,23 +211,23 @@ pub(crate) fn emit_unescape_error( Applicability::MaybeIncorrect, ); } - err.emit(); + err.emit() } EscapeError::OutOfRangeHexEscape => { - dcx.emit_err(UnescapeError::OutOfRangeHexEscape(err_span)); + dcx.emit_err(UnescapeError::OutOfRangeHexEscape(err_span)) } EscapeError::LeadingUnderscoreUnicodeEscape => { let (c, span) = last_char(); dcx.emit_err(UnescapeError::LeadingUnderscoreUnicodeEscape { span, ch: escaped_char(c), - }); + }) } EscapeError::OverlongUnicodeEscape => { - dcx.emit_err(UnescapeError::OverlongUnicodeEscape(err_span)); + dcx.emit_err(UnescapeError::OverlongUnicodeEscape(err_span)) } EscapeError::UnclosedUnicodeEscape => { - dcx.emit_err(UnescapeError::UnclosedUnicodeEscape(err_span, err_span.shrink_to_hi())); + dcx.emit_err(UnescapeError::UnclosedUnicodeEscape(err_span, err_span.shrink_to_hi())) } EscapeError::NoBraceInUnicodeEscape => { let mut suggestion = "\\u{".to_owned(); @@ -248,23 +246,17 @@ pub(crate) fn emit_unescape_error( } else { (Some(err_span), NoBraceUnicodeSub::Help) }; - dcx.emit_err(UnescapeError::NoBraceInUnicodeEscape { span: err_span, label, sub }); + dcx.emit_err(UnescapeError::NoBraceInUnicodeEscape { span: err_span, label, sub }) } EscapeError::UnicodeEscapeInByte => { - dcx.emit_err(UnescapeError::UnicodeEscapeInByte(err_span)); + dcx.emit_err(UnescapeError::UnicodeEscapeInByte(err_span)) } EscapeError::EmptyUnicodeEscape => { - dcx.emit_err(UnescapeError::EmptyUnicodeEscape(err_span)); - } - EscapeError::ZeroChars => { - dcx.emit_err(UnescapeError::ZeroChars(err_span)); - } - EscapeError::LoneSlash => { - dcx.emit_err(UnescapeError::LoneSlash(err_span)); - } - EscapeError::NulInCStr => { - dcx.emit_err(UnescapeError::NulInCStr { span: err_span }); + dcx.emit_err(UnescapeError::EmptyUnicodeEscape(err_span)) } + EscapeError::ZeroChars => dcx.emit_err(UnescapeError::ZeroChars(err_span)), + EscapeError::LoneSlash => dcx.emit_err(UnescapeError::LoneSlash(err_span)), + EscapeError::NulInCStr => dcx.emit_err(UnescapeError::NulInCStr { span: err_span }), EscapeError::UnskippedWhitespaceWarning => { let (c, char_span) = last_char(); dcx.emit_warn(UnescapeError::UnskippedWhitespace { @@ -272,11 +264,13 @@ pub(crate) fn emit_unescape_error( ch: escaped_char(c), char_span, }); + return None; } EscapeError::MultipleSkippedLinesWarning => { dcx.emit_warn(UnescapeError::MultipleSkippedLinesWarning(err_span)); + return None; } - } + }) } /// Pushes a character to a message string for error reporting diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 445d5b2ce79..69518287f38 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -46,14 +46,14 @@ use std::ops::{Deref, DerefMut}; use thin_vec::{thin_vec, ThinVec}; /// Creates a placeholder argument. -pub(super) fn dummy_arg(ident: Ident) -> Param { +pub(super) fn dummy_arg(ident: Ident, guar: ErrorGuaranteed) -> Param { let pat = P(Pat { id: ast::DUMMY_NODE_ID, kind: PatKind::Ident(BindingAnnotation::NONE, ident, None), span: ident.span, tokens: None, }); - let ty = Ty { kind: TyKind::Err, span: ident.span, id: ast::DUMMY_NODE_ID, tokens: None }; + let ty = Ty { kind: TyKind::Err(guar), span: ident.span, id: ast::DUMMY_NODE_ID, tokens: None }; Param { attrs: AttrVec::default(), id: ast::DUMMY_NODE_ID, @@ -1540,14 +1540,14 @@ impl<'a> Parser<'a> { pub(super) fn maybe_recover_from_question_mark(&mut self, ty: P<Ty>) -> P<Ty> { if self.token == token::Question { self.bump(); - self.dcx().emit_err(QuestionMarkInType { + let guar = self.dcx().emit_err(QuestionMarkInType { span: self.prev_token.span, sugg: QuestionMarkInTypeSugg { left: ty.span.shrink_to_lo(), right: self.prev_token.span, }, }); - self.mk_ty(ty.span.to(self.prev_token.span), TyKind::Err) + self.mk_ty(ty.span.to(self.prev_token.span), TyKind::Err(guar)) } else { ty } @@ -2304,8 +2304,8 @@ impl<'a> Parser<'a> { pub(super) fn recover_bad_self_param(&mut self, mut param: Param) -> PResult<'a, Param> { let span = param.pat.span; - param.ty.kind = TyKind::Err; - self.dcx().emit_err(SelfParamNotFirst { span }); + let guar = self.dcx().emit_err(SelfParamNotFirst { span }); + param.ty.kind = TyKind::Err(guar); Ok(param) } @@ -2437,7 +2437,7 @@ impl<'a> Parser<'a> { pub(super) fn deduplicate_recovered_params_names(&self, fn_inputs: &mut ThinVec<Param>) { let mut seen_inputs = FxHashSet::default(); for input in fn_inputs.iter_mut() { - let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err) = + let opt_ident = if let (PatKind::Ident(_, ident, _), TyKind::Err(_)) = (&input.pat.kind, &input.ty.kind) { Some(*ident) @@ -2644,8 +2644,10 @@ impl<'a> Parser<'a> { "::", Applicability::MaybeIncorrect, ); - err.emit(); - return Ok(GenericArg::Type(self.mk_ty(start.to(expr.span), TyKind::Err))); + let guar = err.emit(); + return Ok(GenericArg::Type( + self.mk_ty(start.to(expr.span), TyKind::Err(guar)), + )); } else if token::Comma == self.token.kind || self.token.kind.should_end_const_arg() { // Avoid the following output by checking that we consumed a full const arg: diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 1a57474bac2..2424b6c130d 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2140,12 +2140,12 @@ impl<'a> Parser<'a> { Err(err) => { let span = token.uninterpolated_span(); self.bump(); - report_lit_error(self.sess, err, lit, span); + let guar = report_lit_error(self.sess, err, lit, span); // Pack possible quotes and prefixes from the original literal into // the error literal's symbol so they can be pretty-printed faithfully. let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None); let symbol = Symbol::intern(&suffixless_lit.to_string()); - let lit = token::Lit::new(token::Err, symbol, lit.suffix); + let lit = token::Lit::new(token::Err(guar), symbol, lit.suffix); Some( MetaItemLit::from_token_lit(lit, span) .unwrap_or_else(|_| unreachable!()), diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 8050b34956c..a0605b8a44c 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -591,7 +591,23 @@ impl<'a> Parser<'a> { let ty_second = if self.token == token::DotDot { // We need to report this error after `cfg` expansion for compatibility reasons self.bump(); // `..`, do not add it to expected tokens - Some(self.mk_ty(self.prev_token.span, TyKind::Err)) + + // FIXME(nnethercote): AST validation later detects this + // `TyKind::Err` and emits an errors. So why the unchecked + // ErrorGuaranteed? + // - A `span_delayed_bug` doesn't work here, because rustfmt can + // hit this path but then not hit the follow-up path in the AST + // validator that issues the error, which results in ICEs. + // - `TyKind::Dummy` doesn't work, because it ends up reaching HIR + // lowering, which results in ICEs. Changing `TyKind::Dummy` to + // `TyKind::Err` during AST validation might fix that, but that's + // not possible because AST validation doesn't allow mutability. + // + // #121072 will hopefully remove all this special handling of the + // obsolete `impl Trait for ..` and then this can go away. + #[allow(deprecated)] + let guar = rustc_errors::ErrorGuaranteed::unchecked_error_guaranteed(); + Some(self.mk_ty(self.prev_token.span, TyKind::Err(guar))) } else if has_for || self.token.can_begin_type() { Some(self.parse_ty()?) } else { @@ -2628,13 +2644,13 @@ impl<'a> Parser<'a> { p.recover_diff_marker(); let snapshot = p.create_snapshot_for_diagnostic(); let param = p.parse_param_general(req_name, first_param).or_else(|e| { - e.emit(); + let guar = e.emit(); let lo = p.prev_token.span; p.restore_snapshot(snapshot); // Skip every token until next possible arg or end. p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(Delimiter::Parenthesis)]); // Create a placeholder argument for proper arg count (issue #34264). - Ok(dummy_arg(Ident::new(kw::Empty, lo.to(p.prev_token.span)))) + Ok(dummy_arg(Ident::new(kw::Empty, lo.to(p.prev_token.span)), guar)) }); // ...now that we've parsed the first argument, `self` is no longer allowed. first_param = false; @@ -2671,8 +2687,8 @@ impl<'a> Parser<'a> { return if let Some(ident) = this.parameter_without_type(&mut err, pat, is_name_required, first_param) { - err.emit(); - Ok((dummy_arg(ident), TrailingToken::None)) + let guar = err.emit(); + Ok((dummy_arg(ident, guar), TrailingToken::None)) } else { Err(err) }; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 623407eb380..dea2b9e6ca7 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1459,7 +1459,7 @@ impl<'a> Parser<'a> { match self.parse_str_lit() { Ok(str_lit) => Some(str_lit), Err(Some(lit)) => match lit.kind { - ast::LitKind::Err => None, + ast::LitKind::Err(_) => None, _ => { self.dcx().emit_err(NonStringAbiLiteral { span: lit.span }); None diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index e7cad74b4dd..681039999a6 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -678,8 +678,9 @@ impl<'a> Parser<'a> { c.into() } Some(GenericArg::Lifetime(lt)) => { - self.dcx().emit_err(errors::AssocLifetime { span, lifetime: lt.ident.span }); - self.mk_ty(span, ast::TyKind::Err).into() + let guar = + self.dcx().emit_err(errors::AssocLifetime { span, lifetime: lt.ident.span }); + self.mk_ty(span, ast::TyKind::Err(guar)).into() } None => { let after_eq = eq.shrink_to_hi(); @@ -779,7 +780,7 @@ impl<'a> Parser<'a> { // type to determine if error recovery has occurred and if the input is not a // syntactically valid type after all. if let ast::TyKind::Slice(inner_ty) | ast::TyKind::Array(inner_ty, _) = &ty.kind - && let ast::TyKind::Err = inner_ty.kind + && let ast::TyKind::Err(_) = inner_ty.kind && let Some(snapshot) = snapshot && let Some(expr) = self.recover_unbraced_const_arg_that_can_begin_ty(snapshot) diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 157fb9e505a..f79f2a813b2 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -346,8 +346,10 @@ impl<'a> Parser<'a> { AllowCVariadic::No => { // FIXME(Centril): Should we just allow `...` syntactically // anywhere in a type and use semantic restrictions instead? - self.dcx().emit_err(NestedCVariadicType { span: lo.to(self.prev_token.span) }); - TyKind::Err + let guar = self + .dcx() + .emit_err(NestedCVariadicType { span: lo.to(self.prev_token.span) }); + TyKind::Err(guar) } } } else { @@ -493,8 +495,8 @@ impl<'a> Parser<'a> { { // Recover from `[LIT; EXPR]` and `[LIT]` self.bump(); - err.emit(); - self.mk_ty(self.prev_token.span, TyKind::Err) + let guar = err.emit(); + self.mk_ty(self.prev_token.span, TyKind::Err(guar)) } Err(err) => return Err(err), }; diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 2fafbd6d97b..b0982029657 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -70,11 +70,11 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta } } Err(err) => { - report_lit_error(sess, err, token_lit, expr.span); + let guar = report_lit_error(sess, err, token_lit, expr.span); let lit = ast::MetaItemLit { symbol: token_lit.symbol, suffix: token_lit.suffix, - kind: ast::LitKind::Err, + kind: ast::LitKind::Err(guar), span: expr.span, }; MetaItemKind::NameValue(lit) diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index d02e86dd456..96429bb7788 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -616,8 +616,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { Infer, ImplicitSelf, MacCall, - Err, - CVarArgs + CVarArgs, + Dummy, + Err ] ); diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index c36cec6f353..82846e3b4e8 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -3,7 +3,8 @@ use std::num::NonZeroU32; use rustc_ast::token; use rustc_ast::util::literal::LitError; use rustc_errors::{ - codes::*, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, IntoDiagnostic, Level, MultiSpan, + codes::*, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, IntoDiagnostic, + Level, MultiSpan, }; use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; @@ -344,7 +345,12 @@ pub(crate) struct BinaryFloatLiteralNotSupported { pub span: Span, } -pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: Span) { +pub fn report_lit_error( + sess: &ParseSess, + err: LitError, + lit: token::Lit, + span: Span, +) -> ErrorGuaranteed { // Checks if `s` looks like i32 or u1234 etc. fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { s.len() > 1 && s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit()) @@ -372,47 +378,37 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: valid.then(|| format!("0{}{}", base_char.to_ascii_lowercase(), &suffix[1..])) } - let token::Lit { kind, symbol, suffix, .. } = lit; let dcx = &sess.dcx; match err { - // `LexerError` is an error, but it was already reported - // by lexer, so here we don't report it the second time. - LitError::LexerError => {} - LitError::InvalidSuffix => { - if let Some(suffix) = suffix { - dcx.emit_err(InvalidLiteralSuffix { span, kind: kind.descr(), suffix }); - } + LitError::InvalidSuffix(suffix) => { + dcx.emit_err(InvalidLiteralSuffix { span, kind: lit.kind.descr(), suffix }) } - LitError::InvalidIntSuffix => { - let suf = suffix.expect("suffix error with no suffix"); - let suf = suf.as_str(); + LitError::InvalidIntSuffix(suffix) => { + let suf = suffix.as_str(); if looks_like_width_suffix(&['i', 'u'], suf) { // If it looks like a width, try to be helpful. - dcx.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() }); - } else if let Some(fixed) = fix_base_capitalisation(symbol.as_str(), suf) { - dcx.emit_err(InvalidNumLiteralBasePrefix { span, fixed }); + dcx.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() }) + } else if let Some(fixed) = fix_base_capitalisation(lit.symbol.as_str(), suf) { + dcx.emit_err(InvalidNumLiteralBasePrefix { span, fixed }) } else { - dcx.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() }); + dcx.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() }) } } - LitError::InvalidFloatSuffix => { - let suf = suffix.expect("suffix error with no suffix"); - let suf = suf.as_str(); + LitError::InvalidFloatSuffix(suffix) => { + let suf = suffix.as_str(); if looks_like_width_suffix(&['f'], suf) { // If it looks like a width, try to be helpful. - dcx.emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() }); + dcx.emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() }) } else { - dcx.emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() }); + dcx.emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() }) } } - LitError::NonDecimalFloat(base) => { - match base { - 16 => dcx.emit_err(HexadecimalFloatLiteralNotSupported { span }), - 8 => dcx.emit_err(OctalFloatLiteralNotSupported { span }), - 2 => dcx.emit_err(BinaryFloatLiteralNotSupported { span }), - _ => unreachable!(), - }; - } + LitError::NonDecimalFloat(base) => match base { + 16 => dcx.emit_err(HexadecimalFloatLiteralNotSupported { span }), + 8 => dcx.emit_err(OctalFloatLiteralNotSupported { span }), + 2 => dcx.emit_err(BinaryFloatLiteralNotSupported { span }), + _ => unreachable!(), + }, LitError::IntTooLarge(base) => { let max = u128::MAX; let limit = match base { @@ -421,7 +417,7 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: 16 => format!("{max:#x}"), _ => format!("{max}"), }; - dcx.emit_err(IntLiteralTooLarge { span, limit }); + dcx.emit_err(IntLiteralTooLarge { span, limit }) } } } diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 8adb0cbcc9d..288e0a5ca6f 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -11,7 +11,7 @@ use crate::lint::{ }; use crate::Session; use rustc_ast::node_id::NodeId; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc}; use rustc_errors::{emitter::SilentEmitter, DiagCtxt}; use rustc_errors::{ @@ -205,19 +205,19 @@ pub struct ParseSess { /// Places where identifiers that contain invalid Unicode codepoints but that look like they /// should be. Useful to avoid bad tokenization when encountering emoji. We group them to /// provide a single error per unique incorrect identifier. - pub bad_unicode_identifiers: Lock<FxHashMap<Symbol, Vec<Span>>>, + pub bad_unicode_identifiers: Lock<FxIndexMap<Symbol, Vec<Span>>>, source_map: Lrc<SourceMap>, pub buffered_lints: Lock<Vec<BufferedEarlyLint>>, /// Contains the spans of block expressions that could have been incomplete based on the /// operation token that followed it, but that the parser cannot identify without further /// analysis. - pub ambiguous_block_expr_parse: Lock<FxHashMap<Span, Span>>, + pub ambiguous_block_expr_parse: Lock<FxIndexMap<Span, Span>>, pub gated_spans: GatedSpans, pub symbol_gallery: SymbolGallery, /// Environment variables accessed during the build and their values when they exist. - pub env_depinfo: Lock<FxHashSet<(Symbol, Option<Symbol>)>>, + pub env_depinfo: Lock<FxIndexSet<(Symbol, Option<Symbol>)>>, /// File paths accessed during the build. - pub file_depinfo: Lock<FxHashSet<Symbol>>, + pub file_depinfo: Lock<FxIndexSet<Symbol>>, /// Whether cfg(version) should treat the current release as incomplete pub assume_incomplete_release: bool, /// Spans passed to `proc_macro::quote_span`. Each span has a numerical @@ -247,7 +247,7 @@ impl ParseSess { bad_unicode_identifiers: Lock::new(Default::default()), source_map, buffered_lints: Lock::new(vec![]), - ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), + ambiguous_block_expr_parse: Lock::new(Default::default()), gated_spans: GatedSpans::default(), symbol_gallery: SymbolGallery::default(), env_depinfo: Default::default(), diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 41db8059cbe..0dcba0e05f7 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -8,14 +8,16 @@ trait_selection_adjust_signature_remove_borrow = consider adjusting the signatur *[other] arguments } -trait_selection_closure_fn_mut_label = closure is `FnMut` because it mutates the variable `{$place}` here +trait_selection_async_closure_not_fn = async closure does not implement `{$kind}` because it captures state from its environment -trait_selection_closure_fn_once_label = closure is `FnOnce` because it moves the variable `{$place}` out of its environment +trait_selection_closure_fn_mut_label = closure is `{$trait_prefix}FnMut` because it mutates the variable `{$place}` here -trait_selection_closure_kind_mismatch = expected a closure that implements the `{$expected}` trait, but this closure only implements `{$found}` - .label = this closure implements `{$found}`, not `{$expected}` +trait_selection_closure_fn_once_label = closure is `{$trait_prefix}FnOnce` because it moves the variable `{$place}` out of its environment -trait_selection_closure_kind_requirement = the requirement to implement `{$expected}` derives from here +trait_selection_closure_kind_mismatch = expected a closure that implements the `{$trait_prefix}{$expected}` trait, but this closure only implements `{$trait_prefix}{$found}` + .label = this closure implements `{$trait_prefix}{$found}`, not `{$trait_prefix}{$expected}` + +trait_selection_closure_kind_requirement = the requirement to implement `{$trait_prefix}{$expected}` derives from here trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries} diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 20cd573f46e..407fff03e15 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -135,6 +135,8 @@ pub struct ClosureKindMismatch { #[label(trait_selection_closure_kind_requirement)] pub cause_span: Span, + pub trait_prefix: &'static str, + #[subdiagnostic] pub fn_once_label: Option<ClosureFnOnceLabel>, @@ -157,3 +159,11 @@ pub struct ClosureFnMutLabel { pub span: Span, pub place: String, } + +#[derive(Diagnostic)] +#[diag(trait_selection_async_closure_not_fn)] +pub(crate) struct AsyncClosureNotFn { + #[primary_span] + pub span: Span, + pub kind: &'static str, +} diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index eacdd9fde51..73bf66f6689 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -1,7 +1,10 @@ //! Dealing with trait goals, i.e. `T: Trait<'a, U>`. +use crate::traits::supertrait_def_ids; + use super::assembly::{self, structural_traits, Candidate}; use super::{EvalCtxt, GoalSource, SolverMode}; +use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def_id::DefId; use rustc_hir::{LangItem, Movability}; use rustc_infer::traits::query::NoSolution; @@ -663,13 +666,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { let tcx = self.tcx(); let Goal { predicate: (a_ty, _b_ty), .. } = goal; - // All of a's auto traits need to be in b's auto traits. - let auto_traits_compatible = - b_data.auto_traits().all(|b| a_data.auto_traits().any(|a| a == b)); - if !auto_traits_compatible { - return vec![]; - } - let mut responses = vec![]; // If the principal def ids match (or are both none), then we're not doing // trait upcasting. We're just removing auto traits (or shortening the lifetime). @@ -757,6 +753,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ) -> QueryResult<'tcx> { let param_env = goal.param_env; + // We may upcast to auto traits that are either explicitly listed in + // the object type's bounds, or implied by the principal trait ref's + // supertraits. + let a_auto_traits: FxIndexSet<DefId> = a_data + .auto_traits() + .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| { + supertrait_def_ids(self.tcx(), principal_def_id) + .filter(|def_id| self.tcx().trait_is_auto(*def_id)) + })) + .collect(); + // More than one projection in a_ty's bounds may match the projection // in b_ty's bound. Use this to first determine *which* apply without // having any inference side-effects. We process obligations because @@ -806,7 +813,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } // Check that b_ty's auto traits are present in a_ty's bounds. ty::ExistentialPredicate::AutoTrait(def_id) => { - if !a_data.auto_traits().any(|source_def_id| source_def_id == def_id) { + if !a_auto_traits.contains(&def_id) { return Err(NoSolution); } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 73effb33560..68b1a0d4e61 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -2,7 +2,9 @@ use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _}; use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as _}; -use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch}; +use crate::errors::{ + AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, +}; use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::InferCtxtExt as _; @@ -959,34 +961,102 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn emit_specialized_closure_kind_error( &self, obligation: &PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + mut trait_ref: ty::PolyTraitRef<'tcx>, ) -> Option<ErrorGuaranteed> { - let self_ty = trait_ref.self_ty().skip_binder(); - if let ty::Closure(closure_def_id, closure_args) = *self_ty.kind() - && let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id()) - && let Some(found_kind) = self.closure_kind(self_ty) + // If `AsyncFnKindHelper` is not implemented, that means that the closure kind + // doesn't extend the goal kind. This is worth reporting, but we can only do so + // if we actually know which closure this goal comes from, so look at the cause + // to see if we can extract that information. + if Some(trait_ref.def_id()) == self.tcx.lang_items().async_fn_kind_helper() + && let Some(found_kind) = trait_ref.skip_binder().args.type_at(0).to_opt_closure_kind() + && let Some(expected_kind) = + trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind() && !found_kind.extends(expected_kind) - && let sig = closure_args.as_closure().sig() - && self.can_sub( - obligation.param_env, - trait_ref, - sig.map_bound(|sig| { - ty::TraitRef::new( - self.tcx, - trait_ref.def_id(), - [trait_ref.self_ty().skip_binder(), sig.inputs()[0]], - ) - }), - ) { - let mut err = - self.report_closure_error(&obligation, closure_def_id, found_kind, expected_kind); - self.note_obligation_cause(&mut err, &obligation); - self.point_at_returns_when_relevant(&mut err, &obligation); - Some(err.emit()) - } else { - None + if let Some((_, Some(parent))) = obligation.cause.code().parent() { + // If we have a derived obligation, then the parent will be a `AsyncFn*` goal. + trait_ref = parent.to_poly_trait_ref(); + } else if let &ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = + obligation.cause.code() + && let Some(typeck_results) = &self.typeck_results + && let ty::Closure(closure_def_id, _) | ty::CoroutineClosure(closure_def_id, _) = + *typeck_results.node_type(arg_hir_id).kind() + { + // Otherwise, extract the closure kind from the obligation. + let mut err = self.report_closure_error( + &obligation, + closure_def_id, + found_kind, + expected_kind, + "async ", + ); + self.note_obligation_cause(&mut err, &obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); + return Some(err.emit()); + } + } + + let self_ty = trait_ref.self_ty().skip_binder(); + + if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id()) { + let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() { + ty::Closure(def_id, args) => { + (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None) + } + ty::CoroutineClosure(def_id, args) => ( + def_id, + args.as_coroutine_closure() + .coroutine_closure_sig() + .map_bound(|sig| sig.tupled_inputs_ty), + Some(args.as_coroutine_closure().coroutine_captures_by_ref_ty()), + ), + _ => return None, + }; + + let expected_args = trait_ref.map_bound(|trait_ref| trait_ref.args.type_at(1)); + + // Verify that the arguments are compatible. If the signature is + // mismatched, then we have a totally different error to report. + if self.enter_forall(found_args, |found_args| { + self.enter_forall(expected_args, |expected_args| { + !self.can_sub(obligation.param_env, expected_args, found_args) + }) + }) { + return None; + } + + if let Some(found_kind) = self.closure_kind(self_ty) + && !found_kind.extends(expected_kind) + { + let mut err = self.report_closure_error( + &obligation, + closure_def_id, + found_kind, + expected_kind, + "", + ); + self.note_obligation_cause(&mut err, &obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); + return Some(err.emit()); + } + + // If the closure has captures, then perhaps the reason that the trait + // is unimplemented is because async closures don't implement `Fn`/`FnMut` + // if they have captures. + if let Some(by_ref_captures) = by_ref_captures + && let ty::FnPtr(sig) = by_ref_captures.kind() + && !sig.skip_binder().output().is_unit() + { + let mut err = self.tcx.dcx().create_err(AsyncClosureNotFn { + span: self.tcx.def_span(closure_def_id), + kind: expected_kind.as_str(), + }); + self.note_obligation_cause(&mut err, &obligation); + self.point_at_returns_when_relevant(&mut err, &obligation); + return Some(err.emit()); + } } + None } fn fn_arg_obligation( @@ -1493,6 +1563,7 @@ pub(super) trait InferCtxtPrivExt<'tcx> { closure_def_id: DefId, found_kind: ty::ClosureKind, kind: ty::ClosureKind, + trait_prefix: &'static str, ) -> DiagnosticBuilder<'tcx>; fn report_cyclic_signature_error( @@ -3376,6 +3447,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { closure_def_id: DefId, found_kind: ty::ClosureKind, kind: ty::ClosureKind, + trait_prefix: &'static str, ) -> DiagnosticBuilder<'tcx> { let closure_span = self.tcx.def_span(closure_def_id); @@ -3384,6 +3456,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { expected: kind, found: found_kind, cause_span: obligation.cause.span, + trait_prefix, fn_once_label: None, fn_mut_label: None, }; diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 149dc4c75a7..39f4ceda9f1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -10,7 +10,7 @@ use std::ops::ControlFlow; use hir::def_id::DefId; use hir::LangItem; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_hir as hir; use rustc_infer::traits::ObligationCause; use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError}; @@ -968,52 +968,61 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // // We always perform upcasting coercions when we can because of reason // #2 (region bounds). - let auto_traits_compatible = b_data - .auto_traits() - // All of a's auto traits need to be in b's auto traits. - .all(|b| a_data.auto_traits().any(|a| a == b)); - if auto_traits_compatible { - let principal_def_id_a = a_data.principal_def_id(); - let principal_def_id_b = b_data.principal_def_id(); - if principal_def_id_a == principal_def_id_b { - // no cyclic + let principal_def_id_a = a_data.principal_def_id(); + let principal_def_id_b = b_data.principal_def_id(); + if principal_def_id_a == principal_def_id_b { + // We may upcast to auto traits that are either explicitly listed in + // the object type's bounds, or implied by the principal trait ref's + // supertraits. + let a_auto_traits: FxIndexSet<DefId> = a_data + .auto_traits() + .chain(principal_def_id_a.into_iter().flat_map(|principal_def_id| { + util::supertrait_def_ids(self.tcx(), principal_def_id) + .filter(|def_id| self.tcx().trait_is_auto(*def_id)) + })) + .collect(); + let auto_traits_compatible = b_data + .auto_traits() + // All of a's auto traits need to be in b's auto traits. + .all(|b| a_auto_traits.contains(&b)); + if auto_traits_compatible { candidates.vec.push(BuiltinUnsizeCandidate); - } else if principal_def_id_a.is_some() && principal_def_id_b.is_some() { - // not casual unsizing, now check whether this is trait upcasting coercion. - let principal_a = a_data.principal().unwrap(); - let target_trait_did = principal_def_id_b.unwrap(); - let source_trait_ref = principal_a.with_self_ty(self.tcx(), source); - if let Some(deref_trait_ref) = self.need_migrate_deref_output_trait_object( - source, - obligation.param_env, - &obligation.cause, - ) { - if deref_trait_ref.def_id() == target_trait_did { - return; - } + } + } else if principal_def_id_a.is_some() && principal_def_id_b.is_some() { + // not casual unsizing, now check whether this is trait upcasting coercion. + let principal_a = a_data.principal().unwrap(); + let target_trait_did = principal_def_id_b.unwrap(); + let source_trait_ref = principal_a.with_self_ty(self.tcx(), source); + if let Some(deref_trait_ref) = self.need_migrate_deref_output_trait_object( + source, + obligation.param_env, + &obligation.cause, + ) { + if deref_trait_ref.def_id() == target_trait_did { + return; } + } - for (idx, upcast_trait_ref) in - util::supertraits(self.tcx(), source_trait_ref).enumerate() - { - self.infcx.probe(|_| { - if upcast_trait_ref.def_id() == target_trait_did - && let Ok(nested) = self.match_upcast_principal( - obligation, - upcast_trait_ref, - a_data, - b_data, - a_region, - b_region, - ) - { - if nested.is_none() { - candidates.ambiguous = true; - } - candidates.vec.push(TraitUpcastingUnsizeCandidate(idx)); + for (idx, upcast_trait_ref) in + util::supertraits(self.tcx(), source_trait_ref).enumerate() + { + self.infcx.probe(|_| { + if upcast_trait_ref.def_id() == target_trait_did + && let Ok(nested) = self.match_upcast_principal( + obligation, + upcast_trait_ref, + a_data, + b_data, + a_region, + b_region, + ) + { + if nested.is_none() { + candidates.ambiguous = true; } - }) - } + candidates.vec.push(TraitUpcastingUnsizeCandidate(idx)); + } + }) } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index ab0c53e6a9b..5bcf46a96ed 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2526,6 +2526,17 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let tcx = self.tcx(); let mut nested = vec![]; + // We may upcast to auto traits that are either explicitly listed in + // the object type's bounds, or implied by the principal trait ref's + // supertraits. + let a_auto_traits: FxIndexSet<DefId> = a_data + .auto_traits() + .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| { + util::supertrait_def_ids(tcx, principal_def_id) + .filter(|def_id| tcx.trait_is_auto(*def_id)) + })) + .collect(); + let upcast_principal = normalize_with_depth_to( self, obligation.param_env, @@ -2588,7 +2599,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } // Check that b_ty's auto traits are present in a_ty's bounds. ty::ExistentialPredicate::AutoTrait(def_id) => { - if !a_data.auto_traits().any(|source_def_id| source_def_id == def_id) { + if !a_auto_traits.contains(&def_id) { return Err(SelectionError::Unimplemented); } } |
