Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
74c99d9
Document NonNull layout guarantees
0xEgao Jun 23, 2026
b587ba0
Add do_not_recommend test
mejrs Jul 6, 2026
60aa191
Pretty-print user self types too.
cjgillot Jun 23, 2026
393f1f2
enable `do_not_recommend` attr for method call errors in current solver
mejrs Jul 9, 2026
08d79a6
chore: add codegen test for issue 91010
amirHdev Jul 10, 2026
77bce37
Rename `select_trait_candidate`
mejrs Jul 11, 2026
e8f64cc
rustc_target: Add acquire-release to implied features of v8
taiki-e Jul 12, 2026
c674878
Add a case to the `multiple-tail-expr-behind-cfg.rs` test
nnethercote Jul 13, 2026
8955385
Fix typo in `attr_on_non_tail_expr`
nnethercote Jul 13, 2026
5a5d130
add regression tests
qaijuang Jun 6, 2026
6be6d75
fix relative paths in private import suggestions
qaijuang Jun 6, 2026
59a0940
address suggested nits
qaijuang Jul 11, 2026
db1ab0b
split only rustfix eligible test
qaijuang Jul 11, 2026
7478c62
Rollup merge of #159208 - nnethercote:fix-attr_on_non_tail_expr-typo,…
jhpratt Jul 13, 2026
457c167
Rollup merge of #157524 - qaijuang:fix-private-import-relative-path, …
jhpratt Jul 13, 2026
57f2da6
Rollup merge of #158325 - 0xEgao:docs-non-null, r=RalfJung
jhpratt Jul 13, 2026
de0111a
Rollup merge of #158882 - mejrs:do_not_recommend_old_solver, r=khyperia
jhpratt Jul 13, 2026
0205d3b
Rollup merge of #158982 - cjgillot:pretty-ascribe-user-ty, r=davidtwco
jhpratt Jul 13, 2026
c438c5f
Rollup merge of #159069 - amirHdev:add-codegen-test-issue-91010, r=nn…
jhpratt Jul 13, 2026
ebc78e1
Rollup merge of #159163 - taiki-e:armv8-target-feature, r=davidtwco
jhpratt Jul 13, 2026
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
16 changes: 12 additions & 4 deletions compiler/rustc_hir_typeck/src/method/probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1892,13 +1892,19 @@ impl<'tcx> Pick<'tcx> {
}

impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
fn select_trait_candidate(
fn select_trait_candidate_for_diagnostics(
&self,
trait_ref: ty::TraitRef<'tcx>,
) -> traits::SelectionResult<'tcx, traits::Selection<'tcx>> {
let obligation =
traits::Obligation::new(self.tcx, self.misc(self.span), self.param_env, trait_ref);
traits::SelectionContext::new(self).select(&obligation)
let candidate = traits::SelectionContext::new(self).select(&obligation);
if let Ok(Some(traits::ImplSource::UserDefined(impl_source_user_defined_data))) = &candidate
&& self.infcx.tcx.do_not_recommend_impl(impl_source_user_defined_data.impl_def_id)
{
return Err(traits::SelectionError::Unimplemented);
}
candidate
}

/// Used for ambiguous method call error reporting. Uses probing that throws away the result internally,
Expand Down Expand Up @@ -1926,7 +1932,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
xform_self_ty,
self_ty,
);
match self.select_trait_candidate(trait_ref) {
match self.select_trait_candidate_for_diagnostics(trait_ref) {
Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => {
// If only a single impl matches, make the error message point
// to that impl.
Expand Down Expand Up @@ -2094,7 +2100,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
ocx.register_obligation(obligation);
} else {
result = ProbeResult::NoMatch;
if let Ok(Some(candidate)) = self.select_trait_candidate(trait_ref) {
if let Ok(Some(candidate)) =
self.select_trait_candidate_for_diagnostics(trait_ref)
{
for nested_obligation in candidate.nested_obligations() {
if !self.infcx.predicate_may_hold(&nested_obligation) {
possibly_unsatisfied_predicates.push((
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_middle/src/ty/generic_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::ptr::NonNull;
use rustc_data_structures::intern::Interned;
use rustc_errors::{DiagArgValue, IntoDiagArg};
use rustc_hir::def_id::DefId;
use rustc_macros::{StableHash, TyDecodable, TyEncodable, extension};
use rustc_macros::{Lift, StableHash, TyDecodable, TyEncodable, extension};
use rustc_serialize::{Decodable, Encodable};
use rustc_type_ir::WithCachedTypeInfo;
use rustc_type_ir::walk::TypeWalker;
Expand Down Expand Up @@ -715,7 +715,7 @@ impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeVisitable<TyCtxt<'tcx>> for &'tcx
/// Stores the user-given args to reach some fully qualified path
/// (e.g., `<T>::Item` or `<T as Trait>::Item`).
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
#[derive(StableHash, TypeFoldable, TypeVisitable)]
#[derive(StableHash, TypeFoldable, TypeVisitable, Lift)]
pub struct UserArgs<'tcx> {
/// The args for the item as given by the user.
pub args: GenericArgsRef<'tcx>,
Expand All @@ -742,7 +742,7 @@ pub struct UserArgs<'tcx> {
/// the self type, giving `Foo<?A>`. Finally, we unify that with
/// the self type here, which contains `?A` to be `&'static u32`
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
#[derive(StableHash, TypeFoldable, TypeVisitable)]
#[derive(StableHash, TypeFoldable, TypeVisitable, Lift)]
pub struct UserSelfTy<'tcx> {
pub impl_def_id: DefId,
pub self_ty: Ty<'tcx>,
Expand Down
23 changes: 23 additions & 0 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3418,6 +3418,29 @@ define_print_and_forward_display! {
self.kind().print(p)?;
}

ty::UserTypeKind<'tcx> {
match *self {
Self::Ty(ty) => {
write!(p, "Ty(")?;
ty.print(p)?;
}
Self::TypeOf(def_id, ty::UserArgs { args, user_self_ty }) => {
write!(p, "TypeOf(")?;
p.print_def_path(def_id, args)?;
if let Some(ty::UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
write!(p, " at <impl ")?;
let key = p.tcx().def_key(impl_def_id);
let parent_def_id = DefId { index: key.parent.unwrap(), ..impl_def_id };
p.print_def_path(parent_def_id, &[])?;
write!(p, "::<{}> for ", key.disambiguated_data.as_sym(false))?;
self_ty.print(p)?;
write!(p, ">")?;
}
}
}
write!(p, ")")?;
}

GenericArg<'tcx> {
match self.kind() {
GenericArgKind::Lifetime(lt) => lt.print(p)?,
Expand Down
24 changes: 6 additions & 18 deletions compiler/rustc_middle/src/ty/typeck_results.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use rustc_hir::{
self as hir, BindingMode, ByRef, HirId, ItemLocalId, ItemLocalMap, ItemLocalSet, Mutability,
};
use rustc_index::IndexVec;
use rustc_macros::{StableHash, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
use rustc_macros::{Lift, StableHash, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
use rustc_session::Session;
use rustc_span::Span;

Expand Down Expand Up @@ -798,7 +798,7 @@ impl<'tcx> UserType<'tcx> {
/// from constants that are named via paths, like `Foo::<A>::new` and
/// so forth.
#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable)]
#[derive(Eq, Hash, StableHash, TypeFoldable, TypeVisitable)]
#[derive(Eq, Hash, StableHash, TypeFoldable, TypeVisitable, Lift)]
pub enum UserTypeKind<'tcx> {
Ty(Ty<'tcx>),

Expand Down Expand Up @@ -863,24 +863,12 @@ impl<'tcx> IsIdentity for CanonicalUserType<'tcx> {

impl<'tcx> std::fmt::Display for UserType<'tcx> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.bounds.is_empty() {
self.kind.fmt(f)
} else {
self.kind.fmt(f)?;
self.kind.fmt(f)?;
for b in self.bounds {
write!(f, " + ")?;
std::fmt::Debug::fmt(&self.bounds, f)
}
}
}

impl<'tcx> std::fmt::Display for UserTypeKind<'tcx> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Ty(arg0) => {
ty::print::with_no_trimmed_paths!(write!(f, "Ty({})", arg0))
}
Self::TypeOf(arg0, arg1) => write!(f, "TypeOf({:?}, {:?})", arg0, arg1),
b.fmt(f)?;
}
Ok(())
}
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_parse/src/parser/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -873,7 +873,7 @@ impl<'a> Parser<'a> {
&& let ast::AttrKind::Normal(next_attr_kind) = next_attr.kind
&& let Some(next_attr_args_span) = next_attr_kind.item.args.span()
&& let [next_segment] = &next_attr_kind.item.path.segments[..]
&& segment.ident.name == sym::cfg
&& next_segment.ident.name == sym::cfg
{
let next_expr = match snapshot.parse_expr() {
Ok(next_expr) => next_expr,
Expand Down
112 changes: 90 additions & 22 deletions compiler/rustc_resolve/src/diagnostics/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2433,18 +2433,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
Some(path)
}

/// Shortens a candidate import path to use `super::` (up to 1 level) or `self::` (same module)
/// relative to the current scope, if possible. Only applies to crate-local items and
/// only when the resulting path is actually shorter than the original.
fn shorten_candidate_path(
&self,
suggestion: &mut ImportSuggestion,
current_module: Module<'ra>,
) {
self.shorten_import_path(suggestion.did, &mut suggestion.path, current_module);
}

/// Shortens an import path to use `super::` (up to 1 level) or `self::` (same module)
/// relative to the current scope, if possible. Only applies to crate-local items and
/// only when the resulting path is actually shorter than the original.
fn shorten_import_path(
&self,
did: Option<DefId>,
path: &mut Path,
current_module: Module<'ra>,
) {
const MAX_SUPER_PATH_ITEMS_IN_SUGGESTION: usize = 1;

// Only shorten local items.
if suggestion.did.is_none_or(|did| !did.is_local()) {
if did.is_none_or(|did| !did.is_local()) {
return;
}

Expand All @@ -2457,12 +2466,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// doesn't start with `Crate`, prepend it (edition 2015 paths are relative
// to the crate root without an explicit `crate::` prefix).
let candidate_names = {
let filtered_segments: Vec<_> = suggestion
.path
.segments
.iter()
.filter(|segment| segment.ident.name != kw::PathRoot)
.collect();
let filtered_segments: Vec<_> =
path.segments.iter().filter(|segment| segment.ident.name != kw::PathRoot).collect();

let mut candidate_names: Vec<Symbol> =
filtered_segments.iter().map(|segment| segment.ident.name).collect();
Expand Down Expand Up @@ -2511,11 +2516,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}

// Only apply if the result is strictly shorter than the original path.
if new_segments.len() >= suggestion.path.segments.len() {
if new_segments.len() >= path.segments.len() {
return;
}

suggestion.path = Path { span: suggestion.path.span, segments: new_segments };
*path = Path { span: path.span, segments: new_segments };
}

fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) {
Expand Down Expand Up @@ -2668,17 +2673,80 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {

match binding.kind {
DeclKind::Import { source_decl, import, .. } => {
// Don't include `{{root}}` in suggestions - it's an internal symbol
// that should never be shown to users.
let path = import
.module_path
.iter()
.filter(|seg| seg.ident.name != kw::PathRoot)
.map(|seg| seg.ident.clone())
.chain(std::iter::once(ident))
.collect::<Vec<_>>();
let through_reexport = !matches!(source_decl.kind, DeclKind::Def(_));
sugg_paths.push((path, through_reexport));
let uses_relative_path = import
.module_path
.first()
.is_some_and(|seg| matches!(seg.ident.name, kw::SelfLower | kw::Super));
let res_def_id = res.opt_def_id();
let path = if uses_relative_path {
// A path recovered from `self`/`super` is only useful if both the
// target and every module segment can be named from the failing use site.
let module_path = if let Some(ModuleOrUniformRoot::Module(module)) =
import.imported_module.get()
&& module.is_local()
&& let Some(module_path) = self.module_path_names(module)
&& let Some(mut def_id) = module.opt_def_id()
&& res_def_id.is_none_or(|def_id| {
self.is_accessible_from(
self.tcx.visibility(def_id),
parent_scope.module,
)
}) {
// `module_path_names` tells us the resolved module's canonical path.
// Before suggesting that path from the failing use site, make sure
// every segment in it can actually be named from there.
let mut visible_from_use_site = true;
while let Some(parent) = self.tcx.opt_parent(def_id) {
if !self.is_accessible_from(
self.tcx.visibility(def_id),
parent_scope.module,
) {
visible_from_use_site = false;
break;
}
if parent.is_top_level_module() {
break;
}
def_id = parent;
}
if visible_from_use_site { Some(module_path) } else { None }
} else {
None
};

module_path.map(|module_path| {
// `import.module_path` is relative to the import's module, not to the
// failing use site.
let mut path = Path {
span: ident.span,
segments: module_path
.into_iter()
.chain(std::iter::once(ident.name))
.map(|name| {
ast::PathSegment::from_ident(Ident::with_dummy_span(name))
})
.collect(),
};
self.shorten_import_path(res_def_id, &mut path, parent_scope.module);
path.segments.iter().map(|seg| seg.ident).collect()
})
} else {
// Don't include `{{root}}` in suggestions - it's an internal symbol
// that should never be shown to users.
Some(
import
.module_path
.iter()
.filter(|seg| seg.ident.name != kw::PathRoot)
.map(|seg| seg.ident.clone())
.chain(std::iter::once(ident))
.collect::<Vec<_>>(),
)
};
if let Some(path) = path {
sugg_paths.push((path, through_reexport));
}
}
DeclKind::Def(_) => {}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_target/src/target_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ static ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
("v6m", Unstable(sym::arm_target_feature), &["v6"]),
("v6t2", Unstable(sym::arm_target_feature), &["v6k", "v8m", "thumb2"]),
("v7", Unstable(sym::arm_target_feature), &["v6t2"]),
("v8", Unstable(sym::arm_target_feature), &["v7"]),
("v8", Unstable(sym::arm_target_feature), &["v7", "acquire-release"]),
("v8.1m.main", Unstable(sym::arm_target_feature), &["v8m.main"]),
("v8m", Unstable(sym::arm_target_feature), &["v6m"]),
("v8m.main", Unstable(sym::arm_target_feature), &["v7"]),
Expand Down
4 changes: 2 additions & 2 deletions library/core/src/num/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ impl_zeroable_primitive!(
///
/// `NonZero<T>` is guaranteed to have the same layout and bit validity as `T`
/// with the exception that the all-zero bit pattern is invalid.
/// `Option<NonZero<T>>` is guaranteed to be compatible with `T`, including in
/// `Option<NonZero<T>>` is guaranteed to be ABI-compatible with `T`, including in
/// FFI.
///
/// Thanks to the [null pointer optimization], `NonZero<T>` and
Expand Down Expand Up @@ -525,7 +525,7 @@ macro_rules! nonzero_integer {
///
#[doc = concat!("`", stringify!($Ty), "` is guaranteed to have the same layout and bit validity as `", stringify!($Int), "`")]
/// with the exception that `0` is not a valid instance.
#[doc = concat!("`Option<", stringify!($Ty), ">` is guaranteed to be compatible with `", stringify!($Int), "`,")]
#[doc = concat!("`Option<", stringify!($Ty), ">` is guaranteed to be ABI-compatible with `", stringify!($Int), "`,")]
/// including in FFI.
///
/// Thanks to the [null pointer optimization],
Expand Down
7 changes: 6 additions & 1 deletion library/core/src/ptr/non_null.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ use crate::{fmt, hash, intrinsics, mem, ptr};
/// it is your responsibility to ensure that `as_mut` is never called, and `as_ptr`
/// is never used for mutation.
///
/// # Representation
/// # Layout
///
/// `NonNull<T>` is guaranteed to have the same layout and bit validity as `*mut T`
/// with the exception that a null pointer is invalid.
/// `Option<NonNull<T>>` is guaranteed to be ABI-compatible with `*mut T`, including in
/// FFI.
///
/// Thanks to the [null pointer optimization],
/// `NonNull<T>` and `Option<NonNull<T>>`
Expand Down
28 changes: 28 additions & 0 deletions tests/codegen-llvm/issues/issue-91010.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Regression test for preserving constant return values after a use of the
// same local through `black_box` or formatting.

//@ compile-flags: -Copt-level=3

#![crate_type = "lib"]

use std::hint::black_box;

// CHECK-LABEL: @black_box_ref_constant
#[no_mangle]
pub fn black_box_ref_constant() -> i32 {
let x = 1;
black_box(&x);

// CHECK: ret i32 1
x
}

// CHECK-LABEL: @format_ref_constant
#[no_mangle]
pub fn format_ref_constant() -> i32 {
let x = 1;
println!("{}", x);

// CHECK: ret i32 1
x
}
Loading
Loading