Skip to content

Commit 1b3e686

Browse files
committed
Auto merge of #113646 - matthiaskrgr:rollup-1q6tmow, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #113353 (Implement selection for `Unsize` for better coercion behavior) - #113553 (Make Placeholder, GeneratorWitness*, Infer and Error unreachable on SMIR rustc_ty_to_ty) - #113598 (Update cargo) - #113603 (Test simd-wide-sum for codegen error) - #113613 (Allow to have `-` in rustdoc-json test file name) - #113615 (llvm-wrapper: adapt for LLVM API change) - #113616 (Fix bootstrap.py uname error) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 33a2c24 + 7ea4387 commit 1b3e686

File tree

18 files changed

+228
-33
lines changed

18 files changed

+228
-33
lines changed

compiler/rustc_hir_typeck/src/coercion.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
636636
Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)))
637637
if traits.contains(&trait_pred.def_id()) =>
638638
{
639+
let trait_pred = self.resolve_vars_if_possible(trait_pred);
639640
if unsize_did == trait_pred.def_id() {
640641
let self_ty = trait_pred.self_ty();
641642
let unsize_ty = trait_pred.trait_ref.substs[1].expect_ty();
@@ -662,7 +663,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
662663
// Uncertain or unimplemented.
663664
Ok(None) => {
664665
if trait_pred.def_id() == unsize_did {
665-
let trait_pred = self.resolve_vars_if_possible(trait_pred);
666666
let self_ty = trait_pred.self_ty();
667667
let unsize_ty = trait_pred.trait_ref.substs[1].expect_ty();
668668
debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred);

compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,7 @@ LLVMRustOptimize(
667667
assert(!PGOUsePath && !PGOSampleUsePath);
668668
PGOOpt = PGOOptions(PGOGenPath, "", "",
669669
#if LLVM_VERSION_GE(17, 0)
670+
"",
670671
FS,
671672
#endif
672673
PGOOptions::IRInstr, PGOOptions::NoCSAction,
@@ -675,20 +676,23 @@ LLVMRustOptimize(
675676
assert(!PGOSampleUsePath);
676677
PGOOpt = PGOOptions(PGOUsePath, "", "",
677678
#if LLVM_VERSION_GE(17, 0)
679+
"",
678680
FS,
679681
#endif
680682
PGOOptions::IRUse, PGOOptions::NoCSAction,
681683
DebugInfoForProfiling);
682684
} else if (PGOSampleUsePath) {
683685
PGOOpt = PGOOptions(PGOSampleUsePath, "", "",
684686
#if LLVM_VERSION_GE(17, 0)
687+
"",
685688
FS,
686689
#endif
687690
PGOOptions::SampleUse, PGOOptions::NoCSAction,
688691
DebugInfoForProfiling);
689692
} else if (DebugInfoForProfiling) {
690693
PGOOpt = PGOOptions("", "", "",
691694
#if LLVM_VERSION_GE(17, 0)
695+
"",
692696
FS,
693697
#endif
694698
PGOOptions::NoAction, PGOOptions::NoCSAction,

compiler/rustc_smir/src/rustc_smir/mod.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -103,21 +103,23 @@ impl<'tcx> Tables<'tcx> {
103103
ty::Ref(_, _, _) => todo!(),
104104
ty::FnDef(_, _) => todo!(),
105105
ty::FnPtr(_) => todo!(),
106-
ty::Placeholder(..) => todo!(),
107106
ty::Dynamic(_, _, _) => todo!(),
108107
ty::Closure(_, _) => todo!(),
109108
ty::Generator(_, _, _) => todo!(),
110-
ty::GeneratorWitness(_) => todo!(),
111-
ty::GeneratorWitnessMIR(_, _) => todo!(),
112109
ty::Never => todo!(),
113110
ty::Tuple(fields) => TyKind::RigidTy(RigidTy::Tuple(
114111
fields.iter().map(|ty| self.intern_ty(ty)).collect(),
115112
)),
116113
ty::Alias(_, _) => todo!(),
117114
ty::Param(_) => todo!(),
118115
ty::Bound(_, _) => todo!(),
119-
ty::Infer(_) => todo!(),
120-
ty::Error(_) => todo!(),
116+
ty::Placeholder(..)
117+
| ty::GeneratorWitness(_)
118+
| ty::GeneratorWitnessMIR(_, _)
119+
| ty::Infer(_)
120+
| ty::Error(_) => {
121+
unreachable!();
122+
}
121123
}
122124
}
123125

compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs

+144-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::ops::ControlFlow;
22

3+
use rustc_hir as hir;
34
use rustc_hir::def_id::DefId;
45
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
56
use rustc_infer::traits::util::supertraits;
@@ -11,7 +12,7 @@ use rustc_middle::traits::{
1112
ImplSource, ImplSourceObjectData, ImplSourceTraitUpcastingData, ImplSourceUserDefinedData,
1213
ObligationCause, SelectionError,
1314
};
14-
use rustc_middle::ty::{self, TyCtxt};
15+
use rustc_middle::ty::{self, Ty, TyCtxt};
1516
use rustc_span::DUMMY_SP;
1617

1718
use crate::solve::assembly::{BuiltinImplSource, Candidate, CandidateSource};
@@ -113,6 +114,12 @@ impl<'tcx> InferCtxtSelectExt<'tcx> for InferCtxt<'tcx> {
113114
),
114115
) => rematch_object(self, goal, nested_obligations),
115116

117+
(Certainty::Maybe(_), CandidateSource::BuiltinImpl(BuiltinImplSource::Misc))
118+
if self.tcx.lang_items().unsize_trait() == Some(goal.predicate.def_id()) =>
119+
{
120+
rematch_unsize(self, goal, nested_obligations)
121+
}
122+
116123
// Technically some builtin impls have nested obligations, but if
117124
// `Certainty::Yes`, then they should've all been verified and don't
118125
// need re-checking.
@@ -232,6 +239,9 @@ fn rematch_object<'tcx>(
232239
{
233240
assert_eq!(source_kind, ty::Dyn, "cannot upcast dyn*");
234241
if let ty::Dynamic(data, _, ty::Dyn) = goal.predicate.trait_ref.substs.type_at(1).kind() {
242+
// FIXME: We also need to ensure that the source lifetime outlives the
243+
// target lifetime. This doesn't matter for codegen, though, and only
244+
// *really* matters if the goal's certainty is ambiguous.
235245
(true, data.principal().unwrap().with_self_ty(infcx.tcx, self_ty))
236246
} else {
237247
bug!()
@@ -305,3 +315,136 @@ fn rematch_object<'tcx>(
305315
ImplSource::Object(ImplSourceObjectData { vtable_base, nested })
306316
}))
307317
}
318+
319+
/// The `Unsize` trait is particularly important to coercion, so we try rematch it.
320+
/// NOTE: This must stay in sync with `consider_builtin_unsize_candidate` in trait
321+
/// goal assembly in the solver, both for soundness and in order to avoid ICEs.
322+
fn rematch_unsize<'tcx>(
323+
infcx: &InferCtxt<'tcx>,
324+
goal: Goal<'tcx, ty::TraitPredicate<'tcx>>,
325+
mut nested: Vec<PredicateObligation<'tcx>>,
326+
) -> SelectionResult<'tcx, Selection<'tcx>> {
327+
let tcx = infcx.tcx;
328+
let a_ty = goal.predicate.self_ty();
329+
let b_ty = goal.predicate.trait_ref.substs.type_at(1);
330+
331+
match (a_ty.kind(), b_ty.kind()) {
332+
(_, &ty::Dynamic(data, region, ty::Dyn)) => {
333+
// Check that the type implements all of the predicates of the def-id.
334+
// (i.e. the principal, all of the associated types match, and any auto traits)
335+
nested.extend(data.iter().map(|pred| {
336+
Obligation::new(
337+
infcx.tcx,
338+
ObligationCause::dummy(),
339+
goal.param_env,
340+
pred.with_self_ty(tcx, a_ty),
341+
)
342+
}));
343+
// The type must be Sized to be unsized.
344+
let sized_def_id = tcx.require_lang_item(hir::LangItem::Sized, None);
345+
nested.push(Obligation::new(
346+
infcx.tcx,
347+
ObligationCause::dummy(),
348+
goal.param_env,
349+
ty::TraitRef::new(tcx, sized_def_id, [a_ty]),
350+
));
351+
// The type must outlive the lifetime of the `dyn` we're unsizing into.
352+
nested.push(Obligation::new(
353+
infcx.tcx,
354+
ObligationCause::dummy(),
355+
goal.param_env,
356+
ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region)),
357+
));
358+
}
359+
// `[T; n]` -> `[T]` unsizing
360+
(&ty::Array(a_elem_ty, ..), &ty::Slice(b_elem_ty)) => {
361+
nested.extend(
362+
infcx
363+
.at(&ObligationCause::dummy(), goal.param_env)
364+
.eq(DefineOpaqueTypes::No, a_elem_ty, b_elem_ty)
365+
.expect("expected rematch to succeed")
366+
.into_obligations(),
367+
);
368+
}
369+
// Struct unsizing `Struct<T>` -> `Struct<U>` where `T: Unsize<U>`
370+
(&ty::Adt(a_def, a_substs), &ty::Adt(b_def, b_substs))
371+
if a_def.is_struct() && a_def.did() == b_def.did() =>
372+
{
373+
let unsizing_params = tcx.unsizing_params_for_adt(a_def.did());
374+
// We must be unsizing some type parameters. This also implies
375+
// that the struct has a tail field.
376+
if unsizing_params.is_empty() {
377+
bug!("expected rematch to succeed")
378+
}
379+
380+
let tail_field = a_def
381+
.non_enum_variant()
382+
.fields
383+
.raw
384+
.last()
385+
.expect("expected unsized ADT to have a tail field");
386+
let tail_field_ty = tcx.type_of(tail_field.did);
387+
388+
let a_tail_ty = tail_field_ty.subst(tcx, a_substs);
389+
let b_tail_ty = tail_field_ty.subst(tcx, b_substs);
390+
391+
// Substitute just the unsizing params from B into A. The type after
392+
// this substitution must be equal to B. This is so we don't unsize
393+
// unrelated type parameters.
394+
let new_a_substs =
395+
tcx.mk_substs_from_iter(a_substs.iter().enumerate().map(|(i, a)| {
396+
if unsizing_params.contains(i as u32) { b_substs[i] } else { a }
397+
}));
398+
let unsized_a_ty = Ty::new_adt(tcx, a_def, new_a_substs);
399+
400+
nested.extend(
401+
infcx
402+
.at(&ObligationCause::dummy(), goal.param_env)
403+
.eq(DefineOpaqueTypes::No, unsized_a_ty, b_ty)
404+
.expect("expected rematch to succeed")
405+
.into_obligations(),
406+
);
407+
408+
// Finally, we require that `TailA: Unsize<TailB>` for the tail field
409+
// types.
410+
nested.push(Obligation::new(
411+
tcx,
412+
ObligationCause::dummy(),
413+
goal.param_env,
414+
ty::TraitRef::new(tcx, goal.predicate.def_id(), [a_tail_ty, b_tail_ty]),
415+
));
416+
}
417+
// Tuple unsizing `(.., T)` -> `(.., U)` where `T: Unsize<U>`
418+
(&ty::Tuple(a_tys), &ty::Tuple(b_tys))
419+
if a_tys.len() == b_tys.len() && !a_tys.is_empty() =>
420+
{
421+
let (a_last_ty, a_rest_tys) = a_tys.split_last().unwrap();
422+
let b_last_ty = b_tys.last().unwrap();
423+
424+
// Substitute just the tail field of B., and require that they're equal.
425+
let unsized_a_ty =
426+
Ty::new_tup_from_iter(tcx, a_rest_tys.iter().chain([b_last_ty]).copied());
427+
nested.extend(
428+
infcx
429+
.at(&ObligationCause::dummy(), goal.param_env)
430+
.eq(DefineOpaqueTypes::No, unsized_a_ty, b_ty)
431+
.expect("expected rematch to succeed")
432+
.into_obligations(),
433+
);
434+
435+
// Similar to ADTs, require that the rest of the fields are equal.
436+
nested.push(Obligation::new(
437+
tcx,
438+
ObligationCause::dummy(),
439+
goal.param_env,
440+
ty::TraitRef::new(tcx, goal.predicate.def_id(), [*a_last_ty, *b_last_ty]),
441+
));
442+
}
443+
// FIXME: We *could* ICE here if either:
444+
// 1. the certainty is `Certainty::Yes`,
445+
// 2. we're in codegen (which should mean `Certainty::Yes`).
446+
_ => return Ok(None),
447+
}
448+
449+
Ok(Some(ImplSource::Builtin(nested)))
450+
}

src/bootstrap/bootstrap.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ def default_build_triple(verbose):
256256
if uname is None:
257257
return 'x86_64-pc-windows-msvc'
258258

259-
kernel, cputype, processor = uname.decode(default_encoding).split()
259+
kernel, cputype, processor = uname.decode(default_encoding).split(maxsplit=2)
260260

261261
# The goal here is to come up with the same triple as LLVM would,
262262
# at least for the subset of platforms we're willing to target.

src/tools/compiletest/src/header.rs

+9-12
Original file line numberDiff line numberDiff line change
@@ -541,16 +541,15 @@ impl TestProps {
541541
}
542542

543543
fn update_pass_mode(&mut self, ln: &str, revision: Option<&str>, config: &Config) {
544-
let check_no_run = |s| {
545-
if config.mode != Mode::Ui && config.mode != Mode::Incremental {
546-
panic!("`{}` header is only supported in UI and incremental tests", s);
547-
}
548-
if config.mode == Mode::Incremental
549-
&& !revision.map_or(false, |r| r.starts_with("cfail"))
550-
&& !self.revisions.iter().all(|r| r.starts_with("cfail"))
551-
{
552-
panic!("`{}` header is only supported in `cfail` incremental tests", s);
544+
let check_no_run = |s| match (config.mode, s) {
545+
(Mode::Ui, _) => (),
546+
(Mode::Codegen, "build-pass") => (),
547+
(Mode::Incremental, _) => {
548+
if revision.is_some() && !self.revisions.iter().all(|r| r.starts_with("cfail")) {
549+
panic!("`{s}` header is only supported in `cfail` incremental tests")
550+
}
553551
}
552+
(mode, _) => panic!("`{s}` header is not supported in `{mode}` tests"),
554553
};
555554
let pass_mode = if config.parse_name_directive(ln, "check-pass") {
556555
check_no_run("check-pass");
@@ -559,9 +558,7 @@ impl TestProps {
559558
check_no_run("build-pass");
560559
Some(PassMode::Build)
561560
} else if config.parse_name_directive(ln, "run-pass") {
562-
if config.mode != Mode::Ui {
563-
panic!("`run-pass` header is only supported in UI tests")
564-
}
561+
check_no_run("run-pass");
565562
Some(PassMode::Run)
566563
} else {
567564
None

src/tools/compiletest/src/runtest.rs

+4
Original file line numberDiff line numberDiff line change
@@ -2752,6 +2752,10 @@ impl<'test> TestCx<'test> {
27522752
self.fatal_proc_rec("compilation failed!", &proc_res);
27532753
}
27542754

2755+
if let Some(PassMode::Build) = self.pass_mode() {
2756+
return;
2757+
}
2758+
27552759
let output_path = self.output_base_name().with_extension("ll");
27562760
let proc_res = self.verify_with_filecheck(&output_path);
27572761
if !proc_res.status.success() {

src/tools/jsondocck/src/cache.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ impl Cache {
1515
/// Create a new cache, used to read files only once and otherwise store their contents.
1616
pub fn new(config: &Config) -> Cache {
1717
let root = Path::new(&config.doc_dir);
18-
let filename = Path::new(&config.template).file_stem().unwrap();
19-
let file_path = root.join(&Path::with_extension(Path::new(filename), "json"));
18+
// `filename` needs to replace `-` with `_` to be sure the JSON path will always be valid.
19+
let filename =
20+
Path::new(&config.template).file_stem().unwrap().to_str().unwrap().replace('-', "_");
21+
let file_path = root.join(&Path::with_extension(Path::new(&filename), "json"));
2022
let content = fs::read_to_string(&file_path).expect("failed to read JSON file");
2123

2224
Cache {

src/tools/jsondoclint/src/main.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::io::{BufWriter, Write};
2+
use std::path::{Path, PathBuf};
23

34
use anyhow::{bail, Result};
45
use clap::Parser;
@@ -25,7 +26,7 @@ enum ErrorKind {
2526

2627
#[derive(Debug, Serialize)]
2728
struct JsonOutput {
28-
path: String,
29+
path: PathBuf,
2930
errors: Vec<Error>,
3031
}
3132

@@ -45,6 +46,12 @@ struct Cli {
4546
fn main() -> Result<()> {
4647
let Cli { path, verbose, json_output } = Cli::parse();
4748

49+
// We convert `-` into `_` for the file name to be sure the JSON path will always be correct.
50+
let path = Path::new(&path);
51+
let filename = path.file_name().unwrap().to_str().unwrap().replace('-', "_");
52+
let parent = path.parent().unwrap();
53+
let path = parent.join(&filename);
54+
4855
let contents = fs::read_to_string(&path)?;
4956
let krate: Crate = serde_json::from_str(&contents)?;
5057
assert_eq!(krate.format_version, FORMAT_VERSION);
@@ -101,7 +108,7 @@ fn main() -> Result<()> {
101108
ErrorKind::Custom(msg) => eprintln!("{}: {}", err.id.0, msg),
102109
}
103110
}
104-
bail!("Errors validating json {path}");
111+
bail!("Errors validating json {}", path.display());
105112
}
106113

107114
Ok(())

src/tools/tidy/src/deps.rs

+3
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ const EXCEPTIONS_CARGO: &[(&str, &str)] = &[
5656
// tidy-alphabetical-start
5757
("bitmaps", "MPL-2.0+"),
5858
("bytesize", "Apache-2.0"),
59+
("ciborium", "Apache-2.0"),
60+
("ciborium-io", "Apache-2.0"),
61+
("ciborium-ll", "Apache-2.0"),
5962
("dunce", "CC0-1.0 OR MIT-0 OR Apache-2.0"),
6063
("fiat-crypto", "MIT OR Apache-2.0 OR BSD-1-Clause"),
6164
("im-rc", "MPL-2.0+"),

src/tools/tidy/src/ui_tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::path::{Path, PathBuf};
1010

1111
const ENTRY_LIMIT: usize = 900;
1212
// FIXME: The following limits should be reduced eventually.
13-
const ISSUES_ENTRY_LIMIT: usize = 1896;
13+
const ISSUES_ENTRY_LIMIT: usize = 1894;
1414
const ROOT_ENTRY_LIMIT: usize = 870;
1515

1616
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[

0 commit comments

Comments
 (0)