Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
095f89b
Add 'bit' and 'set_bit' methods to integral types;
bjoernager Oct 14, 2025
a812bac
Render `Deref` methods on aliased items
GuillaumeGomez Sep 30, 2026
0c442ea
Improve `is_doc_subtype_of` to work better for doc aliases
GuillaumeGomez Oct 2, 2026
a388dd0
Add new `is_deref[_mut]_trait` methods to simplify code
GuillaumeGomez Oct 2, 2026
6e5f760
Remove duplicated code to query `Deref` impls
GuillaumeGomez Oct 2, 2026
e1e1dc8
Remove `is_same_generic` test as it cannot work with the new argument…
GuillaumeGomez Oct 2, 2026
b747376
Add rustdoc-html test to illustrate known limits to dereferencing to …
GuillaumeGomez Oct 5, 2026
2cab4ca
nuttx: use updated pollfd definition
bkueng Sep 23, 2026
2e1670b
Strenghten `deref` and `deref_mut` checks to ensure we don't compare …
GuillaumeGomez Nov 5, 2026
dc5ab20
Add multi-level `Deref` test
GuillaumeGomez Nov 5, 2026
4efd167
Introduce `OptimizationObjective` and fix the entry shim's size attri…
cezarbbb Oct 26, 2026
45bea6c
add tests for -Zcrate-attr ordering
Albab-Hasan Nov 5, 2026
851c9e0
apply -Zcrate-attr attributes before the crate attributes
Albab-Hasan Nov 5, 2026
bfe04e6
Rollup merge of #164784 - cezarbbb:overhaul-size-flags, r=oli-obk
Zalathar Nov 7, 2026
1edcba0
Rollup merge of #147696 - bjoernager:bit, r=hanna-kruppe
Zalathar Nov 7, 2026
71979ed
Rollup merge of #163202 - bkueng:nuttx_poll_update, r=hanna-kruppe
Zalathar Nov 7, 2026
9725504
Rollup merge of #163571 - GuillaumeGomez:deref-on-aliased, r=Urgau
Zalathar Nov 7, 2026
5f1b924
Rollup merge of #165482 - Albab-Hasan:crate-attr-tests, r=oli-obk
Zalathar Nov 7, 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: 7 additions & 8 deletions compiler/rustc_builtin_macros/src/cmdline_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rustc_session::parse::ParseSess;
use rustc_span::FileName;

pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
for raw_attr in attrs {
let injected = attrs.iter().filter_map(|raw_attr| {
let source = format!("#![{raw_attr}]");
let parse = || -> Result<ast::Attribute, Vec<Diag<'_>>> {
let tokens = source_str_to_stream(
Expand All @@ -22,16 +22,15 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
})
.map_err(|e| vec![e])
};
let meta = match parse() {
Ok(meta) => meta,
match parse() {
Ok(meta) => Some(meta),
Err(errs) => {
for err in errs {
err.emit();
}
continue;
None
}
};

krate.attrs.push(meta);
}
}
});
krate.attrs.splice(0..0, injected);
}
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,8 @@ pub(crate) fn default_optimisation_attrs<'ll>(
sess: &Session,
) -> SmallVec<[&'ll Attribute; 2]> {
let mut attrs = SmallVec::new();
// Either attribute satisfies LLVM's combined size predicate, but the software pipeliner reads
// `optsize` alone, so a `z` build needs both.
match sess.opts.optimize {
OptLevel::Size => {
attrs.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx));
Expand Down
19 changes: 9 additions & 10 deletions compiler/rustc_codegen_llvm/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,15 @@ pub(crate) fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> OwnedTar
target_machine_factory(tcx.sess, tcx.backend_optimization_level(()))(tcx.dcx(), config)
}

fn to_llvm_opt_settings(cfg: config::OptLevel) -> (llvm::CodeGenOptLevel, llvm::CodeGenOptSize) {
// `s` and `z` are the same codegen level; what tells LLVM that they are size builds is the
// per-function attribute, not this setting.
fn to_llvm_opt_level(cfg: config::OptLevel) -> llvm::CodeGenOptLevel {
use self::config::OptLevel::*;
match cfg {
No => (llvm::CodeGenOptLevel::None, llvm::CodeGenOptSizeNone),
Less => (llvm::CodeGenOptLevel::Less, llvm::CodeGenOptSizeNone),
More => (llvm::CodeGenOptLevel::Default, llvm::CodeGenOptSizeNone),
Aggressive => (llvm::CodeGenOptLevel::Aggressive, llvm::CodeGenOptSizeNone),
Size => (llvm::CodeGenOptLevel::Default, llvm::CodeGenOptSizeDefault),
SizeMin => (llvm::CodeGenOptLevel::Default, llvm::CodeGenOptSizeAggressive),
No => llvm::CodeGenOptLevel::None,
Less => llvm::CodeGenOptLevel::Less,
More | Size | SizeMin => llvm::CodeGenOptLevel::Default,
Aggressive => llvm::CodeGenOptLevel::Aggressive,
}
}

Expand Down Expand Up @@ -184,7 +184,7 @@ pub(crate) fn target_machine_factory(

let reloc_model = to_llvm_relocation_model(sess.relocation_model());

let (opt_level, _) = to_llvm_opt_settings(optlvl);
let opt_level = to_llvm_opt_level(optlvl);
let float_abi = to_llvm_float_abi(sess.target.llvm_floatabi);

let ffunction_sections =
Expand Down Expand Up @@ -594,8 +594,7 @@ pub(crate) unsafe fn llvm_optimize<'ll>(
vectorize_slp = false;
vectorize_loop = false;
} else {
unroll_loops =
opt_level != config::OptLevel::Size && opt_level != config::OptLevel::SizeMin;
unroll_loops = opt_level.objective() != config::OptimizationObjective::Size;
merge_functions = config.merge_functions;
vectorize_slp = config.vectorize_slp;
vectorize_loop = config.vectorize_loop;
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_codegen_llvm/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,11 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &attrs);
}

fn apply_default_optimisation_attrs(&self, llfn: &'ll Value) {
let attrs = attributes::default_optimisation_attrs(self, self.sess());
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &attrs);
}

fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
let entry_name = self.sess().target.entry_name.as_ref();
if self.get_declared_value(entry_name).is_none() {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1707,6 +1707,7 @@ fn gen_fn<'a, 'll, 'tcx>(
let llfn = cx.declare_fn(name, fn_abi, None);
cx.set_frame_pointer_type(llfn);
cx.apply_target_cpu_attr(llfn);
cx.apply_default_optimisation_attrs(llfn);
// FIXME(eddyb) find a nicer way to do this.
llvm::set_linkage(llfn, llvm::Linkage::InternalLinkage);
let llbb = Builder::append_block(cx, llfn, "entry-block");
Expand Down
9 changes: 0 additions & 9 deletions compiler/rustc_codegen_llvm/src/llvm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use rustc_abi::{AddressSpace, Align, Size, WrappingRange};
use rustc_llvm::RustString;

pub(crate) use self::CallConv::*;
pub(crate) use self::CodeGenOptSize::*;
pub(crate) use self::conversions::*;
pub(crate) use self::ffi::*;
pub(crate) use self::metadata_kind::*;
Expand Down Expand Up @@ -195,14 +194,6 @@ impl AttributePlace {
}
}

#[derive(Copy, Clone, PartialEq)]
#[repr(C)]
pub(crate) enum CodeGenOptSize {
CodeGenOptSizeNone = 0,
CodeGenOptSizeDefault = 1,
CodeGenOptSizeAggressive = 2,
}

pub(crate) fn SetInstructionCallConv(instr: &Value, cc: CallConv) {
unsafe {
LLVMSetInstructionCallConv(instr, cc as c_uint);
Expand Down
7 changes: 3 additions & 4 deletions compiler/rustc_codegen_ssa/src/back/linker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ impl<'a> GccLinker<'a> {
self.link_arg(&arg);
}

// The plugin has no distinct size setting: `s` and `z` both map to `O2`, as `More` does.
let opt_level = match self.sess.opts.optimize {
config::OptLevel::No => "O0",
config::OptLevel::Less => "O1",
Expand Down Expand Up @@ -698,9 +699,7 @@ impl<'a> Linker for GccLinker<'a> {

// GNU-style linkers support optimization with -O. GNU ld doesn't
// need a numeric argument, but other linkers do.
if self.sess.opts.optimize == config::OptLevel::More
|| self.sess.opts.optimize == config::OptLevel::Aggressive
{
if self.sess.optimization_objective() == config::OptimizationObjective::Speed {
self.link_arg("-O1");
}
}
Expand Down Expand Up @@ -1021,7 +1020,7 @@ impl<'a> Linker for MsvcLinker<'a> {
// MSVC's ICF (Identical COMDAT Folding) link optimization is
// slow for Rust and thus we disable it by default when not in
// optimization build.
if self.sess.opts.optimize != config::OptLevel::No {
if self.sess.optimization_objective() != config::OptimizationObjective::None {
self.link_arg("/OPT:REF,ICF");
} else {
// It is necessary to specify NOICF here, because /OPT:REF
Expand Down
18 changes: 7 additions & 11 deletions compiler/rustc_codegen_ssa/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use rustc_metadata::fs::copy_to_stdout;
use rustc_middle::dep_graph::{WorkProduct, WorkProductMap};
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{
self, JobsMode, Lto, OptLevel, OutFileName, OutputFilenames, OutputType, Passes,
SwitchWithOptPath,
self, JobsMode, Lto, OptLevel, OptimizationObjective, OutFileName, OutputFilenames, OutputType,
Passes, SwitchWithOptPath,
};
use rustc_session::{BorrowedIncrCompSession, IncrCompSession, Session};
use rustc_span::source_map::SourceMap;
Expand Down Expand Up @@ -231,8 +231,7 @@ impl ModuleConfig {
// Copy what clang does by turning on loop vectorization at O2 and
// slp vectorization at O3.
vectorize_loop: !sess.opts.cg.no_vectorize_loops
&& (sess.opts.optimize == config::OptLevel::More
|| sess.opts.optimize == config::OptLevel::Aggressive),
&& sess.optimization_objective() == OptimizationObjective::Speed,
vectorize_slp: !sess.opts.cg.no_vectorize_slp
&& sess.opts.optimize == config::OptLevel::Aggressive,

Expand All @@ -247,13 +246,10 @@ impl ModuleConfig {
// O2 and O3) since it can be useful for reducing code size.
merge_functions: match sess.merge_functions() {
MergeFunctions::Disabled => false,
MergeFunctions::Trampolines | MergeFunctions::Aliases => {
use config::OptLevel::*;
match sess.opts.optimize {
Aggressive | More | SizeMin | Size => true,
Less | No => false,
}
}
MergeFunctions::Trampolines | MergeFunctions::Aliases => matches!(
sess.optimization_objective(),
OptimizationObjective::Speed | OptimizationObjective::Size
),
},

emit_lifetime_markers: sess.emit_lifetime_markers(),
Expand Down
35 changes: 13 additions & 22 deletions compiler/rustc_codegen_ssa/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,8 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// `main` should respect same config for frame pointer elimination as rest of code
cx.set_frame_pointer_type(llfn);
cx.apply_target_cpu_attr(llfn);
// The shim has no item behind it, so it does not go through the per-item attribute path.
cx.apply_default_optimisation_attrs(llfn);

let llbb = Bx::append_block(cx, llfn, "top");
let mut bx = Bx::build(cx, llbb);
Expand Down Expand Up @@ -1217,23 +1219,16 @@ impl CrateInfo {

pub(crate) fn provide(providers: &mut Providers) {
providers.backend_optimization_level = |tcx, cratenum| {
let for_speed = match tcx.sess.opts.optimize {
// If globally no optimisation is done, #[optimize] has no effect.
//
// This is done because if we ended up "upgrading" to `-O2` here, we’d populate the
// pass manager and it is likely that some module-wide passes (such as inliner or
// cross-function constant propagation) would ignore the `optnone` annotation we put
// on the functions, thus necessarily involving these functions into optimisations.
config::OptLevel::No => return config::OptLevel::No,
// If globally optimise-speed is already specified, just use that level.
config::OptLevel::Less => return config::OptLevel::Less,
config::OptLevel::More => return config::OptLevel::More,
config::OptLevel::Aggressive => return config::OptLevel::Aggressive,
// If globally optimize-for-size has been requested, use -O2 instead (if optimize(size)
// are present).
config::OptLevel::Size => config::OptLevel::More,
config::OptLevel::SizeMin => config::OptLevel::More,
};
let global = tcx.sess.opts.optimize;

// Nothing to promote outside a size build. At `-Copt-level=0` the upgrade would populate
// the pass manager, and its module-wide passes ignore the `optnone` annotation.
if global.objective() != config::OptimizationObjective::Size {
return global;
}

// A speed-marked body in a size build needs a speed level, and `-O2` is the lowest one.
let for_speed = config::OptLevel::More;

let defids = tcx.collect_and_partition_mono_items(cratenum).all_mono_items;

Expand All @@ -1242,11 +1237,7 @@ pub(crate) fn provide(providers: &mut Providers) {
matches!(optimize, OptimizeAttr::Speed)
});

if any_for_speed {
return for_speed;
}

tcx.sess.opts.optimize
if any_for_speed { for_speed } else { global }
};
}

Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_codegen_ssa/src/traits/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ pub trait MiscCodegenMethods<'tcx>: BackendTypes {
fn sess(&self) -> &Session;
fn set_frame_pointer_type(&self, llfn: Self::Function);
fn apply_target_cpu_attr(&self, llfn: Self::Function);
/// Applies the compilation's optimization attributes to a function that no item produced,
/// such as the C entry shim.
fn apply_default_optimisation_attrs(&self, _llfn: Self::Function) {}
/// Declares the extern "C" main function for the entry point. Returns None if the symbol
/// already exists.
fn declare_c_main(&self, fn_type: Self::FunctionSignature) -> Option<Self::Function>;
Expand Down
34 changes: 30 additions & 4 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,33 @@ impl OptLevel {
_ => 2,
}
}

/// Maps a general opt-level onto the objective it is trying to achieve.
pub fn objective(&self) -> OptimizationObjective {
match self {
OptLevel::No => OptimizationObjective::None,
OptLevel::Less => OptimizationObjective::Balanced,
OptLevel::More | OptLevel::Aggressive => OptimizationObjective::Speed,
OptLevel::Size | OptLevel::SizeMin => OptimizationObjective::Size,
}
}
}

/// What a compilation, or a single item, is being asked to optimize *for*.
///
/// Unlike [`OptLevel`], speed and size are alternatives here rather than degrees of the same
/// thing. Sites that map a level onto an LLVM or linker flag, where `s` and `z` produce different
/// flags, still match on [`OptLevel`].
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum OptimizationObjective {
/// Nothing is optimized, so there is no objective (`-Copt-level=0`).
None,
/// Optimize, without a strong preference for speed over size (`-Copt-level=1`).
Balanced,
/// Favor runtime speed over binary size (`-Copt-level=2`/`3`, `#[optimize(speed)]`).
Speed,
/// Favor binary size over runtime speed (`-Copt-level=s`/`z`, `#[optimize(size)]`).
Size,
}

/// This is what the `LtoCli` values get mapped to after resolving defaults and
Expand Down Expand Up @@ -1572,10 +1599,9 @@ impl Options {
pub fn share_generics(&self) -> bool {
match self.unstable_opts.share_generics {
Some(setting) => setting,
None => match self.optimize {
OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
OptLevel::More | OptLevel::Aggressive => false,
},
// Sharing instantiations means fewer copies, at the cost of leaving them opaque to
// speed optimizations. That is a good trade unless speed is what is asked for.
None => self.optimize.objective() != OptimizationObjective::Speed,
}
}

Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -988,6 +988,11 @@ impl Session {
self.opts.unstable_opts.mir_opt_level.unwrap_or_else(|| self.opts.optimize.mir_opt_level())
}

/// What this compilation optimizes for; see [`config::OptimizationObjective`].
pub fn optimization_objective(&self) -> config::OptimizationObjective {
self.opts.optimize.objective()
}

/// Calculates the flavor of LTO to use for this compilation.
pub fn lto(&self) -> config::Lto {
// If our target has codegen requirements ignore the command line
Expand Down
72 changes: 72 additions & 0 deletions library/core/src/num/int_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,78 @@ macro_rules! int_impl {
#[stable(feature = "int_bits_const", since = "1.53.0")]
pub const BITS: u32 = <$UnsignedT>::BITS;

/// Tests the value of a specific bit.
///
/// # Panics
///
/// If overflow checks are enabled, this method will panic if the provided index is
/// greater than or equal to [`BITS`].
///
/// [`BITS`]: Self::BITS
///
/// # Examples
///
/// ```
/// #![feature(get_set_bit)]
///
#[doc = concat!("let n = 0b111_1001", stringify!($SelfT), ";")]
///
/// assert!(n.bit(0));
/// assert!(!n.bit(1));
/// assert!(!n.bit(2));
/// assert!(n.bit(3));
/// assert!(n.bit(4));
/// assert!(n.bit(5));
/// assert!(n.bit(6));
/// ```
#[unstable(feature = "get_set_bit", issue = "147702")]
#[rustc_const_unstable(feature = "get_set_bit", issue = "147702")]
#[rustc_inherit_overflow_checks]
#[inline]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[track_caller]
pub const fn bit(self, index: u32) -> bool {
self.cast_unsigned().bit(index)
}

/// Sets the value of a specific bit.
///
/// # Panics
///
/// If overflow checks are enabled, this method will panic if the provided index is
/// greater than or equal to [`BITS`].
///
/// [`BITS`]: Self::BITS
///
/// # Examples
///
/// ```
/// #![feature(get_set_bit)]
///
#[doc = concat!("let mut n = 0b101_0101", stringify!($SelfT), ";")]
///
/// n = n.set_bit(0, false);
/// n = n.set_bit(1, true);
/// n = n.set_bit(2, false);
/// n = n.set_bit(3, true);
/// n = n.set_bit(4, false);
/// n = n.set_bit(5, true);
/// n = n.set_bit(6, false);
///
/// assert_eq!(n, 0b010_1010);
/// ```
#[unstable(feature = "get_set_bit", issue = "147702")]
#[rustc_const_unstable(feature = "get_set_bit", issue = "147702")]
#[rustc_inherit_overflow_checks]
#[inline]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[track_caller]
pub const fn set_bit(self, index: u32, value: bool) -> Self {
self.cast_unsigned().set_bit(index, value).cast_signed()
}

/// Returns the number of ones in the binary representation of `self`.
///
/// # Examples
Expand Down
Loading
Loading