Skip to content

Commit eb1e588

Browse files
committed
Auto merge of rust-lang#97014 - Mark-Simulacrum:beta-next, r=Mark-Simulacrum
[beta] backports This backports/rolls up: * Quick fix for rust-lang#96223. rust-lang#96679 * [beta] Revert rust-lang#92519 on beta rust-lang#96556 * [beta] Clippy backport ICE/infinite loop fix rust-lang#96740 * Revert "Prefer projection candidates instead of param_env candidates for Sized predicates" rust-lang#96593
2 parents cf5fd89 + 97f0d7f commit eb1e588

File tree

14 files changed

+205
-96
lines changed

14 files changed

+205
-96
lines changed

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
713713
return false;
714714
}
715715

716-
let orig_ty = old_pred.self_ty().skip_binder();
716+
// This is a quick fix to resolve an ICE (#96223).
717+
// This change should probably be deeper.
718+
// As suggested by @jackh726, `mk_trait_obligation_with_new_self_ty` could take a `Binder<(TraitRef, Ty)>
719+
// instead of `Binder<Ty>` leading to some changes to its call places.
720+
let Some(orig_ty) = old_pred.self_ty().no_bound_vars() else {
721+
return false;
722+
};
717723
let mk_result = |new_ty| {
718724
let obligation =
719725
self.mk_trait_obligation_with_new_self_ty(param_env, old_pred, new_ty);

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

-4
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
175175

176176
let needs_infer = stack.obligation.predicate.has_infer_types_or_consts();
177177

178-
let sized_predicate = self.tcx().lang_items().sized_trait()
179-
== Some(stack.obligation.predicate.skip_binder().def_id());
180-
181178
// If there are STILL multiple candidates, we can further
182179
// reduce the list by dropping duplicates -- including
183180
// resolving specializations.
@@ -186,7 +183,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
186183
while i < candidates.len() {
187184
let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| {
188185
self.candidate_should_be_dropped_in_favor_of(
189-
sized_predicate,
190186
&candidates[i],
191187
&candidates[j],
192188
needs_infer,

compiler/rustc_trait_selection/src/traits/select/mod.rs

+8-12
Original file line numberDiff line numberDiff line change
@@ -1553,7 +1553,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
15531553
/// See the comment for "SelectionCandidate" for more details.
15541554
fn candidate_should_be_dropped_in_favor_of(
15551555
&mut self,
1556-
sized_predicate: bool,
15571556
victim: &EvaluatedCandidate<'tcx>,
15581557
other: &EvaluatedCandidate<'tcx>,
15591558
needs_infer: bool,
@@ -1625,16 +1624,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16251624
// Drop otherwise equivalent non-const fn pointer candidates
16261625
(FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => true,
16271626

1628-
// If obligation is a sized predicate or the where-clause bound is
1629-
// global, prefer the projection or object candidate. See issue
1630-
// #50825 and #89352.
1631-
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
1632-
sized_predicate || is_global(cand)
1633-
}
1634-
(ParamCandidate(ref cand), ObjectCandidate(_) | ProjectionCandidate(_)) => {
1635-
!(sized_predicate || is_global(cand))
1636-
}
1637-
16381627
// Global bounds from the where clause should be ignored
16391628
// here (see issue #50825). Otherwise, we have a where
16401629
// clause so don't go around looking for impls.
@@ -1650,8 +1639,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
16501639
| BuiltinUnsizeCandidate
16511640
| TraitUpcastingUnsizeCandidate(_)
16521641
| BuiltinCandidate { .. }
1653-
| TraitAliasCandidate(..),
1642+
| TraitAliasCandidate(..)
1643+
| ObjectCandidate(_)
1644+
| ProjectionCandidate(_),
16541645
) => !is_global(cand),
1646+
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
1647+
// Prefer these to a global where-clause bound
1648+
// (see issue #50825).
1649+
is_global(cand)
1650+
}
16551651
(
16561652
ImplCandidate(_)
16571653
| ClosureCandidate

library/std/src/sys/windows/process.rs

+28-39
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ use crate::path::{Path, PathBuf};
1919
use crate::ptr;
2020
use crate::sys::c;
2121
use crate::sys::c::NonZeroDWORD;
22-
use crate::sys::cvt;
2322
use crate::sys::fs::{File, OpenOptions};
2423
use crate::sys::handle::Handle;
2524
use crate::sys::path;
2625
use crate::sys::pipe::{self, AnonPipe};
2726
use crate::sys::stdio;
27+
use crate::sys::{cvt, to_u16s};
2828
use crate::sys_common::mutex::StaticMutex;
2929
use crate::sys_common::process::{CommandEnv, CommandEnvs};
3030
use crate::sys_common::{AsInner, IntoInner};
@@ -269,13 +269,8 @@ impl Command {
269269
None
270270
};
271271
let program = resolve_exe(&self.program, || env::var_os("PATH"), child_paths)?;
272-
// Case insensitive "ends_with" of UTF-16 encoded ".bat" or ".cmd"
273-
let is_batch_file = matches!(
274-
program.len().checked_sub(5).and_then(|i| program.get(i..)),
275-
Some([46, 98 | 66, 97 | 65, 116 | 84, 0] | [46, 99 | 67, 109 | 77, 100 | 68, 0])
276-
);
277272
let mut cmd_str =
278-
make_command_line(&program, &self.args, self.force_quotes_enabled, is_batch_file)?;
273+
make_command_line(program.as_os_str(), &self.args, self.force_quotes_enabled)?;
279274
cmd_str.push(0); // add null terminator
280275

281276
// stolen from the libuv code.
@@ -314,6 +309,7 @@ impl Command {
314309
si.hStdOutput = stdout.as_raw_handle();
315310
si.hStdError = stderr.as_raw_handle();
316311

312+
let program = to_u16s(&program)?;
317313
unsafe {
318314
cvt(c::CreateProcessW(
319315
program.as_ptr(),
@@ -370,7 +366,7 @@ fn resolve_exe<'a>(
370366
exe_path: &'a OsStr,
371367
parent_paths: impl FnOnce() -> Option<OsString>,
372368
child_paths: Option<&OsStr>,
373-
) -> io::Result<Vec<u16>> {
369+
) -> io::Result<PathBuf> {
374370
// Early return if there is no filename.
375371
if exe_path.is_empty() || path::has_trailing_slash(exe_path) {
376372
return Err(io::const_io_error!(
@@ -392,19 +388,19 @@ fn resolve_exe<'a>(
392388
if has_exe_suffix {
393389
// The application name is a path to a `.exe` file.
394390
// Let `CreateProcessW` figure out if it exists or not.
395-
return path::maybe_verbatim(Path::new(exe_path));
391+
return Ok(exe_path.into());
396392
}
397393
let mut path = PathBuf::from(exe_path);
398394

399395
// Append `.exe` if not already there.
400396
path = path::append_suffix(path, EXE_SUFFIX.as_ref());
401-
if let Some(path) = program_exists(&path) {
397+
if program_exists(&path) {
402398
return Ok(path);
403399
} else {
404400
// It's ok to use `set_extension` here because the intent is to
405401
// remove the extension that was just added.
406402
path.set_extension("");
407-
return path::maybe_verbatim(&path);
403+
return Ok(path);
408404
}
409405
} else {
410406
ensure_no_nuls(exe_path)?;
@@ -419,7 +415,7 @@ fn resolve_exe<'a>(
419415
if !has_extension {
420416
path.set_extension(EXE_EXTENSION);
421417
}
422-
program_exists(&path)
418+
if program_exists(&path) { Some(path) } else { None }
423419
});
424420
if let Some(path) = result {
425421
return Ok(path);
@@ -435,10 +431,10 @@ fn search_paths<Paths, Exists>(
435431
parent_paths: Paths,
436432
child_paths: Option<&OsStr>,
437433
mut exists: Exists,
438-
) -> Option<Vec<u16>>
434+
) -> Option<PathBuf>
439435
where
440436
Paths: FnOnce() -> Option<OsString>,
441-
Exists: FnMut(PathBuf) -> Option<Vec<u16>>,
437+
Exists: FnMut(PathBuf) -> Option<PathBuf>,
442438
{
443439
// 1. Child paths
444440
// This is for consistency with Rust's historic behaviour.
@@ -490,18 +486,17 @@ where
490486
}
491487

492488
/// Check if a file exists without following symlinks.
493-
fn program_exists(path: &Path) -> Option<Vec<u16>> {
489+
fn program_exists(path: &Path) -> bool {
494490
unsafe {
495-
let path = path::maybe_verbatim(path).ok()?;
496-
// Getting attributes using `GetFileAttributesW` does not follow symlinks
497-
// and it will almost always be successful if the link exists.
498-
// There are some exceptions for special system files (e.g. the pagefile)
499-
// but these are not executable.
500-
if c::GetFileAttributesW(path.as_ptr()) == c::INVALID_FILE_ATTRIBUTES {
501-
None
502-
} else {
503-
Some(path)
504-
}
491+
to_u16s(path)
492+
.map(|path| {
493+
// Getting attributes using `GetFileAttributesW` does not follow symlinks
494+
// and it will almost always be successful if the link exists.
495+
// There are some exceptions for special system files (e.g. the pagefile)
496+
// but these are not executable.
497+
c::GetFileAttributesW(path.as_ptr()) != c::INVALID_FILE_ATTRIBUTES
498+
})
499+
.unwrap_or(false)
505500
}
506501
}
507502

@@ -735,12 +730,7 @@ enum Quote {
735730

736731
// Produces a wide string *without terminating null*; returns an error if
737732
// `prog` or any of the `args` contain a nul.
738-
fn make_command_line(
739-
prog: &[u16],
740-
args: &[Arg],
741-
force_quotes: bool,
742-
is_batch_file: bool,
743-
) -> io::Result<Vec<u16>> {
733+
fn make_command_line(prog: &OsStr, args: &[Arg], force_quotes: bool) -> io::Result<Vec<u16>> {
744734
// Encode the command and arguments in a command line string such
745735
// that the spawned process may recover them using CommandLineToArgvW.
746736
let mut cmd: Vec<u16> = Vec::new();
@@ -749,18 +739,17 @@ fn make_command_line(
749739
// need to add an extra pair of quotes surrounding the whole command line
750740
// so they are properly passed on to the script.
751741
// See issue #91991.
742+
let is_batch_file = Path::new(prog)
743+
.extension()
744+
.map(|ext| ext.eq_ignore_ascii_case("cmd") || ext.eq_ignore_ascii_case("bat"))
745+
.unwrap_or(false);
752746
if is_batch_file {
753747
cmd.push(b'"' as u16);
754748
}
755749

756-
// Always quote the program name so CreateProcess to avoid ambiguity when
757-
// the child process parses its arguments.
758-
// Note that quotes aren't escaped here because they can't be used in arg0.
759-
// But that's ok because file paths can't contain quotes.
760-
cmd.push(b'"' as u16);
761-
cmd.extend_from_slice(prog.strip_suffix(&[0]).unwrap_or(prog));
762-
cmd.push(b'"' as u16);
763-
750+
// Always quote the program name so CreateProcess doesn't interpret args as
751+
// part of the name if the binary wasn't found first time.
752+
append_arg(&mut cmd, prog, Quote::Always)?;
764753
for arg in args {
765754
cmd.push(' ' as u16);
766755
let (arg, quote) = match arg {

library/std/src/sys/windows/process/tests.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,11 @@ use super::Arg;
33
use crate::env;
44
use crate::ffi::{OsStr, OsString};
55
use crate::process::Command;
6-
use crate::sys::to_u16s;
76

87
#[test]
98
fn test_raw_args() {
109
let command_line = &make_command_line(
11-
&to_u16s("quoted exe").unwrap(),
10+
OsStr::new("quoted exe"),
1211
&[
1312
Arg::Regular(OsString::from("quote me")),
1413
Arg::Raw(OsString::from("quote me *not*")),
@@ -17,7 +16,6 @@ fn test_raw_args() {
1716
Arg::Regular(OsString::from("optional-quotes")),
1817
],
1918
false,
20-
false,
2119
)
2220
.unwrap();
2321
assert_eq!(
@@ -30,10 +28,9 @@ fn test_raw_args() {
3028
fn test_make_command_line() {
3129
fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
3230
let command_line = &make_command_line(
33-
&to_u16s(prog).unwrap(),
31+
OsStr::new(prog),
3432
&args.iter().map(|a| Arg::Regular(OsString::from(a))).collect::<Vec<_>>(),
3533
force_quotes,
36-
false,
3734
)
3835
.unwrap();
3936
String::from_utf16(command_line).unwrap()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-89352.rs:36:13
3+
|
4+
LL | let a = A::reborrow::<'ai, 's>(self.a.clone());
5+
| ^ lifetime mismatch
6+
|
7+
= note: expected type `<<A as GenAssoc<T>>::Iter<'s> as Sized>`
8+
found type `<<A as GenAssoc<T>>::Iter<'ai> as Sized>`
9+
note: the lifetime `'s` as defined here...
10+
--> $DIR/issue-89352.rs:35:13
11+
|
12+
LL | fn iter<'s>(&'s self) -> Self::Iter<'s> {
13+
| ^^
14+
note: ...does not necessarily outlive the lifetime `'ai` as defined here
15+
--> $DIR/issue-89352.rs:30:6
16+
|
17+
LL | impl<'ai, T: 'ai, A: GenAssoc<T>> GenAssoc<T> for Wrapper<'ai, T, A>
18+
| ^^^
19+
20+
error: aborting due to previous error
21+
22+
For more information about this error, try `rustc --explain E0308`.

src/test/ui/generic-associated-types/issue-89352.rs src/test/ui/generic-associated-types/bugs/issue-89352.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
1-
// check-pass
1+
// revisions: base nll
2+
// ignore-compare-mode-nll
3+
//[nll] compile-flags: -Z borrowck=mir
4+
5+
//[base] check-fail
6+
//[nll] check-pass
7+
// known-bug
8+
9+
// This should pass, but we end up with `A::Iter<'ai>: Sized` for some specific
10+
// `'ai`. We also know that `for<'at> A::Iter<'at>: Sized` from the definition,
11+
// but we prefer param env candidates. We changed this to preference in #92191,
12+
// but this led to unintended consequences (#93262). Suprisingly, this passes
13+
// under NLL. So only a bug in migrate mode.
214

315
#![feature(generic_associated_types)]
416

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// check-pass
2+
3+
#![feature(generic_associated_types)]
4+
5+
pub trait Trait {
6+
type Assoc<'a> where Self: 'a;
7+
}
8+
9+
pub trait Foo<T: Trait>
10+
where
11+
for<'a> T::Assoc<'a>: Clone
12+
{}
13+
14+
pub struct Type;
15+
16+
impl<T: Trait> Foo<T> for Type
17+
where
18+
for<'a> T::Assoc<'a>: Clone
19+
{}
20+
21+
fn main() {}
+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Previously ICEd because we didn't properly track binders in suggestions
2+
// check-fail
3+
4+
pub trait Foo<'de>: Sized {}
5+
6+
pub trait Bar<'a>: 'static {
7+
type Inner: 'a;
8+
}
9+
10+
pub trait Fubar {
11+
type Bar: for<'a> Bar<'a>;
12+
}
13+
14+
pub struct Baz<T>(pub T);
15+
16+
impl<'de, T> Foo<'de> for Baz<T> where T: Foo<'de> {}
17+
18+
struct Empty;
19+
20+
impl<M> Dummy<M> for Empty
21+
where
22+
M: Fubar,
23+
for<'de> Baz<<M::Bar as Bar<'de>>::Inner>: Foo<'de>,
24+
{
25+
}
26+
27+
pub trait Dummy<M>
28+
where
29+
M: Fubar,
30+
{
31+
}
32+
33+
pub struct EmptyBis<'a>(&'a [u8]);
34+
35+
impl<'a> Bar<'a> for EmptyBis<'static> {
36+
type Inner = EmptyBis<'a>;
37+
}
38+
39+
pub struct EmptyMarker;
40+
41+
impl Fubar for EmptyMarker {
42+
type Bar = EmptyBis<'static>;
43+
}
44+
45+
fn icey_bounds<D: Dummy<EmptyMarker>>(p: &D) {}
46+
47+
fn trigger_ice() {
48+
let p = Empty;
49+
icey_bounds(&p); //~ERROR the trait bound
50+
}
51+
52+
fn main() {}

0 commit comments

Comments
 (0)