Skip to content

Commit f021d99

Browse files
committed
lint: revamp ImproperCTypes diagnostic architecture for nested notes and help messages
1 parent c94848c commit f021d99

File tree

2 files changed

+146
-45
lines changed

2 files changed

+146
-45
lines changed

compiler/rustc_lint/src/lints.rs

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1851,13 +1851,44 @@ pub(crate) struct UnpredictableFunctionPointerComparisonsSuggestion<'a> {
18511851
pub right: Span,
18521852
}
18531853

1854+
pub(crate) struct ImproperCTypesLayer<'a> {
1855+
pub ty: Ty<'a>,
1856+
pub inner_ty: Option<Ty<'a>>,
1857+
pub note: DiagMessage,
1858+
pub span_note: Option<Span>,
1859+
pub help: Option<DiagMessage>,
1860+
}
1861+
1862+
impl<'a> Subdiagnostic for ImproperCTypesLayer<'a> {
1863+
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
1864+
self,
1865+
diag: &mut Diag<'_, G>,
1866+
f: &F,
1867+
) {
1868+
diag.arg("ty", self.ty);
1869+
if let Some(ty) = self.inner_ty {
1870+
diag.arg("inner_ty", ty);
1871+
}
1872+
1873+
if let Some(help) = self.help {
1874+
let msg = f(diag, help.into());
1875+
diag.help(msg);
1876+
}
1877+
1878+
let msg = f(diag, self.note.into());
1879+
diag.note(msg);
1880+
if let Some(note) = self.span_note {
1881+
let msg = f(diag, fluent::lint_note.into());
1882+
diag.span_note(note, msg);
1883+
};
1884+
}
1885+
}
1886+
18541887
pub(crate) struct ImproperCTypes<'a> {
18551888
pub ty: Ty<'a>,
18561889
pub desc: &'a str,
18571890
pub label: Span,
1858-
pub help: Option<DiagMessage>,
1859-
pub note: DiagMessage,
1860-
pub span_note: Option<Span>,
1891+
pub reasons: Vec<ImproperCTypesLayer<'a>>,
18611892
}
18621893

18631894
// Used because of the complexity of Option<DiagMessage>, DiagMessage, and Option<Span>
@@ -1867,12 +1898,8 @@ impl<'a> LintDiagnostic<'a, ()> for ImproperCTypes<'_> {
18671898
diag.arg("ty", self.ty);
18681899
diag.arg("desc", self.desc);
18691900
diag.span_label(self.label, fluent::lint_label);
1870-
if let Some(help) = self.help {
1871-
diag.help(help);
1872-
}
1873-
diag.note(self.note);
1874-
if let Some(note) = self.span_note {
1875-
diag.span_note(note, fluent::lint_note);
1901+
for reason in self.reasons.into_iter() {
1902+
diag.subdiagnostic(reason);
18761903
}
18771904
}
18781905
}

compiler/rustc_lint/src/types.rs

Lines changed: 110 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ mod improper_ctypes;
2222
use crate::lints::{
2323
AmbiguousWidePointerComparisons, AmbiguousWidePointerComparisonsAddrMetadataSuggestion,
2424
AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad,
25-
AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons,
26-
InvalidNanComparisonsSuggestion, UnpredictableFunctionPointerComparisons,
27-
UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons,
28-
VariantSizeDifferencesDiag,
25+
AtomicOrderingStore, ImproperCTypes, ImproperCTypesLayer, InvalidAtomicOrderingDiag,
26+
InvalidNanComparisons, InvalidNanComparisonsSuggestion,
27+
UnpredictableFunctionPointerComparisons, UnpredictableFunctionPointerComparisonsSuggestion,
28+
UnusedComparisons, VariantSizeDifferencesDiag,
2929
};
3030
use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
3131

@@ -727,7 +727,19 @@ struct CTypesVisitorState<'tcx> {
727727
enum FfiResult<'tcx> {
728728
FfiSafe,
729729
FfiPhantom(Ty<'tcx>),
730-
FfiUnsafe { ty: Ty<'tcx>, reason: DiagMessage, help: Option<DiagMessage> },
730+
FfiUnsafe {
731+
ty: Ty<'tcx>,
732+
reason: DiagMessage,
733+
help: Option<DiagMessage>,
734+
},
735+
// NOTE: this `allow` is only here for one retroactively-added commit
736+
#[allow(dead_code)]
737+
FfiUnsafeWrapper {
738+
ty: Ty<'tcx>,
739+
reason: DiagMessage,
740+
help: Option<DiagMessage>,
741+
wrapped: Box<FfiResult<'tcx>>,
742+
},
731743
}
732744

733745
pub(crate) fn nonnull_optimization_guaranteed<'tcx>(
@@ -933,12 +945,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
933945
/// Check if the type is array and emit an unsafe type lint.
934946
fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
935947
if let ty::Array(..) = ty.kind() {
936-
self.emit_ffi_unsafe_type_lint(
948+
self.emit_ffi_unsafe_type_lint(ty.clone(), sp, vec![ImproperCTypesLayer {
937949
ty,
938-
sp,
939-
fluent::lint_improper_ctypes_array_reason,
940-
Some(fluent::lint_improper_ctypes_array_help),
941-
);
950+
note: fluent::lint_improper_ctypes_array_reason,
951+
help: Some(fluent::lint_improper_ctypes_array_help),
952+
inner_ty: None,
953+
span_note: None,
954+
}]);
942955
true
943956
} else {
944957
false
@@ -995,9 +1008,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
9951008
all_phantom &= match self.check_field_type_for_ffi(acc, field, args) {
9961009
FfiSafe => false,
9971010
// `()` fields are FFI-safe!
998-
FfiUnsafe { ty, .. } if ty.is_unit() => false,
1011+
FfiUnsafe { ty, .. } | FfiUnsafeWrapper { ty, .. } if ty.is_unit() => false,
9991012
FfiPhantom(..) => true,
1000-
r @ FfiUnsafe { .. } => return r,
1013+
r @ (FfiUnsafe { .. } | FfiUnsafeWrapper { .. }) => return r,
10011014
}
10021015
}
10031016

@@ -1278,8 +1291,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12781291
&mut self,
12791292
ty: Ty<'tcx>,
12801293
sp: Span,
1281-
note: DiagMessage,
1282-
help: Option<DiagMessage>,
1294+
mut reasons: Vec<ImproperCTypesLayer<'tcx>>,
12831295
) {
12841296
let lint = match self.mode {
12851297
CItemKind::Declaration => IMPROPER_CTYPES,
@@ -1289,21 +1301,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
12891301
CItemKind::Declaration => "block",
12901302
CItemKind::Definition => "fn",
12911303
};
1292-
let span_note = if let ty::Adt(def, _) = ty.kind()
1293-
&& let Some(sp) = self.cx.tcx.hir().span_if_local(def.did())
1294-
{
1295-
Some(sp)
1296-
} else {
1297-
None
1298-
};
1299-
self.cx.emit_span_lint(lint, sp, ImproperCTypes {
1300-
ty,
1301-
desc,
1302-
label: sp,
1303-
help,
1304-
note,
1305-
span_note,
1306-
});
1304+
for reason in reasons.iter_mut() {
1305+
reason.span_note = if let ty::Adt(def, _) = reason.ty.kind()
1306+
&& let Some(sp) = self.cx.tcx.hir().span_if_local(def.did())
1307+
{
1308+
Some(sp)
1309+
} else {
1310+
None
1311+
};
1312+
}
1313+
1314+
self.cx.emit_span_lint(lint, sp, ImproperCTypes { ty, desc, label: sp, reasons });
13071315
}
13081316

13091317
fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
@@ -1332,7 +1340,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13321340
.visit_with(&mut ProhibitOpaqueTypes)
13331341
.break_value()
13341342
{
1335-
self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint_improper_ctypes_opaque, None);
1343+
self.emit_ffi_unsafe_type_lint(ty.clone(), sp, vec![ImproperCTypesLayer {
1344+
ty,
1345+
note: fluent::lint_improper_ctypes_opaque,
1346+
span_note: Some(sp),
1347+
help: None,
1348+
inner_ty: None,
1349+
}]);
13361350
true
13371351
} else {
13381352
false
@@ -1371,15 +1385,75 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
13711385
match self.check_type_for_ffi(&mut acc, ty) {
13721386
FfiResult::FfiSafe => {}
13731387
FfiResult::FfiPhantom(ty) => {
1374-
self.emit_ffi_unsafe_type_lint(
1388+
self.emit_ffi_unsafe_type_lint(ty.clone(), sp, vec![ImproperCTypesLayer {
13751389
ty,
1376-
sp,
1377-
fluent::lint_improper_ctypes_only_phantomdata,
1378-
None,
1379-
);
1390+
note: fluent::lint_improper_ctypes_only_phantomdata,
1391+
span_note: None, // filled later
1392+
help: None,
1393+
inner_ty: None,
1394+
}]);
13801395
}
13811396
FfiResult::FfiUnsafe { ty, reason, help } => {
1382-
self.emit_ffi_unsafe_type_lint(ty, sp, reason, help);
1397+
self.emit_ffi_unsafe_type_lint(ty.clone(), sp, vec![ImproperCTypesLayer {
1398+
ty,
1399+
help,
1400+
note: reason,
1401+
span_note: None, // filled later
1402+
inner_ty: None,
1403+
}]);
1404+
}
1405+
ffir @ FfiResult::FfiUnsafeWrapper { .. } => {
1406+
let mut last_ty = None;
1407+
let mut ffiresult_recursor = Some(&ffir);
1408+
let mut cimproper_layers: Vec<ImproperCTypesLayer<'tcx>> = vec![];
1409+
1410+
// this whole while block converts the arbitrarily-deep
1411+
// FfiResult stack to a ImproperCTypesLayer Vec
1412+
while let Some(ref ffir_rec) = ffiresult_recursor {
1413+
match ffir_rec {
1414+
FfiResult::FfiPhantom(ty) => {
1415+
last_ty = Some(ty.clone());
1416+
let len = cimproper_layers.len();
1417+
if len > 0 {
1418+
cimproper_layers[len - 1].inner_ty = last_ty.clone();
1419+
}
1420+
cimproper_layers.push(ImproperCTypesLayer {
1421+
ty: ty.clone(),
1422+
inner_ty: None,
1423+
help: None,
1424+
note: fluent::lint_improper_ctypes_only_phantomdata,
1425+
span_note: None, // filled later
1426+
});
1427+
ffiresult_recursor = None;
1428+
}
1429+
FfiResult::FfiUnsafe { ty, reason, help }
1430+
| FfiResult::FfiUnsafeWrapper { ty, reason, help, .. } => {
1431+
last_ty = Some(ty.clone());
1432+
let len = cimproper_layers.len();
1433+
if len > 0 {
1434+
cimproper_layers[len - 1].inner_ty = last_ty.clone();
1435+
}
1436+
cimproper_layers.push(ImproperCTypesLayer {
1437+
ty: ty.clone(),
1438+
inner_ty: None,
1439+
help: help.clone(),
1440+
note: reason.clone(),
1441+
span_note: None, // filled later
1442+
});
1443+
1444+
if let FfiResult::FfiUnsafeWrapper { wrapped, .. } = ffir_rec {
1445+
ffiresult_recursor = Some(wrapped.as_ref());
1446+
} else {
1447+
ffiresult_recursor = None;
1448+
}
1449+
}
1450+
FfiResult::FfiSafe => {
1451+
bug!("malformed FfiResult stack: it should be unsafe all the way down")
1452+
}
1453+
};
1454+
}
1455+
let last_ty = last_ty.unwrap(); // populated by any run of the `while` block
1456+
self.emit_ffi_unsafe_type_lint(last_ty, sp, cimproper_layers);
13831457
}
13841458
}
13851459
}

0 commit comments

Comments
 (0)