Skip to content

Commit bf6adec

Browse files
committed
Auto merge of rust-lang#133152 - jhpratt:rollup-wkqs5ud, r=jhpratt
Rollup of 7 pull requests Successful merges: - rust-lang#132795 (Check `use<..>` in RPITIT for refinement) - rust-lang#132944 (add parentheses when unboxing suggestion needed) - rust-lang#132993 (Make rustc consider itself a stable compiler when `RUSTC_BOOTSTRAP=-1`) - rust-lang#133130 (`suggest_borrow_generic_arg`: instantiate clauses properly) - rust-lang#133133 (rustdoc-search: add standalone trailing `::` test) - rust-lang#133143 (Diagnostics for let mut in item context) - rust-lang#133147 (Fixup some test directives) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 3fb7e44 + f6374b4 commit bf6adec

28 files changed

+507
-52
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+10-16
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use rustc_middle::mir::{
2727
};
2828
use rustc_middle::ty::print::PrintTraitRefExt as _;
2929
use rustc_middle::ty::{
30-
self, ClauseKind, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast,
30+
self, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast,
3131
suggest_constraining_type_params,
3232
};
3333
use rustc_middle::util::CallKind;
@@ -649,11 +649,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
649649
) -> Option<ty::Mutability> {
650650
let tcx = self.infcx.tcx;
651651
let sig = tcx.fn_sig(callee_did).instantiate_identity().skip_binder();
652-
let clauses = tcx.predicates_of(callee_did).instantiate_identity(self.infcx.tcx).predicates;
652+
let clauses = tcx.predicates_of(callee_did);
653653

654654
// First, is there at least one method on one of `param`'s trait bounds?
655655
// This keeps us from suggesting borrowing the argument to `mem::drop`, e.g.
656-
if !clauses.iter().any(|clause| {
656+
if !clauses.instantiate_identity(tcx).predicates.iter().any(|clause| {
657657
clause.as_trait_clause().is_some_and(|tc| {
658658
tc.self_ty().skip_binder().is_param(param.index)
659659
&& tc.polarity() == ty::PredicatePolarity::Positive
@@ -700,23 +700,17 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
700700
return false;
701701
}
702702

703-
// Test the callee's predicates, substituting a reference in for the self ty
704-
// in bounds on `param`.
705-
clauses.iter().all(|&clause| {
706-
let clause_for_ref = clause.kind().map_bound(|kind| match kind {
707-
ClauseKind::Trait(c) if c.self_ty().is_param(param.index) => {
708-
ClauseKind::Trait(c.with_self_ty(tcx, ref_ty))
709-
}
710-
ClauseKind::Projection(c) if c.self_ty().is_param(param.index) => {
711-
ClauseKind::Projection(c.with_self_ty(tcx, ref_ty))
712-
}
713-
_ => kind,
714-
});
703+
// Test the callee's predicates, substituting in `ref_ty` for the moved argument type.
704+
clauses.instantiate(tcx, new_args).predicates.iter().all(|&(mut clause)| {
705+
// Normalize before testing to see through type aliases and projections.
706+
if let Ok(normalized) = tcx.try_normalize_erasing_regions(self.param_env, clause) {
707+
clause = normalized;
708+
}
715709
self.infcx.predicate_must_hold_modulo_regions(&Obligation::new(
716710
tcx,
717711
ObligationCause::dummy(),
718712
self.param_env,
719-
ty::EarlyBinder::bind(clause_for_ref).instantiate(tcx, generic_args),
713+
clause,
720714
))
721715
})
722716
}) {

compiler/rustc_feature/src/lib.rs

+12-7
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,19 @@ impl UnstableFeatures {
7474
// Returns whether `krate` should be counted as unstable
7575
let is_unstable_crate =
7676
|var: &str| krate.is_some_and(|name| var.split(',').any(|new_krate| new_krate == name));
77-
// `true` if we should enable unstable features for bootstrapping.
78-
let bootstrap =
79-
std::env::var("RUSTC_BOOTSTRAP").is_ok_and(|var| var == "1" || is_unstable_crate(&var));
80-
match (disable_unstable_features, bootstrap) {
81-
(_, true) => UnstableFeatures::Cheat,
82-
(true, _) => UnstableFeatures::Disallow,
83-
(false, _) => UnstableFeatures::Allow,
77+
78+
let bootstrap = std::env::var("RUSTC_BOOTSTRAP").ok();
79+
if let Some(val) = bootstrap.as_deref() {
80+
match val {
81+
val if val == "1" || is_unstable_crate(val) => return UnstableFeatures::Cheat,
82+
// Hypnotize ourselves so that we think we are a stable compiler and thus don't
83+
// allow any unstable features.
84+
"-1" => return UnstableFeatures::Disallow,
85+
_ => {}
86+
}
8487
}
88+
89+
if disable_unstable_features { UnstableFeatures::Disallow } else { UnstableFeatures::Allow }
8590
}
8691

8792
pub fn is_nightly_build(&self) -> bool {

compiler/rustc_feature/src/tests.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ fn rustc_bootstrap_parsing() {
1818
assert!(!is_bootstrap("x,y,z", Some("a")));
1919
assert!(!is_bootstrap("x,y,z", None));
2020

21-
// this is technically a breaking change, but there are no stability guarantees for RUSTC_BOOTSTRAP
21+
// `RUSTC_BOOTSTRAP=0` is not recognized.
2222
assert!(!is_bootstrap("0", None));
23+
24+
// `RUSTC_BOOTSTRAP=-1` is force-stable, no unstable features allowed.
25+
let is_force_stable = |krate| {
26+
std::env::set_var("RUSTC_BOOTSTRAP", "-1");
27+
matches!(UnstableFeatures::from_environment(krate), UnstableFeatures::Disallow)
28+
};
29+
assert!(is_force_stable(None));
30+
// Does not support specifying any crate.
31+
assert!(is_force_stable(Some("x")));
32+
assert!(is_force_stable(Some("x,y,z")));
2333
}

compiler/rustc_feature/src/unstable.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ pub struct EnabledLangFeature {
5454
pub stable_since: Option<Symbol>,
5555
}
5656

57-
/// Information abhout an enabled library feature.
57+
/// Information about an enabled library feature.
5858
#[derive(Debug, Copy, Clone)]
5959
pub struct EnabledLibFeature {
6060
pub gate_name: Symbol,

compiler/rustc_hir_analysis/messages.ftl

+5
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,11 @@ hir_analysis_rpitit_refined = impl trait in impl method signature does not match
448448
.note = add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
449449
.feedback_note = we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
450450
451+
hir_analysis_rpitit_refined_lifetimes = impl trait in impl method captures fewer lifetimes than in trait
452+
.suggestion = modify the `use<..>` bound to capture the same lifetimes that the trait does
453+
.note = add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
454+
.feedback_note = we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
455+
451456
hir_analysis_self_in_impl_self =
452457
`Self` is not valid in the self type of an impl block
453458
.note = replace `Self` with a different type

compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs

+101-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
use itertools::Itertools as _;
12
use rustc_data_structures::fx::FxIndexSet;
23
use rustc_hir as hir;
3-
use rustc_hir::def_id::DefId;
4+
use rustc_hir::def_id::{DefId, LocalDefId};
45
use rustc_infer::infer::TyCtxtInferExt;
56
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
67
use rustc_lint_defs::builtin::{REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT_REACHABLE};
@@ -75,6 +76,8 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
7576
let mut trait_bounds = vec![];
7677
// Bounds that we find on the RPITITs in the impl signature.
7778
let mut impl_bounds = vec![];
79+
// Pairs of trait and impl opaques.
80+
let mut pairs = vec![];
7881

7982
for trait_projection in collector.types.into_iter().rev() {
8083
let impl_opaque_args = trait_projection.args.rebase_onto(tcx, trait_m.def_id, impl_m_args);
@@ -121,6 +124,8 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
121124
tcx.explicit_item_bounds(impl_opaque.def_id)
122125
.iter_instantiated_copied(tcx, impl_opaque.args),
123126
));
127+
128+
pairs.push((trait_projection, impl_opaque));
124129
}
125130

126131
let hybrid_preds = tcx
@@ -212,6 +217,39 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
212217
return;
213218
}
214219
}
220+
221+
// Make sure that the RPITIT doesn't capture fewer regions than
222+
// the trait definition. We hard-error if it captures *more*, since that
223+
// is literally unrepresentable in the type system; however, we may be
224+
// promising stronger outlives guarantees if we capture *fewer* regions.
225+
for (trait_projection, impl_opaque) in pairs {
226+
let impl_variances = tcx.variances_of(impl_opaque.def_id);
227+
let impl_captures: FxIndexSet<_> = impl_opaque
228+
.args
229+
.iter()
230+
.zip_eq(impl_variances)
231+
.filter(|(_, v)| **v == ty::Invariant)
232+
.map(|(arg, _)| arg)
233+
.collect();
234+
235+
let trait_variances = tcx.variances_of(trait_projection.def_id);
236+
let mut trait_captures = FxIndexSet::default();
237+
for (arg, variance) in trait_projection.args.iter().zip_eq(trait_variances) {
238+
if *variance != ty::Invariant {
239+
continue;
240+
}
241+
arg.visit_with(&mut CollectParams { params: &mut trait_captures });
242+
}
243+
244+
if !trait_captures.iter().all(|arg| impl_captures.contains(arg)) {
245+
report_mismatched_rpitit_captures(
246+
tcx,
247+
impl_opaque.def_id.expect_local(),
248+
trait_captures,
249+
is_internal,
250+
);
251+
}
252+
}
215253
}
216254

217255
struct ImplTraitInTraitCollector<'tcx> {
@@ -342,3 +380,65 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Anonymize<'tcx> {
342380
self.tcx.anonymize_bound_vars(t)
343381
}
344382
}
383+
384+
struct CollectParams<'a, 'tcx> {
385+
params: &'a mut FxIndexSet<ty::GenericArg<'tcx>>,
386+
}
387+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CollectParams<'_, 'tcx> {
388+
fn visit_ty(&mut self, ty: Ty<'tcx>) {
389+
if let ty::Param(_) = ty.kind() {
390+
self.params.insert(ty.into());
391+
} else {
392+
ty.super_visit_with(self);
393+
}
394+
}
395+
fn visit_region(&mut self, r: ty::Region<'tcx>) {
396+
match r.kind() {
397+
ty::ReEarlyParam(_) | ty::ReLateParam(_) => {
398+
self.params.insert(r.into());
399+
}
400+
_ => {}
401+
}
402+
}
403+
fn visit_const(&mut self, ct: ty::Const<'tcx>) {
404+
if let ty::ConstKind::Param(_) = ct.kind() {
405+
self.params.insert(ct.into());
406+
} else {
407+
ct.super_visit_with(self);
408+
}
409+
}
410+
}
411+
412+
fn report_mismatched_rpitit_captures<'tcx>(
413+
tcx: TyCtxt<'tcx>,
414+
impl_opaque_def_id: LocalDefId,
415+
mut trait_captured_args: FxIndexSet<ty::GenericArg<'tcx>>,
416+
is_internal: bool,
417+
) {
418+
let Some(use_bound_span) =
419+
tcx.hir_node_by_def_id(impl_opaque_def_id).expect_opaque_ty().bounds.iter().find_map(
420+
|bound| match *bound {
421+
rustc_hir::GenericBound::Use(_, span) => Some(span),
422+
hir::GenericBound::Trait(_) | hir::GenericBound::Outlives(_) => None,
423+
},
424+
)
425+
else {
426+
// I have no idea when you would ever undercapture without a `use<..>`.
427+
tcx.dcx().delayed_bug("expected use<..> to undercapture in an impl opaque");
428+
return;
429+
};
430+
431+
trait_captured_args
432+
.sort_by_cached_key(|arg| !matches!(arg.unpack(), ty::GenericArgKind::Lifetime(_)));
433+
let suggestion = format!("use<{}>", trait_captured_args.iter().join(", "));
434+
435+
tcx.emit_node_span_lint(
436+
if is_internal { REFINING_IMPL_TRAIT_INTERNAL } else { REFINING_IMPL_TRAIT_REACHABLE },
437+
tcx.local_def_id_to_hir_id(impl_opaque_def_id),
438+
use_bound_span,
439+
crate::errors::ReturnPositionImplTraitInTraitRefinedLifetimes {
440+
suggestion_span: use_bound_span,
441+
suggestion,
442+
},
443+
);
444+
}

compiler/rustc_hir_analysis/src/errors.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1153,6 +1153,16 @@ pub(crate) struct ReturnPositionImplTraitInTraitRefined<'tcx> {
11531153
pub return_ty: Ty<'tcx>,
11541154
}
11551155

1156+
#[derive(LintDiagnostic)]
1157+
#[diag(hir_analysis_rpitit_refined_lifetimes)]
1158+
#[note]
1159+
#[note(hir_analysis_feedback_note)]
1160+
pub(crate) struct ReturnPositionImplTraitInTraitRefinedLifetimes {
1161+
#[suggestion(applicability = "maybe-incorrect", code = "{suggestion}")]
1162+
pub suggestion_span: Span,
1163+
pub suggestion: String,
1164+
}
1165+
11561166
#[derive(Diagnostic)]
11571167
#[diag(hir_analysis_inherent_ty_outside, code = E0390)]
11581168
#[help]

compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs

+24-9
Original file line numberDiff line numberDiff line change
@@ -2648,15 +2648,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
26482648
}
26492649

26502650
let make_sugg = |expr: &Expr<'_>, span: Span, sugg: &str| {
2651-
let needs_parens = match expr.kind {
2652-
// parenthesize if needed (Issue #46756)
2653-
hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
2654-
// parenthesize borrows of range literals (Issue #54505)
2655-
_ if is_range_literal(expr) => true,
2656-
_ => false,
2657-
};
2658-
2659-
if needs_parens {
2651+
if self.needs_parentheses(expr) {
26602652
(
26612653
vec![
26622654
(span.shrink_to_lo(), format!("{prefix}{sugg}(")),
@@ -2869,6 +2861,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
28692861
return None;
28702862
}
28712863

2864+
if self.needs_parentheses(expr) {
2865+
return Some((
2866+
vec![
2867+
(span, format!("{suggestion}(")),
2868+
(expr.span.shrink_to_hi(), ")".to_string()),
2869+
],
2870+
message,
2871+
Applicability::MachineApplicable,
2872+
true,
2873+
false,
2874+
));
2875+
}
2876+
28722877
return Some((
28732878
vec![(span, suggestion)],
28742879
message,
@@ -2897,6 +2902,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
28972902
false
28982903
}
28992904

2905+
fn needs_parentheses(&self, expr: &hir::Expr<'_>) -> bool {
2906+
match expr.kind {
2907+
// parenthesize if needed (Issue #46756)
2908+
hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
2909+
// parenthesize borrows of range literals (Issue #54505)
2910+
_ if is_range_literal(expr) => true,
2911+
_ => false,
2912+
}
2913+
}
2914+
29002915
pub(crate) fn suggest_cast(
29012916
&self,
29022917
err: &mut Diag<'_>,

compiler/rustc_parse/src/parser/item.rs

+25-8
Original file line numberDiff line numberDiff line change
@@ -77,18 +77,35 @@ impl<'a> Parser<'a> {
7777
if !self.eat(term) {
7878
let token_str = super::token_descr(&self.token);
7979
if !self.maybe_consume_incorrect_semicolon(items.last().map(|x| &**x)) {
80+
let is_let = self.token.is_keyword(kw::Let);
81+
let is_let_mut = is_let && self.look_ahead(1, |t| t.is_keyword(kw::Mut));
82+
let let_has_ident = is_let && !is_let_mut && self.is_kw_followed_by_ident(kw::Let);
83+
8084
let msg = format!("expected item, found {token_str}");
8185
let mut err = self.dcx().struct_span_err(self.token.span, msg);
82-
let span = self.token.span;
83-
if self.is_kw_followed_by_ident(kw::Let) {
84-
err.span_label(
85-
span,
86-
"consider using `const` or `static` instead of `let` for global variables",
87-
);
86+
87+
let label = if is_let {
88+
"`let` cannot be used for global variables"
8889
} else {
89-
err.span_label(span, "expected item")
90-
.note("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>");
90+
"expected item"
9191
};
92+
err.span_label(self.token.span, label);
93+
94+
if is_let {
95+
if is_let_mut {
96+
err.help("consider using `static` and a `Mutex` instead of `let mut`");
97+
} else if let_has_ident {
98+
err.span_suggestion_short(
99+
self.token.span,
100+
"consider using `static` or `const` instead of `let`",
101+
"static",
102+
Applicability::MaybeIncorrect,
103+
);
104+
} else {
105+
err.help("consider using `static` or `const` instead of `let`");
106+
}
107+
}
108+
err.note("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>");
92109
return Err(err);
93110
}
94111
}

tests/incremental/hygiene/load_cached_hygiene.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// This causes hygiene information to be saved to the incr cache.
88
// 2. One function is the foreign crate is modified. This causes the
99
// optimized mir for an unmodified function to be loaded from the
10-
//@ incremental cache and written out to the crate metadata.
10+
// incremental cache and written out to the crate metadata.
1111
// 3. In the process of loading and writing out this function's MIR,
1212
// we load hygiene information from the incremental cache and
1313
// write it to our metadata.

tests/rustdoc-js/trailing.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// exact-check
2+
const EXPECTED = {
3+
'query': 'inner::',
4+
'others': [
5+
{ 'path': 'trailing::inner', 'name': 'function' },
6+
],
7+
}

tests/rustdoc-js/trailing.rs

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub mod inner {
2+
pub fn function() {}
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: the option `Z` is only accepted on the nightly compiler
2+
3+
help: consider switching to a nightly toolchain: `rustup default nightly`
4+
5+
note: selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>
6+
7+
note: for more information about Rust's stability policy, see <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#unstable-features>
8+
9+
error: 1 nightly option were parsed
10+

0 commit comments

Comments
 (0)