Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 7 pull requests #133152

Merged
merged 15 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading