Skip to content

Rollup of 8 pull requests #140324

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Apr 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3699,6 +3699,9 @@ dependencies = [
[[package]]
name = "rustc_fs_util"
version = "0.0.0"
dependencies = [
"tempfile",
]

[[package]]
name = "rustc_graphviz"
Expand Down Expand Up @@ -4011,7 +4014,6 @@ dependencies = [
"rustc_session",
"rustc_span",
"rustc_target",
"tempfile",
"tracing",
]

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_ssa/src/back/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ use object::read::archive::ArchiveFile;
use object::read::macho::FatArch;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::memmap::Mmap;
use rustc_fs_util::TempDirBuilder;
use rustc_session::Session;
use rustc_span::Symbol;
use tempfile::Builder as TempFileBuilder;
use tracing::trace;

use super::metadata::search_for_section;
Expand Down Expand Up @@ -501,7 +501,7 @@ impl<'a> ArArchiveBuilder<'a> {
// it creates. We need it to be the default mode for back compat reasons however. (See
// #107495) To handle this we are telling tempfile to create a temporary directory instead
// and then inside this directory create a file using File::create.
let archive_tmpdir = TempFileBuilder::new()
let archive_tmpdir = TempDirBuilder::new()
.suffix(".temp-archive")
.tempdir_in(output.parent().unwrap_or_else(|| Path::new("")))
.map_err(|err| {
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_errors::{DiagCtxtHandle, LintDiagnostic};
use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
use rustc_fs_util::{TempDirBuilder, fix_windows_verbatim_for_gcc, try_canonicalize};
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_macros::LintDiagnostic;
use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file};
Expand Down Expand Up @@ -48,7 +48,6 @@ use rustc_target::spec::{
LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel,
SanitizerSet, SplitDebuginfo,
};
use tempfile::Builder as TempFileBuilder;
use tracing::{debug, info, warn};

use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
Expand Down Expand Up @@ -100,7 +99,7 @@ pub fn link_binary(
});

if outputs.outputs.should_link() {
let tmpdir = TempFileBuilder::new()
let tmpdir = TempDirBuilder::new()
.prefix("rustc")
.tempdir()
.unwrap_or_else(|error| sess.dcx().emit_fatal(errors::CreateTempDir { error }));
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_fs_util/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ edition = "2024"

[dependencies]
# tidy-alphabetical-start
tempfile = "3.7.1"
# tidy-alphabetical-end
46 changes: 44 additions & 2 deletions compiler/rustc_fs_util/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::ffi::CString;
use std::ffi::{CString, OsStr};
use std::path::{Path, PathBuf, absolute};
use std::{fs, io};
use std::{env, fs, io};

use tempfile::TempDir;

// Unfortunately, on windows, it looks like msvcrt.dll is silently translating
// verbatim paths under the hood to non-verbatim paths! This manifests itself as
Expand Down Expand Up @@ -102,3 +104,43 @@ pub fn path_to_c_string(p: &Path) -> CString {
pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
fs::canonicalize(&path).or_else(|_| absolute(&path))
}

pub struct TempDirBuilder<'a, 'b> {
builder: tempfile::Builder<'a, 'b>,
}

impl<'a, 'b> TempDirBuilder<'a, 'b> {
pub fn new() -> Self {
Self { builder: tempfile::Builder::new() }
}

pub fn prefix<S: AsRef<OsStr> + ?Sized>(&mut self, prefix: &'a S) -> &mut Self {
self.builder.prefix(prefix);
self
}

pub fn suffix<S: AsRef<OsStr> + ?Sized>(&mut self, suffix: &'b S) -> &mut Self {
self.builder.suffix(suffix);
self
}

pub fn tempdir_in<P: AsRef<Path>>(&self, dir: P) -> io::Result<TempDir> {
let dir = dir.as_ref();
// On Windows in CI, we had been getting fairly frequent "Access is denied"
// errors when creating temporary directories.
// So this implements a simple retry with backoff loop.
#[cfg(windows)]
for wait in 1..11 {
match self.builder.tempdir_in(dir) {
Err(e) if e.kind() == io::ErrorKind::PermissionDenied => {}
t => return t,
}
std::thread::sleep(std::time::Duration::from_millis(1 << wait));
}
self.builder.tempdir_in(dir)
}

pub fn tempdir(&self) -> io::Result<TempDir> {
self.tempdir_in(env::temp_dir())
}
}
1 change: 1 addition & 0 deletions compiler/rustc_llvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ pub fn initialize_available_targets() {
LLVMInitializeXtensaTargetInfo,
LLVMInitializeXtensaTarget,
LLVMInitializeXtensaTargetMC,
LLVMInitializeXtensaAsmPrinter,
LLVMInitializeXtensaAsmParser
);
init_target!(
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_metadata/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ rustc_serialize = { path = "../rustc_serialize" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
tempfile = "3.2"
tracing = "0.1"
# tidy-alphabetical-end

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_metadata/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ use std::path::{Path, PathBuf};
use std::{fs, io};

use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_fs_util::TempDirBuilder;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{CrateType, OutFileName, OutputType};
use rustc_session::output::filename_for_metadata;
use rustc_session::{MetadataKind, Session};
use tempfile::Builder as TempFileBuilder;

use crate::errors::{
BinaryOutputToTty, FailedCopyToStdout, FailedCreateEncodedMetadata, FailedCreateFile,
Expand Down Expand Up @@ -45,7 +45,7 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) {
// final destination, with an `fs::rename` call. In order for the rename to
// always succeed, the temporary file needs to be on the same filesystem,
// which is why we create it inside the output directory specifically.
let metadata_tmpdir = TempFileBuilder::new()
let metadata_tmpdir = TempDirBuilder::new()
.prefix("rmeta")
.tempdir_in(out_filename.parent().unwrap_or_else(|| Path::new("")))
.unwrap_or_else(|err| tcx.dcx().emit_fatal(FailedCreateTempdir { err }));
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
self.defaultness(def_id).has_value()
}

fn impl_specializes(self, impl_def_id: Self::DefId, victim_def_id: Self::DefId) -> bool {
self.specializes((impl_def_id, victim_def_id))
}

fn impl_is_default(self, impl_def_id: DefId) -> bool {
self.defaultness(impl_def_id).is_default()
}
Expand Down
73 changes: 72 additions & 1 deletion compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use rustc_type_ir::{
};
use tracing::{debug, instrument};

use super::has_only_region_constraints;
use super::trait_goals::TraitGoalProvenVia;
use crate::delegate::SolverDelegate;
use crate::solve::inspect::ProbeKind;
Expand Down Expand Up @@ -771,6 +772,69 @@ where
}
})
}
}

pub(super) enum AllowInferenceConstraints {
Yes,
No,
}

impl<D, I> EvalCtxt<'_, D>
where
D: SolverDelegate<Interner = I>,
I: Interner,
{
/// Check whether we can ignore impl candidates due to specialization.
///
/// This is only necessary for `feature(specialization)` and seems quite ugly.
pub(super) fn filter_specialized_impls(
&mut self,
allow_inference_constraints: AllowInferenceConstraints,
candidates: &mut Vec<Candidate<I>>,
) {
match self.typing_mode() {
TypingMode::Coherence => return,
TypingMode::Analysis { .. }
| TypingMode::Borrowck { .. }
| TypingMode::PostBorrowckAnalysis { .. }
| TypingMode::PostAnalysis => {}
}

let mut i = 0;
'outer: while i < candidates.len() {
let CandidateSource::Impl(victim_def_id) = candidates[i].source else {
i += 1;
continue;
};

for (j, c) in candidates.iter().enumerate() {
if i == j {
continue;
}

let CandidateSource::Impl(other_def_id) = c.source else {
continue;
};

// See if we can toss out `victim` based on specialization.
//
// While this requires us to know *for sure* that the `lhs` impl applies
// we still use modulo regions here. This is fine as specialization currently
// assumes that specializing impls have to be always applicable, meaning that
// the only allowed region constraints may be constraints also present on the default impl.
if matches!(allow_inference_constraints, AllowInferenceConstraints::Yes)
|| has_only_region_constraints(c.result)
{
if self.cx().impl_specializes(other_def_id, victim_def_id) {
candidates.remove(i);
continue 'outer;
}
}
}

i += 1;
}
}

/// Assemble and merge candidates for goals which are related to an underlying trait
/// goal. Right now, this is normalizes-to and host effect goals.
Expand Down Expand Up @@ -857,7 +921,7 @@ where
}
}
TraitGoalProvenVia::Misc => {
let candidates =
let mut candidates =
self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);

// Prefer "orphaned" param-env normalization predicates, which are used
Expand All @@ -871,6 +935,13 @@ where
return Ok(response);
}

// We drop specialized impls to allow normalization via a final impl here. In case
// the specializing impl has different inference constraints from the specialized
// impl, proving the trait goal is already ambiguous, so we never get here. This
// means we can just ignore inference constraints and don't have to special-case
// constraining the normalized-to `term`.
self.filter_specialized_impls(AllowInferenceConstraints::Yes, &mut candidates);

let responses: Vec<_> = candidates.iter().map(|c| c.result).collect();
if let Some(response) = self.try_merge_responses(&responses) {
Ok(response)
Expand Down
10 changes: 3 additions & 7 deletions compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use rustc_type_ir::{
};
use tracing::{instrument, trace};

use super::has_only_region_constraints;
use crate::coherence;
use crate::delegate::SolverDelegate;
use crate::solve::inspect::{self, ProofTreeBuilder};
Expand Down Expand Up @@ -476,13 +477,8 @@ where
Ok(response) => response,
};

let has_changed = if !response.value.var_values.is_identity_modulo_regions()
|| !response.value.external_constraints.opaque_types.is_empty()
{
HasChanged::Yes
} else {
HasChanged::No
};
let has_changed =
if !has_only_region_constraints(response) { HasChanged::Yes } else { HasChanged::No };

let (normalization_nested_goals, certainty) =
self.instantiate_and_apply_query_response(goal.param_env, orig_values, response);
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_next_trait_solver/src/solve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,17 @@ fn has_no_inference_or_external_constraints<I: Interner>(
&& normalization_nested_goals.is_empty()
}

fn has_only_region_constraints<I: Interner>(response: ty::Canonical<I, Response<I>>) -> bool {
let ExternalConstraintsData {
region_constraints: _,
ref opaque_types,
ref normalization_nested_goals,
} = *response.value.external_constraints;
response.value.var_values.is_identity_modulo_regions()
&& opaque_types.is_empty()
&& normalization_nested_goals.is_empty()
}

impl<'a, D, I> EvalCtxt<'a, D>
where
D: SolverDelegate<Interner = I>,
Expand Down
27 changes: 22 additions & 5 deletions compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,18 +213,35 @@ where
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
};

// In case the associated item is hidden due to specialization, we have to
// return ambiguity this would otherwise be incomplete, resulting in
// unsoundness during coherence (#105782).
let target_item_def_id = match ecx.fetch_eligible_assoc_item(
goal_trait_ref,
goal.predicate.def_id(),
impl_def_id,
) {
Ok(Some(target_item_def_id)) => target_item_def_id,
Ok(None) => {
return ecx
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
match ecx.typing_mode() {
// In case the associated item is hidden due to specialization, we have to
// return ambiguity this would otherwise be incomplete, resulting in
// unsoundness during coherence (#105782).
ty::TypingMode::Coherence => {
return ecx.evaluate_added_goals_and_make_canonical_response(
Certainty::AMBIGUOUS,
);
}
// Outside of coherence, we treat the associated item as rigid instead.
ty::TypingMode::Analysis { .. }
| ty::TypingMode::Borrowck { .. }
| ty::TypingMode::PostBorrowckAnalysis { .. }
| ty::TypingMode::PostAnalysis => {
ecx.structurally_instantiate_normalizes_to_term(
goal,
goal.predicate.alias,
);
return ecx
.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
}
};
}
Err(guar) => return error_response(ecx, guar),
};
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use tracing::{instrument, trace};

use crate::delegate::SolverDelegate;
use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
use crate::solve::assembly::{self, AssembleCandidatesFrom, Candidate};
use crate::solve::assembly::{self, AllowInferenceConstraints, AssembleCandidatesFrom, Candidate};
use crate::solve::inspect::ProbeKind;
use crate::solve::{
BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
Expand Down Expand Up @@ -1338,6 +1338,8 @@ where
};
}

self.filter_specialized_impls(AllowInferenceConstraints::No, &mut candidates);

// If there are *only* global where bounds, then make sure to return that this
// is still reported as being proven-via the param-env so that rigid projections
// operate correctly. Otherwise, drop all global where-bounds before merging the
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_parse/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,8 @@ parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns ar

parse_nul_in_c_str = null characters in C string literals are not supported

parse_or_in_let_chain = `||` operators are not supported in let chain conditions

parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters
parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings
parse_out_of_range_hex_escape = out of range hex escape
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,13 @@ pub(crate) struct ExpectedExpressionFoundLet {
pub comparison: Option<MaybeComparison>,
}

#[derive(Diagnostic)]
#[diag(parse_or_in_let_chain)]
pub(crate) struct OrInLetChain {
#[primary_span]
pub span: Span,
}

#[derive(Subdiagnostic, Clone, Copy)]
#[multipart_suggestion(
parse_maybe_missing_let,
Expand Down
Loading
Loading