Skip to content

Commit

Permalink
Auto merge of rust-lang#133152 - jhpratt:rollup-wkqs5ud, r=jhpratt
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Nov 18, 2024
2 parents 3fb7e44 + f6374b4 commit bf6adec
Show file tree
Hide file tree
Showing 28 changed files with 507 additions and 52 deletions.
26 changes: 10 additions & 16 deletions compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use rustc_middle::mir::{
};
use rustc_middle::ty::print::PrintTraitRefExt as _;
use rustc_middle::ty::{
self, ClauseKind, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast,
self, PredicateKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, Upcast,
suggest_constraining_type_params,
};
use rustc_middle::util::CallKind;
Expand Down Expand Up @@ -649,11 +649,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
) -> Option<ty::Mutability> {
let tcx = self.infcx.tcx;
let sig = tcx.fn_sig(callee_did).instantiate_identity().skip_binder();
let clauses = tcx.predicates_of(callee_did).instantiate_identity(self.infcx.tcx).predicates;
let clauses = tcx.predicates_of(callee_did);

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

// Test the callee's predicates, substituting a reference in for the self ty
// in bounds on `param`.
clauses.iter().all(|&clause| {
let clause_for_ref = clause.kind().map_bound(|kind| match kind {
ClauseKind::Trait(c) if c.self_ty().is_param(param.index) => {
ClauseKind::Trait(c.with_self_ty(tcx, ref_ty))
}
ClauseKind::Projection(c) if c.self_ty().is_param(param.index) => {
ClauseKind::Projection(c.with_self_ty(tcx, ref_ty))
}
_ => kind,
});
// Test the callee's predicates, substituting in `ref_ty` for the moved argument type.
clauses.instantiate(tcx, new_args).predicates.iter().all(|&(mut clause)| {
// Normalize before testing to see through type aliases and projections.
if let Ok(normalized) = tcx.try_normalize_erasing_regions(self.param_env, clause) {
clause = normalized;
}
self.infcx.predicate_must_hold_modulo_regions(&Obligation::new(
tcx,
ObligationCause::dummy(),
self.param_env,
ty::EarlyBinder::bind(clause_for_ref).instantiate(tcx, generic_args),
clause,
))
})
}) {
Expand Down
19 changes: 12 additions & 7 deletions compiler/rustc_feature/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,19 @@ impl UnstableFeatures {
// Returns whether `krate` should be counted as unstable
let is_unstable_crate =
|var: &str| krate.is_some_and(|name| var.split(',').any(|new_krate| new_krate == name));
// `true` if we should enable unstable features for bootstrapping.
let bootstrap =
std::env::var("RUSTC_BOOTSTRAP").is_ok_and(|var| var == "1" || is_unstable_crate(&var));
match (disable_unstable_features, bootstrap) {
(_, true) => UnstableFeatures::Cheat,
(true, _) => UnstableFeatures::Disallow,
(false, _) => UnstableFeatures::Allow,

let bootstrap = std::env::var("RUSTC_BOOTSTRAP").ok();
if let Some(val) = bootstrap.as_deref() {
match val {
val if val == "1" || is_unstable_crate(val) => return UnstableFeatures::Cheat,
// Hypnotize ourselves so that we think we are a stable compiler and thus don't
// allow any unstable features.
"-1" => return UnstableFeatures::Disallow,
_ => {}
}
}

if disable_unstable_features { UnstableFeatures::Disallow } else { UnstableFeatures::Allow }
}

pub fn is_nightly_build(&self) -> bool {
Expand Down
12 changes: 11 additions & 1 deletion compiler/rustc_feature/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ fn rustc_bootstrap_parsing() {
assert!(!is_bootstrap("x,y,z", Some("a")));
assert!(!is_bootstrap("x,y,z", None));

// this is technically a breaking change, but there are no stability guarantees for RUSTC_BOOTSTRAP
// `RUSTC_BOOTSTRAP=0` is not recognized.
assert!(!is_bootstrap("0", None));

// `RUSTC_BOOTSTRAP=-1` is force-stable, no unstable features allowed.
let is_force_stable = |krate| {
std::env::set_var("RUSTC_BOOTSTRAP", "-1");
matches!(UnstableFeatures::from_environment(krate), UnstableFeatures::Disallow)
};
assert!(is_force_stable(None));
// Does not support specifying any crate.
assert!(is_force_stable(Some("x")));
assert!(is_force_stable(Some("x,y,z")));
}
2 changes: 1 addition & 1 deletion compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ pub struct EnabledLangFeature {
pub stable_since: Option<Symbol>,
}

/// Information abhout an enabled library feature.
/// Information about an enabled library feature.
#[derive(Debug, Copy, Clone)]
pub struct EnabledLibFeature {
pub gate_name: Symbol,
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,11 @@ hir_analysis_rpitit_refined = impl trait in impl method signature does not match
.note = add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
.feedback_note = we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
hir_analysis_rpitit_refined_lifetimes = impl trait in impl method captures fewer lifetimes than in trait
.suggestion = modify the `use<..>` bound to capture the same lifetimes that the trait does
.note = add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate
.feedback_note = we are soliciting feedback, see issue #121718 <https://github.com/rust-lang/rust/issues/121718> for more information
hir_analysis_self_in_impl_self =
`Self` is not valid in the self type of an impl block
.note = replace `Self` with a different type
Expand Down
102 changes: 101 additions & 1 deletion compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use itertools::Itertools as _;
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_lint_defs::builtin::{REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT_REACHABLE};
Expand Down Expand Up @@ -75,6 +76,8 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
let mut trait_bounds = vec![];
// Bounds that we find on the RPITITs in the impl signature.
let mut impl_bounds = vec![];
// Pairs of trait and impl opaques.
let mut pairs = vec![];

for trait_projection in collector.types.into_iter().rev() {
let impl_opaque_args = trait_projection.args.rebase_onto(tcx, trait_m.def_id, impl_m_args);
Expand Down Expand Up @@ -121,6 +124,8 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
tcx.explicit_item_bounds(impl_opaque.def_id)
.iter_instantiated_copied(tcx, impl_opaque.args),
));

pairs.push((trait_projection, impl_opaque));
}

let hybrid_preds = tcx
Expand Down Expand Up @@ -212,6 +217,39 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
return;
}
}

// Make sure that the RPITIT doesn't capture fewer regions than
// the trait definition. We hard-error if it captures *more*, since that
// is literally unrepresentable in the type system; however, we may be
// promising stronger outlives guarantees if we capture *fewer* regions.
for (trait_projection, impl_opaque) in pairs {
let impl_variances = tcx.variances_of(impl_opaque.def_id);
let impl_captures: FxIndexSet<_> = impl_opaque
.args
.iter()
.zip_eq(impl_variances)
.filter(|(_, v)| **v == ty::Invariant)
.map(|(arg, _)| arg)
.collect();

let trait_variances = tcx.variances_of(trait_projection.def_id);
let mut trait_captures = FxIndexSet::default();
for (arg, variance) in trait_projection.args.iter().zip_eq(trait_variances) {
if *variance != ty::Invariant {
continue;
}
arg.visit_with(&mut CollectParams { params: &mut trait_captures });
}

if !trait_captures.iter().all(|arg| impl_captures.contains(arg)) {
report_mismatched_rpitit_captures(
tcx,
impl_opaque.def_id.expect_local(),
trait_captures,
is_internal,
);
}
}
}

struct ImplTraitInTraitCollector<'tcx> {
Expand Down Expand Up @@ -342,3 +380,65 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Anonymize<'tcx> {
self.tcx.anonymize_bound_vars(t)
}
}

struct CollectParams<'a, 'tcx> {
params: &'a mut FxIndexSet<ty::GenericArg<'tcx>>,
}
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for CollectParams<'_, 'tcx> {
fn visit_ty(&mut self, ty: Ty<'tcx>) {
if let ty::Param(_) = ty.kind() {
self.params.insert(ty.into());
} else {
ty.super_visit_with(self);
}
}
fn visit_region(&mut self, r: ty::Region<'tcx>) {
match r.kind() {
ty::ReEarlyParam(_) | ty::ReLateParam(_) => {
self.params.insert(r.into());
}
_ => {}
}
}
fn visit_const(&mut self, ct: ty::Const<'tcx>) {
if let ty::ConstKind::Param(_) = ct.kind() {
self.params.insert(ct.into());
} else {
ct.super_visit_with(self);
}
}
}

fn report_mismatched_rpitit_captures<'tcx>(
tcx: TyCtxt<'tcx>,
impl_opaque_def_id: LocalDefId,
mut trait_captured_args: FxIndexSet<ty::GenericArg<'tcx>>,
is_internal: bool,
) {
let Some(use_bound_span) =
tcx.hir_node_by_def_id(impl_opaque_def_id).expect_opaque_ty().bounds.iter().find_map(
|bound| match *bound {
rustc_hir::GenericBound::Use(_, span) => Some(span),
hir::GenericBound::Trait(_) | hir::GenericBound::Outlives(_) => None,
},
)
else {
// I have no idea when you would ever undercapture without a `use<..>`.
tcx.dcx().delayed_bug("expected use<..> to undercapture in an impl opaque");
return;
};

trait_captured_args
.sort_by_cached_key(|arg| !matches!(arg.unpack(), ty::GenericArgKind::Lifetime(_)));
let suggestion = format!("use<{}>", trait_captured_args.iter().join(", "));

tcx.emit_node_span_lint(
if is_internal { REFINING_IMPL_TRAIT_INTERNAL } else { REFINING_IMPL_TRAIT_REACHABLE },
tcx.local_def_id_to_hir_id(impl_opaque_def_id),
use_bound_span,
crate::errors::ReturnPositionImplTraitInTraitRefinedLifetimes {
suggestion_span: use_bound_span,
suggestion,
},
);
}
10 changes: 10 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1153,6 +1153,16 @@ pub(crate) struct ReturnPositionImplTraitInTraitRefined<'tcx> {
pub return_ty: Ty<'tcx>,
}

#[derive(LintDiagnostic)]
#[diag(hir_analysis_rpitit_refined_lifetimes)]
#[note]
#[note(hir_analysis_feedback_note)]
pub(crate) struct ReturnPositionImplTraitInTraitRefinedLifetimes {
#[suggestion(applicability = "maybe-incorrect", code = "{suggestion}")]
pub suggestion_span: Span,
pub suggestion: String,
}

#[derive(Diagnostic)]
#[diag(hir_analysis_inherent_ty_outside, code = E0390)]
#[help]
Expand Down
33 changes: 24 additions & 9 deletions compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2648,15 +2648,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}

let make_sugg = |expr: &Expr<'_>, span: Span, sugg: &str| {
let needs_parens = match expr.kind {
// parenthesize if needed (Issue #46756)
hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
// parenthesize borrows of range literals (Issue #54505)
_ if is_range_literal(expr) => true,
_ => false,
};

if needs_parens {
if self.needs_parentheses(expr) {
(
vec![
(span.shrink_to_lo(), format!("{prefix}{sugg}(")),
Expand Down Expand Up @@ -2869,6 +2861,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return None;
}

if self.needs_parentheses(expr) {
return Some((
vec![
(span, format!("{suggestion}(")),
(expr.span.shrink_to_hi(), ")".to_string()),
],
message,
Applicability::MachineApplicable,
true,
false,
));
}

return Some((
vec![(span, suggestion)],
message,
Expand Down Expand Up @@ -2897,6 +2902,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
false
}

fn needs_parentheses(&self, expr: &hir::Expr<'_>) -> bool {
match expr.kind {
// parenthesize if needed (Issue #46756)
hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
// parenthesize borrows of range literals (Issue #54505)
_ if is_range_literal(expr) => true,
_ => false,
}
}

pub(crate) fn suggest_cast(
&self,
err: &mut Diag<'_>,
Expand Down
33 changes: 25 additions & 8 deletions compiler/rustc_parse/src/parser/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,35 @@ impl<'a> Parser<'a> {
if !self.eat(term) {
let token_str = super::token_descr(&self.token);
if !self.maybe_consume_incorrect_semicolon(items.last().map(|x| &**x)) {
let is_let = self.token.is_keyword(kw::Let);
let is_let_mut = is_let && self.look_ahead(1, |t| t.is_keyword(kw::Mut));
let let_has_ident = is_let && !is_let_mut && self.is_kw_followed_by_ident(kw::Let);

let msg = format!("expected item, found {token_str}");
let mut err = self.dcx().struct_span_err(self.token.span, msg);
let span = self.token.span;
if self.is_kw_followed_by_ident(kw::Let) {
err.span_label(
span,
"consider using `const` or `static` instead of `let` for global variables",
);

let label = if is_let {
"`let` cannot be used for global variables"
} else {
err.span_label(span, "expected item")
.note("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>");
"expected item"
};
err.span_label(self.token.span, label);

if is_let {
if is_let_mut {
err.help("consider using `static` and a `Mutex` instead of `let mut`");
} else if let_has_ident {
err.span_suggestion_short(
self.token.span,
"consider using `static` or `const` instead of `let`",
"static",
Applicability::MaybeIncorrect,
);
} else {
err.help("consider using `static` or `const` instead of `let`");
}
}
err.note("for a full list of items that can appear in modules, see <https://doc.rust-lang.org/reference/items.html>");
return Err(err);
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/incremental/hygiene/load_cached_hygiene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// This causes hygiene information to be saved to the incr cache.
// 2. One function is the foreign crate is modified. This causes the
// optimized mir for an unmodified function to be loaded from the
//@ incremental cache and written out to the crate metadata.
// incremental cache and written out to the crate metadata.
// 3. In the process of loading and writing out this function's MIR,
// we load hygiene information from the incremental cache and
// write it to our metadata.
Expand Down
7 changes: 7 additions & 0 deletions tests/rustdoc-js/trailing.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// exact-check
const EXPECTED = {
'query': 'inner::',
'others': [
{ 'path': 'trailing::inner', 'name': 'function' },
],
}
3 changes: 3 additions & 0 deletions tests/rustdoc-js/trailing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod inner {
pub fn function() {}
}
10 changes: 10 additions & 0 deletions tests/ui/bootstrap/rustc_bootstap.force_stable.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: the option `Z` is only accepted on the nightly compiler

help: consider switching to a nightly toolchain: `rustup default nightly`

note: selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>

note: for more information about Rust's stability policy, see <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#unstable-features>

error: 1 nightly option were parsed

Loading

0 comments on commit bf6adec

Please sign in to comment.