Auto merge of #95351 - Dylan-DPC:rollup-o1il7tx, r=Dylan-DPC
Rollup of 5 pull requests Successful merges: - #91981 (Recover suggestions and useful information lost in previous PR) - #93469 (Skip pointing out ambiguous impls in alloc/std crates too in inference errors) - #95335 (Move resolve_path to rustc_builtin_macros and make it private) - #95340 (interpret: with enforce_number_validity, ensure integers are truly Scalar::Int (i.e., no pointers)) - #95341 (ARMv6K Horizon OS has_thread_local support) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
185a3f0a11
51 changed files with 281 additions and 149 deletions
|
@ -3,15 +3,17 @@ use rustc_ast::ptr::P;
|
|||
use rustc_ast::token;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::PResult;
|
||||
use rustc_expand::base::{self, *};
|
||||
use rustc_expand::module::DirOwnership;
|
||||
use rustc_parse::parser::{ForceCollect, Parser};
|
||||
use rustc_parse::{self, new_parser_from_file};
|
||||
use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::{self, Pos, Span};
|
||||
use rustc_span::{self, FileName, Pos, Span};
|
||||
|
||||
use smallvec::SmallVec;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
||||
// These macros all relate to the file system; they either return
|
||||
|
@ -102,7 +104,7 @@ pub fn expand_include<'cx>(
|
|||
return DummyResult::any(sp);
|
||||
};
|
||||
// The file will be added to the code map by the parser
|
||||
let file = match cx.resolve_path(file, sp) {
|
||||
let file = match resolve_path(cx, file, sp) {
|
||||
Ok(f) => f,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
|
@ -171,7 +173,7 @@ pub fn expand_include_str(
|
|||
let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_str!") else {
|
||||
return DummyResult::any(sp);
|
||||
};
|
||||
let file = match cx.resolve_path(file, sp) {
|
||||
let file = match resolve_path(cx, file, sp) {
|
||||
Ok(f) => f,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
|
@ -205,7 +207,7 @@ pub fn expand_include_bytes(
|
|||
let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_bytes!") else {
|
||||
return DummyResult::any(sp);
|
||||
};
|
||||
let file = match cx.resolve_path(file, sp) {
|
||||
let file = match resolve_path(cx, file, sp) {
|
||||
Ok(f) => f,
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
|
@ -220,3 +222,40 @@ pub fn expand_include_bytes(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves a `path` mentioned inside Rust code, returning an absolute path.
|
||||
///
|
||||
/// This unifies the logic used for resolving `include_X!`.
|
||||
fn resolve_path<'a>(
|
||||
cx: &mut ExtCtxt<'a>,
|
||||
path: impl Into<PathBuf>,
|
||||
span: Span,
|
||||
) -> PResult<'a, PathBuf> {
|
||||
let path = path.into();
|
||||
|
||||
// Relative paths are resolved relative to the file in which they are found
|
||||
// after macro expansion (that is, they are unhygienic).
|
||||
if !path.is_absolute() {
|
||||
let callsite = span.source_callsite();
|
||||
let mut result = match cx.source_map().span_to_filename(callsite) {
|
||||
FileName::Real(name) => name
|
||||
.into_local_path()
|
||||
.expect("attempting to resolve a file path in an external file"),
|
||||
FileName::DocTest(path, _) => path,
|
||||
other => {
|
||||
return Err(cx.struct_span_err(
|
||||
span,
|
||||
&format!(
|
||||
"cannot resolve relative path in non-file source `{}`",
|
||||
cx.source_map().filename_for_diagnostics(&other)
|
||||
),
|
||||
));
|
||||
}
|
||||
};
|
||||
result.pop();
|
||||
result.push(path);
|
||||
Ok(result)
|
||||
} else {
|
||||
Ok(path)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -444,6 +444,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
match scalar.try_to_int() {
|
||||
Ok(int) => int.is_null(),
|
||||
Err(_) => {
|
||||
// Can only happen during CTFE.
|
||||
let ptr = self.scalar_to_ptr(scalar);
|
||||
match self.memory.ptr_try_get_alloc(ptr) {
|
||||
Ok((alloc_id, offset, _)) => {
|
||||
|
@ -455,7 +456,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// Note that one-past-the-end (offset == size) is still inbounds, and never null.
|
||||
offset > size
|
||||
}
|
||||
Err(offset) => offset == 0,
|
||||
Err(_offset) => bug!("a non-int scalar is always a pointer"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ use std::hash::Hash;
|
|||
|
||||
use super::{
|
||||
alloc_range, CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine,
|
||||
MemPlaceMeta, OpTy, ScalarMaybeUninit, ValueVisitor,
|
||||
MemPlaceMeta, OpTy, Scalar, ScalarMaybeUninit, ValueVisitor,
|
||||
};
|
||||
|
||||
macro_rules! throw_validation_failure {
|
||||
|
@ -521,8 +521,11 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
|||
// NOTE: Keep this in sync with the array optimization for int/float
|
||||
// types below!
|
||||
if M::enforce_number_validity(self.ecx) {
|
||||
// Integers/floats in CTFE: Must be scalar bits, pointers are dangerous
|
||||
let is_bits = value.check_init().map_or(false, |v| v.try_to_int().is_ok());
|
||||
// Integers/floats with number validity: Must be scalar bits, pointers are dangerous.
|
||||
// As a special exception we *do* match on a `Scalar` here, since we truly want
|
||||
// to know its underlying representation (and *not* cast it to an integer).
|
||||
let is_bits =
|
||||
value.check_init().map_or(false, |v| matches!(v, Scalar::Int(..)));
|
||||
if !is_bits {
|
||||
throw_validation_failure!(self.path,
|
||||
{ "{:x}", value } expected { "initialized plain (non-pointer) bytes" }
|
||||
|
|
|
@ -10,7 +10,7 @@ use rustc_ast::{self as ast, AstLike, Attribute, Item, NodeId, PatKind};
|
|||
use rustc_attr::{self as attr, Deprecation, Stability};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::sync::{self, Lrc};
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
|
||||
use rustc_lint_defs::BuiltinLintDiagnostics;
|
||||
use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS};
|
||||
|
@ -20,7 +20,7 @@ use rustc_span::edition::Edition;
|
|||
use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId};
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{FileName, MultiSpan, Span, DUMMY_SP};
|
||||
use rustc_span::{MultiSpan, Span, DUMMY_SP};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use std::default::Default;
|
||||
|
@ -1128,41 +1128,6 @@ impl<'a> ExtCtxt<'a> {
|
|||
pub fn check_unused_macros(&mut self) {
|
||||
self.resolver.check_unused_macros();
|
||||
}
|
||||
|
||||
/// Resolves a `path` mentioned inside Rust code, returning an absolute path.
|
||||
///
|
||||
/// This unifies the logic used for resolving `include_X!`.
|
||||
///
|
||||
/// FIXME: move this to `rustc_builtin_macros` and make it private.
|
||||
pub fn resolve_path(&self, path: impl Into<PathBuf>, span: Span) -> PResult<'a, PathBuf> {
|
||||
let path = path.into();
|
||||
|
||||
// Relative paths are resolved relative to the file in which they are found
|
||||
// after macro expansion (that is, they are unhygienic).
|
||||
if !path.is_absolute() {
|
||||
let callsite = span.source_callsite();
|
||||
let mut result = match self.source_map().span_to_filename(callsite) {
|
||||
FileName::Real(name) => name
|
||||
.into_local_path()
|
||||
.expect("attempting to resolve a file path in an external file"),
|
||||
FileName::DocTest(path, _) => path,
|
||||
other => {
|
||||
return Err(self.struct_span_err(
|
||||
span,
|
||||
&format!(
|
||||
"cannot resolve relative path in non-file source `{}`",
|
||||
self.source_map().filename_for_diagnostics(&other)
|
||||
),
|
||||
));
|
||||
}
|
||||
};
|
||||
result.pop();
|
||||
result.push(path);
|
||||
Ok(result)
|
||||
} else {
|
||||
Ok(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Extracts a string literal from the macro expanded version of `expr`,
|
||||
|
|
|
@ -333,6 +333,9 @@ pub fn same_type_modulo_infer<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
|
|||
)
|
||||
| (&ty::Infer(ty::InferTy::TyVar(_)), _)
|
||||
| (_, &ty::Infer(ty::InferTy::TyVar(_))) => true,
|
||||
(&ty::Ref(reg_a, ty_a, mut_a), &ty::Ref(reg_b, ty_b, mut_b)) => {
|
||||
reg_a == reg_b && mut_a == mut_b && same_type_modulo_infer(*ty_a, *ty_b)
|
||||
}
|
||||
_ => a == b,
|
||||
}
|
||||
}
|
||||
|
@ -602,7 +605,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
match *cause.code() {
|
||||
ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
|
||||
let ty = self.resolve_vars_if_possible(root_ty);
|
||||
if ty.is_suggestable() {
|
||||
if !matches!(ty.kind(), ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_)))
|
||||
{
|
||||
// don't show type `_`
|
||||
err.span_label(span, format!("this expression has type `{}`", ty));
|
||||
}
|
||||
|
|
|
@ -1434,6 +1434,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
value.fold_with(&mut r)
|
||||
}
|
||||
|
||||
pub fn resolve_numeric_literals_with_default<T>(&self, value: T) -> T
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
||||
if !value.needs_infer() {
|
||||
return value; // Avoid duplicated subst-folding.
|
||||
}
|
||||
let mut r = InferenceLiteralEraser { tcx: self.tcx };
|
||||
value.fold_with(&mut r)
|
||||
}
|
||||
|
||||
/// Returns the first unresolved variable contained in `T`. In the
|
||||
/// process of visiting `T`, this will resolve (where possible)
|
||||
/// type variables in `T`, but it never constructs the final,
|
||||
|
@ -1785,6 +1796,26 @@ impl<'tcx> TyOrConstInferVar<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Replace `{integer}` with `i32` and `{float}` with `f64`.
|
||||
/// Used only for diagnostics.
|
||||
struct InferenceLiteralEraser<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<'tcx> for InferenceLiteralEraser<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
match ty.kind() {
|
||||
ty::Infer(ty::IntVar(_) | ty::FreshIntTy(_)) => self.tcx.types.i32,
|
||||
ty::Infer(ty::FloatVar(_) | ty::FreshFloatTy(_)) => self.tcx.types.f64,
|
||||
_ => ty.super_fold_with(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ShallowResolver<'a, 'tcx> {
|
||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ pub fn target() -> Target {
|
|||
pre_link_args,
|
||||
exe_suffix: ".elf".to_string(),
|
||||
no_default_libraries: false,
|
||||
has_thread_local: true,
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1954,7 +1954,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
|||
|
||||
if self.is_tainted_by_errors()
|
||||
&& crate_names.len() == 1
|
||||
&& crate_names[0] == "`core`"
|
||||
&& ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str())
|
||||
&& spans.len() == 0
|
||||
{
|
||||
// Avoid complaining about other inference issues for expressions like
|
||||
|
|
|
@ -11,6 +11,7 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::GenericArg;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::ty::{
|
||||
self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, Ty, TyCtxt,
|
||||
};
|
||||
|
@ -83,7 +84,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
if let Some(param_local_id) = param.def_id.as_local() {
|
||||
let param_hir_id = tcx.hir().local_def_id_to_hir_id(param_local_id);
|
||||
let param_name = tcx.hir().ty_param_name(param_hir_id);
|
||||
let param_type = tcx.type_of(param.def_id);
|
||||
let param_type = tcx.infer_ctxt().enter(|infcx| {
|
||||
infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id))
|
||||
});
|
||||
if param_type.is_suggestable() {
|
||||
err.span_suggestion(
|
||||
tcx.def_span(src_def_id),
|
||||
|
|
|
@ -521,6 +521,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
can_suggest: bool,
|
||||
fn_id: hir::HirId,
|
||||
) -> bool {
|
||||
let found =
|
||||
self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
|
||||
// Only suggest changing the return type for methods that
|
||||
// haven't set a return type at all (and aren't `fn main()` or an impl).
|
||||
match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) {
|
||||
|
@ -528,13 +530,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
err.span_suggestion(
|
||||
span,
|
||||
"try adding a return type",
|
||||
format!("-> {} ", self.resolve_vars_with_obligations(found)),
|
||||
format!("-> {} ", found),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
true
|
||||
}
|
||||
(&hir::FnRetTy::DefaultReturn(span), false, true, true) => {
|
||||
err.span_label(span, "possibly return type missing here?");
|
||||
// FIXME: if `found` could be `impl Iterator` or `impl Fn*`, we should suggest
|
||||
// that.
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"a return type might be missing here",
|
||||
"-> _ ".to_string(),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
true
|
||||
}
|
||||
(&hir::FnRetTy::DefaultReturn(span), _, false, true) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue