Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
87f9e6e
tests: Ignore dynamic-loading-cdylib on musl hosts
Gelbpunkt Oct 10, 2026
250643c
More `tests/rustdoc-html` cleanups
GuillaumeGomez Oct 11, 2026
f3ace40
Tweak wording to not mention closures unnecessarily
estebank Oct 12, 2026
dc2da07
Be more accurate on expected and found signatures
estebank Oct 12, 2026
6314d17
Implement attribute parser for #[rustc_assert_variance]
RuleOfSix Sep 30, 2026
5f5e9ab
Fully implement rustc_assert_variance. Add additional span data to Ru…
RuleOfSix Oct 1, 2026
c56b6ee
Fix handling of lifetime names for rustc_assert_variance
RuleOfSix Oct 1, 2026
6abfa1c
- Box `RustcAssertVariance` in `AttributeKind` to prevent increasing …
RuleOfSix Oct 1, 2026
576a9e5
- Change rustc_assert_variance attribute to be attached to generic pa…
RuleOfSix Oct 1, 2026
6d5354f
Improve diagnostic messages for rustc_assert_variance and update ui t…
RuleOfSix Oct 3, 2026
07c2c7c
Annotate std types with rustc_assert_variance: phantom variance marke…
RuleOfSix Oct 3, 2026
b138c7b
Add positive test case for a bivariant lifetime parameter in tests/ui…
RuleOfSix Oct 3, 2026
46395c5
bootstrap: add an rpath to LLVM library for LLVM tools
danieljhkim Oct 12, 2026
d0fa966
Add the link to the musl website
Gelbpunkt Oct 12, 2026
1f3611e
tests: cover dead_code_pub_in_binary expectations with --test
paradoxicalguy Oct 12, 2026
2b90a47
fix delegation generic parameter remapping ICEs
paradoxicalguy Oct 4, 2026
8ac481b
Rollup merge of #163798 - paradoxicalguy:delegation-const-clause-1627…
jhpratt Oct 12, 2026
58c344e
Rollup merge of #164134 - danieljhkim:fix-rust-objcopy-rpath, r=Kobzol
jhpratt Oct 12, 2026
881bfb6
Rollup merge of #164190 - estebank:fn-signatures, r=chenyukang
jhpratt Oct 12, 2026
be595cc
Rollup merge of #163578 - RuleOfSix:rustc-assert-variance-attr, r=mejrs
jhpratt Oct 12, 2026
fcd1286
Rollup merge of #164126 - Gelbpunkt:dynamic-loading-cdylib-musl, r=fo…
jhpratt Oct 12, 2026
d1fbf0c
Rollup merge of #164171 - GuillaumeGomez:clean-rustdoc-html-tests, r=…
jhpratt Oct 12, 2026
ca5e8ae
Rollup merge of #164221 - paradoxicalguy:tests-dead-code-pub-in-binar…
jhpratt Oct 12, 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
15 changes: 15 additions & 0 deletions compiler/rustc_attr_ir/src/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,15 @@ impl fmt::Display for AutoDiffItem {
}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(StableHash, Encodable, Decodable, PrintAttribute)]
pub enum RustcAssertVarianceKind {
Covariant,
Invariant,
Contravariant,
Bivariant,
}

#[derive(Clone, Debug, StableHash, Encodable, Decodable, PrintAttribute)]
pub struct UnstableRemovedFeature {
pub feature: Symbol,
Expand Down Expand Up @@ -1145,6 +1154,12 @@ pub enum AttributeKind {
/// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint).
RustcAsPtr,

/// Represents `#[rustc_assert_variance]`.
RustcAssertVariance {
span: Span,
kind: RustcAssertVarianceKind,
},

/// Represents `#[rustc_autodiff]`.
RustcAutodiff(Option<Box<RustcAutodiff>>),

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_attr_ir/src/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ impl AttributeKind {
RustcAllowIncoherentImpl(..) => No,
RustcAllowLifetimeDependentSpecialization => No,
RustcAsPtr => Yes,
RustcAssertVariance { .. } => No,
RustcAutodiff(..) => Yes,
RustcBodyStability { .. } => No,
RustcBuiltinMacro { .. } => Yes,
Expand Down Expand Up @@ -323,6 +324,7 @@ impl AttributeKind {
RustcAllowIncoherentImpl(..) => false,
RustcAllowLifetimeDependentSpecialization => false,
RustcAsPtr => false,
RustcAssertVariance { .. } => false,
RustcAutodiff(..) => false,
RustcBodyStability { .. } => false,
RustcBuiltinMacro { .. } => false,
Expand Down
55 changes: 53 additions & 2 deletions compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use std::path::PathBuf;
use rustc_ast::{GenericParamKind, ItemKind, LitIntType, LitKind, MetaItemLit};
use rustc_attr_ir::lang_items::LangItem;
use rustc_attr_ir::{
BorrowckGraphvizFormatKind, CguFields, CguKind, RustcCleanAttribute, RustcCleanQueries,
RustcMirKind,
BorrowckGraphvizFormatKind, CguFields, CguKind, RustcAssertVarianceKind, RustcCleanAttribute,
RustcCleanQueries, RustcMirKind,
};
use rustc_data_structures::fx::FxHashMap;
use rustc_feature::AttributeStability;
Expand Down Expand Up @@ -1168,3 +1168,54 @@ impl NoArgsAttributeParser for RustcCanonicalSymbolParser {
);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCanonicalSymbol;
}

pub(crate) struct RustcAssertVarianceParser;

impl SingleAttributeParser for RustcAssertVarianceParser {
const PATH: &[Symbol] = &[sym::rustc_assert_variance];

const STABILITY: AttributeStability = unstable!(rustc_attrs);

const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
Allow(Target::TypeParam),
Allow(Target::LifetimeParam),
Allow(Target::ConstParam),
]);

const TEMPLATE: AttributeTemplate =
template!(OneOf: &[sym::covariant, sym::invariant, sym::contravariant, sym::bivariant]);

fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
let arg = cx.expect_single_element_list(args, cx.attr_span)?;

let mut fail_arg = |span| {
cx.adcx().expected_specific_argument(
span,
&[sym::covariant, sym::invariant, sym::contravariant, sym::bivariant],
)
};

let Some(arg) = arg.meta_item_no_args() else {
fail_arg(arg.span());
return None;
};

let Some(arg) = arg.ident() else {
fail_arg(arg.span());
return None;
};

let kind = match arg.name {
sym::covariant => RustcAssertVarianceKind::Covariant,
sym::invariant => RustcAssertVarianceKind::Invariant,
sym::contravariant => RustcAssertVarianceKind::Contravariant,
sym::bivariant => RustcAssertVarianceKind::Bivariant,
_ => {
fail_arg(arg.span);
return None;
}
};

Some(AttributeKind::RustcAssertVariance { span: cx.attr_span, kind })
}
}
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ attribute_parsers!(
Single<ReexportTestHarnessMainParser>,
Single<RustcAbiParser>,
Single<RustcAllocatorZeroedVariantParser>,
Single<RustcAssertVarianceParser>,
Single<RustcAutodiffParser>,
Single<RustcBuiltinMacroParser>,
Single<RustcDeprecatedSafe2024Parser>,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[
// types (as well as any others in future).
sym::rustc_lint_opt_deny_field_access,
sym::rustc_diagnostic_opaque,
sym::rustc_assert_variance,

// ==========================================================================
// Internal attributes, Const related:
Expand Down
144 changes: 107 additions & 37 deletions compiler/rustc_hir_analysis/src/delegation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{DelegationSelfTyPropagationKind, PathSegment};
use rustc_middle::ty::{
self, ConstKind, EarlyBinder, GenericArg, GenericArgKind, RegionKind, Ty, TyCtxt, TypeFoldable,
TypeFolder, TypeSuperFoldable, TypeVisitableExt,
TypeFolder, TypeSuperFoldable, TypeVisitableExt, Upcast,
};
use rustc_span::{ErrorGuaranteed, Span, kw};

Expand All @@ -23,46 +23,65 @@ struct ParamIndexRemapper<'tcx> {
tcx: TyCtxt<'tcx>,
remap_table: RemapTable,
delegation_parent_consts: FxHashSet<ty::ParamConst>,
arg_kinds: Vec<ty::GenericArgKind<'tcx>>,
}

impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ParamIndexRemapper<'tcx> {
impl<'tcx> ParamIndexRemapper<'tcx> {
fn try_remap(
&self,
source_index: u32,
expected_kind: ty::GenericArgKind<'tcx>,
) -> Result<u32, ()> {
self.remap_table
.get(&source_index)
.copied()
.filter(|&idx| {
self.arg_kinds.get(idx as usize).is_some_and(|kind| {
std::mem::discriminant(&expected_kind) == std::mem::discriminant(kind)
})
})
.ok_or(())
}
}

impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for ParamIndexRemapper<'tcx> {
type Error = ();

fn cx(&self) -> TyCtxt<'tcx> {
self.tcx
}

fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
if !ty.has_param() {
return ty;
return Ok(ty);
}

if let ty::Param(param) = ty.kind()
&& let Some(index) = self.remap_table.get(&param.index)
{
return Ty::new_param(self.tcx, *index, param.name);
if let ty::Param(param) = ty.kind() {
let index = self.try_remap(param.index, ty::GenericArgKind::Type(ty))?;
return Ok(Ty::new_param(self.tcx, index, param.name));
}
ty.super_fold_with(self)

ty.try_super_fold_with(self)
}

fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
if let ty::ReEarlyParam(param) = r.kind()
&& let Some(index) = self.remap_table.get(&param.index).copied()
{
return ty::Region::new_early_param(
fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, Self::Error> {
if let ty::ReEarlyParam(param) = r.kind() {
let index = self.try_remap(param.index, ty::GenericArgKind::Lifetime(r))?;
return Ok(ty::Region::new_early_param(
self.tcx,
ty::EarlyParamRegion { index, name: param.name },
);
));
}
r
Ok(r)
}

fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
if let ty::ConstKind::Param(param) = ct.kind()
&& let Some(idx) = self.remap_table.get(&param.index)
{
let param = ty::ParamConst::new(*idx, param.name);
return ty::Const::new_param(self.tcx, param);
fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
if let ty::ConstKind::Param(param) = ct.kind() {
let idx = self.try_remap(param.index, ty::GenericArgKind::Const(ct))?;
let param = ty::ParamConst::new(idx, param.name);
return Ok(ty::Const::new_param(self.tcx, param));
}
ct.super_fold_with(self)
ct.try_super_fold_with(self)
}
}

Expand Down Expand Up @@ -479,7 +498,7 @@ pub(crate) fn inherit_clauses_for_delegation_item<'tcx>(
mut self,
f: impl Fn(DefId) -> ty::GenericClauses<'tcx>,
def_id: DefId,
) -> Self {
) -> Result<Self, ()> {
let clauses = f(def_id);
let args = self.args.as_slice();

Expand Down Expand Up @@ -521,8 +540,9 @@ pub(crate) fn inherit_clauses_for_delegation_item<'tcx>(
// it came from delegation parent, and if so we do not process its `ConstArgHasType`
// clause.
// (Issue #158675).
let new_clause = clause.0.try_fold_with(&mut self.folder)?;
if let ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _)) =
clause.0.as_predicate().fold_with(&mut self.folder).kind().skip_binder()
new_clause.as_predicate().kind().skip_binder()
{
let unnorm_const = EarlyBinder::bind(self.tcx, ct).instantiate(self.tcx, args);
if let ty::ConstKind::Param(param) = unnorm_const.skip_norm_wip().kind()
Expand All @@ -532,7 +552,6 @@ pub(crate) fn inherit_clauses_for_delegation_item<'tcx>(
}
}

let new_clause = clause.0.fold_with(&mut self.folder);
self.clauses.push((
EarlyBinder::bind(self.tcx, new_clause)
.instantiate(self.tcx, args)
Expand All @@ -541,17 +560,17 @@ pub(crate) fn inherit_clauses_for_delegation_item<'tcx>(
));
}

self
Ok(self)
}

fn with_clauses(
mut self,
f: impl Fn(DefId) -> ty::GenericClauses<'tcx> + Copy,
def_id: DefId,
) -> Self {
) -> Result<Self, ()> {
let preds = f(def_id);
if let Some(parent_def_id) = preds.parent {
self = self.with_own_clauses(f, parent_def_id);
self = self.with_own_clauses(f, parent_def_id)?;
}

self.with_own_clauses(f, def_id)
Expand All @@ -572,16 +591,47 @@ pub(crate) fn inherit_clauses_for_delegation_item<'tcx>(
// `explicit_clauses_of` is used here to avoid copying `Self: Trait` clause.
// Note: `clauses_of` query can also add inferred outlives clauses, but that
// is not the case here as `sig_id` is either a trait or a function.
let clauses = match inh_kind {
let collector = match inh_kind {
InheritanceKind::WithParent(false) => {
collector.with_clauses(|def_id| tcx.explicit_clauses_of(def_id), sig_id)
}
InheritanceKind::WithParent(true) => {
collector.with_clauses(|def_id| tcx.clauses_of(def_id), sig_id)
}
InheritanceKind::Own => collector.with_own_clauses(|def_id| tcx.clauses_of(def_id), sig_id),
}
.clauses;
};

let clauses = match collector {
Ok(collector) => collector.clauses,
Err(()) => {
tcx.dcx().emit_err(crate::diagnostics::DelegationInheritanceFailed {
span: tcx.def_span(def_id),
kind: "predicates",
callee_span: tcx.def_span(sig_id),
});

// Even on error, the delegated item's const parameters need their
// types in the parameter environment.
tcx.generics_of(def_id)
.own_params
.iter()
.filter_map(|param| {
if !matches!(param.kind, ty::GenericParamDefKind::Const { .. }) {
return None;
}

let ct =
ty::Const::new_param(tcx, ty::ParamConst::new(param.index, param.name));
let ct_ty = tcx.type_of(param.def_id).instantiate_identity().skip_norm_wip();

Some((
ty::ClauseKind::ConstArgHasType(ct, ct_ty).upcast(tcx),
tcx.def_span(param.def_id),
))
})
.collect::<Vec<_>>()
}
};

ty::GenericClauses { parent, clauses: tcx.arena.alloc_from_iter(clauses) }
}
Expand All @@ -607,7 +657,8 @@ fn create_folder_and_args<'tcx>(
})
.collect();

(ParamIndexRemapper { tcx, remap_table, delegation_parent_consts }, args)
let arg_kinds = args.iter().map(|arg| arg.kind()).collect();
(ParamIndexRemapper { tcx, remap_table, delegation_parent_consts, arg_kinds }, args)
}

fn check_constraints<'tcx>(
Expand All @@ -633,21 +684,40 @@ fn check_constraints<'tcx>(
ret
}

fn error_sig_for_delegation<'tcx>(
tcx: TyCtxt<'tcx>,
sig_id: DefId,
err: ErrorGuaranteed,
) -> &'tcx [Ty<'tcx>] {
let sig_len = tcx.fn_sig(sig_id).instantiate_identity().skip_binder().inputs().len() + 1;
let err_type = Ty::new_error(tcx, err);
tcx.arena.alloc_from_iter((0..sig_len).map(|_| err_type))
}

pub(crate) fn inherit_sig_for_delegation_item<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
) -> &'tcx [Ty<'tcx>] {
let sig_id = tcx.hir_opt_delegation_sig_id(def_id).expect("Delegation must have sig_id");
let caller_sig = tcx.fn_sig(sig_id);
if let Err(err) = check_constraints(tcx, def_id, sig_id) {
let sig_len = caller_sig.instantiate_identity().skip_binder().inputs().len() + 1;
let err_type = Ty::new_error(tcx, err);
return tcx.arena.alloc_from_iter((0..sig_len).map(|_| err_type));
return error_sig_for_delegation(tcx, sig_id, err);
}

let (parent_args, child_args) = tcx.delegation_user_specified_args(def_id);
let (mut folder, args) = create_folder_and_args(tcx, def_id, sig_id, parent_args, child_args);
let caller_sig = EarlyBinder::bind(tcx, caller_sig.skip_binder().fold_with(&mut folder));
let folded_sig = match caller_sig.skip_binder().try_fold_with(&mut folder) {
Ok(sig) => sig,
Err(()) => {
let err = tcx.dcx().emit_err(crate::diagnostics::DelegationInheritanceFailed {
span: tcx.def_span(def_id),
kind: "signature",
callee_span: tcx.def_span(sig_id),
});
return error_sig_for_delegation(tcx, sig_id, err);
}
};
let caller_sig = EarlyBinder::bind(tcx, folded_sig);

let sig = caller_sig.instantiate(tcx, args.as_slice()).skip_binder();
let output = std::iter::once(sig.output());
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_hir_analysis/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1706,6 +1706,16 @@ pub(crate) struct OnlyCurrentTraitsPointerSugg<'a> {
pub ptr_ty: Ty<'a>,
}

#[derive(Diagnostic)]
#[diag("failed to inherit delegation {$kind}")]
pub(crate) struct DelegationInheritanceFailed {
#[primary_span]
pub span: Span,
pub kind: &'static str,
#[label("callee defined here")]
pub callee_span: Span,
}

#[derive(Diagnostic)]
#[diag("{$descr}")]
pub(crate) struct UnsupportedDelegation<'a> {
Expand Down
Loading
Loading