Auto merge of #3301 - rust-lang:rustup-2024-02-16, r=saethlin
Automatic Rustup
This commit is contained in:
commit
c335b4e4a0
216 changed files with 2522 additions and 1015 deletions
|
|
@ -4588,6 +4588,7 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_hir",
|
||||
"rustc_middle",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"scoped-tls",
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(_))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
@ -323,7 +328,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
)
|
||||
}
|
||||
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
|
||||
ExprKind::Err => hir::ExprKind::Err(self.dcx().has_errors().unwrap()),
|
||||
ExprKind::Err => {
|
||||
hir::ExprKind::Err(self.dcx().span_delayed_bug(e.span, "lowered ExprKind::Err"))
|
||||
}
|
||||
ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
|
||||
|
||||
ExprKind::Paren(_) | ExprKind::ForLoop { .. } => {
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
|
|
|
|||
|
|
@ -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?;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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 =
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -249,11 +256,37 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
|
|||
tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key))
|
||||
}
|
||||
|
||||
#[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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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])?;
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -759,14 +759,57 @@ where
|
|||
}
|
||||
|
||||
/// Copies the data from an operand to a place.
|
||||
/// `allow_transmute` indicates whether the layouts may disagree.
|
||||
/// 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)]
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
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")]
|
||||
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)?)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)?;
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -98,6 +98,26 @@ impl<'tcx> MirPass<'tcx> for Validator {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce that coroutine-closure layouts are identical.
|
||||
if let Some(layout) = body.coroutine_layout()
|
||||
&& let Some(by_move_body) = body.coroutine_by_move_body()
|
||||
&& let Some(by_move_layout) = by_move_body.coroutine_layout()
|
||||
{
|
||||
if layout != by_move_layout {
|
||||
// If this turns out not to be true, please let compiler-errors know.
|
||||
// It is possible to support, but requires some changes to the layout
|
||||
// computation code.
|
||||
cfg_checker.fail(
|
||||
Location::START,
|
||||
format!(
|
||||
"Coroutine layout differs from by-move coroutine layout:\n\
|
||||
layout: {layout:#?}\n\
|
||||
by_move_layout: {by_move_layout:#?}",
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 => {}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
CoerceMany::with_coercion_sites(coerce_first, arms)
|
||||
};
|
||||
|
||||
let mut other_arms = vec![]; // Used only for diagnostics.
|
||||
let mut prior_non_diverging_arms = vec![]; // Used only for diagnostics.
|
||||
let mut prior_arm = None;
|
||||
for arm in arms {
|
||||
if let Some(e) = &arm.guard {
|
||||
|
|
@ -118,9 +118,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
prior_arm_ty,
|
||||
prior_arm_span,
|
||||
scrut_span: scrut.span,
|
||||
scrut_hir_id: scrut.hir_id,
|
||||
source: match_src,
|
||||
prior_arms: other_arms.clone(),
|
||||
prior_non_diverging_arms: prior_non_diverging_arms.clone(),
|
||||
opt_suggest_box_span,
|
||||
})),
|
||||
),
|
||||
|
|
@ -142,16 +141,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
false,
|
||||
);
|
||||
|
||||
other_arms.push(arm_span);
|
||||
if other_arms.len() > 5 {
|
||||
other_arms.remove(0);
|
||||
}
|
||||
|
||||
if !arm_ty.is_never() {
|
||||
// When a match arm has type `!`, then it doesn't influence the expected type for
|
||||
// the following arm. If all of the prior arms are `!`, then the influence comes
|
||||
// from elsewhere and we shouldn't point to any previous arm.
|
||||
prior_arm = Some((arm_block_id, arm_ty, arm_span));
|
||||
|
||||
prior_non_diverging_arms.push(arm_span);
|
||||
if prior_non_diverging_arms.len() > 5 {
|
||||
prior_non_diverging_arms.remove(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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[..] {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -777,10 +777,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
prior_arm_span,
|
||||
prior_arm_ty,
|
||||
source,
|
||||
ref prior_arms,
|
||||
ref prior_non_diverging_arms,
|
||||
opt_suggest_box_span,
|
||||
scrut_span,
|
||||
scrut_hir_id,
|
||||
..
|
||||
}) => match source {
|
||||
hir::MatchSource::TryDesugar(scrut_hir_id) => {
|
||||
|
|
@ -817,12 +816,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
});
|
||||
let source_map = self.tcx.sess.source_map();
|
||||
let mut any_multiline_arm = source_map.is_multiline(arm_span);
|
||||
if prior_arms.len() <= 4 {
|
||||
for sp in prior_arms {
|
||||
if prior_non_diverging_arms.len() <= 4 {
|
||||
for sp in prior_non_diverging_arms {
|
||||
any_multiline_arm |= source_map.is_multiline(*sp);
|
||||
err.span_label(*sp, format!("this is found to be of type `{t}`"));
|
||||
}
|
||||
} else if let Some(sp) = prior_arms.last() {
|
||||
} else if let Some(sp) = prior_non_diverging_arms.last() {
|
||||
any_multiline_arm |= source_map.is_multiline(*sp);
|
||||
err.span_label(
|
||||
*sp,
|
||||
|
|
@ -848,24 +847,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
) {
|
||||
err.subdiagnostic(subdiag);
|
||||
}
|
||||
if let hir::Node::Expr(m) = self.tcx.parent_hir_node(scrut_hir_id)
|
||||
&& let hir::Node::Stmt(stmt) = self.tcx.parent_hir_node(m.hir_id)
|
||||
&& let hir::StmtKind::Expr(_) = stmt.kind
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
stmt.span.shrink_to_hi(),
|
||||
"consider using a semicolon here, but this will discard any values \
|
||||
in the match arms",
|
||||
";",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
if let Some(ret_sp) = opt_suggest_box_span {
|
||||
// Get return type span and point to it.
|
||||
self.suggest_boxing_for_return_impl_trait(
|
||||
err,
|
||||
ret_sp,
|
||||
prior_arms.iter().chain(std::iter::once(&arm_span)).copied(),
|
||||
prior_non_diverging_arms
|
||||
.iter()
|
||||
.chain(std::iter::once(&arm_span))
|
||||
.copied(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,10 +203,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
})
|
||||
}
|
||||
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
|
||||
prior_arms,
|
||||
prior_non_diverging_arms,
|
||||
..
|
||||
}) => {
|
||||
if let [.., arm_span] = &prior_arms[..] {
|
||||
if let [.., arm_span] = &prior_non_diverging_arms[..] {
|
||||
Some(ConsiderAddingAwait::BothFuturesSugg {
|
||||
first: arm_span.shrink_to_hi(),
|
||||
second: exp_span.shrink_to_hi(),
|
||||
|
|
@ -234,11 +234,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() })
|
||||
}
|
||||
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
|
||||
ref prior_arms,
|
||||
ref prior_non_diverging_arms,
|
||||
..
|
||||
}) => Some({
|
||||
ConsiderAddingAwait::FutureSuggMultiple {
|
||||
spans: prior_arms.iter().map(|arm| arm.shrink_to_hi()).collect(),
|
||||
spans: prior_non_diverging_arms
|
||||
.iter()
|
||||
.map(|arm| arm.shrink_to_hi())
|
||||
.collect(),
|
||||
}
|
||||
}),
|
||||
_ => None,
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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()?;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 => {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>>,
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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::{
|
||||
|
|
|
|||
|
|
@ -86,7 +86,8 @@ rustc_index::newtype_index! {
|
|||
pub struct CoroutineSavedLocal {}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct CoroutineSavedTy<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
/// Source info corresponding to the local in the original MIR body.
|
||||
|
|
@ -96,7 +97,8 @@ pub struct CoroutineSavedTy<'tcx> {
|
|||
}
|
||||
|
||||
/// The layout of coroutine state.
|
||||
#[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
#[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
|
||||
pub struct CoroutineLayout<'tcx> {
|
||||
/// The type of every local stored inside the coroutine.
|
||||
pub field_tys: IndexVec<CoroutineSavedLocal, CoroutineSavedTy<'tcx>>,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -569,9 +569,8 @@ pub struct MatchExpressionArmCause<'tcx> {
|
|||
pub prior_arm_ty: Ty<'tcx>,
|
||||
pub prior_arm_span: Span,
|
||||
pub scrut_span: Span,
|
||||
pub scrut_hir_id: hir::HirId,
|
||||
pub source: hir::MatchSource,
|
||||
pub prior_arms: Vec<Span>,
|
||||
pub prior_non_diverging_arms: Vec<Span>,
|
||||
pub opt_suggest_box_span: Option<Span>,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1053,6 +1053,22 @@ impl<'tcx> TyCtxtAt<'tcx> {
|
|||
name: Symbol,
|
||||
def_kind: DefKind,
|
||||
) -> TyCtxtFeed<'tcx, LocalDefId> {
|
||||
let feed = self.tcx.create_def(parent, name, def_kind);
|
||||
|
||||
feed.def_span(self.span);
|
||||
feed
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
/// `tcx`-dependent operations performed for every created definition.
|
||||
pub fn create_def(
|
||||
self,
|
||||
parent: LocalDefId,
|
||||
name: Symbol,
|
||||
def_kind: DefKind,
|
||||
) -> TyCtxtFeed<'tcx, LocalDefId> {
|
||||
let data = def_kind.def_path_data(name);
|
||||
// The following call has the side effect of modifying the tables inside `definitions`.
|
||||
// These very tables are relied on by the incr. comp. engine to decode DepNodes and to
|
||||
// decode the on-disk cache.
|
||||
|
|
@ -1067,18 +1083,6 @@ impl<'tcx> TyCtxtAt<'tcx> {
|
|||
// This is fine because:
|
||||
// - those queries are `eval_always` so we won't miss their result changing;
|
||||
// - this write will have happened before these queries are called.
|
||||
let def_id = self.tcx.create_def(parent, name, def_kind);
|
||||
|
||||
let feed = self.tcx.feed_local_def_id(def_id);
|
||||
feed.def_span(self.span);
|
||||
feed
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
/// `tcx`-dependent operations performed for every created definition.
|
||||
pub fn create_def(self, parent: LocalDefId, name: Symbol, def_kind: DefKind) -> LocalDefId {
|
||||
let data = def_kind.def_path_data(name);
|
||||
let def_id = self.untracked.definitions.write().create_def(parent, data);
|
||||
|
||||
// This function modifies `self.definitions` using a side-effect.
|
||||
|
|
@ -1098,7 +1102,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
feed.visibility(ty::Visibility::Restricted(parent_mod));
|
||||
}
|
||||
|
||||
def_id
|
||||
feed
|
||||
}
|
||||
|
||||
pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + 'tcx {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// Otherwise, this method can be used as follows:
|
||||
/// is complete, that type variable will be unified with one of
|
||||
/// the integral types.
|
||||
///
|
||||
/// ```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()
|
||||
/// && let Some(closure_kind) = args.as_closure().kind_ty().to_opt_closure_kind()
|
||||
/// {
|
||||
/// // your code
|
||||
/// 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:?}");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// 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)
|
||||
/// 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()
|
||||
/// {
|
||||
/// 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,
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -137,7 +137,9 @@ impl<'tcx> TerminatorClassifier<'tcx> for CallRecursion<'tcx> {
|
|||
|
||||
let func_ty = func.ty(body, tcx);
|
||||
if let ty::FnDef(callee, args) = *func_ty.kind() {
|
||||
let normalized_args = tcx.normalize_erasing_regions(param_env, args);
|
||||
let Ok(normalized_args) = tcx.try_normalize_erasing_regions(param_env, args) else {
|
||||
return false;
|
||||
};
|
||||
let (callee, call_args) = if let Ok(Some(instance)) =
|
||||
Instance::resolve(tcx, param_env, callee, normalized_args)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -265,7 +265,8 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs {
|
|||
let body = &tcx.mir_const(def).borrow();
|
||||
|
||||
if body.return_ty().references_error() {
|
||||
assert!(tcx.dcx().has_errors().is_some(), "mir_const_qualif: MIR had errors");
|
||||
// It's possible to reach here without an error being emitted (#121103).
|
||||
tcx.dcx().span_delayed_bug(body.span, "mir_const_qualif: MIR had errors");
|
||||
return Default::default();
|
||||
}
|
||||
|
||||
|
|
@ -652,7 +653,6 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
|
|||
debug!("about to call mir_drops_elaborated...");
|
||||
let body = tcx.mir_drops_elaborated_and_const_checked(did).steal();
|
||||
let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::NotConst);
|
||||
debug!("body: {:#?}", body);
|
||||
|
||||
if body.tainted_by_errors.is_some() {
|
||||
return body;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
|
|||
}
|
||||
|
||||
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
debug!("remove_noop_landing_pads({:?})", body);
|
||||
let def_id = body.source.def_id();
|
||||
debug!(?def_id);
|
||||
self.remove_nop_landing_pads(body)
|
||||
}
|
||||
}
|
||||
|
|
@ -81,8 +82,6 @@ impl RemoveNoopLandingPads {
|
|||
}
|
||||
|
||||
fn remove_nop_landing_pads(&self, body: &mut Body<'_>) {
|
||||
debug!("body: {:#?}", body);
|
||||
|
||||
// Skip the pass if there are no blocks with a resume terminator.
|
||||
let has_resume = body
|
||||
.basic_blocks
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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!()),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue