Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a29d5cf
std::net: clamp multicast ttl value to u8 max.
devnexen Mar 19, 2026
80bae85
addressing feedback
devnexen Mar 19, 2026
1e444b4
address feedback
devnexen Mar 31, 2026
6f30978
convert to u8 early on before casting to the platform type
devnexen Apr 2, 2026
79d5626
lint ineffective #[unstable] annotations on re-exports
amirHdev Aug 16, 2026
7b7695d
handle std fallout from unstable re-export lint
amirHdev Aug 17, 2026
7249fbc
allow clippy on unstable re-export suppressions
amirHdev Aug 17, 2026
e22c3c2
add dedicated lint for ineffective unstable re-exports
amirHdev Aug 18, 2026
fbec8a6
refine unstable reexport lint
amirHdev Aug 19, 2026
b91102a
generalize re-export stability checks
amirHdev Aug 27, 2026
73e6922
fix s390x re-export stability metadata
amirHdev Aug 28, 2026
a246018
fix incompatible reexport stability diagnostics
amirHdev Aug 29, 2026
baaac65
only lint ineffective unstable re-exports
amirHdev Sep 10, 2026
8a0d8f7
avoid depending on Reexport's module path
amirHdev Sep 10, 2026
be9d5a8
fix tidy formatting
amirHdev Sep 10, 2026
081b1b5
std: Make a lot of pub items crate private instead (ignore os/sys)
pacak Aug 23, 2026
38c649f
prevent ICE from `derive` on `repr(packed)` enum
cyrgani Sep 10, 2026
d8059af
handle unstable modules in ineffective reexport lint
amirHdev Sep 13, 2026
1017887
avoid stability lookup without reexports
amirHdev Sep 13, 2026
f5557b0
fix bootstrap doctest for ineffective unstable reexports
amirHdev Sep 13, 2026
d559cfd
Fix unsound reborrows of raw ptrs from custom allocators
maxdexh Sep 13, 2026
d9e1945
add test
maxdexh Sep 13, 2026
f371233
Rollup merge of #162732 - maxdexh:water-leak, r=Darksonn
jhpratt Sep 13, 2026
5555001
Rollup merge of #154113 - devnexen:socket_mod_ttl_fix, r=Mark-Simulacrum
jhpratt Sep 13, 2026
0a99780
Rollup merge of #161178 - amirHdev:unstable-reexport, r=mejrs
jhpratt Sep 13, 2026
952097f
Rollup merge of #161612 - pacak:unreachable-pub, r=clarfonthey
jhpratt Sep 13, 2026
b776bdf
Rollup merge of #162717 - cyrgani:one-ice-less-derived, r=folkertdev
jhpratt Sep 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
8 changes: 5 additions & 3 deletions compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,11 +481,13 @@ impl<'a> TraitDef<'a> {
self.expand_struct_def(cx, struct_def, *ident, generics, from_scratch, is_packed)
}
ast::ItemKind::Enum(ident, generics, enum_def) => {
// We ignore `is_packed` here, because `repr(packed)`
// enums cause an error later on.
//
// We can skip generating the impl here, because `repr(packed)`
// enums cause an error later on and to prevent ICEs like #133025.
// This can only cause further compilation errors
// downstream in blatantly illegal code, so it is fine.
if is_packed {
return;
}
self.expand_enum_def(cx, enum_def, *ident, generics, from_scratch)
}
ast::ItemKind::Union(ident, generics, struct_def) => {
Expand Down
20 changes: 12 additions & 8 deletions compiler/rustc_lint/src/levels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -969,14 +969,18 @@ where
let mut lint = Diag::new(dcx, level, msg!("unknown lint: `{$name}`"))
.with_arg("name", lint_id.lint.name_lower())
.with_note(msg!("the `{$name}` lint is unstable"));
rustc_session::diagnostics::add_feature_diagnostics_for_issue(
&mut lint,
sess,
feature,
GateIssue::Language,
lint_from_cli,
None,
);
// `staged_api` is only intended for the standard library, so don't
// suggest enabling it just to use this lint.
if feature != sym::staged_api {
rustc_session::diagnostics::add_feature_diagnostics_for_issue(
&mut lint,
sess,
feature,
GateIssue::Language,
lint_from_cli,
None,
);
}
lint
}
}
Expand Down
34 changes: 34 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub mod hardwired {
HIDDEN_GLOB_REEXPORTS,
ILL_FORMED_ATTRIBUTE_INPUT,
INCOMPLETE_INCLUDE,
INEFFECTIVE_UNSTABLE_REEXPORTS,
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
INLINE_NO_SANITIZE,
INVALID_DOC_ATTRIBUTES,
Expand Down Expand Up @@ -2816,6 +2817,39 @@ declare_lint! {
"detects deprecation attributes with no effect",
}

declare_lint! {
/// The `ineffective_unstable_reexports` lint detects `#[unstable]`
/// attributes on re-exports where the attribute does not make the
/// re-exported path unstable.
///
/// ### Example
///
#[cfg_attr(bootstrap, doc = "```rust,ignore")]
#[cfg_attr(not(bootstrap), doc = "```rust,compile_fail")]
/// #![feature(staged_api)]
/// #![stable(feature = "test", since = "1.0.0")]
///
/// #[stable(feature = "test", since = "1.0.0")]
/// pub struct S;
///
/// #[unstable(feature = "reexport", issue = "none")]
/// pub use self::S as T;
///
/// fn main() {}
#[doc = "```"]
///
#[cfg_attr(not(bootstrap), doc = "{{produces}}")]
///
/// ### Explanation
///
/// `#[unstable]` on a re-export does not make a stable path unstable
/// re-exports inside unstable modules are already on an unstable path
pub INEFFECTIVE_UNSTABLE_REEXPORTS,
Deny,
"detects ineffective `#[unstable]` attributes on re-exports",
@feature_gate = staged_api;
}

declare_lint! {
/// The `ineffective_unstable_trait_impl` lint detects `#[unstable]` attributes which are not used.
///
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_passes/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -950,6 +950,10 @@ pub(crate) struct UnnecessaryPartialStableFeature {
#[note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information")]
pub(crate) struct IneffectiveUnstableImpl;

#[derive(Diagnostic)]
#[diag("`#[unstable]` does not make this re-exported path unstable")]
pub(crate) struct IneffectiveUnstableReexport;

// FIXME(jdonszelmann): move back to rustc_attr
#[derive(Diagnostic)]
#[diag(
Expand Down
168 changes: 166 additions & 2 deletions compiler/rustc_passes/src/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ use rustc_hir::{
UsePath, VERSION_PLACEHOLDER, Variant, find_attr,
};
use rustc_lint_defs::builtin::{
DEPRECATED, DUPLICATE_FEATURES, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, STABLE_FEATURES,
DEPRECATED, DUPLICATE_FEATURES, INEFFECTIVE_UNSTABLE_REEXPORTS,
INEFFECTIVE_UNSTABLE_TRAIT_IMPL, STABLE_FEATURES,
};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures};
Expand Down Expand Up @@ -522,7 +523,9 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
/// Cross-references the feature names of unstable APIs with enabled
/// features and possibly prints errors.
fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, mod_id: LocalModId) {
tcx.hir_visit_item_likes_in_module(mod_id, &mut Checker { tcx });
let mut checker = Checker { tcx, mod_id, unstable_reexports: FxIndexMap::default() };
tcx.hir_visit_item_likes_in_module(mod_id, &mut checker);
checker.emit_ineffective_unstable_reexports();

let is_staged_api =
tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api();
Expand Down Expand Up @@ -552,8 +555,155 @@ pub(crate) fn provide(providers: &mut Providers) {
};
}

struct UnstableReexport {
hir_id: HirId,
span: Span,
has_target: bool,
all_targets_stable: bool,
}

struct Checker<'tcx> {
tcx: TyCtxt<'tcx>,
mod_id: LocalModId,
unstable_reexports: FxIndexMap<Span, UnstableReexport>,
}

impl<'tcx> Checker<'tcx> {
fn unstable_reexport_span(&self, item: &'tcx hir::Item<'tcx>) -> Option<Span> {
let attrs = self.tcx.hir_attrs(item.hir_id());
let (stability, span) =
find_attr!(attrs, Stability { stability, span } => (*stability, *span))?;

stability.level.is_unstable().then_some(span)
}

fn classify_reexport_targets<Id>(
&self,
targets: impl IntoIterator<Item = Res<Id>>,
) -> (bool, bool) {
let mut has_target = false;
let mut all_targets_stable = true;

for res in targets {
match res {
Res::Def(_, def_id) => {
has_target = true;

match self.tcx.lookup_stability(def_id) {
Some(stability) if stability.level.is_unstable() => {
all_targets_stable = false;
}
Some(_) => {}

None => {
// Items from crates without staged API metadata are
// effectively stable. Unmarked items in staged API
// crates are diagnosed by the existing stability checks.
if self.tcx.lookup_stability(def_id.krate.as_def_id()).is_some() {
all_targets_stable = false;
}
}
}
}

// Primitives are stable and have no DefId.
Res::PrimTy(_) => {
has_target = true;
}

// Do not lint if the target cannot be classified.
_ => {
all_targets_stable = false;
}
}
}

(has_target, all_targets_stable)
}

fn record_unstable_reexport(
&mut self,
item: &'tcx hir::Item<'tcx>,
attr_span: Span,
span: Span,
has_target: bool,
all_targets_stable: bool,
) {
let entry = self.unstable_reexports.entry(attr_span).or_insert(UnstableReexport {
hir_id: item.hir_id(),
span,
has_target: false,
all_targets_stable: true,
});

entry.has_target |= has_target;
entry.all_targets_stable &= all_targets_stable;
}

fn check_single_unstable_reexport(
&mut self,
item: &'tcx hir::Item<'tcx>,
path: &'tcx UsePath<'tcx>,
) {
let Some(attr_span) = self.unstable_reexport_span(item) else {
return;
};

let (has_target, all_targets_stable) =
self.classify_reexport_targets(path.res.present_items());

self.record_unstable_reexport(item, attr_span, path.span, has_target, all_targets_stable);
}

fn check_glob_unstable_reexport(
&mut self,
item: &'tcx hir::Item<'tcx>,
path: &'tcx UsePath<'tcx>,
) {
let Some(attr_span) = self.unstable_reexport_span(item) else {
return;
};

let glob_def_id = item.owner_id.def_id.to_def_id();

let targets = self
.tcx
.module_children_local(self.mod_id.to_local_def_id())
.iter()
.filter(|child| {
child.reexport_chain.iter().any(|reexport| reexport.id() == Some(glob_def_id))
})
.map(|child| child.res);

let (has_target, all_targets_stable) = self.classify_reexport_targets(targets);

self.record_unstable_reexport(item, attr_span, path.span, has_target, all_targets_stable);
}

fn containing_module_is_unstable(&self) -> bool {
self.tcx
.lookup_stability(self.mod_id.to_local_def_id())
.is_some_and(|stability| stability.level.is_unstable())
}

fn emit_ineffective_unstable_reexports(&self) {
// an unstable module already makes its re-exports unstable
// keep the explicit annotation without linting it as ineffective
if self.unstable_reexports.is_empty() || self.containing_module_is_unstable() {
return;
}

for reexport in self.unstable_reexports.values() {
if reexport.has_target && reexport.all_targets_stable {
self.tcx.emit_node_span_lint(
INEFFECTIVE_UNSTABLE_REEXPORTS,
reexport.hir_id,
reexport.span,
diagnostics::IneffectiveUnstableReexport,
);
}
}
}
}

impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
Expand Down Expand Up @@ -582,6 +732,20 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
self.tcx.check_stability(def_id, Some(item.hir_id()), item.span, None);
}

hir::ItemKind::Use(path, hir::UseKind::Single(_))
if self.tcx.features().staged_api()
&& self.tcx.local_visibility(item.owner_id.def_id).is_public() =>
{
self.check_single_unstable_reexport(item, path);
}

hir::ItemKind::Use(path, hir::UseKind::Glob)
if self.tcx.features().staged_api()
&& self.tcx.local_visibility(item.owner_id.def_id).is_public() =>
{
self.check_glob_unstable_reexport(item, path);
}

// For implementations of traits, check the stability of each item
// individually as it's possible to have a stable trait with unstable
// items.
Expand Down
2 changes: 1 addition & 1 deletion library/alloc/src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1780,7 +1780,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
pub fn into_unique(b: Self) -> (Unique<T>, A) {
let (ptr, alloc) = Box::into_raw_with_allocator(b);
// SAFETY: Pointer is valid and unique.
unsafe { (Unique::from(&mut *ptr), alloc) }
unsafe { (Unique::new_unchecked(ptr), alloc) }
}

/// Returns a raw mutable pointer to the `Box`'s contents.
Expand Down
14 changes: 6 additions & 8 deletions library/alloc/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -802,16 +802,14 @@ impl<T, A: Allocator> Rc<T, A> {
{
// Construct the inner in the "uninitialized" state with a single
// weak reference.
let (uninit_raw_ptr, alloc) = Box::into_raw_with_allocator(Box::new_in(
let (uninit_ptr, alloc) = Box::into_non_null_with_allocator(Box::new_in(
RcInner {
strong: Cell::new(0),
weak: Cell::new(1),
value: mem::MaybeUninit::<T>::uninit(),
},
alloc,
));
// ignore-tidy-undocumented-unsafe
let uninit_ptr: NonNull<_> = (unsafe { &mut *uninit_raw_ptr }).into();
let init_ptr: NonNull<RcInner<T>> = uninit_ptr.cast();

let weak = Weak { ptr: init_ptr, alloc };
Expand Down Expand Up @@ -863,12 +861,12 @@ impl<T, A: Allocator> Rc<T, A> {
// pointers, which ensures that the weak destructor never frees
// the allocation while the strong destructor is running, even
// if the weak pointer is stored inside the strong one.
let (ptr, alloc) = Box::into_unique(Box::try_new_in(
let (ptr, alloc) = Box::into_non_null_with_allocator(Box::try_new_in(
RcInner { strong: Cell::new(1), weak: Cell::new(1), value },
alloc,
)?);
// ignore-tidy-undocumented-unsafe
Ok(unsafe { Self::from_inner_in(ptr.into(), alloc) })
// SAFETY: Pointer is valid.
Ok(unsafe { Self::from_inner_in(ptr, alloc) })
}

/// Constructs a new `Rc` with uninitialized contents, in the provided allocator, returning an
Expand Down Expand Up @@ -4340,7 +4338,7 @@ impl<T, A: Allocator> UniqueRc<T, A> {
#[must_use]
// #[unstable(feature = "allocator_api", issue = "32838")]
pub fn new_in(value: T, alloc: A) -> Self {
let (ptr, alloc) = Box::into_unique(Box::new_in(
let (ptr, alloc) = Box::into_non_null_with_allocator(Box::new_in(
RcInner {
strong: Cell::new(0),
// keep one weak reference so if all the weak pointers that are created are dropped
Expand All @@ -4350,7 +4348,7 @@ impl<T, A: Allocator> UniqueRc<T, A> {
},
alloc,
));
Self { ptr: ptr.into(), _marker: PhantomData, _marker2: PhantomData, alloc }
Self { ptr, _marker: PhantomData, _marker2: PhantomData, alloc }
}

#[cfg(not(no_global_oom_handling))]
Expand Down
Loading
Loading