Skip to content

Commit 90c34fa

Browse files
committed
Auto merge of #102377 - matthiaskrgr:rollup-1zvj50t, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #101555 (Stabilize `#![feature(mixed_integer_ops)]`) - #102253 (rustdoc: use CSS containment to speed up render) - #102281 (make invalid_value lint a bit smarter around enums) - #102284 (Structured suggestion for missing `mut`/`const` in raw pointer) - #102330 (rustdoc: remove no-op CSS `.srclink { font-weight; font-size }`) - #102337 (Avoid LLVM-deprecated `Optional::hasValue`) - #102356 (session: remove now-unnecessary lint `#[allow]`s) - #102367 (rustdoc: remove redundant `#help-button` CSS) - #102369 (Fix search result colors) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents 470e518 + f28ac30 commit 90c34fa

25 files changed

+593
-295
lines changed

Diff for: compiler/rustc_lint/src/builtin.rs

+117-51
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ use rustc_middle::lint::in_external_macro;
4646
use rustc_middle::ty::layout::{LayoutError, LayoutOf};
4747
use rustc_middle::ty::print::with_no_trimmed_paths;
4848
use rustc_middle::ty::subst::GenericArgKind;
49-
use rustc_middle::ty::Instance;
50-
use rustc_middle::ty::{self, Ty, TyCtxt};
49+
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, VariantDef};
5150
use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
5251
use rustc_span::edition::Edition;
5352
use rustc_span::source_map::Spanned;
@@ -2425,12 +2424,63 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
24252424
None
24262425
}
24272426

2428-
/// Test if this enum has several actually "existing" variants.
2429-
/// Zero-sized uninhabited variants do not always have a tag assigned and thus do not "exist".
2430-
fn is_multi_variant<'tcx>(adt: ty::AdtDef<'tcx>) -> bool {
2431-
// As an approximation, we only count dataless variants. Those are definitely inhabited.
2432-
let existing_variants = adt.variants().iter().filter(|v| v.fields.is_empty()).count();
2433-
existing_variants > 1
2427+
/// Determines whether the given type is inhabited. `None` means that we don't know.
2428+
fn ty_inhabited<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<bool> {
2429+
use rustc_type_ir::sty::TyKind::*;
2430+
if !cx.tcx.type_uninhabited_from(cx.param_env.and(ty)).is_empty() {
2431+
// This is definitely uninhabited from some module.
2432+
return Some(false);
2433+
}
2434+
match ty.kind() {
2435+
Never => Some(false),
2436+
Int(_) | Uint(_) | Float(_) | Bool | Char | RawPtr(_) => Some(true),
2437+
// Fallback for more complicated types. (Note that `&!` might be considered
2438+
// uninhabited so references are "complicated", too.)
2439+
_ => None,
2440+
}
2441+
}
2442+
/// Determines whether a product type formed from a list of types is inhabited.
2443+
fn tys_inhabited<'tcx>(
2444+
cx: &LateContext<'tcx>,
2445+
tys: impl Iterator<Item = Ty<'tcx>>,
2446+
) -> Option<bool> {
2447+
let mut definitely_inhabited = true; // with no fields, we are definitely inhabited.
2448+
for ty in tys {
2449+
match ty_inhabited(cx, ty) {
2450+
// If any type is uninhabited, the product is uninhabited.
2451+
Some(false) => return Some(false),
2452+
// Otherwise go searching for a `None`.
2453+
None => {
2454+
// We don't know.
2455+
definitely_inhabited = false;
2456+
}
2457+
Some(true) => {}
2458+
}
2459+
}
2460+
if definitely_inhabited { Some(true) } else { None }
2461+
}
2462+
2463+
fn variant_find_init_error<'tcx>(
2464+
cx: &LateContext<'tcx>,
2465+
variant: &VariantDef,
2466+
substs: ty::SubstsRef<'tcx>,
2467+
descr: &str,
2468+
init: InitKind,
2469+
) -> Option<InitError> {
2470+
variant.fields.iter().find_map(|field| {
2471+
ty_find_init_error(cx, field.ty(cx.tcx, substs), init).map(|(mut msg, span)| {
2472+
if span.is_none() {
2473+
// Point to this field, should be helpful for figuring
2474+
// out where the source of the error is.
2475+
let span = cx.tcx.def_span(field.did);
2476+
write!(&mut msg, " (in this {descr})").unwrap();
2477+
(msg, Some(span))
2478+
} else {
2479+
// Just forward.
2480+
(msg, span)
2481+
}
2482+
})
2483+
})
24342484
}
24352485

24362486
/// Return `Some` only if we are sure this type does *not*
@@ -2468,14 +2518,15 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
24682518
RawPtr(_) if init == InitKind::Uninit => {
24692519
Some(("raw pointers must not be uninitialized".to_string(), None))
24702520
}
2471-
// Recurse and checks for some compound types.
2521+
// Recurse and checks for some compound types. (but not unions)
24722522
Adt(adt_def, substs) if !adt_def.is_union() => {
24732523
// First check if this ADT has a layout attribute (like `NonNull` and friends).
24742524
use std::ops::Bound;
24752525
match cx.tcx.layout_scalar_valid_range(adt_def.did()) {
24762526
// We exploit here that `layout_scalar_valid_range` will never
24772527
// return `Bound::Excluded`. (And we have tests checking that we
24782528
// handle the attribute correctly.)
2529+
// We don't add a span since users cannot declare such types anyway.
24792530
(Bound::Included(lo), _) if lo > 0 => {
24802531
return Some((format!("`{}` must be non-null", ty), None));
24812532
}
@@ -2492,50 +2543,65 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
24922543
}
24932544
_ => {}
24942545
}
2495-
// Now, recurse.
2496-
match adt_def.variants().len() {
2497-
0 => Some(("enums with no variants have no valid value".to_string(), None)),
2498-
1 => {
2499-
// Struct, or enum with exactly one variant.
2500-
// Proceed recursively, check all fields.
2501-
let variant = &adt_def.variant(VariantIdx::from_u32(0));
2502-
variant.fields.iter().find_map(|field| {
2503-
ty_find_init_error(cx, field.ty(cx.tcx, substs), init).map(
2504-
|(mut msg, span)| {
2505-
if span.is_none() {
2506-
// Point to this field, should be helpful for figuring
2507-
// out where the source of the error is.
2508-
let span = cx.tcx.def_span(field.did);
2509-
write!(
2510-
&mut msg,
2511-
" (in this {} field)",
2512-
adt_def.descr()
2513-
)
2514-
.unwrap();
2515-
(msg, Some(span))
2516-
} else {
2517-
// Just forward.
2518-
(msg, span)
2519-
}
2520-
},
2521-
)
2522-
})
2523-
}
2524-
// Multi-variant enum.
2525-
_ => {
2526-
if init == InitKind::Uninit && is_multi_variant(*adt_def) {
2527-
let span = cx.tcx.def_span(adt_def.did());
2528-
Some((
2529-
"enums have to be initialized to a variant".to_string(),
2530-
Some(span),
2531-
))
2532-
} else {
2533-
// In principle, for zero-initialization we could figure out which variant corresponds
2534-
// to tag 0, and check that... but for now we just accept all zero-initializations.
2535-
None
2536-
}
2546+
// Handle structs.
2547+
if adt_def.is_struct() {
2548+
return variant_find_init_error(
2549+
cx,
2550+
adt_def.non_enum_variant(),
2551+
substs,
2552+
"struct field",
2553+
init,
2554+
);
2555+
}
2556+
// And now, enums.
2557+
let span = cx.tcx.def_span(adt_def.did());
2558+
let mut potential_variants = adt_def.variants().iter().filter_map(|variant| {
2559+
let inhabited = tys_inhabited(
2560+
cx,
2561+
variant.fields.iter().map(|field| field.ty(cx.tcx, substs)),
2562+
);
2563+
let definitely_inhabited = match inhabited {
2564+
// Entirely skip uninhbaited variants.
2565+
Some(false) => return None,
2566+
// Forward the others, but remember which ones are definitely inhabited.
2567+
Some(true) => true,
2568+
None => false,
2569+
};
2570+
Some((variant, definitely_inhabited))
2571+
});
2572+
let Some(first_variant) = potential_variants.next() else {
2573+
return Some(("enums with no inhabited variants have no valid value".to_string(), Some(span)));
2574+
};
2575+
// So we have at least one potentially inhabited variant. Might we have two?
2576+
let Some(second_variant) = potential_variants.next() else {
2577+
// There is only one potentially inhabited variant. So we can recursively check that variant!
2578+
return variant_find_init_error(
2579+
cx,
2580+
&first_variant.0,
2581+
substs,
2582+
"field of the only potentially inhabited enum variant",
2583+
init,
2584+
);
2585+
};
2586+
// So we have at least two potentially inhabited variants.
2587+
// If we can prove that we have at least two *definitely* inhabited variants,
2588+
// then we have a tag and hence leaving this uninit is definitely disallowed.
2589+
// (Leaving it zeroed could be okay, depending on which variant is encoded as zero tag.)
2590+
if init == InitKind::Uninit {
2591+
let definitely_inhabited = (first_variant.1 as usize)
2592+
+ (second_variant.1 as usize)
2593+
+ potential_variants
2594+
.filter(|(_variant, definitely_inhabited)| *definitely_inhabited)
2595+
.count();
2596+
if definitely_inhabited > 1 {
2597+
return Some((
2598+
"enums with multiple inhabited variants have to be initialized to a variant".to_string(),
2599+
Some(span),
2600+
));
25372601
}
25382602
}
2603+
// We couldn't find anything wrong here.
2604+
None
25392605
}
25402606
Tuple(..) => {
25412607
// Proceed recursively, check all fields.

Diff for: compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1044,7 +1044,7 @@ extern "C" void LLVMRustSetModulePIELevel(LLVMModuleRef M) {
10441044
extern "C" void LLVMRustSetModuleCodeModel(LLVMModuleRef M,
10451045
LLVMRustCodeModel Model) {
10461046
auto CM = fromRust(Model);
1047-
if (!CM.hasValue())
1047+
if (!CM)
10481048
return;
10491049
unwrap(M)->setCodeModel(*CM);
10501050
}

Diff for: compiler/rustc_parse/src/parser/ty.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -397,10 +397,13 @@ impl<'a> Parser<'a> {
397397
fn parse_ty_ptr(&mut self) -> PResult<'a, TyKind> {
398398
let mutbl = self.parse_const_or_mut().unwrap_or_else(|| {
399399
let span = self.prev_token.span;
400-
let msg = "expected mut or const in raw pointer type";
401-
self.struct_span_err(span, msg)
402-
.span_label(span, msg)
403-
.help("use `*mut T` or `*const T` as appropriate")
400+
self.struct_span_err(span, "expected `mut` or `const` keyword in raw pointer type")
401+
.span_suggestions(
402+
span.shrink_to_hi(),
403+
"add `mut` or `const` here",
404+
["mut ".to_string(), "const ".to_string()].into_iter(),
405+
Applicability::HasPlaceholders,
406+
)
404407
.emit();
405408
Mutability::Not
406409
});

Diff for: compiler/rustc_session/src/parse.rs

-8
Original file line numberDiff line numberDiff line change
@@ -376,8 +376,6 @@ impl ParseSess {
376376
}
377377

378378
#[rustc_lint_diagnostics]
379-
#[allow(rustc::diagnostic_outside_of_impl)]
380-
#[allow(rustc::untranslatable_diagnostic)]
381379
pub fn struct_err(
382380
&self,
383381
msg: impl Into<DiagnosticMessage>,
@@ -386,22 +384,16 @@ impl ParseSess {
386384
}
387385

388386
#[rustc_lint_diagnostics]
389-
#[allow(rustc::diagnostic_outside_of_impl)]
390-
#[allow(rustc::untranslatable_diagnostic)]
391387
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
392388
self.span_diagnostic.struct_warn(msg)
393389
}
394390

395391
#[rustc_lint_diagnostics]
396-
#[allow(rustc::diagnostic_outside_of_impl)]
397-
#[allow(rustc::untranslatable_diagnostic)]
398392
pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
399393
self.span_diagnostic.struct_fatal(msg)
400394
}
401395

402396
#[rustc_lint_diagnostics]
403-
#[allow(rustc::diagnostic_outside_of_impl)]
404-
#[allow(rustc::untranslatable_diagnostic)]
405397
pub fn struct_diagnostic<G: EmissionGuarantee>(
406398
&self,
407399
msg: impl Into<DiagnosticMessage>,

0 commit comments

Comments
 (0)