Skip to content

Commit 3ebe60c

Browse files
committed
Auto merge of rust-lang#154659 - chenyukang:rollup-D1UvH9O, r=chenyukang
Rollup of 5 pull requests Successful merges: - rust-lang#152935 (c-variadic: error when we can't guarantee that the backend does the right thing) - rust-lang#153207 (std::net: clamp linger timeout value to prevent silent truncation.) - rust-lang#154592 (Fix `mismatched_lifetime_syntaxes` suggestions for hidden path lifetimes) - rust-lang#154643 (fix pin docs) - rust-lang#154648 (Clarify `ty::List`)
2 parents 12ab1cf + 18f8cd2 commit 3ebe60c

21 files changed

Lines changed: 520 additions & 60 deletions

File tree

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,7 +762,7 @@ impl<'a> AstValidator<'a> {
762762
match fn_ctxt {
763763
FnCtxt::Foreign => return,
764764
FnCtxt::Free | FnCtxt::Assoc(_) => {
765-
if !self.sess.target.arch.supports_c_variadic_definitions() {
765+
if !self.sess.target.supports_c_variadic_definitions() {
766766
self.dcx().emit_err(errors::CVariadicNotSupported {
767767
variadic_span: variadic_param.span,
768768
target: &*self.sess.target.llvm_target,

compiler/rustc_codegen_llvm/src/va_arg.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,9 +1186,10 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
11861186
// Clang uses the LLVM implementation for these architectures.
11871187
bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx))
11881188
}
1189-
Arch::Other(_) => {
1190-
// For custom targets, use the LLVM va_arg instruction as a fallback.
1191-
bx.va_arg(addr.immediate(), bx.cx.layout_of(target_ty).llvm_type(bx.cx))
1189+
Arch::Other(ref arch) => {
1190+
// Just to be safe we error out explicitly here, instead of crossing our fingers that
1191+
// the default LLVM implementation has the correct behavior for this target.
1192+
bug!("c-variadic functions are not currently implemented for custom target {arch}")
11921193
}
11931194
}
11941195
}

compiler/rustc_lint/src/lifetime_syntax.rs

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -387,26 +387,24 @@ fn emit_mismatch_diagnostic<'tcx>(
387387
build_mismatch_suggestion(info.lifetime.ident.as_str(), &suggest_change_to_explicit_bound)
388388
});
389389

390-
let is_bound_static = bound_lifetime.is_some_and(|info| info.lifetime.is_static());
391-
392-
tracing::debug!(?bound_lifetime, ?explicit_bound_suggestion, ?is_bound_static);
390+
tracing::debug!(?bound_lifetime, ?explicit_bound_suggestion);
393391

394392
let should_suggest_mixed =
395393
// Do we have a mixed case?
396394
(saw_a_reference && saw_a_path) &&
397395
// Is there anything to change?
398396
(!suggest_change_to_mixed_implicit.is_empty() ||
399397
!suggest_change_to_mixed_explicit_anonymous.is_empty()) &&
400-
// If we have `'static`, we don't want to remove it.
401-
!is_bound_static;
398+
// If we have a named lifetime, prefer consistent naming.
399+
bound_lifetime.is_none();
402400

403401
let mixed_suggestion = should_suggest_mixed.then(|| {
404402
let implicit_suggestions = make_implicit_suggestions(&suggest_change_to_mixed_implicit);
405403

406-
let explicit_anonymous_suggestions = suggest_change_to_mixed_explicit_anonymous
407-
.iter()
408-
.map(|info| info.suggestion("'_"))
409-
.collect();
404+
let explicit_anonymous_suggestions = build_mismatch_suggestions_for_lifetime(
405+
"'_",
406+
&suggest_change_to_mixed_explicit_anonymous,
407+
);
410408

411409
lints::MismatchedLifetimeSyntaxesSuggestion::Mixed {
412410
implicit_suggestions,
@@ -426,8 +424,8 @@ fn emit_mismatch_diagnostic<'tcx>(
426424
!suggest_change_to_implicit.is_empty() &&
427425
// We never want to hide the lifetime in a path (or similar).
428426
allow_suggesting_implicit &&
429-
// If we have `'static`, we don't want to remove it.
430-
!is_bound_static;
427+
// If we have a named lifetime, prefer consistent naming.
428+
bound_lifetime.is_none();
431429

432430
let implicit_suggestion = should_suggest_implicit.then(|| {
433431
let suggestions = make_implicit_suggestions(&suggest_change_to_implicit);
@@ -448,8 +446,10 @@ fn emit_mismatch_diagnostic<'tcx>(
448446
let should_suggest_explicit_anonymous =
449447
// Is there anything to change?
450448
!suggest_change_to_explicit_anonymous.is_empty() &&
451-
// If we have `'static`, we don't want to remove it.
452-
!is_bound_static;
449+
// If we already have a mixed suggestion, avoid overlapping alternatives.
450+
mixed_suggestion.is_none() &&
451+
// If we have a named lifetime, prefer consistent naming.
452+
bound_lifetime.is_none();
453453

454454
let explicit_anonymous_suggestion = should_suggest_explicit_anonymous
455455
.then(|| build_mismatch_suggestion("'_", &suggest_change_to_explicit_anonymous));
@@ -483,7 +483,7 @@ fn build_mismatch_suggestion(
483483
) -> lints::MismatchedLifetimeSyntaxesSuggestion {
484484
let lifetime_name = lifetime_name.to_owned();
485485

486-
let suggestions = infos.iter().map(|info| info.suggestion(&lifetime_name)).collect();
486+
let suggestions = build_mismatch_suggestions_for_lifetime(&lifetime_name, infos);
487487

488488
lints::MismatchedLifetimeSyntaxesSuggestion::Explicit {
489489
lifetime_name,
@@ -492,6 +492,57 @@ fn build_mismatch_suggestion(
492492
}
493493
}
494494

495+
fn build_mismatch_suggestions_for_lifetime(
496+
lifetime_name: &str,
497+
infos: &[&Info<'_>],
498+
) -> Vec<(Span, String)> {
499+
use hir::{AngleBrackets, LifetimeSource, LifetimeSyntax};
500+
501+
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
502+
enum PathSuggestionKind {
503+
Missing,
504+
Empty,
505+
Full,
506+
}
507+
508+
let mut suggestions = Vec::new();
509+
let mut path_counts: FxIndexMap<(hir::HirId, PathSuggestionKind), (Span, usize)> =
510+
FxIndexMap::default();
511+
512+
for info in infos {
513+
let lifetime = info.lifetime;
514+
if matches!(lifetime.syntax, LifetimeSyntax::Implicit) {
515+
if let LifetimeSource::Path { angle_brackets } = lifetime.source {
516+
let (span, kind) = match angle_brackets {
517+
AngleBrackets::Missing => {
518+
(lifetime.ident.span.shrink_to_hi(), PathSuggestionKind::Missing)
519+
}
520+
AngleBrackets::Empty => (lifetime.ident.span, PathSuggestionKind::Empty),
521+
AngleBrackets::Full => (lifetime.ident.span, PathSuggestionKind::Full),
522+
};
523+
let entry = path_counts.entry((info.ty.hir_id, kind)).or_insert((span, 0));
524+
entry.1 += 1;
525+
continue;
526+
}
527+
}
528+
suggestions.push(info.suggestion(lifetime_name));
529+
}
530+
531+
for ((_ty_hir_id, kind), (span, count)) in path_counts {
532+
let repeated = std::iter::repeat(lifetime_name).take(count).collect::<Vec<_>>().join(", ");
533+
534+
let suggestion = match kind {
535+
PathSuggestionKind::Missing => format!("<{repeated}>"),
536+
PathSuggestionKind::Empty => repeated,
537+
PathSuggestionKind::Full => format!("{repeated}, "),
538+
};
539+
540+
suggestions.push((span, suggestion));
541+
}
542+
543+
suggestions
544+
}
545+
495546
#[derive(Debug)]
496547
struct Info<'tcx> {
497548
lifetime: &'tcx hir::Lifetime,

compiler/rustc_lint/src/lints.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use std::num::NonZero;
44

5+
use rustc_data_structures::fx::FxIndexMap;
56
use rustc_errors::codes::*;
67
use rustc_errors::formatting::DiagMessageAddArg;
78
use rustc_errors::{
@@ -3231,8 +3232,23 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for MismatchedLifetimeSyntaxes
32313232
diag.span_label(s, msg!("the lifetime is named here"));
32323233
}
32333234

3235+
let mut hidden_output_counts: FxIndexMap<Span, usize> = FxIndexMap::default();
32343236
for s in self.outputs.hidden {
3235-
diag.span_label(s, msg!("the same lifetime is hidden here"));
3237+
*hidden_output_counts.entry(s).or_insert(0) += 1;
3238+
}
3239+
for (span, count) in hidden_output_counts {
3240+
let label = msg!(
3241+
"the same {$count ->
3242+
[one] lifetime
3243+
*[other] lifetimes
3244+
} {$count ->
3245+
[one] is
3246+
*[other] are
3247+
} hidden here"
3248+
)
3249+
.arg("count", count)
3250+
.format();
3251+
diag.span_label(span, label);
32363252
}
32373253
for s in self.outputs.elided {
32383254
diag.span_label(s, msg!("the same lifetime is elided here"));

compiler/rustc_middle/src/query/erase.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,6 @@ pub fn restore_val<T: Erasable>(erased_value: Erased<T>) -> T {
109109
unsafe { transmute_unchecked::<MaybeUninit<T::Storage>, T>(data) }
110110
}
111111

112-
// FIXME(#151565): Using `T: ?Sized` here should let us remove the separate
113-
// impls for fat reference types.
114112
impl<T> Erasable for &'_ T {
115113
type Storage = [u8; size_of::<&'_ ()>()];
116114
}
@@ -119,12 +117,14 @@ impl<T> Erasable for &'_ [T] {
119117
type Storage = [u8; size_of::<&'_ [()]>()];
120118
}
121119

122-
impl<T> Erasable for &'_ ty::List<T> {
123-
type Storage = [u8; size_of::<&'_ ty::List<()>>()];
124-
}
125-
126-
impl<T> Erasable for &'_ ty::ListWithCachedTypeInfo<T> {
127-
type Storage = [u8; size_of::<&'_ ty::ListWithCachedTypeInfo<()>>()];
120+
// Note: this impl does not overlap with the impl for `&'_ T` above because `RawList` is unsized
121+
// and does not satisfy the implicit `T: Sized` bound.
122+
//
123+
// Furthermore, even if that implicit bound was removed (by adding `T: ?Sized`) this impl still
124+
// wouldn't overlap because `?Sized` is equivalent to `MetaSized` and `RawList` does not satisfy
125+
// `MetaSized` because it contains an extern type.
126+
impl<H, T> Erasable for &'_ ty::RawList<H, T> {
127+
type Storage = [u8; size_of::<&'_ ty::RawList<(), ()>>()];
128128
}
129129

130130
impl<T> Erasable for Result<&'_ T, traits::query::NoSolution> {

compiler/rustc_middle/src/ty/list.rs

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,18 @@ pub type List<T> = RawList<(), T>;
3737
#[repr(C)]
3838
pub struct RawList<H, T> {
3939
skel: ListSkeleton<H, T>,
40-
opaque: OpaqueListContents,
40+
41+
// `List`/`RawList` is variable-sized. So we want it to be an unsized
42+
// type because calling `size_of::<List<Foo>>` would be dangerous.
43+
//
44+
// We also want `&List`/`&RawList` to be thin pointers.
45+
//
46+
// A field with an extern type is a hacky way to achieve this. (See
47+
// https://github.com/rust-lang/rust/pull/154399#issuecomment-4157036415
48+
// for some discussion.) This field is never directly manipulated because
49+
// `RawList` instances are created with manual memory layout in
50+
// `from_arena`.
51+
_extern_ty: ExternTy,
4152
}
4253

4354
/// A [`RawList`] without the unsized tail. This type is used for layout computation
@@ -47,7 +58,8 @@ struct ListSkeleton<H, T> {
4758
header: H,
4859
len: usize,
4960
/// Although this claims to be a zero-length array, in practice `len`
50-
/// elements are actually present.
61+
/// elements are actually present. This is achieved with manual memory
62+
/// layout in `from_arena`. See also the comment on `RawList::_extern_ty`.
5163
data: [T; 0],
5264
}
5365

@@ -58,9 +70,7 @@ impl<T> Default for &List<T> {
5870
}
5971

6072
unsafe extern "C" {
61-
/// A dummy type used to force `List` to be unsized while not requiring
62-
/// references to it be wide pointers.
63-
type OpaqueListContents;
73+
type ExternTy;
6474
}
6575

6676
impl<H, T> RawList<H, T> {
@@ -257,12 +267,13 @@ impl<'a, H, T: Copy> IntoIterator for &'a RawList<H, T> {
257267

258268
unsafe impl<H: Sync, T: Sync> Sync for RawList<H, T> {}
259269

260-
// We need this since `List` uses extern type `OpaqueListContents`.
270+
// We need this because `List` uses the extern type `ExternTy`.
261271
unsafe impl<H: DynSync, T: DynSync> DynSync for RawList<H, T> {}
262272

263273
// Safety:
264-
// Layouts of `ListSkeleton<H, T>` and `RawList<H, T>` are the same, modulo opaque tail,
265-
// thus aligns of `ListSkeleton<H, T>` and `RawList<H, T>` must be the same.
274+
// Layouts of `ListSkeleton<H, T>` and `RawList<H, T>` are the same, modulo the
275+
// `_extern_ty` field (which is never instantiated in practice). Therefore,
276+
// aligns of `ListSkeleton<H, T>` and `RawList<H, T>` must be the same.
266277
unsafe impl<H, T> Aligned for RawList<H, T> {
267278
#[cfg(bootstrap)]
268279
const ALIGN: ptr::Alignment = align_of::<ListSkeleton<H, T>>();
@@ -310,3 +321,14 @@ impl<'tcx> From<FlagComputation<TyCtxt<'tcx>>> for TypeInfo {
310321
}
311322
}
312323
}
324+
325+
#[cfg(target_pointer_width = "64")]
326+
mod size_asserts {
327+
use rustc_data_structures::static_assert_size;
328+
329+
use super::*;
330+
// tidy-alphabetical-start
331+
static_assert_size!(&List<u32>, 8); // thin pointer
332+
static_assert_size!(&RawList<u8, u32>, 8); // thin pointer
333+
// tidy-alphabetical-end
334+
}

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ pub use self::context::{
8585
};
8686
pub use self::fold::*;
8787
pub use self::instance::{Instance, InstanceKind, ReifyReason};
88+
pub(crate) use self::list::RawList;
8889
pub use self::list::{List, ListWithCachedTypeInfo};
8990
pub use self::opaque_types::OpaqueTypeKey;
9091
pub use self::pattern::{Pattern, PatternKind};

compiler/rustc_target/src/spec/mod.rs

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1952,24 +1952,6 @@ impl Arch {
19521952
}
19531953
}
19541954

1955-
pub fn supports_c_variadic_definitions(&self) -> bool {
1956-
use Arch::*;
1957-
1958-
match self {
1959-
// These targets just do not support c-variadic definitions.
1960-
Bpf | SpirV => false,
1961-
1962-
// We don't know if the target supports c-variadic definitions, but we don't want
1963-
// to needlessly restrict custom target.json configurations.
1964-
Other(_) => true,
1965-
1966-
AArch64 | AmdGpu | Arm | Arm64EC | Avr | CSky | Hexagon | LoongArch32 | LoongArch64
1967-
| M68k | Mips | Mips32r6 | Mips64 | Mips64r6 | Msp430 | Nvptx64 | PowerPC
1968-
| PowerPC64 | RiscV32 | RiscV64 | S390x | Sparc | Sparc64 | Wasm32 | Wasm64 | X86
1969-
| X86_64 | Xtensa => true,
1970-
}
1971-
}
1972-
19731955
/// Whether `#[rustc_scalable_vector]` is supported for a target architecture
19741956
pub fn supports_scalable_vectors(&self) -> bool {
19751957
use Arch::*;
@@ -2214,6 +2196,33 @@ impl Target {
22142196

22152197
Ok(dl)
22162198
}
2199+
2200+
pub fn supports_c_variadic_definitions(&self) -> bool {
2201+
use Arch::*;
2202+
2203+
match self.arch {
2204+
// The c-variadic ABI for this target may change in the future, per this comment in
2205+
// clang:
2206+
//
2207+
// > To be compatible with GCC's behaviors, we force arguments with
2208+
// > 2×XLEN-bit alignment and size at most 2×XLEN bits like `long long`,
2209+
// > `unsigned long long` and `double` to have 4-byte alignment. This
2210+
// > behavior may be changed when RV32E/ILP32E is ratified.
2211+
RiscV32 if self.llvm_abiname == LlvmAbi::Ilp32e => false,
2212+
2213+
// These targets just do not support c-variadic definitions.
2214+
Bpf | SpirV => false,
2215+
2216+
// We don't know how c-variadics work for this target. Using the default LLVM
2217+
// fallback implementation may work, but just to be safe we disallow this.
2218+
Other(_) => false,
2219+
2220+
AArch64 | AmdGpu | Arm | Arm64EC | Avr | CSky | Hexagon | LoongArch32 | LoongArch64
2221+
| M68k | Mips | Mips32r6 | Mips64 | Mips64r6 | Msp430 | Nvptx64 | PowerPC
2222+
| PowerPC64 | RiscV32 | RiscV64 | S390x | Sparc | Sparc64 | Wasm32 | Wasm64 | X86
2223+
| X86_64 | Xtensa => true,
2224+
}
2225+
}
22172226
}
22182227

22192228
pub trait HasTargetSpec {

library/core/src/pin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,7 @@
740740
//!
741741
//! While counter-intuitive, it's often the easier choice: if you do not expose a
742742
//! <code>[Pin]<[&mut] Field></code>, you do not need to be careful about other code
743-
//! moving out of that field, you just have to ensure is that you never create pinning
743+
//! moving out of that field, you just have to ensure that you never create a pinning
744744
//! reference to that field. This does of course also mean that if you decide a field does not
745745
//! have structural pinning, you must not write [`unsafe`] code that assumes (invalidly) that the
746746
//! field *is* structurally pinned!

library/std/src/sys/net/connection/socket/hermit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ impl Socket {
260260
pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
261261
let linger = netc::linger {
262262
l_onoff: linger.is_some() as i32,
263-
l_linger: linger.unwrap_or_default().as_secs() as libc::c_int,
263+
l_linger: cmp::min(linger.unwrap_or_default().as_secs(), c_int::MAX as u64) as c_int,
264264
};
265265

266266
unsafe { setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger) }

0 commit comments

Comments
 (0)