diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 12a19ae5c3db9..2399259a82198 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -55,11 +55,20 @@ pub enum InstructionSetAttr { #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub enum OptimizeAttr { + /// `#[optimize(none)]` None, + /// `#[optimize(speed)]` Speed, + /// `#[optimize(size)]` Size, } +impl OptimizeAttr { + pub fn is_none(&self) -> bool { + matches!(*self, OptimizeAttr::None) + } +} + /// Represents the following attributes: /// /// - `#[stable]` diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index ad38814a68b6d..4b93cf6e7dac6 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -336,14 +336,17 @@ pub fn from_fn_attrs<'ll, 'tcx>( let mut to_add = SmallVec::<[_; 16]>::new(); match codegen_fn_attrs.optimize { - OptimizeAttr::None => { + None => { to_add.extend(default_optimisation_attrs(cx)); } - OptimizeAttr::Size => { + Some(OptimizeAttr::None) => { + to_add.push(llvm::AttributeKind::OptimizeNone.create_attr(cx.llcx)); + } + Some(OptimizeAttr::Size) => { to_add.push(llvm::AttributeKind::MinSize.create_attr(cx.llcx)); to_add.push(llvm::AttributeKind::OptimizeForSize.create_attr(cx.llcx)); } - OptimizeAttr::Speed => {} + Some(OptimizeAttr::Speed) => {} } let inline = diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index f4e44e63d73cc..93a63840b65f9 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -1024,8 +1024,8 @@ pub fn provide(providers: &mut Providers) { let any_for_speed = defids.items().any(|id| { let CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id); match optimize { - attr::OptimizeAttr::None | attr::OptimizeAttr::Size => false, - attr::OptimizeAttr::Speed => true, + None | Some(attr::OptimizeAttr::None | attr::OptimizeAttr::Size) => false, + Some(attr::OptimizeAttr::Speed) => true, } }); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 4ab20c154ccd0..07e2e5815e43c 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -559,7 +559,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } }); - codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| { + codegen_fn_attrs.optimize = attrs.iter().fold(None, |ia, attr| { if !attr.has_name(sym::optimize) { return ia; } @@ -573,14 +573,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { inline_span = Some(attr.span); if items.len() != 1 { err(attr.span, "expected one argument"); - OptimizeAttr::None + None } else if list_contains_name(items, sym::size) { - OptimizeAttr::Size + Some(OptimizeAttr::Size) } else if list_contains_name(items, sym::speed) { - OptimizeAttr::Speed + Some(OptimizeAttr::Speed) + } else if list_contains_name(items, sym::none) { + Some(OptimizeAttr::None) } else { err(items[0].span(), "invalid argument"); - OptimizeAttr::None + None } } Some(MetaItemKind::NameValue(_)) => ia, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 72ea55d5999a2..d93f69f270360 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -532,7 +532,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), // RFC 2412 gated!( - optimize, Normal, template!(List: "size|speed"), ErrorPreceding, + optimize, Normal, template!(List: "none|size|speed"), ErrorPreceding, EncodeCrossCrate::No, optimize_attribute, experimental!(optimize) ), diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index ff6a3a9c12d36..07bada65885f0 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -11,8 +11,8 @@ pub struct CodegenFnAttrs { pub flags: CodegenFnAttrFlags, /// Parsed representation of the `#[inline]` attribute pub inline: InlineAttr, - /// Parsed representation of the `#[optimize]` attribute - pub optimize: OptimizeAttr, + /// Parsed representation of the `#[optimize]` attribute if present + pub optimize: Option, /// The `#[export_name = "..."]` attribute, indicating a custom symbol a /// function should be exported under pub export_name: Option, @@ -137,7 +137,7 @@ impl CodegenFnAttrs { CodegenFnAttrs { flags: CodegenFnAttrFlags::empty(), inline: InlineAttr::None, - optimize: OptimizeAttr::None, + optimize: None, export_name: None, link_name: None, link_ordinal: None, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 46c4d586f6ad9..1886c4f8c9fc7 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -443,6 +443,9 @@ pub struct Body<'tcx> { /// If `-Cinstrument-coverage` is not active, or if an individual function /// is not eligible for coverage, then this should always be `None`. pub function_coverage_info: Option>, + + /// Whether optimization is disabled by `#[optimize(none)]` + pub optimization_disabled: bool, } impl<'tcx> Body<'tcx> { @@ -457,6 +460,7 @@ impl<'tcx> Body<'tcx> { span: Span, coroutine: Option>>, tainted_by_errors: Option, + optimization_disabled: bool, ) -> Self { // We need `arg_count` locals, and one for the return place. assert!( @@ -486,6 +490,7 @@ impl<'tcx> Body<'tcx> { tainted_by_errors, coverage_info_hi: None, function_coverage_info: None, + optimization_disabled, }; body.is_polymorphic = body.has_non_region_param(); body @@ -517,6 +522,7 @@ impl<'tcx> Body<'tcx> { tainted_by_errors: None, coverage_info_hi: None, function_coverage_info: None, + optimization_disabled: false, }; body.is_polymorphic = body.has_non_region_param(); body diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs index 28477e527c721..d3374f29b2da2 100644 --- a/compiler/rustc_mir_build/src/build/custom/mod.rs +++ b/compiler/rustc_mir_build/src/build/custom/mod.rs @@ -62,6 +62,7 @@ pub(super) fn build_custom_mir<'tcx>( pass_count: 0, coverage_info_hi: None, function_coverage_info: None, + optimization_disabled: false, }; body.local_decls.push(LocalDecl::new(return_ty, return_ty_span)); diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index b98deda8fd022..0f088f5496471 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -718,6 +718,7 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - span, coroutine, Some(guar), + false, ) } @@ -794,6 +795,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + let def_id = self.def_id.to_def_id(); + let optimization_disabled = if self.tcx.def_kind(def_id).has_codegen_attrs() { + self.tcx.codegen_fn_attrs(def_id).optimize.as_ref().is_some_and(|o| o.is_none()) + } else { + false + }; + let mut body = Body::new( MirSource::item(self.def_id.to_def_id()), self.cfg.basic_blocks, @@ -805,6 +813,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.fn_span, self.coroutine, None, + optimization_disabled, ); body.coverage_info_hi = self.coverage_info.map(|b| b.into_done()); body diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 1f214bc42cbe6..c0903b282241d 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -554,6 +554,10 @@ fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if body.optimization_disabled { + return; + } + fn o1(x: T) -> WithMinOptLevel { WithMinOptLevel(1, x) } diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index dc8e50ac8cd28..f812ca0fda6eb 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -1006,6 +1006,7 @@ fn promote_candidates<'tcx>( body.span, None, body.tainted_by_errors, + body.optimization_disabled, ); promoted.phase = MirPhase::Analysis(AnalysisPhase::Initial); diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index f41f3ef656c51..d04e8d5402e1d 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -326,6 +326,7 @@ fn new_body<'tcx>( None, // FIXME(compiler-errors): is this correct? None, + false, ); // Shims do not directly mention any consts. body.set_required_consts(Vec::new()); diff --git a/tests/codegen/optimize-attr-1.rs b/tests/codegen/optimize-attr-1.rs index 3aee44791e0e6..d78307475dff1 100644 --- a/tests/codegen/optimize-attr-1.rs +++ b/tests/codegen/optimize-attr-1.rs @@ -15,6 +15,17 @@ pub fn nothing() -> i32 { 2 + 2 } +// CHECK-LABEL: define{{.*}}i32 @none +// CHECK-SAME: [[NONE_ATTRS:#[0-9]+]] +// SIZE-OPT: alloca +// SPEED-OPT: alloca +#[no_mangle] +#[optimize(none)] +pub fn none() -> i32 { + let arr = [0, 1, 2, 3, 4]; + arr[4] +} + // CHECK-LABEL: define{{.*}}i32 @size // CHECK-SAME: [[SIZE_ATTRS:#[0-9]+]] // SIZE-OPT: ret i32 6 @@ -39,8 +50,10 @@ pub fn speed() -> i32 { // NO-OPT-DAG: attributes [[SIZE_ATTRS]] = {{.*}}minsize{{.*}}optsize{{.*}} // SPEED-OPT-DAG: attributes [[SIZE_ATTRS]] = {{.*}}minsize{{.*}}optsize{{.*}} +// SPEED-OPT-DAG: attributes [[NONE_ATTRS]] = {{.*}}optnone{{.*}} // SIZE-OPT-DAG: attributes [[NOTHING_ATTRS]] = {{.*}}optsize{{.*}} // SIZE-OPT-DAG: attributes [[SIZE_ATTRS]] = {{.*}}minsize{{.*}}optsize{{.*}} +// SIZE-OPT-DAG: attributes [[NONE_ATTRS]] = {{.*}}optnone{{.*}} // SIZE-OPT: attributes [[SPEED_ATTRS]] // SIZE-OPT-NOT: minsize diff --git a/tests/ui/feature-gates/feature-gate-optimize_attribute.rs b/tests/ui/feature-gates/feature-gate-optimize_attribute.rs index 15aa3a6af4ca9..2bdc7644ae049 100644 --- a/tests/ui/feature-gates/feature-gate-optimize_attribute.rs +++ b/tests/ui/feature-gates/feature-gate-optimize_attribute.rs @@ -10,6 +10,9 @@ fn size() {} #[optimize(speed)] //~ ERROR the `#[optimize]` attribute is an experimental feature fn speed() {} +#[optimize(none)] //~ ERROR the `#[optimize]` attribute is an experimental feature +fn none() {} + #[optimize(banana)] //~^ ERROR the `#[optimize]` attribute is an experimental feature //~| ERROR E0722 diff --git a/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr b/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr index 609526150ba2e..dd57830642c67 100644 --- a/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr +++ b/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr @@ -41,6 +41,16 @@ LL | #[optimize(speed)] error[E0658]: the `#[optimize]` attribute is an experimental feature --> $DIR/feature-gate-optimize_attribute.rs:13:1 | +LL | #[optimize(none)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #54882 for more information + = help: add `#![feature(optimize_attribute)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: the `#[optimize]` attribute is an experimental feature + --> $DIR/feature-gate-optimize_attribute.rs:16:1 + | LL | #[optimize(banana)] | ^^^^^^^^^^^^^^^^^^^ | @@ -49,12 +59,12 @@ LL | #[optimize(banana)] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0722]: invalid argument - --> $DIR/feature-gate-optimize_attribute.rs:13:12 + --> $DIR/feature-gate-optimize_attribute.rs:16:12 | LL | #[optimize(banana)] | ^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0658, E0722. For more information about an error, try `rustc --explain E0658`.