Skip to content

Commit

Permalink
Auto merge of rust-lang#137290 - matthiaskrgr:rollup-a7xdbi4, r=matth…
Browse files Browse the repository at this point in the history
…iaskrgr

Rollup of 8 pull requests

Successful merges:

 - rust-lang#120580 (Add `MAX_LEN_UTF8` and `MAX_LEN_UTF16` Constants)
 - rust-lang#132268 (Impl TryFrom<Vec<u8>> for String)
 - rust-lang#136093 (Match Ergonomics 2024: update old-edition behavior of feature gates)
 - rust-lang#136344 (Suggest replacing `.` with `::` in more error diagnostics.)
 - rust-lang#136690 (Use more explicit and reliable ptr select in sort impls)
 - rust-lang#136815 (CI: Stop /msys64/bin from being prepended to PATH in msys2 shell)
 - rust-lang#136923 (Lint `#[must_use]` attributes applied to methods in trait impls)
 - rust-lang#137155 (Organize `OsString`/`OsStr` shims)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Feb 19, 2025
2 parents f280acf + 3964bb1 commit 4e1356b
Show file tree
Hide file tree
Showing 83 changed files with 2,896 additions and 934 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@ jobs:
- name: ensure the stable version number is correct
run: src/ci/scripts/verify-stable-version-number.sh

# Show the environment just before we run the build
# This makes it easier to diagnose problems with the above install scripts.
- name: show the current environment
run: src/ci/scripts/dump-environment.sh

- name: run the build
# Redirect stderr to stdout to avoid reordering the two streams in the GHA logs.
run: src/ci/scripts/run-build-from-ci.sh 2>&1
Expand Down
67 changes: 60 additions & 7 deletions compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,19 @@ enum InheritedRefMatchRule {
/// underlying type is not a reference type, the inherited reference will be consumed.
EatInner,
/// When the underlying type is a reference type, reference patterns consume both layers of
/// reference, i.e. they both reset the binding mode and consume the reference type. Reference
/// patterns are not permitted when there is no underlying reference type, i.e. they can't eat
/// only an inherited reference. This is the current stable Rust behavior.
EatBoth,
/// reference, i.e. they both reset the binding mode and consume the reference type.
EatBoth {
/// If `true`, an inherited reference will be considered when determining whether a reference
/// pattern matches a given type:
/// - If the underlying type is not a reference, a reference pattern may eat the inherited reference;
/// - If the underlying type is a reference, a reference pattern matches if it can eat either one
/// of the underlying and inherited references. E.g. a `&mut` pattern is allowed if either the
/// underlying type is `&mut` or the inherited reference is `&mut`.
/// If `false`, a reference pattern is only matched against the underlying type.
/// This is `false` for stable Rust and `true` for both the `ref_pat_eat_one_layer_2024` and
/// `ref_pat_eat_one_layer_2024_structural` feature gates.
consider_inherited_ref: bool,
},
}

impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Expand All @@ -259,10 +268,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
// Currently, matching against an inherited ref on edition 2024 is an error.
// Use `EatBoth` as a fallback to be similar to stable Rust.
InheritedRefMatchRule::EatBoth
InheritedRefMatchRule::EatBoth { consider_inherited_ref: false }
}
} else {
InheritedRefMatchRule::EatBoth
InheritedRefMatchRule::EatBoth {
consider_inherited_ref: self.tcx.features().ref_pat_eat_one_layer_2024()
|| self.tcx.features().ref_pat_eat_one_layer_2024_structural(),
}
}
}

Expand Down Expand Up @@ -2371,6 +2383,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// NB: This assumes that `&` patterns can match against mutable
// references (RFC 3627, Rule 5). If we implement a pattern typing
// ruleset with Rule 4 but not Rule 5, we'll need to check that here.
// FIXME(ref_pat_eat_one_layer_2024_structural): If we already tried
// matching the real reference, the error message should explain that
// falling back to the inherited reference didn't work. This should be
// the same error as the old-Edition version below.
debug_assert!(ref_pat_matches_mut_ref);
self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
}
Expand All @@ -2381,9 +2397,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return expected;
}
}
InheritedRefMatchRule::EatBoth => {
InheritedRefMatchRule::EatBoth { consider_inherited_ref: true } => {
// Reset binding mode on old editions
pat_info.binding_mode = ByRef::No;

if let ty::Ref(_, inner_ty, _) = *expected.kind() {
// Consume both the inherited and inner references.
if pat_mutbl.is_mut() && inh_mut.is_mut() {
// As a special case, a `&mut` reference pattern will be able to match
// against a reference type of any mutability if the inherited ref is
// mutable. Since this allows us to match against a shared reference
// type, we refer to this as "falling back" to matching the inherited
// reference, though we consume the real reference as well. We handle
// this here to avoid adding this case to the common logic below.
self.check_pat(inner, inner_ty, pat_info);
return expected;
} else {
// Otherwise, use the common logic below for matching the inner
// reference type.
// FIXME(ref_pat_eat_one_layer_2024_structural): If this results in a
// mutability mismatch, the error message should explain that falling
// back to the inherited reference didn't work. This should be the same
// error as the Edition 2024 version above.
}
} else {
// The expected type isn't a reference type, so only match against the
// inherited reference.
if pat_mutbl > inh_mut {
// We can't match a lone inherited shared reference with `&mut`.
self.error_inherited_ref_mutability_mismatch(pat, pat_prefix_span);
}

self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
self.check_pat(inner, expected, pat_info);
return expected;
}
}
InheritedRefMatchRule::EatBoth { consider_inherited_ref: false } => {
// Reset binding mode on stable Rust. This will be a type error below if
// `expected` is not a reference type.
pat_info.binding_mode = ByRef::No;
self.add_rust_2024_migration_desugared_pat(
pat_info.top_info.hir_id,
pat,
Expand Down
47 changes: 29 additions & 18 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1431,37 +1431,48 @@ impl<'tcx> CheckAttrVisitor<'tcx> {

/// Warns against some misuses of `#[must_use]`
fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) {
if !matches!(
if matches!(
target,
Target::Fn
| Target::Enum
| Target::Struct
| Target::Union
| Target::Method(_)
| Target::Method(MethodKind::Trait { body: false } | MethodKind::Inherent)
| Target::ForeignFn
// `impl Trait` in return position can trip
// `unused_must_use` if `Trait` is marked as
// `#[must_use]`
| Target::Trait
) {
let article = match target {
Target::ExternCrate
| Target::Enum
| Target::Impl
| Target::Expression
| Target::Arm
| Target::AssocConst
| Target::AssocTy => "an",
_ => "a",
};
return;
}

self.tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES,
hir_id,
attr.span,
errors::MustUseNoEffect { article, target },
);
// `#[must_use]` can be applied to a trait method definition with a default body
if let Target::Method(MethodKind::Trait { body: true }) = target
&& let parent_def_id = self.tcx.hir().get_parent_item(hir_id).def_id
&& let containing_item = self.tcx.hir().expect_item(parent_def_id)
&& let hir::ItemKind::Trait(..) = containing_item.kind
{
return;
}

let article = match target {
Target::ExternCrate
| Target::Enum
| Target::Impl
| Target::Expression
| Target::Arm
| Target::AssocConst
| Target::AssocTy => "an",
_ => "a",
};

self.tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES,
hir_id,
attr.span,
errors::MustUseNoEffect { article, target },
);
}

/// Checks if `#[must_not_suspend]` is applied to a struct, enum, union, or trait.
Expand Down
88 changes: 64 additions & 24 deletions compiler/rustc_resolve/src/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rustc_ast::ptr::P;
use rustc_ast::visit::{FnCtxt, FnKind, LifetimeCtxt, Visitor, walk_ty};
use rustc_ast::{
self as ast, AssocItemKind, DUMMY_NODE_ID, Expr, ExprKind, GenericParam, GenericParamKind,
Item, ItemKind, MethodCall, NodeId, Path, Ty, TyKind,
Item, ItemKind, MethodCall, NodeId, Path, PathSegment, Ty, TyKind,
};
use rustc_ast_pretty::pprust::where_bound_predicate_to_string;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
Expand Down Expand Up @@ -1529,7 +1529,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
Applicability::MaybeIncorrect,
);
true
} else if kind == DefKind::Struct
} else if matches!(kind, DefKind::Struct | DefKind::TyAlias)
&& let Some(lhs_source_span) = lhs_span.find_ancestor_inside(expr.span)
&& let Ok(snippet) = this.r.tcx.sess.source_map().span_to_snippet(lhs_source_span)
{
Expand Down Expand Up @@ -1566,7 +1566,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
}
};

let mut bad_struct_syntax_suggestion = |this: &mut Self, def_id: DefId| {
let bad_struct_syntax_suggestion = |this: &mut Self, err: &mut Diag<'_>, def_id: DefId| {
let (followed_by_brace, closing_brace) = this.followed_by_brace(span);

match source {
Expand Down Expand Up @@ -1740,12 +1740,10 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
}
}
(
Res::Def(kind @ (DefKind::Mod | DefKind::Trait), _),
Res::Def(kind @ (DefKind::Mod | DefKind::Trait | DefKind::TyAlias), _),
PathSource::Expr(Some(parent)),
) => {
if !path_sep(self, err, parent, kind) {
return false;
}
) if path_sep(self, err, parent, kind) => {
return true;
}
(
Res::Def(DefKind::Enum, def_id),
Expand Down Expand Up @@ -1777,13 +1775,13 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
let (ctor_def, ctor_vis, fields) = if let Some(struct_ctor) = struct_ctor {
if let PathSource::Expr(Some(parent)) = source {
if let ExprKind::Field(..) | ExprKind::MethodCall(..) = parent.kind {
bad_struct_syntax_suggestion(self, def_id);
bad_struct_syntax_suggestion(self, err, def_id);
return true;
}
}
struct_ctor
} else {
bad_struct_syntax_suggestion(self, def_id);
bad_struct_syntax_suggestion(self, err, def_id);
return true;
};

Expand Down Expand Up @@ -1861,7 +1859,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
err.span_label(span, "constructor is not visible here due to private fields");
}
(Res::Def(DefKind::Union | DefKind::Variant, def_id), _) if ns == ValueNS => {
bad_struct_syntax_suggestion(self, def_id);
bad_struct_syntax_suggestion(self, err, def_id);
}
(Res::Def(DefKind::Ctor(_, CtorKind::Const), def_id), _) if ns == ValueNS => {
match source {
Expand Down Expand Up @@ -2471,31 +2469,73 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
def_id: DefId,
span: Span,
) {
let Some(variants) = self.collect_enum_ctors(def_id) else {
let Some(variant_ctors) = self.collect_enum_ctors(def_id) else {
err.note("you might have meant to use one of the enum's variants");
return;
};

let suggest_only_tuple_variants =
matches!(source, PathSource::TupleStruct(..)) || source.is_call();
if suggest_only_tuple_variants {
// If the expression is a field-access or method-call, try to find a variant with the field/method name
// that could have been intended, and suggest replacing the `.` with `::`.
// Otherwise, suggest adding `::VariantName` after the enum;
// and if the expression is call-like, only suggest tuple variants.
let (suggest_path_sep_dot_span, suggest_only_tuple_variants) = match source {
// `Type(a, b)` in a pattern, only suggest adding a tuple variant after `Type`.
PathSource::TupleStruct(..) => (None, true),
PathSource::Expr(Some(expr)) => match &expr.kind {
// `Type(a, b)`, only suggest adding a tuple variant after `Type`.
ExprKind::Call(..) => (None, true),
// `Type.Foo(a, b)`, suggest replacing `.` -> `::` if variant `Foo` exists and is a tuple variant,
// otherwise suggest adding a variant after `Type`.
ExprKind::MethodCall(box MethodCall {
receiver,
span,
seg: PathSegment { ident, .. },
..
}) => {
let dot_span = receiver.span.between(*span);
let found_tuple_variant = variant_ctors.iter().any(|(path, _, ctor_kind)| {
*ctor_kind == CtorKind::Fn
&& path.segments.last().is_some_and(|seg| seg.ident == *ident)
});
(found_tuple_variant.then_some(dot_span), false)
}
// `Type.Foo`, suggest replacing `.` -> `::` if variant `Foo` exists and is a unit or tuple variant,
// otherwise suggest adding a variant after `Type`.
ExprKind::Field(base, ident) => {
let dot_span = base.span.between(ident.span);
let found_tuple_or_unit_variant = variant_ctors.iter().any(|(path, ..)| {
path.segments.last().is_some_and(|seg| seg.ident == *ident)
});
(found_tuple_or_unit_variant.then_some(dot_span), false)
}
_ => (None, false),
},
_ => (None, false),
};

if let Some(dot_span) = suggest_path_sep_dot_span {
err.span_suggestion_verbose(
dot_span,
"use the path separator to refer to a variant",
"::",
Applicability::MaybeIncorrect,
);
} else if suggest_only_tuple_variants {
// Suggest only tuple variants regardless of whether they have fields and do not
// suggest path with added parentheses.
let mut suggestable_variants = variants
let mut suggestable_variants = variant_ctors
.iter()
.filter(|(.., kind)| *kind == CtorKind::Fn)
.map(|(variant, ..)| path_names_to_string(variant))
.collect::<Vec<_>>();
suggestable_variants.sort();

let non_suggestable_variant_count = variants.len() - suggestable_variants.len();
let non_suggestable_variant_count = variant_ctors.len() - suggestable_variants.len();

let source_msg = if source.is_call() {
"to construct"
} else if matches!(source, PathSource::TupleStruct(..)) {
let source_msg = if matches!(source, PathSource::TupleStruct(..)) {
"to match against"
} else {
unreachable!()
"to construct"
};

if !suggestable_variants.is_empty() {
Expand All @@ -2514,7 +2554,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
}

// If the enum has no tuple variants..
if non_suggestable_variant_count == variants.len() {
if non_suggestable_variant_count == variant_ctors.len() {
err.help(format!("the enum has no tuple variants {source_msg}"));
}

Expand All @@ -2537,7 +2577,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
}
};

let mut suggestable_variants = variants
let mut suggestable_variants = variant_ctors
.iter()
.filter(|(_, def_id, kind)| !needs_placeholder(*def_id, *kind))
.map(|(variant, _, kind)| (path_names_to_string(variant), kind))
Expand All @@ -2564,7 +2604,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
);
}

let mut suggestable_variants_with_placeholders = variants
let mut suggestable_variants_with_placeholders = variant_ctors
.iter()
.filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind))
.map(|(variant, _, kind)| (path_names_to_string(variant), kind))
Expand Down
1 change: 1 addition & 0 deletions library/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
#![feature(box_uninit_write)]
#![feature(bstr)]
#![feature(bstr_internals)]
#![feature(char_max_len)]
#![feature(clone_to_uninit)]
#![feature(coerce_unsized)]
#![feature(const_eval_select)]
Expand Down
Loading

0 comments on commit 4e1356b

Please sign in to comment.