Skip to content

Commit 398fa21

Browse files
committed
Auto merge of #112253 - matthiaskrgr:rollup-c37jpm5, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #111659 (suggest `Option::as_deref(_mut)` on type mismatch in option combinator if it passes typeck) - #111702 (Option::map_or_else: Show an example of integrating with Result) - #111878 (Fix codegen test suite for bare-metal-like targets) - #111969 (bootstrap: Make `clean` respect `dry-run`) - #111998 (Add other workspaces to `linkedProjects` in rust_analyzer_settings) - #112215 (only suppress coercion error if type is definitely unsized) - #112231 (Make sure the build.rustc version is either the same or 1 apart (revised)) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 2f5e6bb + d4f87d1 commit 398fa21

40 files changed

+586
-80
lines changed

Diff for: compiler/rustc_hir_typeck/src/coercion.rs

+19-11
Original file line numberDiff line numberDiff line change
@@ -1595,7 +1595,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
15951595
Some(blk_id),
15961596
);
15971597
if !fcx.tcx.features().unsized_locals {
1598-
unsized_return = self.is_return_ty_unsized(fcx, blk_id);
1598+
unsized_return = self.is_return_ty_definitely_unsized(fcx);
15991599
}
16001600
if let Some(expression) = expression
16011601
&& let hir::ExprKind::Loop(loop_blk, ..) = expression.kind {
@@ -1614,8 +1614,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
16141614
None,
16151615
);
16161616
if !fcx.tcx.features().unsized_locals {
1617-
let id = fcx.tcx.hir().parent_id(id);
1618-
unsized_return = self.is_return_ty_unsized(fcx, id);
1617+
unsized_return = self.is_return_ty_definitely_unsized(fcx);
16191618
}
16201619
}
16211620
_ => {
@@ -1896,15 +1895,24 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
18961895
err.help("you could instead create a new `enum` with a variant for each returned type");
18971896
}
18981897

1899-
fn is_return_ty_unsized<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
1900-
if let Some((_, fn_decl, _)) = fcx.get_fn_decl(blk_id)
1901-
&& let hir::FnRetTy::Return(ty) = fn_decl.output
1902-
&& let ty = fcx.astconv().ast_ty_to_ty( ty)
1903-
&& let ty::Dynamic(..) = ty.kind()
1904-
{
1905-
return true;
1898+
/// Checks whether the return type is unsized via an obligation, which makes
1899+
/// sure we consider `dyn Trait: Sized` where clauses, which are trivially
1900+
/// false but technically valid for typeck.
1901+
fn is_return_ty_definitely_unsized(&self, fcx: &FnCtxt<'_, 'tcx>) -> bool {
1902+
if let Some(sig) = fcx.body_fn_sig() {
1903+
!fcx.predicate_may_hold(&Obligation::new(
1904+
fcx.tcx,
1905+
ObligationCause::dummy(),
1906+
fcx.param_env,
1907+
ty::TraitRef::new(
1908+
fcx.tcx,
1909+
fcx.tcx.require_lang_item(hir::LangItem::Sized, None),
1910+
[sig.output()],
1911+
),
1912+
))
1913+
} else {
1914+
false
19061915
}
1907-
false
19081916
}
19091917

19101918
pub fn complete<'a>(self, fcx: &FnCtxt<'a, 'tcx>) -> Ty<'tcx> {

Diff for: compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+95-9
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_data_structures::fx::FxHashSet;
1313
use rustc_data_structures::stack::ensure_sufficient_stack;
1414
use rustc_errors::{
1515
error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder,
16-
ErrorGuaranteed, MultiSpan, Style,
16+
ErrorGuaranteed, MultiSpan, Style, SuggestionStyle,
1717
};
1818
use rustc_hir as hir;
1919
use rustc_hir::def::DefKind;
@@ -362,6 +362,15 @@ pub trait TypeErrCtxtExt<'tcx> {
362362
err: &mut Diagnostic,
363363
trait_pred: ty::PolyTraitPredicate<'tcx>,
364364
);
365+
366+
fn suggest_option_method_if_applicable(
367+
&self,
368+
failed_pred: ty::Predicate<'tcx>,
369+
param_env: ty::ParamEnv<'tcx>,
370+
err: &mut Diagnostic,
371+
expr: &hir::Expr<'_>,
372+
);
373+
365374
fn note_function_argument_obligation(
366375
&self,
367376
body_id: LocalDefId,
@@ -3521,15 +3530,92 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
35213530
err.replace_span_with(path.ident.span, true);
35223531
}
35233532
}
3524-
if let Some(Node::Expr(hir::Expr {
3525-
kind:
3526-
hir::ExprKind::Call(hir::Expr { span, .. }, _)
3527-
| hir::ExprKind::MethodCall(hir::PathSegment { ident: Ident { span, .. }, .. }, ..),
3528-
..
3529-
})) = hir.find(call_hir_id)
3533+
3534+
if let Some(Node::Expr(expr)) = hir.find(call_hir_id) {
3535+
if let hir::ExprKind::Call(hir::Expr { span, .. }, _)
3536+
| hir::ExprKind::MethodCall(
3537+
hir::PathSegment { ident: Ident { span, .. }, .. },
3538+
..,
3539+
) = expr.kind
3540+
{
3541+
if Some(*span) != err.span.primary_span() {
3542+
err.span_label(*span, "required by a bound introduced by this call");
3543+
}
3544+
}
3545+
3546+
if let hir::ExprKind::MethodCall(_, expr, ..) = expr.kind {
3547+
self.suggest_option_method_if_applicable(failed_pred, param_env, err, expr);
3548+
}
3549+
}
3550+
}
3551+
3552+
fn suggest_option_method_if_applicable(
3553+
&self,
3554+
failed_pred: ty::Predicate<'tcx>,
3555+
param_env: ty::ParamEnv<'tcx>,
3556+
err: &mut Diagnostic,
3557+
expr: &hir::Expr<'_>,
3558+
) {
3559+
let tcx = self.tcx;
3560+
let infcx = self.infcx;
3561+
let Some(typeck_results) = self.typeck_results.as_ref() else { return };
3562+
3563+
// Make sure we're dealing with the `Option` type.
3564+
let Some(option_ty_adt) = typeck_results.expr_ty_adjusted(expr).ty_adt_def() else { return };
3565+
if !tcx.is_diagnostic_item(sym::Option, option_ty_adt.did()) {
3566+
return;
3567+
}
3568+
3569+
// Given the predicate `fn(&T): FnOnce<(U,)>`, extract `fn(&T)` and `(U,)`,
3570+
// then suggest `Option::as_deref(_mut)` if `U` can deref to `T`
3571+
if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate { trait_ref, .. }))
3572+
= failed_pred.kind().skip_binder()
3573+
&& tcx.is_fn_trait(trait_ref.def_id)
3574+
&& let [self_ty, found_ty] = trait_ref.substs.as_slice()
3575+
&& let Some(fn_ty) = self_ty.as_type().filter(|ty| ty.is_fn())
3576+
&& let fn_sig @ ty::FnSig {
3577+
abi: abi::Abi::Rust,
3578+
c_variadic: false,
3579+
unsafety: hir::Unsafety::Normal,
3580+
..
3581+
} = fn_ty.fn_sig(tcx).skip_binder()
3582+
3583+
// Extract first param of fn sig with peeled refs, e.g. `fn(&T)` -> `T`
3584+
&& let Some(&ty::Ref(_, target_ty, needs_mut)) = fn_sig.inputs().first().map(|t| t.kind())
3585+
&& !target_ty.has_escaping_bound_vars()
3586+
3587+
// Extract first tuple element out of fn trait, e.g. `FnOnce<(U,)>` -> `U`
3588+
&& let Some(ty::Tuple(tys)) = found_ty.as_type().map(Ty::kind)
3589+
&& let &[found_ty] = tys.as_slice()
3590+
&& !found_ty.has_escaping_bound_vars()
3591+
3592+
// Extract `<U as Deref>::Target` assoc type and check that it is `T`
3593+
&& let Some(deref_target_did) = tcx.lang_items().deref_target()
3594+
&& let projection = tcx.mk_projection(deref_target_did, tcx.mk_substs(&[ty::GenericArg::from(found_ty)]))
3595+
&& let Ok(deref_target) = tcx.try_normalize_erasing_regions(param_env, projection)
3596+
&& deref_target == target_ty
35303597
{
3531-
if Some(*span) != err.span.primary_span() {
3532-
err.span_label(*span, "required by a bound introduced by this call");
3598+
let help = if let hir::Mutability::Mut = needs_mut
3599+
&& let Some(deref_mut_did) = tcx.lang_items().deref_mut_trait()
3600+
&& infcx
3601+
.type_implements_trait(deref_mut_did, iter::once(found_ty), param_env)
3602+
.must_apply_modulo_regions()
3603+
{
3604+
Some(("call `Option::as_deref_mut()` first", ".as_deref_mut()"))
3605+
} else if let hir::Mutability::Not = needs_mut {
3606+
Some(("call `Option::as_deref()` first", ".as_deref()"))
3607+
} else {
3608+
None
3609+
};
3610+
3611+
if let Some((msg, sugg)) = help {
3612+
err.span_suggestion_with_style(
3613+
expr.span.shrink_to_hi(),
3614+
msg,
3615+
sugg,
3616+
Applicability::MaybeIncorrect,
3617+
SuggestionStyle::ShowAlways
3618+
);
35333619
}
35343620
}
35353621
}

Diff for: library/core/src/option.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -1138,7 +1138,7 @@ impl<T> Option<T> {
11381138
/// Computes a default function result (if none), or
11391139
/// applies a different function to the contained value (if any).
11401140
///
1141-
/// # Examples
1141+
/// # Basic examples
11421142
///
11431143
/// ```
11441144
/// let k = 21;
@@ -1149,6 +1149,25 @@ impl<T> Option<T> {
11491149
/// let x: Option<&str> = None;
11501150
/// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42);
11511151
/// ```
1152+
///
1153+
/// # Handling a Result-based fallback
1154+
///
1155+
/// A somewhat common occurrence when dealing with optional values
1156+
/// in combination with [`Result<T, E>`] is the case where one wants to invoke
1157+
/// a fallible fallback if the option is not present. This example
1158+
/// parses a command line argument (if present), or the contents of a file to
1159+
/// an integer. However, unlike accessing the command line argument, reading
1160+
/// the file is fallible, so it must be wrapped with `Ok`.
1161+
///
1162+
/// ```no_run
1163+
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
1164+
/// let v: u64 = std::env::args()
1165+
/// .nth(1)
1166+
/// .map_or_else(|| std::fs::read_to_string("/etc/someconfig.conf"), Ok)?
1167+
/// .parse()?;
1168+
/// # Ok(())
1169+
/// # }
1170+
/// ```
11521171
#[inline]
11531172
#[stable(feature = "rust1", since = "1.0.0")]
11541173
pub fn map_or_else<U, D, F>(self, default: D, f: F) -> U

Diff for: src/bootstrap/Cargo.lock

+7
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ dependencies = [
5858
"once_cell",
5959
"opener",
6060
"pretty_assertions",
61+
"semver",
6162
"serde",
6263
"serde_derive",
6364
"serde_json",
@@ -645,6 +646,12 @@ version = "1.1.0"
645646
source = "registry+https://github.com/rust-lang/crates.io-index"
646647
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
647648

649+
[[package]]
650+
name = "semver"
651+
version = "1.0.17"
652+
source = "registry+https://github.com/rust-lang/crates.io-index"
653+
checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
654+
648655
[[package]]
649656
name = "serde"
650657
version = "1.0.160"

Diff for: src/bootstrap/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ walkdir = "2"
5757
sysinfo = { version = "0.26.0", optional = true }
5858
clap = { version = "4.2.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] }
5959
clap_complete = "4.2.2"
60+
semver = "1.0.17"
6061

6162
# Solaris doesn't support flock() and thus fd-lock is not option now
6263
[target.'cfg(not(target_os = "solaris"))'.dependencies]

Diff for: src/bootstrap/clean.rs

+4
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ clean_crate_tree! {
8585
}
8686

8787
fn clean_default(build: &Build, all: bool) {
88+
if build.config.dry_run() {
89+
return;
90+
}
91+
8892
rm_rf("tmp".as_ref());
8993

9094
if all {

Diff for: src/bootstrap/config.rs

+43-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use crate::flags::{Color, Flags, Warnings};
2525
use crate::util::{exe, output, t};
2626
use build_helper::detail_exit_macro;
2727
use once_cell::sync::OnceCell;
28+
use semver::Version;
2829
use serde::{Deserialize, Deserializer};
2930
use serde_derive::Deserialize;
3031

@@ -1114,10 +1115,14 @@ impl Config {
11141115
config.out = crate::util::absolute(&config.out);
11151116
}
11161117

1117-
config.initial_rustc = build.rustc.map(PathBuf::from).unwrap_or_else(|| {
1118+
config.initial_rustc = if let Some(rustc) = build.rustc {
1119+
config.check_build_rustc_version(&rustc);
1120+
PathBuf::from(rustc)
1121+
} else {
11181122
config.download_beta_toolchain();
11191123
config.out.join(config.build.triple).join("stage0/bin/rustc")
1120-
});
1124+
};
1125+
11211126
config.initial_cargo = build
11221127
.cargo
11231128
.map(|cargo| {
@@ -1779,6 +1784,42 @@ impl Config {
17791784
self.rust_codegen_backends.get(0).cloned()
17801785
}
17811786

1787+
pub fn check_build_rustc_version(&self, rustc_path: &str) {
1788+
if self.dry_run() {
1789+
return;
1790+
}
1791+
1792+
// check rustc version is same or lower with 1 apart from the building one
1793+
let mut cmd = Command::new(rustc_path);
1794+
cmd.arg("--version");
1795+
let rustc_output = output(&mut cmd)
1796+
.lines()
1797+
.next()
1798+
.unwrap()
1799+
.split(' ')
1800+
.nth(1)
1801+
.unwrap()
1802+
.split('-')
1803+
.next()
1804+
.unwrap()
1805+
.to_owned();
1806+
let rustc_version = Version::parse(&rustc_output.trim()).unwrap();
1807+
let source_version =
1808+
Version::parse(&fs::read_to_string(self.src.join("src/version")).unwrap().trim())
1809+
.unwrap();
1810+
if !(source_version == rustc_version
1811+
|| (source_version.major == rustc_version.major
1812+
&& source_version.minor == rustc_version.minor + 1))
1813+
{
1814+
let prev_version = format!("{}.{}.x", source_version.major, source_version.minor - 1);
1815+
eprintln!(
1816+
"Unexpected rustc version: {}, we should use {}/{} to build source with {}",
1817+
rustc_version, prev_version, source_version, source_version
1818+
);
1819+
detail_exit_macro!(1);
1820+
}
1821+
}
1822+
17821823
/// Returns the commit to download, or `None` if we shouldn't download CI artifacts.
17831824
fn download_ci_rustc_commit(&self, download_rustc: Option<StringOrBool>) -> Option<String> {
17841825
// If `download-rustc` is not set, default to rebuilding.

Diff for: src/bootstrap/setup.rs

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ static SETTINGS_HASHES: &[&str] = &[
3131
"ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8",
3232
"56e7bf011c71c5d81e0bf42e84938111847a810eee69d906bba494ea90b51922",
3333
"af1b5efe196aed007577899db9dae15d6dbc923d6fa42fa0934e68617ba9bbe0",
34+
"3468fea433c25fff60be6b71e8a215a732a7b1268b6a83bf10d024344e140541",
3435
];
3536
static RUST_ANALYZER_SETTINGS: &str = include_str!("../etc/rust_analyzer_settings.json");
3637

Diff for: src/etc/rust_analyzer_settings.json

+8-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@
77
"check",
88
"--json-output"
99
],
10-
"rust-analyzer.linkedProjects": ["src/bootstrap/Cargo.toml", "Cargo.toml"],
10+
"rust-analyzer.linkedProjects": [
11+
"Cargo.toml",
12+
"src/tools/x/Cargo.toml",
13+
"src/bootstrap/Cargo.toml",
14+
"src/tools/rust-analyzer/Cargo.toml",
15+
"compiler/rustc_codegen_cranelift/Cargo.toml",
16+
"compiler/rustc_codegen_gcc/Cargo.toml"
17+
],
1118
"rust-analyzer.rustfmt.overrideCommand": [
1219
"./build/host/rustfmt/bin/rustfmt",
1320
"--edition=2021"

Diff for: src/tools/x/Cargo.lock

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# This file is automatically @generated by Cargo.
22
# It is not intended for manual editing.
3+
version = 3
4+
35
[[package]]
46
name = "x"
5-
version = "0.1.0"
7+
version = "0.1.1"

Diff for: tests/codegen/box-maybe-uninit-llvm14.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,4 @@ pub fn box_uninitialized2() -> Box<MaybeUninit<[usize; 1024 * 1024]>> {
3131
// Hide the LLVM 15+ `allocalign` attribute in the declaration of __rust_alloc
3232
// from the CHECK-NOT above. We don't check the attributes here because we can't rely
3333
// on all of them being set until LLVM 15.
34-
// CHECK: declare noalias{{.*}} @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+.*}} noundef)
34+
// CHECK: declare {{(dso_local )?}}noalias{{.*}} @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+.*}} noundef)

Diff for: tests/codegen/box-maybe-uninit.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,6 @@ pub fn box_uninitialized2() -> Box<MaybeUninit<[usize; 1024 * 1024]>> {
2828

2929
// Hide the `allocalign` attribute in the declaration of __rust_alloc
3030
// from the CHECK-NOT above, and also verify the attributes got set reasonably.
31-
// CHECK: declare noalias noundef ptr @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+}} allocalign noundef) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]]
31+
// CHECK: declare {{(dso_local )?}}noalias noundef ptr @__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+}} allocalign noundef) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]]
3232

33-
// CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned") allocsize(0) uwtable "alloc-family"="__rust_alloc" {{.*}} }
33+
// CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned") allocsize(0) {{(uwtable )?}}"alloc-family"="__rust_alloc" {{.*}} }

Diff for: tests/codegen/call-metadata.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#![crate_type = "lib"]
77

88
pub fn test() {
9-
// CHECK: call noundef i8 @some_true(), !range [[R0:![0-9]+]]
9+
// CHECK: call noundef i8 @some_true(){{( #[0-9]+)?}}, !range [[R0:![0-9]+]]
1010
// CHECK: [[R0]] = !{i8 0, i8 3}
1111
some_true();
1212
}

Diff for: tests/codegen/debug-column.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
fn main() {
77
unsafe {
88
// Column numbers are 1-based. Regression test for #65437.
9-
// CHECK: call void @giraffe(), !dbg [[A:!.*]]
9+
// CHECK: call void @giraffe(){{( #[0-9]+)?}}, !dbg [[A:!.*]]
1010
giraffe();
1111

1212
// Column numbers use byte offests. Regression test for #67360
13-
// CHECK: call void @turtle(), !dbg [[B:!.*]]
13+
// CHECK: call void @turtle(){{( #[0-9]+)?}}, !dbg [[B:!.*]]
1414
/* ż */ turtle();
1515

1616
// CHECK: [[A]] = !DILocation(line: 10, column: 9,

Diff for: tests/codegen/drop.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// ignore-wasm32-bare compiled with panic=abort by default
2+
// needs-unwind - this test verifies the amount of drop calls when unwinding is used
23
// compile-flags: -C no-prepopulate-passes
34

45
#![crate_type = "lib"]

0 commit comments

Comments
 (0)