Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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_parsing/src/attributes/rustc_internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,21 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcNoMirInlineParser {
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoMirInline;
}

pub(crate) struct RustcNoWritableParser;

impl<S: Stage> NoArgsAttributeParser<S> for RustcNoWritableParser {
const PATH: &[Symbol] = &[sym::rustc_no_writable];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Closure),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::TraitImpl)),
Allow(Target::Method(MethodKind::Trait { body: true })),
]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoWritable;
}

pub(crate) struct RustcLintQueryInstabilityParser;

impl<S: Stage> NoArgsAttributeParser<S> for RustcLintQueryInstabilityParser {
Expand Down
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 @@ -309,6 +309,7 @@ attribute_parsers!(
Single<WithoutArgs<RustcNoImplicitAutorefsParser>>,
Single<WithoutArgs<RustcNoImplicitBoundsParser>>,
Single<WithoutArgs<RustcNoMirInlineParser>>,
Single<WithoutArgs<RustcNoWritableParser>>,
Single<WithoutArgs<RustcNonConstTraitMethodParser>>,
Single<WithoutArgs<RustcNonnullOptimizationGuaranteedParser>>,
Single<WithoutArgs<RustcNounwindParser>>,
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_llvm/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,12 @@ trait ArgAttributesExt {
const ABI_AFFECTING_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 1] =
[(ArgAttribute::InReg, llvm::AttributeKind::InReg)];

const OPTIMIZATION_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 4] = [
const OPTIMIZATION_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 5] = [
(ArgAttribute::NoAlias, llvm::AttributeKind::NoAlias),
(ArgAttribute::NonNull, llvm::AttributeKind::NonNull),
(ArgAttribute::ReadOnly, llvm::AttributeKind::ReadOnly),
(ArgAttribute::NoUndef, llvm::AttributeKind::NoUndef),
(ArgAttribute::Writable, llvm::AttributeKind::Writable),
];

const CAPTURES_ATTRIBUTES: [(ArgAttribute, llvm::AttributeKind); 3] = [
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1414,6 +1414,9 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_scalable_vector, Normal, template!(List: &["count"]), WarnFollowing, EncodeCrossCrate::Yes,
"`#[rustc_scalable_vector]` defines a scalable vector type"
),
rustc_attr!(
rustc_no_writable, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, "`#[rustc_no_writable]` stops the compiler from adding the `writable` flag in LLVM, thus under Tree Borrows, mutable retags no longer count as writes"
),

// ==========================================================================
// Internal attributes, Testing:
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1489,6 +1489,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_no_mir_inline]`
RustcNoMirInline,

/// Represents `#[rustc_no_writable]`
RustcNoWritable,

/// Represents `#[rustc_non_const_trait_method]`.
RustcNonConstTraitMethod,

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/attrs/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ impl AttributeKind {
RustcNoImplicitAutorefs => Yes,
RustcNoImplicitBounds => No,
RustcNoMirInline => Yes,
RustcNoWritable => Yes,
RustcNonConstTraitMethod => No, // should be reported via other queries like `constness`
RustcNonnullOptimizationGuaranteed => Yes,
RustcNounwind => No,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(no_profiler_runtime, true);
tracked!(no_trait_vptr, true);
tracked!(no_unique_section_names, true);
tracked!(no_writable, true);
tracked!(offload, vec![Offload::Device]);
tracked!(on_broken_pipe, OnBrokenPipe::Kill);
tracked!(osx_rpath_install_name, true);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::RustcNoImplicitAutorefs
| AttributeKind::RustcNoImplicitBounds
| AttributeKind::RustcNoMirInline
| AttributeKind::RustcNoWritable
| AttributeKind::RustcNonConstTraitMethod
| AttributeKind::RustcNonnullOptimizationGuaranteed
| AttributeKind::RustcNounwind
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2530,6 +2530,8 @@ options! {
"disable generation of trait vptr in vtable for upcasting"),
no_unique_section_names: bool = (false, parse_bool, [TRACKED],
"do not use unique names for text and data sections when -Z function-sections is used"),
no_writable: bool = (false, parse_bool, [TRACKED],
"do not insert the writable LLVM attribute; mutable retags don't count as writes under Tree Borrows"),
normalize_docs: bool = (false, parse_bool, [TRACKED],
"normalize associated items in rustdoc when generating documentation"),
offload: Vec<crate::config::Offload> = (Vec::new(), parse_offload, [TRACKED],
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1751,6 +1751,7 @@ symbols! {
rustc_no_implicit_autorefs,
rustc_no_implicit_bounds,
rustc_no_mir_inline,
rustc_no_writable,
rustc_non_const_trait_method,
rustc_nonnull_optimization_guaranteed,
rustc_nounwind,
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_target/src/callconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@ mod attr_impl {

// The subset of llvm::Attribute needed for arguments, packed into a bitfield.
#[derive(Clone, Copy, Default, Hash, PartialEq, Eq, HashStable_Generic)]
pub struct ArgAttribute(u8);
pub struct ArgAttribute(u16);
bitflags::bitflags! {
impl ArgAttribute: u8 {
impl ArgAttribute: u16 {
const CapturesNone = 0b111;
const CapturesAddress = 0b110;
const CapturesReadOnly = 0b100;
Expand All @@ -121,6 +121,7 @@ mod attr_impl {
const ReadOnly = 1 << 5;
const InReg = 1 << 6;
const NoUndef = 1 << 7;
const Writable = 1 << 8;
}
}
rustc_data_structures::external_bitflags_debug! { ArgAttribute }
Expand Down
13 changes: 12 additions & 1 deletion compiler/rustc_ty_utils/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use std::{assert_matches, iter};

use rustc_abi::Primitive::Pointer;
use rustc_abi::{Align, BackendRepr, ExternAbi, PointerKind, Scalar, Size};
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{self as hir, find_attr};
use rustc_middle::bug;
use rustc_middle::middle::deduced_param_attrs::DeducedParamAttrs;
use rustc_middle::query::Providers;
Expand Down Expand Up @@ -355,6 +355,7 @@ fn arg_attrs_for_rust_scalar<'tcx>(
offset: Size,
is_return: bool,
drop_target_pointee: Option<Ty<'tcx>>,
def_id: Option<DefId>,
) -> ArgAttributes {
let mut attrs = ArgAttributes::new();

Expand Down Expand Up @@ -430,6 +431,15 @@ fn arg_attrs_for_rust_scalar<'tcx>(
// (see <https://github.com/rust-lang/unsafe-code-guidelines/issues/385#issuecomment-1368055745>).
if no_alias && !is_return {
attrs.set(ArgAttribute::NoAlias);

// set writable if no_alias is set, it's a mutable reference and the feature is not disabled
let no_writable = match def_id {
Some(def_id) => find_attr!(tcx, def_id, RustcNoWritable),
None => false, // If no def_id exists, there can't exist an attribute for that def_id so rustc_no_writable can't be set
} || tcx.sess.opts.unstable_opts.no_writable;
if matches!(kind, PointerKind::MutableRef { .. }) && !no_writable {
attrs.set(ArgAttribute::Writable);
}
}

if matches!(kind, PointerKind::SharedRef { frozen: true }) && !is_return {
Expand Down Expand Up @@ -624,6 +634,7 @@ fn fn_abi_new_uncached<'tcx>(
// Only set `drop_target_pointee` for the data part of a wide pointer.
// See `arg_attrs_for_rust_scalar` docs for more information.
drop_target_pointee.filter(|_| offset == Size::ZERO),
determined_fn_def_id,
)
}))
};
Expand Down
5 changes: 5 additions & 0 deletions src/doc/unstable-book/src/compiler-flags/no-writable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# `no-writable`

---

This flag will globally stop the compiler from inserting the [writable](https://llvm.org/docs/LangRef.html#writable) LLVM flag. It also stops [Miri](github.com/rust-lang/miri) from testing for undefined behavior when inserting writes. It has the same effect as applying `#[rustc_no_writable]` to every function.
1 change: 1 addition & 0 deletions src/tools/miri/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,7 @@ Some native rustc `-Z` flags are also very relevant for Miri:
sets this flag per default.
* `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri
enables this per default because it is needed for [Stacked Borrows] and [Tree Borrows].
* `-Zno-writable` disables the strong mode globally, thus disabling the tracking of spurious writes. This also stops the compiler from adding the `writable` attribute. This only has an effect in Miri if [Tree Borrows] are enabled.

Moreover, Miri recognizes some environment variables:

Expand Down
11 changes: 11 additions & 0 deletions src/tools/miri/src/bin/miri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,7 @@ fn main() -> ExitCode {
miri_config.borrow_tracker =
Some(BorrowTrackerMethod::TreeBorrows(TreeBorrowsParams {
precise_interior_mut: true,
writable: true,
}));
} else if arg == "-Zmiri-tree-borrows-no-precise-interior-mut" {
match &mut miri_config.borrow_tracker {
Expand All @@ -530,6 +531,16 @@ fn main() -> ExitCode {
"`-Zmiri-tree-borrows` is required before `-Zmiri-tree-borrows-no-precise-interior-mut`"
),
};
} else if arg == "-Zno-writable" {
match &mut miri_config.borrow_tracker {
Some(BorrowTrackerMethod::TreeBorrows(params)) => {
params.writable = false;
}
_ =>
eprintln!(
"Warning: `-Zno-writable` only has an effect in Miri if `-Zmiri-tree-borrows` is before it. The flag still will have an effect in the compiler."
),
};
} else if arg == "-Zmiri-disable-data-race-detector" {
miri_config.data_race_detector = false;
miri_config.weak_memory_emulation = false;
Expand Down
1 change: 1 addition & 0 deletions src/tools/miri/src/borrow_tracker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ pub enum BorrowTrackerMethod {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct TreeBorrowsParams {
pub precise_interior_mut: bool,
pub writable: bool,
}

impl BorrowTrackerMethod {
Expand Down
2 changes: 2 additions & 0 deletions tests/assembly-llvm/reg-struct-return.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
//@ needs-llvm-components: x86

#![feature(no_core)]
#![feature(rustc_attrs)]
#![no_std]
#![no_core]
#![crate_type = "lib"]
Expand Down Expand Up @@ -131,6 +132,7 @@ mod Large {
}

#[unsafe(no_mangle)]
#[rustc_no_writable] // as we do not want to test this here, disable it
pub unsafe extern "C" fn large_caller(dst: &mut LargeStruct) {
// CHECK-LABEL: large_caller
// CHECK: calll large
Expand Down
2 changes: 1 addition & 1 deletion tests/codegen-llvm/drop-in-place-noalias.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

use std::marker::PhantomPinned;

// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructUnpin{{.*}}(ptr noalias noundef align 4 dereferenceable(12) %{{.+}})
// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructUnpin{{.*}}(ptr noalias noundef writable align 4 dereferenceable(12) %{{.+}})

// CHECK: define internal void @{{.*}}core{{.*}}ptr{{.*}}drop_in_place{{.*}}StructNotUnpin{{.*}}(ptr noundef nonnull align 4 %{{.+}})

Expand Down
16 changes: 11 additions & 5 deletions tests/codegen-llvm/function-arguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,16 +106,22 @@ pub fn named_borrow<'r>(_: &'r i32) {}
#[no_mangle]
pub fn unsafe_borrow(_: &UnsafeInner) {}

// CHECK: @mutable_unsafe_borrow(ptr noalias noundef align 2 dereferenceable(2) %_1)
// CHECK: @mutable_unsafe_borrow(ptr noalias noundef writable align 2 dereferenceable(2) %_1)
// ... unless this is a mutable borrow, those never alias
#[no_mangle]
pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {}

// CHECK: @mutable_borrow(ptr noalias noundef align 4 dereferenceable(4) %_1)
// CHECK: @mutable_borrow(ptr noalias noundef writable align 4 dereferenceable(4) %_1)
// FIXME #25759 This should also have `nocapture`
#[no_mangle]
pub fn mutable_borrow(_: &mut i32) {}

// CHECK: @mutable_borrow_no_writable(ptr noalias noundef align 4 dereferenceable(4) %_1)
// checks that rustc_no_writable removes the writable attribute
#[no_mangle]
#[rustc_no_writable]
pub fn mutable_borrow_no_writable(_: &mut i32) {}

// CHECK: noundef nonnull align 4 ptr @mutable_borrow_ret()
#[no_mangle]
pub fn mutable_borrow_ret() -> &'static mut i32 {
Expand Down Expand Up @@ -147,7 +153,7 @@ pub fn borrowed_struct(_: &S) {}
#[no_mangle]
pub fn option_borrow(_x: Option<&i32>) {}

// CHECK: @option_borrow_mut(ptr noalias noundef align 4 dereferenceable_or_null(4) %_x)
// CHECK: @option_borrow_mut(ptr noalias noundef writable align 4 dereferenceable_or_null(4) %_x)
#[no_mangle]
pub fn option_borrow_mut(_x: Option<&mut i32>) {}

Expand Down Expand Up @@ -216,7 +222,7 @@ pub fn helper(_: usize) {}
pub fn slice(_: &[u8]) {}

// CHECK: @mutable_slice(
// CHECK-SAME: ptr noalias noundef nonnull %_1.0,
// CHECK-SAME: ptr noalias noundef nonnull writable %_1.0,
// CHECK-SAME: [[USIZE]] noundef range({{i32 0, -2147483648|i64 0, -9223372036854775808}}) %_1.1)
// FIXME #25759 This should also have `nocapture`
#[no_mangle]
Expand Down Expand Up @@ -271,7 +277,7 @@ pub fn trait_box_pin2(_: Box<dyn Drop + UnsafeUnpin>) {}

// Same for mutable references (with a non-zero minimal size so that we also see the
// `dereferenceable` disappear).
// CHECK: @trait_mutref(ptr noalias noundef align 4 dereferenceable(4){{( %_1.0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %_1.1)?}})
// CHECK: @trait_mutref(ptr noalias noundef writable align 4 dereferenceable(4){{( %_1.0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %_1.1)?}})
#[no_mangle]
pub fn trait_mutref(_: &mut (i32, dyn Drop + Unpin + UnsafeUnpin)) {}
// CHECK: @trait_mutref_pin1(ptr noundef nonnull align 4{{( %_1.0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %_1.1)?}})
Expand Down
11 changes: 11 additions & 0 deletions tests/codegen-llvm/no-writable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//! The tests here test that the `-Zno-writable` flag has the desired effect.
//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes -Zno-writable
#![crate_type = "lib"]

// CHECK: @mutable_borrow(ptr noalias noundef align 4 dereferenceable(4) %_1)
#[no_mangle]
pub fn mutable_borrow(_: &mut i32) {}

// CHECK: @option_borrow_mut(ptr noalias noundef align 4 dereferenceable_or_null(4) %_x)
#[no_mangle]
pub fn option_borrow_mut(_x: Option<&mut i32>) {}
Loading