Skip to content

Commit 7ac5e96

Browse files
author
Robin Kruppe
committed
[improper_ctypes] Use a 'help:' line for possible fixes
1 parent 1f0e1a0 commit 7ac5e96

File tree

2 files changed

+156
-80
lines changed

2 files changed

+156
-80
lines changed

src/librustc_lint/types.rs

Lines changed: 112 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -353,13 +353,18 @@ struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
353353
cx: &'a LateContext<'a, 'tcx>,
354354
}
355355

356+
struct FfiError {
357+
message: &'static str,
358+
help: Option<&'static str>,
359+
}
360+
356361
enum FfiResult {
357362
FfiSafe,
358363
FfiPhantom,
359-
FfiUnsafe(&'static str),
360-
FfiBadStruct(DefId, &'static str),
361-
FfiBadUnion(DefId, &'static str),
362-
FfiBadEnum(DefId, &'static str),
364+
FfiUnsafe(FfiError),
365+
FfiBadStruct(DefId, FfiError),
366+
FfiBadUnion(DefId, FfiError),
367+
FfiBadEnum(DefId, FfiError),
363368
}
364369

365370
/// Check if this enum can be safely exported based on the
@@ -434,14 +439,18 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
434439
match def.adt_kind() {
435440
AdtKind::Struct => {
436441
if !def.repr.c() && !def.repr.transparent() {
437-
return FfiUnsafe("found struct without foreign-function-safe \
438-
representation annotation in foreign module, \
439-
consider adding a #[repr(C)] attribute to the type");
442+
return FfiUnsafe(FfiError {
443+
message: "found struct without foreign-function-safe \
444+
representation annotation in foreign module",
445+
help: Some("consider adding a #[repr(C)] attribute to the type"),
446+
});
440447
}
441448

442449
if def.non_enum_variant().fields.is_empty() {
443-
return FfiUnsafe("found zero-size struct in foreign module, consider \
444-
adding a member to this struct");
450+
return FfiUnsafe(FfiError {
451+
message: "found zero-size struct in foreign module",
452+
help: Some("consider adding a member to this struct"),
453+
});
445454
}
446455

447456
// We can't completely trust repr(C) and repr(transparent) markings;
@@ -471,8 +480,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
471480
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
472481
return r;
473482
}
474-
FfiUnsafe(s) => {
475-
return FfiBadStruct(def.did, s);
483+
FfiUnsafe(err) => {
484+
return FfiBadStruct(def.did, err);
476485
}
477486
}
478487
}
@@ -481,14 +490,18 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
481490
}
482491
AdtKind::Union => {
483492
if !def.repr.c() {
484-
return FfiUnsafe("found union without foreign-function-safe \
485-
representation annotation in foreign module, \
486-
consider adding a #[repr(C)] attribute to the type");
493+
return FfiUnsafe(FfiError {
494+
message: "found union without foreign-function-safe \
495+
representation annotation in foreign module",
496+
help: Some("consider adding a #[repr(C)] attribute to the type"),
497+
});
487498
}
488499

489500
if def.non_enum_variant().fields.is_empty() {
490-
return FfiUnsafe("found zero-size union in foreign module, consider \
491-
adding a member to this union");
501+
return FfiUnsafe(FfiError {
502+
message: "found zero-size union in foreign module",
503+
help: Some("consider adding a member to this union"),
504+
});
492505
}
493506

494507
let mut all_phantom = true;
@@ -505,8 +518,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
505518
FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
506519
return r;
507520
}
508-
FfiUnsafe(s) => {
509-
return FfiBadUnion(def.did, s);
521+
FfiUnsafe(err) => {
522+
return FfiBadUnion(def.did, err);
510523
}
511524
}
512525
}
@@ -524,18 +537,23 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
524537
if !def.repr.c() && def.repr.int.is_none() {
525538
// Special-case types like `Option<extern fn()>`.
526539
if !is_repr_nullable_ptr(cx, def, substs) {
527-
return FfiUnsafe("found enum without foreign-function-safe \
528-
representation annotation in foreign \
529-
module, consider adding a #[repr(...)] \
530-
attribute to the type");
540+
return FfiUnsafe(FfiError {
541+
message: "found enum without foreign-function-safe \
542+
representation annotation in foreign module",
543+
help: Some("consider adding a #[repr(...)] attribute \
544+
to the type"),
545+
});
531546
}
532547
}
533548

534549
if let Some(int_ty) = def.repr.int {
535550
if !is_ffi_safe(int_ty) {
536551
// FIXME: This shouldn't be reachable: we should check
537552
// this earlier.
538-
return FfiUnsafe("enum has unexpected #[repr(...)] attribute");
553+
return FfiUnsafe(FfiError {
554+
message: "enum has unexpected #[repr(...)] attribute",
555+
help: None,
556+
});
539557
}
540558

541559
// Enum with an explicitly sized discriminant; either
@@ -558,11 +576,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
558576
return r;
559577
}
560578
FfiPhantom => {
561-
return FfiBadEnum(def.did,
562-
"Found phantom data in enum variant");
579+
return FfiBadEnum(def.did, FfiError {
580+
message: "Found phantom data in enum variant",
581+
help: None,
582+
});
563583
}
564-
FfiUnsafe(s) => {
565-
return FfiBadEnum(def.did, s);
584+
FfiUnsafe(err) => {
585+
return FfiBadEnum(def.did, err);
566586
}
567587
}
568588
}
@@ -573,43 +593,57 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
573593
}
574594

575595
ty::TyChar => {
576-
FfiUnsafe("found Rust type `char` in foreign module, while \
577-
`u32` or `libc::wchar_t` should be used")
596+
FfiUnsafe(FfiError {
597+
message: "found Rust type `char` in foreign module",
598+
help: Some("consider using `u32` or `libc::wchar_t`"),
599+
})
578600
}
579601

580602
ty::TyInt(ast::IntTy::I128) => {
581-
FfiUnsafe("found Rust type `i128` in foreign module, but \
582-
128-bit integers don't currently have a known \
583-
stable ABI")
603+
FfiUnsafe(FfiError {
604+
message: "found Rust type `i128` in foreign module, but 128-bit \
605+
integers don't currently have a known stable ABI",
606+
help: None,
607+
})
584608
}
585609

586610
ty::TyUint(ast::UintTy::U128) => {
587-
FfiUnsafe("found Rust type `u128` in foreign module, but \
588-
128-bit integers don't currently have a known \
589-
stable ABI")
611+
FfiUnsafe(FfiError {
612+
message: "found Rust type `u128` in foreign module, but 128-bit \
613+
integers don't currently have a known stable ABI",
614+
help: None,
615+
})
590616
}
591617

592618
// Primitive types with a stable representation.
593619
ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | ty::TyNever => FfiSafe,
594620

595621
ty::TySlice(_) => {
596-
FfiUnsafe("found Rust slice type in foreign module, \
597-
consider using a raw pointer instead")
622+
FfiUnsafe(FfiError {
623+
message: "found Rust slice type in foreign module",
624+
help: Some("consider using a raw pointer instead"),
625+
})
598626
}
599627

600628
ty::TyDynamic(..) => {
601-
FfiUnsafe("found Rust trait type in foreign module, \
602-
consider using a raw pointer instead")
629+
FfiUnsafe(FfiError {
630+
message: "found Rust trait type in foreign module",
631+
help: Some("consider using a raw pointer instead"),
632+
})
603633
}
604634

605635
ty::TyStr => {
606-
FfiUnsafe("found Rust type `str` in foreign module; \
607-
consider using a `*const libc::c_char`")
636+
FfiUnsafe(FfiError {
637+
message: "found Rust type `str` in foreign module",
638+
help: Some("consider using a `*const libc::c_char`"),
639+
})
608640
}
609641

610642
ty::TyTuple(..) => {
611-
FfiUnsafe("found Rust tuple type in foreign module; \
612-
consider using a struct instead")
643+
FfiUnsafe(FfiError {
644+
message: "found Rust tuple type in foreign module",
645+
help: Some("consider using a struct instead"),
646+
})
613647
}
614648

615649
ty::TyRawPtr(ref m) |
@@ -620,9 +654,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
620654
ty::TyFnPtr(sig) => {
621655
match sig.abi() {
622656
Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
623-
return FfiUnsafe("found function pointer with Rust calling convention in \
624-
foreign module; consider using an `extern` function \
625-
pointer")
657+
return FfiUnsafe(FfiError {
658+
message: "found function pointer with Rust calling convention in \
659+
foreign module",
660+
help: Some("consider using an `extern` function pointer"),
661+
})
626662
}
627663
_ => {}
628664
}
@@ -676,34 +712,45 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
676712
&format!("found zero-sized type composed only \
677713
of phantom-data in a foreign-function."));
678714
}
679-
FfiResult::FfiUnsafe(s) => {
680-
self.cx.span_lint(IMPROPER_CTYPES, sp, s);
715+
FfiResult::FfiUnsafe(err) => {
716+
let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, err.message);
717+
if let Some(s) = err.help {
718+
diag.help(s);
719+
}
720+
diag.emit();
681721
}
682-
FfiResult::FfiBadStruct(_, s) => {
722+
FfiResult::FfiBadStruct(_, err) => {
683723
// FIXME: This diagnostic is difficult to read, and doesn't
684724
// point at the relevant field.
685-
self.cx.span_lint(IMPROPER_CTYPES,
686-
sp,
687-
&format!("found non-foreign-function-safe member in struct \
688-
marked #[repr(C)]: {}",
689-
s));
725+
let msg = format!("found non-foreign-function-safe member in struct \
726+
marked #[repr(C)]: {}", err.message);
727+
let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, &msg);
728+
if let Some(s) = err.help {
729+
diag.help(s);
730+
}
731+
diag.emit();
690732
}
691-
FfiResult::FfiBadUnion(_, s) => {
733+
FfiResult::FfiBadUnion(_, err) => {
692734
// FIXME: This diagnostic is difficult to read, and doesn't
693735
// point at the relevant field.
694-
self.cx.span_lint(IMPROPER_CTYPES,
695-
sp,
696-
&format!("found non-foreign-function-safe member in union \
697-
marked #[repr(C)]: {}",
698-
s));
736+
let msg = format!("found non-foreign-function-safe member in union \
737+
marked #[repr(C)]: {}", err.message);
738+
let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, &msg);
739+
if let Some(s) = err.help {
740+
diag.help(s);
741+
}
742+
diag.emit();
699743
}
700-
FfiResult::FfiBadEnum(_, s) => {
744+
FfiResult::FfiBadEnum(_, err) => {
701745
// FIXME: This diagnostic is difficult to read, and doesn't
702746
// point at the relevant variant.
703-
self.cx.span_lint(IMPROPER_CTYPES,
704-
sp,
705-
&format!("found non-foreign-function-safe member in enum: {}",
706-
s));
747+
let msg = format!("found non-foreign-function-safe member in enum: {}",
748+
err.message);
749+
let mut diag = self.cx.struct_span_lint(IMPROPER_CTYPES, sp, &msg);
750+
if let Some(s) = err.help {
751+
diag.help(s);
752+
}
753+
diag.emit();
707754
}
708755
}
709756
}

0 commit comments

Comments
 (0)