use crate::hir::def_id::DefId;
use rustc::hir::lowering::is_range_literal;
use rustc::ty::subst::SubstsRef;
-use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
use rustc::ty::layout::{self, IntegerExt, LayoutOf, VariantIdx, SizeSkeleton};
use rustc::{lint, util};
use rustc_index::vec::Idx;
max: u128,
expr: &'tcx hir::Expr,
parent_expr: &'tcx hir::Expr,
- ty: impl std::fmt::Debug,
+ ty: &str,
) -> bool {
// We only want to handle exclusive (`..`) ranges,
// which are represented as `ExprKind::Struct`.
let mut err = cx.struct_span_lint(
OVERFLOWING_LITERALS,
parent_expr.span,
- &format!("range endpoint is out of range for `{:?}`", ty),
+ &format!("range endpoint is out of range for `{}`", ty),
);
if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) {
use ast::{LitKind, LitIntType};
// We need to preserve the literal's suffix,
// as it may determine typing information.
let suffix = match lit.node {
- LitKind::Int(_, LitIntType::Signed(s)) => format!("{}", s),
- LitKind::Int(_, LitIntType::Unsigned(s)) => format!("{}", s),
+ LitKind::Int(_, LitIntType::Signed(s)) => format!("{}", s.name_str()),
+ LitKind::Int(_, LitIntType::Unsigned(s)) => format!("{}", s.name_str()),
LitKind::Int(_, LitIntType::Unsuffixed) => "".to_owned(),
_ => bug!(),
};
let (t, actually) = match ty {
attr::IntType::SignedInt(t) => {
let actually = sign_extend(val, size) as i128;
- (format!("{:?}", t), actually.to_string())
+ (t.name_str(), actually.to_string())
}
attr::IntType::UnsignedInt(t) => {
let actually = truncate(val, size);
- (format!("{:?}", t), actually.to_string())
+ (t.name_str(), actually.to_string())
}
};
let mut err = cx.struct_span_lint(
// - `uX` => `uY`
//
// No suggestion for: `isize`, `usize`.
-fn get_type_suggestion(t: Ty<'_>, val: u128, negative: bool) -> Option<String> {
+fn get_type_suggestion(t: Ty<'_>, val: u128, negative: bool) -> Option<&'static str> {
use syntax::ast::IntTy::*;
use syntax::ast::UintTy::*;
macro_rules! find_fit {
match $ty {
$($type => {
$(if !negative && val <= uint_ty_range($utypes).1 {
- return Some(format!("{:?}", $utypes))
+ return Some($utypes.name_str())
})*
$(if val <= int_ty_range($itypes).1 as u128 + _neg {
- return Some(format!("{:?}", $itypes))
+ return Some($itypes.name_str())
})*
None
},)+
if let Node::Expr(par_e) = cx.tcx.hir().get(par_id) {
if let hir::ExprKind::Struct(..) = par_e.kind {
if is_range_literal(cx.sess(), par_e)
- && lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t)
+ && lint_overflowing_range_endpoint(cx, lit, v, max, e, par_e, t.name_str())
{
// The overflowing literal lint was overridden.
return;
cx.span_lint(
OVERFLOWING_LITERALS,
e.span,
- &format!("literal out of range for `{:?}`", t),
+ &format!("literal out of range for `{}`", t.name_str()),
);
}
}
}
hir::ExprKind::Struct(..)
if is_range_literal(cx.sess(), par_e) => {
+ let t = t.name_str();
if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, par_e, t) {
// The overflowing literal lint was overridden.
return;
cx.span_lint(
OVERFLOWING_LITERALS,
e.span,
- &format!("literal out of range for `{:?}`", t),
+ &format!("literal out of range for `{}`", t.name_str()),
);
}
}
}
ty::Float(t) => {
let is_infinite = match lit.node {
- ast::LitKind::Float(v, _) |
- ast::LitKind::FloatUnsuffixed(v) => {
+ ast::LitKind::Float(v, _) => {
match t {
ast::FloatTy::F32 => v.as_str().parse().map(f32::is_infinite),
ast::FloatTy::F64 => v.as_str().parse().map(f64::is_infinite),
_ => bug!(),
};
if is_infinite == Ok(true) {
- cx.span_lint(OVERFLOWING_LITERALS,
- e.span,
- &format!("literal out of range for `{:?}`", t));
+ cx.span_lint(
+ OVERFLOWING_LITERALS,
+ e.span,
+ &format!("literal out of range for `{}`", t.name_str()),
+ );
}
}
_ => {}
ty::Array(ty, _) => self.check_type_for_ffi(cache, ty),
ty::FnPtr(sig) => {
- if self.is_internal_abi(sig.abi()) {
- return FfiUnsafe {
- ty,
- reason: "this function pointer has Rust-specific calling convention",
- help: Some("consider using an `extern fn(...) -> ...` \
- function pointer instead"),
- };
+ match sig.abi() {
+ Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
+ return FfiUnsafe {
+ ty,
+ reason: "this function pointer has Rust-specific calling convention",
+ help: Some("consider using an `extern fn(...) -> ...` \
+ function pointer instead"),
+ }
+ }
+ _ => {}
}
let sig = cx.erase_late_bound_regions(&sig);
ty::Foreign(..) => FfiSafe,
- // `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
- // so they are currently ignored for the purposes of this lint, see #65134.
- ty::Param(..) | ty::Projection(..) => FfiSafe,
-
+ ty::Param(..) |
ty::Infer(..) |
ty::Bound(..) |
ty::Error |
ty::GeneratorWitness(..) |
ty::Placeholder(..) |
ty::UnnormalizedProjection(..) |
+ ty::Projection(..) |
ty::Opaque(..) |
ty::FnDef(..) => bug!("unexpected type in foreign function: {:?}", ty),
}
sp: Span,
note: &str,
help: Option<&str>,
- is_foreign_item: bool,
) {
let mut diag = self.cx.struct_span_lint(
IMPROPER_CTYPES,
sp,
- &format!(
- "`extern` {} uses type `{}`, which is not FFI-safe",
- if is_foreign_item { "block" } else { "fn" },
- ty,
- ),
+ &format!("`extern` block uses type `{}`, which is not FFI-safe", ty),
);
diag.span_label(sp, "not FFI-safe");
if let Some(help) = help {
diag.emit();
}
- fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>, is_foreign_item: bool) -> bool {
+ fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
+ use crate::rustc::ty::TypeFoldable;
+
struct ProhibitOpaqueTypes<'tcx> {
ty: Option<Ty<'tcx>>,
};
sp,
"opaque types have no C equivalent",
None,
- is_foreign_item,
);
true
} else {
}
}
- fn check_type_for_ffi_and_report_errors(
- &mut self,
- sp: Span,
- ty: Ty<'tcx>,
- is_foreign_item: bool,
- ) {
+ fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>) {
// We have to check for opaque types before `normalize_erasing_regions`,
// which will replace opaque types with their underlying concrete type.
- if self.check_for_opaque_ty(sp, ty, is_foreign_item) {
+ if self.check_for_opaque_ty(sp, ty) {
// We've already emitted an error due to an opaque type.
return;
}
- let ty = self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty);
+ // it is only OK to use this function because extern fns cannot have
+ // any generic types right now:
+ let ty = self.cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
+
match self.check_type_for_ffi(&mut FxHashSet::default(), ty) {
FfiResult::FfiSafe => {}
FfiResult::FfiPhantom(ty) => {
- self.emit_ffi_unsafe_type_lint(
- ty, sp, "composed only of `PhantomData`", None, is_foreign_item);
+ self.emit_ffi_unsafe_type_lint(ty, sp, "composed only of `PhantomData`", None);
}
FfiResult::FfiUnsafe { ty, reason, help } => {
- self.emit_ffi_unsafe_type_lint(
- ty, sp, reason, help, is_foreign_item);
+ self.emit_ffi_unsafe_type_lint(ty, sp, reason, help);
}
}
}
- fn check_foreign_fn(&mut self, id: hir::HirId, decl: &hir::FnDecl, is_foreign_item: bool) {
+ fn check_foreign_fn(&mut self, id: hir::HirId, decl: &hir::FnDecl) {
let def_id = self.cx.tcx.hir().local_def_id(id);
let sig = self.cx.tcx.fn_sig(def_id);
let sig = self.cx.tcx.erase_late_bound_regions(&sig);
for (input_ty, input_hir) in sig.inputs().iter().zip(&decl.inputs) {
- self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty, is_foreign_item);
+ self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty);
}
if let hir::Return(ref ret_hir) = decl.output {
let ret_ty = sig.output();
if !ret_ty.is_unit() {
- self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty, is_foreign_item);
+ self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty);
}
}
}
fn check_foreign_static(&mut self, id: hir::HirId, span: Span) {
let def_id = self.cx.tcx.hir().local_def_id(id);
let ty = self.cx.tcx.type_of(def_id);
- self.check_type_for_ffi_and_report_errors(span, ty, true);
- }
-
- fn is_internal_abi(&self, abi: Abi) -> bool {
- if let Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
- true
- } else {
- false
- }
+ self.check_type_for_ffi_and_report_errors(span, ty);
}
}
fn check_foreign_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::ForeignItem) {
let mut vis = ImproperCTypesVisitor { cx };
let abi = cx.tcx.hir().get_foreign_abi(it.hir_id);
- if !vis.is_internal_abi(abi) {
+ if let Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
+ // Don't worry about types in internal ABIs.
+ } else {
match it.kind {
hir::ForeignItemKind::Fn(ref decl, _, _) => {
- vis.check_foreign_fn(it.hir_id, decl, true);
+ vis.check_foreign_fn(it.hir_id, decl);
}
hir::ForeignItemKind::Static(ref ty, _) => {
vis.check_foreign_static(it.hir_id, ty.span);
}
}
}
-
- fn check_fn(
- &mut self,
- cx: &LateContext<'a, 'tcx>,
- kind: hir::intravisit::FnKind<'tcx>,
- decl: &'tcx hir::FnDecl,
- _: &'tcx hir::Body,
- _: Span,
- hir_id: hir::HirId,
- ) {
- use hir::intravisit::FnKind;
-
- let abi = match kind {
- FnKind::ItemFn(_, _, header, ..) => (header.abi),
- FnKind::Method(_, sig, ..) => (sig.header.abi),
- _ => return,
- };
-
- let mut vis = ImproperCTypesVisitor { cx };
- if !vis.is_internal_abi(abi) {
- vis.check_foreign_fn(hir_id, decl, false);
- }
- }
}
declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]);