Auto merge of #112530 - matthiaskrgr:rollup-qee1kc1, r=matthiaskrgr
Rollup of 3 pull requests Successful merges: - #112487 (Update documentation for `tools` defaults) - #112513 (Dont compute `opt_suggest_box_span` span for TAIT) - #112528 (bootstrap: Don't override `debuginfo-level = 1` to mean `line-tables-only`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
37998ab508
9 changed files with 139 additions and 130 deletions
|
@ -510,6 +510,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
..
|
||||
} = self.type_var_origin(expected)? else { return None; };
|
||||
|
||||
let Some(rpit_local_def_id) = rpit_def_id.as_local() else { return None; };
|
||||
if !matches!(
|
||||
self.tcx.hir().expect_item(rpit_local_def_id).expect_opaque_ty().origin,
|
||||
hir::OpaqueTyOrigin::FnReturn(..)
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let sig = self.body_fn_sig()?;
|
||||
|
||||
let substs = sig.output().walk().find_map(|arg| {
|
||||
|
|
|
@ -36,9 +36,7 @@
|
|||
//! ```
|
||||
|
||||
use crate::FnCtxt;
|
||||
use rustc_errors::{
|
||||
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
|
||||
};
|
||||
use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
|
@ -58,7 +56,7 @@ use rustc_middle::ty::visit::TypeVisitableExt;
|
|||
use rustc_middle::ty::{self, Ty, TypeAndMut};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{self, BytePos, DesugaringKind, Span};
|
||||
use rustc_span::{self, DesugaringKind};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
||||
|
@ -1702,9 +1700,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
|
||||
let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err);
|
||||
|
||||
let mut pointing_at_return_type = false;
|
||||
let mut fn_output = None;
|
||||
|
||||
let parent_id = fcx.tcx.hir().parent_id(id);
|
||||
let parent = fcx.tcx.hir().get(parent_id);
|
||||
if let Some(expr) = expression
|
||||
|
@ -1717,7 +1712,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
// label pointing out the cause for the type coercion will be wrong
|
||||
// as prior return coercions would not be relevant (#57664).
|
||||
let fn_decl = if let (Some(expr), Some(blk_id)) = (expression, blk_id) {
|
||||
pointing_at_return_type =
|
||||
let pointing_at_return_type =
|
||||
fcx.suggest_mismatched_types_on_tail(&mut err, expr, expected, found, blk_id);
|
||||
if let (Some(cond_expr), true, false) = (
|
||||
fcx.tcx.hir().get_if_cause(expr.hir_id),
|
||||
|
@ -1749,7 +1744,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
|
||||
if let Some((fn_id, fn_decl, can_suggest)) = fn_decl {
|
||||
if blk_id.is_none() {
|
||||
pointing_at_return_type |= fcx.suggest_missing_return_type(
|
||||
fcx.suggest_missing_return_type(
|
||||
&mut err,
|
||||
&fn_decl,
|
||||
expected,
|
||||
|
@ -1758,9 +1753,6 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
fn_id,
|
||||
);
|
||||
}
|
||||
if !pointing_at_return_type {
|
||||
fn_output = Some(&fn_decl.output); // `impl Trait` return type
|
||||
}
|
||||
}
|
||||
|
||||
let parent_id = fcx.tcx.hir().get_parent_item(id);
|
||||
|
@ -1795,106 +1787,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||
);
|
||||
}
|
||||
|
||||
if let (Some(sp), Some(fn_output)) = (ret_coercion_span, fn_output) {
|
||||
self.add_impl_trait_explanation(&mut err, cause, fcx, expected, sp, fn_output);
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
fn add_impl_trait_explanation<'a>(
|
||||
&self,
|
||||
err: &mut Diagnostic,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
sp: Span,
|
||||
fn_output: &hir::FnRetTy<'_>,
|
||||
) {
|
||||
let return_sp = fn_output.span();
|
||||
err.span_label(return_sp, "expected because this return type...");
|
||||
err.span_label(
|
||||
sp,
|
||||
format!("...is found to be `{}` here", fcx.resolve_vars_with_obligations(expected)),
|
||||
);
|
||||
let impl_trait_msg = "for information on `impl Trait`, see \
|
||||
<https://doc.rust-lang.org/book/ch10-02-traits.html\
|
||||
#returning-types-that-implement-traits>";
|
||||
let trait_obj_msg = "for information on trait objects, see \
|
||||
<https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
|
||||
#using-trait-objects-that-allow-for-values-of-different-types>";
|
||||
err.note("to return `impl Trait`, all returned values must be of the same type");
|
||||
err.note(impl_trait_msg);
|
||||
let snippet = fcx
|
||||
.tcx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_snippet(return_sp)
|
||||
.unwrap_or_else(|_| "dyn Trait".to_string());
|
||||
let mut snippet_iter = snippet.split_whitespace();
|
||||
let has_impl = snippet_iter.next().is_some_and(|s| s == "impl");
|
||||
// Only suggest `Box<dyn Trait>` if `Trait` in `impl Trait` is object safe.
|
||||
let mut is_object_safe = false;
|
||||
if let hir::FnRetTy::Return(ty) = fn_output
|
||||
// Get the return type.
|
||||
&& let hir::TyKind::OpaqueDef(..) = ty.kind
|
||||
{
|
||||
let ty = fcx.astconv().ast_ty_to_ty( ty);
|
||||
// Get the `impl Trait`'s `DefId`.
|
||||
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind()
|
||||
// Get the `impl Trait`'s `Item` so that we can get its trait bounds and
|
||||
// get the `Trait`'s `DefId`.
|
||||
&& let hir::ItemKind::OpaqueTy(hir::OpaqueTy { bounds, .. }) =
|
||||
fcx.tcx.hir().expect_item(def_id.expect_local()).kind
|
||||
{
|
||||
// Are of this `impl Trait`'s traits object safe?
|
||||
is_object_safe = bounds.iter().all(|bound| {
|
||||
bound
|
||||
.trait_ref()
|
||||
.and_then(|t| t.trait_def_id())
|
||||
.is_some_and(|def_id| {
|
||||
fcx.tcx.check_is_object_safe(def_id)
|
||||
})
|
||||
})
|
||||
}
|
||||
};
|
||||
if has_impl {
|
||||
if is_object_safe {
|
||||
err.multipart_suggestion(
|
||||
"you could change the return type to be a boxed trait object",
|
||||
vec![
|
||||
(return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box<dyn".to_string()),
|
||||
(return_sp.shrink_to_hi(), ">".to_string()),
|
||||
],
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
let sugg = [sp, cause.span]
|
||||
.into_iter()
|
||||
.flat_map(|sp| {
|
||||
[
|
||||
(sp.shrink_to_lo(), "Box::new(".to_string()),
|
||||
(sp.shrink_to_hi(), ")".to_string()),
|
||||
]
|
||||
.into_iter()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
err.multipart_suggestion(
|
||||
"if you change the return type to expect trait objects, box the returned \
|
||||
expressions",
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.help(format!(
|
||||
"if the trait `{}` were object safe, you could return a boxed trait object",
|
||||
&snippet[5..]
|
||||
));
|
||||
}
|
||||
err.note(trait_obj_msg);
|
||||
}
|
||||
err.help("you could instead create a new `enum` with a variant for each returned type");
|
||||
}
|
||||
|
||||
/// Checks whether the return type is unsized via an obligation, which makes
|
||||
/// sure we consider `dyn Trait: Sized` where clauses, which are trivially
|
||||
/// false but technically valid for typeck.
|
||||
|
|
|
@ -847,7 +847,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
) {
|
||||
err.subdiagnostic(subdiag);
|
||||
}
|
||||
if let Some(ret_sp) = opt_suggest_box_span {
|
||||
// don't suggest wrapping either blocks in `if .. {} else {}`
|
||||
let is_empty_arm = |id| {
|
||||
let hir::Node::Block(blk) = self.tcx.hir().get(id)
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
if blk.expr.is_some() || !blk.stmts.is_empty() {
|
||||
return false;
|
||||
}
|
||||
let Some((_, hir::Node::Expr(expr))) = self.tcx.hir().parent_iter(id).nth(1)
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
matches!(expr.kind, hir::ExprKind::If(..))
|
||||
};
|
||||
if let Some(ret_sp) = opt_suggest_box_span
|
||||
&& !is_empty_arm(then_id)
|
||||
&& !is_empty_arm(else_id)
|
||||
{
|
||||
self.suggest_boxing_for_return_impl_trait(
|
||||
err,
|
||||
ret_sp,
|
||||
|
|
|
@ -1649,12 +1649,7 @@ impl<'a> Builder<'a> {
|
|||
self.config.rust_debuginfo_level_tools
|
||||
}
|
||||
};
|
||||
if debuginfo_level == 1 {
|
||||
// Use less debuginfo than the default to save on disk space.
|
||||
cargo.env(profile_var("DEBUG"), "line-tables-only");
|
||||
} else {
|
||||
cargo.env(profile_var("DEBUG"), debuginfo_level.to_string());
|
||||
};
|
||||
cargo.env(profile_var("DEBUG"), debuginfo_level.to_string());
|
||||
if self.cc[&target].args().iter().any(|arg| arg == "-gz") {
|
||||
rustflags.arg("-Clink-arg=-gz");
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use std::cell::{Cell, RefCell};
|
|||
use std::cmp;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::env;
|
||||
use std::fmt;
|
||||
use std::fmt::{self, Display};
|
||||
use std::fs;
|
||||
use std::io::IsTerminal;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
@ -50,6 +50,57 @@ pub enum DryRun {
|
|||
UserSelected,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub enum DebuginfoLevel {
|
||||
#[default]
|
||||
None,
|
||||
LineTablesOnly,
|
||||
Limited,
|
||||
Full,
|
||||
}
|
||||
|
||||
// NOTE: can't derive(Deserialize) because the intermediate trip through toml::Value only
|
||||
// deserializes i64, and derive() only generates visit_u64
|
||||
impl<'de> Deserialize<'de> for DebuginfoLevel {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
use serde::de::Error;
|
||||
|
||||
Ok(match Deserialize::deserialize(deserializer)? {
|
||||
StringOrInt::String("none") | StringOrInt::Int(0) => DebuginfoLevel::None,
|
||||
StringOrInt::String("line-tables-only") => DebuginfoLevel::LineTablesOnly,
|
||||
StringOrInt::String("limited") | StringOrInt::Int(1) => DebuginfoLevel::Limited,
|
||||
StringOrInt::String("full") | StringOrInt::Int(2) => DebuginfoLevel::Full,
|
||||
StringOrInt::Int(n) => {
|
||||
let other = serde::de::Unexpected::Signed(n);
|
||||
return Err(D::Error::invalid_value(other, &"expected 0, 1, or 2"));
|
||||
}
|
||||
StringOrInt::String(s) => {
|
||||
let other = serde::de::Unexpected::Str(s);
|
||||
return Err(D::Error::invalid_value(
|
||||
other,
|
||||
&"expected none, line-tables-only, limited, or full",
|
||||
));
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Suitable for passing to `-C debuginfo`
|
||||
impl Display for DebuginfoLevel {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
use DebuginfoLevel::*;
|
||||
f.write_str(match self {
|
||||
None => "0",
|
||||
LineTablesOnly => "line-tables-only",
|
||||
Limited => "1",
|
||||
Full => "2",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Global configuration for the entire build and/or bootstrap.
|
||||
///
|
||||
/// This structure is parsed from `config.toml`, and some of the fields are inferred from `git` or build-time parameters.
|
||||
|
@ -159,10 +210,10 @@ pub struct Config {
|
|||
pub rust_overflow_checks: bool,
|
||||
pub rust_overflow_checks_std: bool,
|
||||
pub rust_debug_logging: bool,
|
||||
pub rust_debuginfo_level_rustc: u32,
|
||||
pub rust_debuginfo_level_std: u32,
|
||||
pub rust_debuginfo_level_tools: u32,
|
||||
pub rust_debuginfo_level_tests: u32,
|
||||
pub rust_debuginfo_level_rustc: DebuginfoLevel,
|
||||
pub rust_debuginfo_level_std: DebuginfoLevel,
|
||||
pub rust_debuginfo_level_tools: DebuginfoLevel,
|
||||
pub rust_debuginfo_level_tests: DebuginfoLevel,
|
||||
pub rust_split_debuginfo: SplitDebuginfo,
|
||||
pub rust_rpath: bool,
|
||||
pub rustc_parallel: bool,
|
||||
|
@ -810,6 +861,13 @@ impl Default for StringOrBool {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum StringOrInt<'a> {
|
||||
String(&'a str),
|
||||
Int(i64),
|
||||
}
|
||||
|
||||
define_config! {
|
||||
/// TOML representation of how the Rust build is configured.
|
||||
struct Rust {
|
||||
|
@ -822,11 +880,11 @@ define_config! {
|
|||
overflow_checks: Option<bool> = "overflow-checks",
|
||||
overflow_checks_std: Option<bool> = "overflow-checks-std",
|
||||
debug_logging: Option<bool> = "debug-logging",
|
||||
debuginfo_level: Option<u32> = "debuginfo-level",
|
||||
debuginfo_level_rustc: Option<u32> = "debuginfo-level-rustc",
|
||||
debuginfo_level_std: Option<u32> = "debuginfo-level-std",
|
||||
debuginfo_level_tools: Option<u32> = "debuginfo-level-tools",
|
||||
debuginfo_level_tests: Option<u32> = "debuginfo-level-tests",
|
||||
debuginfo_level: Option<DebuginfoLevel> = "debuginfo-level",
|
||||
debuginfo_level_rustc: Option<DebuginfoLevel> = "debuginfo-level-rustc",
|
||||
debuginfo_level_std: Option<DebuginfoLevel> = "debuginfo-level-std",
|
||||
debuginfo_level_tools: Option<DebuginfoLevel> = "debuginfo-level-tools",
|
||||
debuginfo_level_tests: Option<DebuginfoLevel> = "debuginfo-level-tests",
|
||||
split_debuginfo: Option<String> = "split-debuginfo",
|
||||
run_dsymutil: Option<bool> = "run-dsymutil",
|
||||
backtrace: Option<bool> = "backtrace",
|
||||
|
@ -1478,17 +1536,17 @@ impl Config {
|
|||
|
||||
config.rust_debug_logging = debug_logging.unwrap_or(config.rust_debug_assertions);
|
||||
|
||||
let with_defaults = |debuginfo_level_specific: Option<u32>| {
|
||||
let with_defaults = |debuginfo_level_specific: Option<_>| {
|
||||
debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) {
|
||||
1
|
||||
DebuginfoLevel::Limited
|
||||
} else {
|
||||
0
|
||||
DebuginfoLevel::None
|
||||
})
|
||||
};
|
||||
config.rust_debuginfo_level_rustc = with_defaults(debuginfo_level_rustc);
|
||||
config.rust_debuginfo_level_std = with_defaults(debuginfo_level_std);
|
||||
config.rust_debuginfo_level_tools = with_defaults(debuginfo_level_tools);
|
||||
config.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(0);
|
||||
config.rust_debuginfo_level_tests = debuginfo_level_tests.unwrap_or(DebuginfoLevel::None);
|
||||
|
||||
let download_rustc = config.download_rustc_commit.is_some();
|
||||
// See https://github.com/rust-lang/compiler-team/issues/326
|
||||
|
|
|
@ -9,6 +9,8 @@ debug-logging = true
|
|||
incremental = true
|
||||
# Download rustc from CI instead of building it from source.
|
||||
# This cuts compile times by almost 60x, but means you can't modify the compiler.
|
||||
# Using these defaults will download the stage2 compiler (see `download-rustc`
|
||||
# setting) and the stage2 toolchain should therefore be used for these defaults.
|
||||
download-rustc = "if-unchanged"
|
||||
|
||||
[build]
|
||||
|
|
|
@ -176,6 +176,14 @@ pub fn setup(config: &Config, profile: Profile) {
|
|||
);
|
||||
}
|
||||
|
||||
if profile == Profile::Tools {
|
||||
eprintln!();
|
||||
eprintln!(
|
||||
"note: the `tools` profile sets up the `stage2` toolchain (use \
|
||||
`rustup toolchain link 'name' host/build/stage2` to use rustc)"
|
||||
)
|
||||
}
|
||||
|
||||
let path = &config.config.clone().unwrap_or(PathBuf::from("config.toml"));
|
||||
setup_config_toml(path, profile, config);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
fn test() -> impl std::fmt::Debug {
|
||||
if true {
|
||||
"boo2"
|
||||
} else {
|
||||
//~^ ERROR `if` and `else` have incompatible types
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,16 @@
|
|||
error[E0308]: `if` and `else` have incompatible types
|
||||
--> $DIR/dont-suggest-box-on-empty-else-arm.rs:4:12
|
||||
|
|
||||
LL | if true {
|
||||
| ------- `if` and `else` have incompatible types
|
||||
LL | "boo2"
|
||||
| ------ expected because of this
|
||||
LL | } else {
|
||||
| ____________^
|
||||
LL | |
|
||||
LL | | }
|
||||
| |_____^ expected `&str`, found `()`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Add table
Reference in a new issue