Skip to content

Rollup of 8 pull requests #137290

New issue

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

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

Already on GitHub? # to your account

Merged
merged 34 commits into from
Feb 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
0cd8694
Impl TryFrom<Vec<u8>> for String
elichai Oct 28, 2024
4c9b9d7
Use more explicit and reliable ptr select in sort impls
Voultapher Nov 3, 2024
5573cd3
Prevent /msys64/bin from being prepended to PATH
ChrisDenton Feb 10, 2025
ec8ec41
Print the environment a second time
ChrisDenton Feb 10, 2025
f3515fb
Remove ignored `#[must_use]` attributes from portable-simd
samueltardieu Feb 12, 2025
3e66ba7
Remove ignored `#[must_use]` attributes from Clippy
samueltardieu Feb 12, 2025
eec49bb
add MAX_LEN_UTF8 and MAX_LEN_UTF16 constants
HTGAzureX1212 Feb 2, 2024
09dc38f
Improve WTF-8 comments
thaliaarchi Feb 5, 2025
8b1a3a2
Simplify control flow with while-let
thaliaarchi Feb 6, 2025
05e4175
Synchronize platform adaptors for OsString/OsStr
thaliaarchi Feb 6, 2025
fe37ada
Suggest using :: instead of . in more cases.
zachs18 Jan 30, 2025
bfde43c
Suggest using :: instead of . for enums in some cases.
zachs18 Jan 31, 2025
ae7b45a
When giving a suggestion to use :: instead of . where the rhs is a ma…
zachs18 Jan 31, 2025
e639e88
Lint `#[must_use]` attributes applied to methods in trait impls
samueltardieu Feb 12, 2025
2c37250
Update `.` -> `::` tests for new diff suggestion format.
zachs18 Feb 11, 2025
e24833a
add test revisions for old-edition behavior of feature gates
dianne Jan 23, 2025
3e77657
remove old edition-2021-specific tests
dianne Jan 23, 2025
8dc64a4
"classic2021" and "structural2021" rulesets: add eat-inherited-ref-al…
dianne Jan 26, 2025
443c51d
"structural2021" ruleset: add fallback-to-outer (eat both) deref rule
dianne Jan 26, 2025
1ed74aa
add mixed-edition tests
dianne Jan 26, 2025
2c595d6
update unstable book
dianne Jan 26, 2025
799e0f7
add FIXMEs for diagnostic improvements
dianne Jan 31, 2025
2014962
"classic2021" ruleset: experimentally add fallback-to-outer (eat both)
dianne Jan 26, 2025
37bcc1c
clarify wording on doc comment
dianne Feb 17, 2025
0e758c4
rename `consider_inherited_ref_first` -> `consider_inherited_ref`
dianne Feb 17, 2025
0a15bfb
simplify fallback-to-outer condition on old editions
dianne Feb 17, 2025
84e9f29
Rollup merge of #120580 - HTGAzureX1212:HTGAzureX1212/issue-45795, r=…
matthiaskrgr Feb 19, 2025
7b7b1d4
Rollup merge of #132268 - elichai:string_try_from_vec, r=Amanieu
matthiaskrgr Feb 19, 2025
659838e
Rollup merge of #136093 - dianne:match-2024-for-edition-2021, r=Nadri…
matthiaskrgr Feb 19, 2025
8227910
Rollup merge of #136344 - zachs18:dot_notation_more_defkinds_3, r=dav…
matthiaskrgr Feb 19, 2025
59d2b10
Rollup merge of #136690 - Voultapher:use-more-explicit-and-reliable-p…
matthiaskrgr Feb 19, 2025
40379e2
Rollup merge of #136815 - ChrisDenton:fix-mingw-ci, r=Kobzol
matthiaskrgr Feb 19, 2025
c29cc60
Rollup merge of #136923 - samueltardieu:push-vxxqvqwspssv, r=davidtwco
matthiaskrgr Feb 19, 2025
3964bb1
Rollup merge of #137155 - thaliaarchi:wtf8-organize, r=ChrisDenton
matthiaskrgr Feb 19, 2025
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
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
Loading