Skip to content

Commit 2958d89

Browse files
committed
Auto merge of #140646 - tgross35:rollup-z3hjbm6, r=tgross35
Rollup of 6 pull requests Successful merges: - #137280 (stabilize ptr::swap_nonoverlapping in const) - #140457 (Use target-cpu=z13 on s390x codegen const vector test) - #140619 (Small adjustments to `check_attribute_safety` to make the logic more obvious) - #140625 (Suggest `retain_mut` over `retain` as `Vec::extract_if` alternative) - #140627 (Allow linking rustc and rustdoc against the same single tracing crate) - #140630 (Async drop source info fix for proxy-drop-coroutine) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 13e8790 + 0b8789c commit 2958d89

File tree

16 files changed

+181
-37
lines changed

16 files changed

+181
-37
lines changed

compiler/rustc_expand/src/config.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ impl<'a> StripUnconfigured<'a> {
276276
pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec<Attribute> {
277277
validate_attr::check_attribute_safety(
278278
&self.sess.psess,
279-
AttributeSafety::Normal,
279+
Some(AttributeSafety::Normal),
280280
&cfg_attr,
281281
ast::CRATE_NODE_ID,
282282
);

compiler/rustc_log/src/lib.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use std::env::{self, VarError};
3737
use std::fmt::{self, Display};
3838
use std::io::{self, IsTerminal};
3939

40+
use tracing::dispatcher::SetGlobalDefaultError;
4041
use tracing_core::{Event, Subscriber};
4142
use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
4243
use tracing_subscriber::fmt::FmtContext;
@@ -131,10 +132,10 @@ pub fn init_logger(cfg: LoggerConfig) -> Result<(), Error> {
131132
.without_time()
132133
.event_format(BacktraceFormatter { backtrace_target });
133134
let subscriber = subscriber.with(fmt_layer);
134-
tracing::subscriber::set_global_default(subscriber).unwrap();
135+
tracing::subscriber::set_global_default(subscriber)?;
135136
}
136137
Err(_) => {
137-
tracing::subscriber::set_global_default(subscriber).unwrap();
138+
tracing::subscriber::set_global_default(subscriber)?;
138139
}
139140
};
140141

@@ -180,6 +181,7 @@ pub enum Error {
180181
InvalidColorValue(String),
181182
NonUnicodeColorValue,
182183
InvalidWraptree(String),
184+
AlreadyInit(SetGlobalDefaultError),
183185
}
184186

185187
impl std::error::Error for Error {}
@@ -199,6 +201,13 @@ impl Display for Error {
199201
formatter,
200202
"invalid log WRAPTREE value '{value}': expected a non-negative integer",
201203
),
204+
Error::AlreadyInit(tracing_error) => Display::fmt(tracing_error, formatter),
202205
}
203206
}
204207
}
208+
209+
impl From<SetGlobalDefaultError> for Error {
210+
fn from(tracing_error: SetGlobalDefaultError) -> Self {
211+
Error::AlreadyInit(tracing_error)
212+
}
213+
}

compiler/rustc_middle/src/ty/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1929,13 +1929,17 @@ impl<'tcx> TyCtxt<'tcx> {
19291929
if arg_cor_ty.is_coroutine() {
19301930
let span = self.def_span(def_id);
19311931
let source_info = SourceInfo::outermost(span);
1932+
// Even minimal, empty coroutine has 3 states (RESERVED_VARIANTS),
1933+
// so variant_fields and variant_source_info should have 3 elements.
19321934
let variant_fields: IndexVec<VariantIdx, IndexVec<FieldIdx, CoroutineSavedLocal>> =
19331935
iter::repeat(IndexVec::new()).take(CoroutineArgs::RESERVED_VARIANTS).collect();
1936+
let variant_source_info: IndexVec<VariantIdx, SourceInfo> =
1937+
iter::repeat(source_info).take(CoroutineArgs::RESERVED_VARIANTS).collect();
19341938
let proxy_layout = CoroutineLayout {
19351939
field_tys: [].into(),
19361940
field_names: [].into(),
19371941
variant_fields,
1938-
variant_source_info: [source_info].into(),
1942+
variant_source_info,
19391943
storage_conflicts: BitMatrix::new(0, 0),
19401944
};
19411945
return Some(self.arena.alloc(proxy_layout));

compiler/rustc_parse/src/validate_attr.rs

+47-14
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,13 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) {
2222
return;
2323
}
2424

25-
let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
26-
let attr_item = attr.get_normal_item();
25+
let builtin_attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
2726

28-
// All non-builtin attributes are considered safe
29-
let safety = attr_info.map(|x| x.safety).unwrap_or(AttributeSafety::Normal);
30-
check_attribute_safety(psess, safety, attr, id);
27+
let builtin_attr_safety = builtin_attr_info.map(|x| x.safety);
28+
check_attribute_safety(psess, builtin_attr_safety, attr, id);
3129

3230
// Check input tokens for built-in and key-value attributes.
33-
match attr_info {
31+
match builtin_attr_info {
3432
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
3533
Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => {
3634
match parse_meta(psess, attr) {
@@ -44,6 +42,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) {
4442
}
4543
}
4644
_ => {
45+
let attr_item = attr.get_normal_item();
4746
if let AttrArgs::Eq { .. } = attr_item.args {
4847
// All key-value attributes are restricted to meta-item syntax.
4948
match parse_meta(psess, attr) {
@@ -157,14 +156,21 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte
157156

158157
pub fn check_attribute_safety(
159158
psess: &ParseSess,
160-
safety: AttributeSafety,
159+
builtin_attr_safety: Option<AttributeSafety>,
161160
attr: &Attribute,
162161
id: NodeId,
163162
) {
164163
let attr_item = attr.get_normal_item();
164+
match (builtin_attr_safety, attr_item.unsafety) {
165+
// - Unsafe builtin attribute
166+
// - User wrote `#[unsafe(..)]`, which is permitted on any edition
167+
(Some(AttributeSafety::Unsafe { .. }), Safety::Unsafe(..)) => {
168+
// OK
169+
}
165170

166-
if let AttributeSafety::Unsafe { unsafe_since } = safety {
167-
if let ast::Safety::Default = attr_item.unsafety {
171+
// - Unsafe builtin attribute
172+
// - User did not write `#[unsafe(..)]`
173+
(Some(AttributeSafety::Unsafe { unsafe_since }), Safety::Default) => {
168174
let path_span = attr_item.path.span;
169175

170176
// If the `attr_item`'s span is not from a macro, then just suggest
@@ -199,11 +205,38 @@ pub fn check_attribute_safety(
199205
);
200206
}
201207
}
202-
} else if let Safety::Unsafe(unsafe_span) = attr_item.unsafety {
203-
psess.dcx().emit_err(errors::InvalidAttrUnsafe {
204-
span: unsafe_span,
205-
name: attr_item.path.clone(),
206-
});
208+
209+
// - Normal builtin attribute, or any non-builtin attribute
210+
// - All non-builtin attributes are currently considered safe; writing `#[unsafe(..)]` is
211+
// not permitted on non-builtin attributes or normal builtin attributes
212+
(Some(AttributeSafety::Normal) | None, Safety::Unsafe(unsafe_span)) => {
213+
psess.dcx().emit_err(errors::InvalidAttrUnsafe {
214+
span: unsafe_span,
215+
name: attr_item.path.clone(),
216+
});
217+
}
218+
219+
// - Normal builtin attribute
220+
// - No explicit `#[unsafe(..)]` written.
221+
(Some(AttributeSafety::Normal), Safety::Default) => {
222+
// OK
223+
}
224+
225+
// - Non-builtin attribute
226+
// - No explicit `#[unsafe(..)]` written.
227+
(None, Safety::Default) => {
228+
// OK
229+
}
230+
231+
(
232+
Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None,
233+
Safety::Safe(..),
234+
) => {
235+
psess.dcx().span_delayed_bug(
236+
attr_item.span(),
237+
"`check_attribute_safety` does not expect `Safety::Safe` on attributes",
238+
);
239+
}
207240
}
208241
}
209242

library/alloc/src/vec/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -3659,9 +3659,9 @@ impl<T, A: Allocator> Vec<T, A> {
36593659
///
36603660
/// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
36613661
/// or the iteration short-circuits, then the remaining elements will be retained.
3662-
/// Use [`retain`] with a negated predicate if you do not need the returned iterator.
3662+
/// Use [`retain_mut`] with a negated predicate if you do not need the returned iterator.
36633663
///
3664-
/// [`retain`]: Vec::retain
3664+
/// [`retain_mut`]: Vec::retain_mut
36653665
///
36663666
/// Using this method is equivalent to the following code:
36673667
///

library/core/src/intrinsics/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -3320,7 +3320,6 @@ pub const fn is_val_statically_known<T: Copy>(_arg: T) -> bool {
33203320
#[inline]
33213321
#[rustc_intrinsic]
33223322
#[rustc_intrinsic_const_stable_indirect]
3323-
#[rustc_allow_const_fn_unstable(const_swap_nonoverlapping)] // this is anyway not called since CTFE implements the intrinsic
33243323
pub const unsafe fn typed_swap_nonoverlapping<T>(x: *mut T, y: *mut T) {
33253324
// SAFETY: The caller provided single non-overlapping items behind
33263325
// pointers, so swapping them with `count: 1` is fine.

library/core/src/ptr/mod.rs

+36-1
Original file line numberDiff line numberDiff line change
@@ -1065,10 +1065,45 @@ pub const unsafe fn swap<T>(x: *mut T, y: *mut T) {
10651065
/// assert_eq!(x, [7, 8, 3, 4]);
10661066
/// assert_eq!(y, [1, 2, 9]);
10671067
/// ```
1068+
///
1069+
/// # Const evaluation limitations
1070+
///
1071+
/// If this function is invoked during const-evaluation, the current implementation has a small (and
1072+
/// rarely relevant) limitation: if `count` is at least 2 and the data pointed to by `x` or `y`
1073+
/// contains a pointer that crosses the boundary of two `T`-sized chunks of memory, the function may
1074+
/// fail to evaluate (similar to a panic during const-evaluation). This behavior may change in the
1075+
/// future.
1076+
///
1077+
/// The limitation is illustrated by the following example:
1078+
///
1079+
/// ```
1080+
/// use std::mem::size_of;
1081+
/// use std::ptr;
1082+
///
1083+
/// const { unsafe {
1084+
/// const PTR_SIZE: usize = size_of::<*const i32>();
1085+
/// let mut data1 = [0u8; PTR_SIZE];
1086+
/// let mut data2 = [0u8; PTR_SIZE];
1087+
/// // Store a pointer in `data1`.
1088+
/// data1.as_mut_ptr().cast::<*const i32>().write_unaligned(&42);
1089+
/// // Swap the contents of `data1` and `data2` by swapping `PTR_SIZE` many `u8`-sized chunks.
1090+
/// // This call will fail, because the pointer in `data1` crosses the boundary
1091+
/// // between several of the 1-byte chunks that are being swapped here.
1092+
/// //ptr::swap_nonoverlapping(data1.as_mut_ptr(), data2.as_mut_ptr(), PTR_SIZE);
1093+
/// // Swap the contents of `data1` and `data2` by swapping a single chunk of size
1094+
/// // `[u8; PTR_SIZE]`. That works, as there is no pointer crossing the boundary between
1095+
/// // two chunks.
1096+
/// ptr::swap_nonoverlapping(&mut data1, &mut data2, 1);
1097+
/// // Read the pointer from `data2` and dereference it.
1098+
/// let ptr = data2.as_ptr().cast::<*const i32>().read_unaligned();
1099+
/// assert!(*ptr == 42);
1100+
/// } }
1101+
/// ```
10681102
#[inline]
10691103
#[stable(feature = "swap_nonoverlapping", since = "1.27.0")]
1070-
#[rustc_const_unstable(feature = "const_swap_nonoverlapping", issue = "133668")]
1104+
#[rustc_const_stable(feature = "const_swap_nonoverlapping", since = "CURRENT_RUSTC_VERSION")]
10711105
#[rustc_diagnostic_item = "ptr_swap_nonoverlapping"]
1106+
#[rustc_allow_const_fn_unstable(const_eval_select)] // both implementations behave the same
10721107
pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
10731108
ub_checks::assert_unsafe_precondition!(
10741109
check_library_ub,

library/coretests/tests/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
#![feature(char_max_len)]
1616
#![feature(clone_to_uninit)]
1717
#![feature(const_eval_select)]
18-
#![feature(const_swap_nonoverlapping)]
1918
#![feature(const_trait_impl)]
2019
#![feature(core_intrinsics)]
2120
#![feature(core_intrinsics_fallbacks)]

library/coretests/tests/ptr.rs

+4
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,10 @@ fn test_const_swap_ptr() {
949949
// Make sure they still work.
950950
assert!(*s1.0.ptr == 1);
951951
assert!(*s2.0.ptr == 666);
952+
953+
// This is where we'd swap again using a `u8` type and a `count` of `size_of::<T>()` if it
954+
// were not for the limitation of `swap_nonoverlapping` around pointers crossing multiple
955+
// elements.
952956
};
953957
}
954958

src/librustdoc/lib.rs

+21-5
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,28 @@ pub fn main() {
170170
// NOTE: this compiles both versions of tracing unconditionally, because
171171
// - The compile time hit is not that bad, especially compared to rustdoc's incremental times, and
172172
// - Otherwise, there's no warning that logging is being ignored when `download-rustc` is enabled
173-
// NOTE: The reason this doesn't show double logging when `download-rustc = false` and
174-
// `debug_logging = true` is because all rustc logging goes to its version of tracing (the one
175-
// in the sysroot), and all of rustdoc's logging goes to its version (the one in Cargo.toml).
176173

177-
init_logging(&early_dcx);
178-
rustc_driver::init_logger(&early_dcx, rustc_log::LoggerConfig::from_env("RUSTDOC_LOG"));
174+
crate::init_logging(&early_dcx);
175+
match rustc_log::init_logger(rustc_log::LoggerConfig::from_env("RUSTDOC_LOG")) {
176+
Ok(()) => {}
177+
// With `download-rustc = true` there are definitely 2 distinct tracing crates in the
178+
// dependency graph: one in the downloaded sysroot and one built just now as a dependency of
179+
// rustdoc. So the sysroot's tracing is definitely not yet initialized here.
180+
//
181+
// But otherwise, depending on link style, there may or may not be 2 tracing crates in play.
182+
// The one we just initialized in `crate::init_logging` above is rustdoc's direct dependency
183+
// on tracing. When rustdoc is built by x.py using Cargo, rustc_driver's and rustc_log's
184+
// tracing dependency is distinct from this one and also needs to be initialized (using the
185+
// same RUSTDOC_LOG environment variable for both). Other build systems may use just a
186+
// single tracing crate throughout the rustc and rustdoc build.
187+
//
188+
// The reason initializing 2 tracings does not show double logging when `download-rustc =
189+
// false` and `debug_logging = true` is because all rustc logging goes only to its version
190+
// of tracing (the one in the sysroot) and all of rustdoc's logging only goes to its version
191+
// (the one in Cargo.toml).
192+
Err(rustc_log::Error::AlreadyInit(_)) => {}
193+
Err(error) => early_dcx.early_fatal(error.to_string()),
194+
}
179195

180196
let exit_code = rustc_driver::catch_with_exit_code(|| {
181197
let at_args = rustc_driver::args::raw_args(&early_dcx);

tests/codegen/const-vector.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
1+
//@ revisions: OPT0 OPT0_S390X
2+
//@ [OPT0] ignore-s390x
3+
//@ [OPT0_S390X] only-s390x
4+
//@ [OPT0] compile-flags: -C no-prepopulate-passes -Copt-level=0
5+
//@ [OPT0_S390X] compile-flags: -C no-prepopulate-passes -Copt-level=0 -C target-cpu=z13
26

37
// This test checks that constants of SIMD type are passed as immediate vectors.
48
// We ensure that both vector representations (struct with fields and struct wrapping array) work.

tests/ui/consts/missing_span_in_backtrace.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
//@ compile-flags: -Z ui-testing=no
22

3-
4-
#![feature(const_swap_nonoverlapping)]
53
use std::{
64
mem::{self, MaybeUninit},
75
ptr,

tests/ui/consts/missing_span_in_backtrace.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error[E0080]: evaluation of constant value failed
2-
--> $DIR/missing_span_in_backtrace.rs:16:9
2+
--> $DIR/missing_span_in_backtrace.rs:14:9
33
|
4-
16 | / ptr::swap_nonoverlapping(
5-
17 | | &mut ptr1 as *mut _ as *mut MaybeUninit<u8>,
6-
18 | | &mut ptr2 as *mut _ as *mut MaybeUninit<u8>,
7-
19 | | mem::size_of::<&i32>(),
8-
20 | | );
4+
14 | / ptr::swap_nonoverlapping(
5+
15 | | &mut ptr1 as *mut _ as *mut MaybeUninit<u8>,
6+
16 | | &mut ptr2 as *mut _ as *mut MaybeUninit<u8>,
7+
17 | | mem::size_of::<&i32>(),
8+
18 | | );
99
| |_________^ unable to copy parts of a pointer from memory at ALLOC0
1010
|
1111
note: inside `swap_nonoverlapping::<MaybeUninit<u8>>`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
extern crate proc_macro;
2+
use proc_macro::TokenStream;
3+
4+
#[proc_macro_attribute]
5+
pub fn safe(_attr: TokenStream, item: TokenStream) -> TokenStream {
6+
item
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//! Anti-regression test for `#[safe]` proc-macro attribute.
2+
3+
//@ revisions: unknown_attr proc_macro_attr
4+
//@[proc_macro_attr] proc-macro: safe_attr.rs
5+
//@[proc_macro_attr] check-pass
6+
7+
#![warn(unsafe_attr_outside_unsafe)]
8+
9+
#[cfg(proc_macro_attr)]
10+
extern crate safe_attr;
11+
#[cfg(proc_macro_attr)]
12+
use safe_attr::safe;
13+
14+
#[safe]
15+
//[unknown_attr]~^ ERROR cannot find attribute `safe` in this scope
16+
fn foo() {}
17+
18+
#[safe(no_mangle)]
19+
//[unknown_attr]~^ ERROR cannot find attribute `safe` in this scope
20+
fn bar() {}
21+
22+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: cannot find attribute `safe` in this scope
2+
--> $DIR/safe-proc-macro-attribute.rs:18:3
3+
|
4+
LL | #[safe(no_mangle)]
5+
| ^^^^
6+
7+
error: cannot find attribute `safe` in this scope
8+
--> $DIR/safe-proc-macro-attribute.rs:14:3
9+
|
10+
LL | #[safe]
11+
| ^^^^
12+
13+
error: aborting due to 2 previous errors
14+

0 commit comments

Comments
 (0)