Skip to content

Commit 17067e9

Browse files
committed
Auto merge of #140859 - pietroalbini:pa-stable, r=pietroalbini
[stable] Prepare the 1.87.0 release Preparing the stable artifacts as described in the release process. This PR also includes the following last minute backports: * #140810 * #140601 * #140684 r? `@ghost`
2 parents af91af4 + 908c30b commit 17067e9

24 files changed

+551
-139
lines changed

RELEASES.md

+289
Large diffs are not rendered by default.

compiler/rustc_attr_parsing/src/parser.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_ast_pretty::pprust;
1313
use rustc_errors::DiagCtxtHandle;
1414
use rustc_hir::{self as hir, AttrPath};
1515
use rustc_span::symbol::{Ident, kw, sym};
16-
use rustc_span::{ErrorGuaranteed, Span, Symbol};
16+
use rustc_span::{Span, Symbol};
1717

1818
pub struct SegmentIterator<'a> {
1919
offset: usize,
@@ -176,7 +176,7 @@ impl<'a> ArgParser<'a> {
176176
pub enum MetaItemOrLitParser<'a> {
177177
MetaItemParser(MetaItemParser<'a>),
178178
Lit(MetaItemLit),
179-
Err(Span, ErrorGuaranteed),
179+
Err(Span),
180180
}
181181

182182
impl<'a> MetaItemOrLitParser<'a> {
@@ -186,7 +186,7 @@ impl<'a> MetaItemOrLitParser<'a> {
186186
generic_meta_item_parser.span()
187187
}
188188
MetaItemOrLitParser::Lit(meta_item_lit) => meta_item_lit.span,
189-
MetaItemOrLitParser::Err(span, _) => *span,
189+
MetaItemOrLitParser::Err(span) => *span,
190190
}
191191
}
192192

@@ -495,12 +495,9 @@ impl<'a> MetaItemListParserContext<'a> {
495495
// where the macro didn't expand to a literal. An error is already given
496496
// for this at this point, and then we do continue. This makes this path
497497
// reachable...
498-
let e = self.dcx.span_delayed_bug(
499-
*span,
500-
"expr in place where literal is expected (builtin attr parsing)",
501-
);
502-
503-
return Some(MetaItemOrLitParser::Err(*span, e));
498+
// NOTE: For backward compatibility we can't emit any error / delayed bug here (yet).
499+
// See <https://github.com/rust-lang/rust/issues/140612>
500+
return Some(MetaItemOrLitParser::Err(*span));
504501
} else {
505502
self.next_path()?
506503
};

compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs

+23-7
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
146146

147147
let principal_trait = regular_traits.into_iter().next();
148148

149-
let mut needed_associated_types = vec![];
149+
// A stable ordering of associated types from the principal trait and all its
150+
// supertraits. We use this to ensure that different substitutions of a trait
151+
// don't result in `dyn Trait` types with different projections lists, which
152+
// can be unsound: <https://github.com/rust-lang/rust/pull/136458>.
153+
// We achieve a stable ordering by walking over the unsubstituted principal
154+
// trait ref.
155+
let mut ordered_associated_types = vec![];
156+
150157
if let Some((principal_trait, ref spans)) = principal_trait {
151158
let principal_trait = principal_trait.map_bound(|trait_pred| {
152159
assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
@@ -171,16 +178,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
171178
// FIXME(negative_bounds): Handle this correctly...
172179
let trait_ref =
173180
tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref));
174-
needed_associated_types.extend(
181+
ordered_associated_types.extend(
175182
tcx.associated_items(pred.trait_ref.def_id)
176183
.in_definition_order()
177184
// We only care about associated types.
178185
.filter(|item| item.kind == ty::AssocKind::Type)
179186
// No RPITITs -- they're not dyn-compatible for now.
180187
.filter(|item| !item.is_impl_trait_in_trait())
181-
// If the associated type has a `where Self: Sized` bound,
182-
// we do not need to constrain the associated type.
183-
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
184188
.map(|item| (item.def_id, trait_ref)),
185189
);
186190
}
@@ -252,14 +256,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
252256
}
253257
}
254258

259+
// We compute the list of projection bounds taking the ordered associated types,
260+
// and check if there was an entry in the collected `projection_bounds`. Those
261+
// are computed by first taking the user-written associated types, then elaborating
262+
// the principal trait ref, and only using those if there was no user-written.
263+
// See note below about how we handle missing associated types with `Self: Sized`,
264+
// which are not required to be provided, but are still used if they are provided.
255265
let mut missing_assoc_types = FxIndexSet::default();
256-
let projection_bounds: Vec<_> = needed_associated_types
266+
let projection_bounds: Vec<_> = ordered_associated_types
257267
.into_iter()
258268
.filter_map(|key| {
259269
if let Some(assoc) = projection_bounds.get(&key) {
260270
Some(*assoc)
261271
} else {
262-
missing_assoc_types.insert(key);
272+
// If the associated type has a `where Self: Sized` bound, then
273+
// we do not need to provide the associated type. This results in
274+
// a `dyn Trait` type that has a different number of projection
275+
// bounds, which may lead to type mismatches.
276+
if !tcx.generics_require_sized_self(key.0) {
277+
missing_assoc_types.insert(key);
278+
}
263279
None
264280
}
265281
})

compiler/rustc_middle/src/ty/sty.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,10 @@ impl<'tcx> Ty<'tcx> {
720720
repr: DynKind,
721721
) -> Ty<'tcx> {
722722
if cfg!(debug_assertions) {
723-
let projection_count = obj.projection_bounds().count();
723+
let projection_count = obj
724+
.projection_bounds()
725+
.filter(|item| !tcx.generics_require_sized_self(item.item_def_id()))
726+
.count();
724727
let expected_count: usize = obj
725728
.principal_def_id()
726729
.into_iter()

src/ci/channel

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
beta
1+
stable

src/tools/clippy/clippy_lints/src/entry.rs

+18-15
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,13 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
9595
return;
9696
};
9797

98-
if then_search.is_key_used_and_no_copy || else_search.is_key_used_and_no_copy {
99-
span_lint(cx, MAP_ENTRY, expr.span, lint_msg);
100-
return;
101-
}
102-
10398
if then_search.edits.is_empty() && else_search.edits.is_empty() {
10499
// No insertions
105100
return;
101+
} else if then_search.is_key_used_and_no_copy || else_search.is_key_used_and_no_copy {
102+
// If there are other uses of the key, and the key is not copy,
103+
// we cannot perform a fix automatically, but continue to emit a lint.
104+
None
106105
} else if then_search.edits.is_empty() || else_search.edits.is_empty() {
107106
// if .. { insert } else { .. } or if .. { .. } else { insert }
108107
let ((then_str, entry_kind), else_str) = match (else_search.edits.is_empty(), contains_expr.negated) {
@@ -123,10 +122,10 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
123122
snippet_with_applicability(cx, then_expr.span, "{ .. }", &mut app),
124123
),
125124
};
126-
format!(
125+
Some(format!(
127126
"if let {}::{entry_kind} = {map_str}.entry({key_str}) {then_str} else {else_str}",
128127
map_ty.entry_path(),
129-
)
128+
))
130129
} else {
131130
// if .. { insert } else { insert }
132131
let ((then_str, then_entry), (else_str, else_entry)) = if contains_expr.negated {
@@ -142,13 +141,13 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
142141
};
143142
let indent_str = snippet_indent(cx, expr.span);
144143
let indent_str = indent_str.as_deref().unwrap_or("");
145-
format!(
144+
Some(format!(
146145
"match {map_str}.entry({key_str}) {{\n{indent_str} {entry}::{then_entry} => {}\n\
147146
{indent_str} {entry}::{else_entry} => {}\n{indent_str}}}",
148147
reindent_multiline(&then_str, true, Some(4 + indent_str.len())),
149148
reindent_multiline(&else_str, true, Some(4 + indent_str.len())),
150149
entry = map_ty.entry_path(),
151-
)
150+
))
152151
}
153152
} else {
154153
if then_search.edits.is_empty() {
@@ -163,17 +162,17 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
163162
} else {
164163
then_search.snippet_occupied(cx, then_expr.span, &mut app)
165164
};
166-
format!(
165+
Some(format!(
167166
"if let {}::{entry_kind} = {map_str}.entry({key_str}) {body_str}",
168167
map_ty.entry_path(),
169-
)
168+
))
170169
} else if let Some(insertion) = then_search.as_single_insertion() {
171170
let value_str = snippet_with_context(cx, insertion.value.span, then_expr.span.ctxt(), "..", &mut app).0;
172171
if contains_expr.negated {
173172
if insertion.value.can_have_side_effects() {
174-
format!("{map_str}.entry({key_str}).or_insert_with(|| {value_str});")
173+
Some(format!("{map_str}.entry({key_str}).or_insert_with(|| {value_str});"))
175174
} else {
176-
format!("{map_str}.entry({key_str}).or_insert({value_str});")
175+
Some(format!("{map_str}.entry({key_str}).or_insert({value_str});"))
177176
}
178177
} else {
179178
// TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here.
@@ -183,7 +182,7 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
183182
} else {
184183
let block_str = then_search.snippet_closure(cx, then_expr.span, &mut app);
185184
if contains_expr.negated {
186-
format!("{map_str}.entry({key_str}).or_insert_with(|| {block_str});")
185+
Some(format!("{map_str}.entry({key_str}).or_insert_with(|| {block_str});"))
187186
} else {
188187
// TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here.
189188
// This would need to be a different lint.
@@ -192,7 +191,11 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass {
192191
}
193192
};
194193

195-
span_lint_and_sugg(cx, MAP_ENTRY, expr.span, lint_msg, "try", sugg, app);
194+
if let Some(sugg) = sugg {
195+
span_lint_and_sugg(cx, MAP_ENTRY, expr.span, lint_msg, "try", sugg, app);
196+
} else {
197+
span_lint(cx, MAP_ENTRY, expr.span, lint_msg);
198+
}
196199
}
197200
}
198201

src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ fn is_variant_or_wildcard(cx: &LateContext<'_>, pat: &Pat<'_>, can_be_wild: bool
8585
/// contains `Err(IDENT)`, `None` otherwise.
8686
fn is_ok_or_err<'hir>(cx: &LateContext<'_>, pat: &Pat<'hir>) -> Option<(bool, &'hir Ident)> {
8787
if let PatKind::TupleStruct(qpath, [arg], _) = &pat.kind
88-
&& let PatKind::Binding(BindingMode::NONE, _, ident, _) = &arg.kind
88+
&& let PatKind::Binding(BindingMode::NONE, _, ident, None) = &arg.kind
8989
&& let res = cx.qpath_res(qpath, pat.hir_id)
9090
&& let Res::Def(DefKind::Ctor(..), id) = res
9191
&& let id @ Some(_) = cx.tcx.opt_parent(id)

src/tools/clippy/clippy_lints/src/ptr.rs

+22-13
Original file line numberDiff line numberDiff line change
@@ -786,9 +786,9 @@ fn check_ptr_eq<'tcx>(
786786
}
787787

788788
// Remove one level of usize conversion if any
789-
let (left, right) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) {
790-
(Some(lhs), Some(rhs)) => (lhs, rhs),
791-
_ => (left, right),
789+
let (left, right, usize_peeled) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) {
790+
(Some(lhs), Some(rhs)) => (lhs, rhs, true),
791+
_ => (left, right, false),
792792
};
793793

794794
// This lint concerns raw pointers
@@ -797,10 +797,16 @@ fn check_ptr_eq<'tcx>(
797797
return;
798798
}
799799

800-
let (left_var, right_var) = (peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty));
800+
let ((left_var, left_casts_peeled), (right_var, right_casts_peeled)) =
801+
(peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty));
801802

802-
if let Some(left_snip) = left_var.span.get_source_text(cx)
803-
&& let Some(right_snip) = right_var.span.get_source_text(cx)
803+
if !(usize_peeled || left_casts_peeled || right_casts_peeled) {
804+
return;
805+
}
806+
807+
let mut app = Applicability::MachineApplicable;
808+
let left_snip = Sugg::hir_with_context(cx, left_var, expr.span.ctxt(), "_", &mut app);
809+
let right_snip = Sugg::hir_with_context(cx, right_var, expr.span.ctxt(), "_", &mut app);
804810
{
805811
let Some(top_crate) = std_or_core(cx) else { return };
806812
let invert = if op == BinOpKind::Eq { "" } else { "!" };
@@ -811,15 +817,16 @@ fn check_ptr_eq<'tcx>(
811817
format!("use `{top_crate}::ptr::eq` when comparing raw pointers"),
812818
"try",
813819
format!("{invert}{top_crate}::ptr::eq({left_snip}, {right_snip})"),
814-
Applicability::MachineApplicable,
820+
app,
815821
);
816822
}
817823
}
818824

819825
// If the given expression is a cast to a usize, return the lhs of the cast
820826
// E.g., `foo as *const _ as usize` returns `foo as *const _`.
821827
fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
822-
if cx.typeck_results().expr_ty(cast_expr) == cx.tcx.types.usize
828+
if !cast_expr.span.from_expansion()
829+
&& cx.typeck_results().expr_ty(cast_expr) == cx.tcx.types.usize
823830
&& let ExprKind::Cast(expr, _) = cast_expr.kind
824831
{
825832
Some(expr)
@@ -828,16 +835,18 @@ fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>
828835
}
829836
}
830837

831-
// Peel raw casts if the remaining expression can be coerced to it
832-
fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> &'tcx Expr<'tcx> {
833-
if let ExprKind::Cast(inner, _) = expr.kind
838+
// Peel raw casts if the remaining expression can be coerced to it, and whether casts have been
839+
// peeled or not.
840+
fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> (&'tcx Expr<'tcx>, bool) {
841+
if !expr.span.from_expansion()
842+
&& let ExprKind::Cast(inner, _) = expr.kind
834843
&& let ty::RawPtr(target_ty, _) = expr_ty.kind()
835844
&& let inner_ty = cx.typeck_results().expr_ty(inner)
836845
&& let ty::RawPtr(inner_target_ty, _) | ty::Ref(_, inner_target_ty, _) = inner_ty.kind()
837846
&& target_ty == inner_target_ty
838847
{
839-
peel_raw_casts(cx, inner, inner_ty)
848+
(peel_raw_casts(cx, inner, inner_ty).0, true)
840849
} else {
841-
expr
850+
(expr, false)
842851
}
843852
}

src/tools/clippy/tests/ui/entry.fixed

+22
Original file line numberDiff line numberDiff line change
@@ -226,4 +226,26 @@ fn issue11976() {
226226
}
227227
}
228228

229+
mod issue14449 {
230+
use std::collections::BTreeMap;
231+
232+
pub struct Meow {
233+
map: BTreeMap<String, String>,
234+
}
235+
236+
impl Meow {
237+
fn pet(&self, _key: &str, _v: u32) -> u32 {
238+
42
239+
}
240+
}
241+
242+
pub fn f(meow: &Meow, x: String) {
243+
if meow.map.contains_key(&x) {
244+
let _ = meow.pet(&x, 1);
245+
} else {
246+
let _ = meow.pet(&x, 0);
247+
}
248+
}
249+
}
250+
229251
fn main() {}

src/tools/clippy/tests/ui/entry.rs

+22
Original file line numberDiff line numberDiff line change
@@ -232,4 +232,26 @@ fn issue11976() {
232232
}
233233
}
234234

235+
mod issue14449 {
236+
use std::collections::BTreeMap;
237+
238+
pub struct Meow {
239+
map: BTreeMap<String, String>,
240+
}
241+
242+
impl Meow {
243+
fn pet(&self, _key: &str, _v: u32) -> u32 {
244+
42
245+
}
246+
}
247+
248+
pub fn f(meow: &Meow, x: String) {
249+
if meow.map.contains_key(&x) {
250+
let _ = meow.pet(&x, 1);
251+
} else {
252+
let _ = meow.pet(&x, 0);
253+
}
254+
}
255+
}
256+
235257
fn main() {}

src/tools/clippy/tests/ui/manual_ok_err.fixed

+5
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ fn no_lint() {
8080
Ok(3) => None,
8181
Ok(v) => Some(v),
8282
};
83+
84+
let _ = match funcall() {
85+
Ok(v @ 1..) => Some(v),
86+
_ => None,
87+
};
8388
}
8489

8590
const fn cf(x: Result<u32, &'static str>) -> Option<u32> {

src/tools/clippy/tests/ui/manual_ok_err.rs

+5
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ fn no_lint() {
116116
Ok(3) => None,
117117
Ok(v) => Some(v),
118118
};
119+
120+
let _ = match funcall() {
121+
Ok(v @ 1..) => Some(v),
122+
_ => None,
123+
};
119124
}
120125

121126
const fn cf(x: Result<u32, &'static str>) -> Option<u32> {

src/tools/clippy/tests/ui/manual_ok_err.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ LL | | };
9494
| |_____^ help: replace with: `(-S).ok()`
9595

9696
error: manual implementation of `ok`
97-
--> tests/ui/manual_ok_err.rs:132:12
97+
--> tests/ui/manual_ok_err.rs:137:12
9898
|
9999
LL | } else if let Ok(n) = "1".parse::<u8>() {
100100
| ____________^

0 commit comments

Comments
 (0)