Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 5 pull requests #110940

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions compiler/rustc_arena/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl<T> ArenaChunk<T> {
#[inline]
unsafe fn new(capacity: usize) -> ArenaChunk<T> {
ArenaChunk {
storage: NonNull::new(Box::into_raw(Box::new_uninit_slice(capacity))).unwrap(),
storage: NonNull::new_unchecked(Box::into_raw(Box::new_uninit_slice(capacity))),
entries: 0,
}
}
Expand All @@ -85,7 +85,7 @@ impl<T> ArenaChunk<T> {
// The branch on needs_drop() is an -O1 performance optimization.
// Without the branch, dropping TypedArena<u8> takes linear time.
if mem::needs_drop::<T>() {
let slice = &mut *(self.storage.as_mut());
let slice = self.storage.as_mut();
ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut slice[..len]));
}
}
Expand All @@ -104,7 +104,7 @@ impl<T> ArenaChunk<T> {
// A pointer as large as possible for zero-sized elements.
ptr::invalid_mut(!0)
} else {
self.start().add((*self.storage.as_ptr()).len())
self.start().add(self.storage.len())
}
}
}
Expand Down Expand Up @@ -288,7 +288,7 @@ impl<T> TypedArena<T> {
// If the previous chunk's len is less than HUGE_PAGE
// bytes, then this chunk will be least double the previous
// chunk's size.
new_cap = (*last_chunk.storage.as_ptr()).len().min(HUGE_PAGE / elem_size / 2);
new_cap = last_chunk.storage.len().min(HUGE_PAGE / elem_size / 2);
new_cap *= 2;
} else {
new_cap = PAGE / elem_size;
Expand Down Expand Up @@ -396,7 +396,7 @@ impl DroplessArena {
// If the previous chunk's len is less than HUGE_PAGE
// bytes, then this chunk will be least double the previous
// chunk's size.
new_cap = (*last_chunk.storage.as_ptr()).len().min(HUGE_PAGE / 2);
new_cap = last_chunk.storage.len().min(HUGE_PAGE / 2);
new_cap *= 2;
} else {
new_cap = PAGE;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
ungated!(link_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
ungated!(no_link, Normal, template!(Word), WarnFollowing),
ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, @only_local: true),
ungated!(repr, Normal, template!(List: "C"), DuplicatesOk),
ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
ungated!(no_mangle, Normal, template!(Word), WarnFollowing, @only_local: true),
Expand Down
166 changes: 149 additions & 17 deletions compiler/rustc_lint/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1250,17 +1250,45 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
}
}

fn check_foreign_fn(&mut self, def_id: LocalDefId, decl: &hir::FnDecl<'_>) {
/// Check if a function's argument types and result type are "ffi-safe".
///
/// Argument types and the result type are checked for functions with external ABIs.
/// For functions with internal ABIs, argument types and the result type are walked to find
/// fn-ptr types that have external ABIs, as these still need checked.
fn check_maybe_foreign_fn(
&mut self,
abi: SpecAbi,
def_id: LocalDefId,
decl: &'tcx hir::FnDecl<'_>,
) {
let sig = self.cx.tcx.fn_sig(def_id).subst_identity();
let sig = self.cx.tcx.erase_late_bound_regions(sig);

let is_internal_abi = self.is_internal_abi(abi);
let check_ty = |this: &mut ImproperCTypesVisitor<'a, 'tcx>,
hir_ty: &'tcx hir::Ty<'_>,
ty: Ty<'tcx>,
is_return_type: bool| {
// If this function has an external ABI, then its arguments and return type should be
// checked..
if !is_internal_abi {
this.check_type_for_ffi_and_report_errors(hir_ty.span, ty, false, is_return_type);
return;
}

// ..but if this function has an internal ABI, then search the argument or return type
// for any fn-ptr types with external ABI, which should be checked..
for (fn_ptr_ty, span) in this.find_fn_ptr_ty_with_external_abi(hir_ty, ty) {
this.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, false, is_return_type);
}
};

for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
self.check_type_for_ffi_and_report_errors(input_hir.span, *input_ty, false, false);
check_ty(self, input_hir, *input_ty, false);
}

if let hir::FnRetTy::Return(ref ret_hir) = decl.output {
let ret_ty = sig.output();
self.check_type_for_ffi_and_report_errors(ret_hir.span, ret_ty, false, true);
check_ty(self, ret_hir, sig.output(), true);
}
}

Expand All @@ -1275,28 +1303,134 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
SpecAbi::Rust | SpecAbi::RustCall | SpecAbi::RustIntrinsic | SpecAbi::PlatformIntrinsic
)
}

/// Find any fn-ptr types with external ABIs in `ty`.
///
/// For example, `Option<extern "C" fn()>` returns `extern "C" fn()`
fn find_fn_ptr_ty_with_external_abi(
&self,
hir_ty: &hir::Ty<'tcx>,
ty: Ty<'tcx>,
) -> Vec<(Ty<'tcx>, Span)> {
struct FnPtrFinder<'parent, 'a, 'tcx> {
visitor: &'parent ImproperCTypesVisitor<'a, 'tcx>,
spans: Vec<Span>,
tys: Vec<Ty<'tcx>>,
}

impl<'parent, 'a, 'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'parent, 'a, 'tcx> {
fn visit_ty(&mut self, ty: &'_ hir::Ty<'_>) {
debug!(?ty);
if let hir::TyKind::BareFn(hir::BareFnTy { abi, .. }) = ty.kind
&& !self.visitor.is_internal_abi(*abi)
{
self.spans.push(ty.span);
}

hir::intravisit::walk_ty(self, ty)
}
}

impl<'vis, 'a, 'tcx> ty::visit::TypeVisitor<TyCtxt<'tcx>> for FnPtrFinder<'vis, 'a, 'tcx> {
type BreakTy = Ty<'tcx>;

fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::FnPtr(sig) = ty.kind() && !self.visitor.is_internal_abi(sig.abi()) {
self.tys.push(ty);
}

ty.super_visit_with(self)
}
}

let mut visitor = FnPtrFinder { visitor: &*self, spans: Vec::new(), tys: Vec::new() };
self.cx
.tcx
.try_normalize_erasing_regions(self.cx.param_env, ty)
.unwrap_or(ty)
.visit_with(&mut visitor);
hir::intravisit::Visitor::visit_ty(&mut visitor, hir_ty);

iter::zip(visitor.tys.drain(..), visitor.spans.drain(..)).collect()
}
}

impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations {
fn check_foreign_item(&mut self, cx: &LateContext<'_>, it: &hir::ForeignItem<'_>) {
fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, it: &hir::ForeignItem<'tcx>) {
let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Declaration };
let abi = cx.tcx.hir().get_foreign_abi(it.hir_id());

if !vis.is_internal_abi(abi) {
match it.kind {
hir::ForeignItemKind::Fn(ref decl, _, _) => {
vis.check_foreign_fn(it.owner_id.def_id, decl);
}
hir::ForeignItemKind::Static(ref ty, _) => {
vis.check_foreign_static(it.owner_id, ty.span);
}
hir::ForeignItemKind::Type => (),
match it.kind {
hir::ForeignItemKind::Fn(ref decl, _, _) => {
vis.check_maybe_foreign_fn(abi, it.owner_id.def_id, decl);
}
hir::ForeignItemKind::Static(ref ty, _) if !vis.is_internal_abi(abi) => {
vis.check_foreign_static(it.owner_id, ty.span);
}
hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (),
}
}
}

impl ImproperCTypesDefinitions {
fn check_ty_maybe_containing_foreign_fnptr<'tcx>(
&mut self,
cx: &LateContext<'tcx>,
hir_ty: &'tcx hir::Ty<'_>,
ty: Ty<'tcx>,
) {
let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Definition };
for (fn_ptr_ty, span) in vis.find_fn_ptr_ty_with_external_abi(hir_ty, ty) {
vis.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, true, false);
}
}
}

/// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in
/// `extern "C" { }` blocks):
///
/// - `extern "<abi>" fn` definitions are checked in the same way as the
/// `ImproperCtypesDeclarations` visitor checks functions if `<abi>` is external (e.g. "C").
/// - All other items which contain types (e.g. other functions, struct definitions, etc) are
/// checked for extern fn-ptrs with external ABIs.
impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
match item.kind {
hir::ItemKind::Static(ty, ..)
| hir::ItemKind::Const(ty, ..)
| hir::ItemKind::TyAlias(ty, ..) => {
self.check_ty_maybe_containing_foreign_fnptr(
cx,
ty,
cx.tcx.type_of(item.owner_id).subst_identity(),
);
}
// See `check_fn`..
hir::ItemKind::Fn(..) => {}
// See `check_field_def`..
hir::ItemKind::Union(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) => {}
// Doesn't define something that can contain a external type to be checked.
hir::ItemKind::Impl(..)
| hir::ItemKind::TraitAlias(..)
| hir::ItemKind::Trait(..)
| hir::ItemKind::OpaqueTy(..)
| hir::ItemKind::GlobalAsm(..)
| hir::ItemKind::ForeignMod { .. }
| hir::ItemKind::Mod(..)
| hir::ItemKind::Macro(..)
| hir::ItemKind::Use(..)
| hir::ItemKind::ExternCrate(..) => {}
}
}

fn check_field_def(&mut self, cx: &LateContext<'tcx>, field: &'tcx hir::FieldDef<'tcx>) {
self.check_ty_maybe_containing_foreign_fnptr(
cx,
field.ty,
cx.tcx.type_of(field.def_id).subst_identity(),
);
}

fn check_fn(
&mut self,
cx: &LateContext<'tcx>,
Expand All @@ -1315,9 +1449,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions {
};

let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Definition };
if !vis.is_internal_abi(abi) {
vis.check_foreign_fn(id, decl);
}
vis.check_maybe_foreign_fn(abi, id, decl);
}
}

Expand Down
10 changes: 6 additions & 4 deletions compiler/rustc_target/src/abi/call/x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,9 @@ fn reg_component(cls: &[Option<Class>], i: &mut usize, size: Size) -> Option<Reg
}
}

fn cast_target(cls: &[Option<Class>], size: Size) -> CastTarget {
fn cast_target(cls: &[Option<Class>], size: Size) -> Option<CastTarget> {
let mut i = 0;
let lo = reg_component(cls, &mut i, size).unwrap();
let lo = reg_component(cls, &mut i, size)?;
let offset = Size::from_bytes(8) * (i as u64);
let mut target = CastTarget::from(lo);
if size > offset {
Expand All @@ -164,7 +164,7 @@ fn cast_target(cls: &[Option<Class>], size: Size) -> CastTarget {
}
}
assert_eq!(reg_component(cls, &mut i, Size::ZERO), None);
target
Some(target)
}

const MAX_INT_REGS: usize = 6; // RDI, RSI, RDX, RCX, R8, R9
Expand Down Expand Up @@ -227,7 +227,9 @@ where
// split into sized chunks passed individually
if arg.layout.is_aggregate() {
let size = arg.layout.size;
arg.cast_to(cast_target(cls, size))
if let Some(cast_target) = cast_target(cls, size) {
arg.cast_to(cast_target);
}
} else {
arg.extend_integer_width_to(32);
}
Expand Down
19 changes: 13 additions & 6 deletions compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use rustc_infer::infer::at::ToTrace;
use rustc_infer::infer::canonical::CanonicalVarValues;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{
DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, TyCtxtInferExt,
DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, RegionVariableOrigin,
TyCtxtInferExt,
};
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::ObligationCause;
Expand Down Expand Up @@ -223,18 +224,20 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
{
debug!("rerunning goal to check result is stable");
let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
let canonical_response =
let new_canonical_response =
EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?;
if !canonical_response.value.var_values.is_identity() {
if !new_canonical_response.value.var_values.is_identity() {
bug!(
"unstable result: re-canonicalized goal={canonical_goal:#?} \
response={canonical_response:#?}"
first_response={canonical_response:#?} \
second_response={new_canonical_response:#?}"
);
}
if certainty != canonical_response.value.certainty {
if certainty != new_canonical_response.value.certainty {
bug!(
"unstable certainty: {certainty:#?} re-canonicalized goal={canonical_goal:#?} \
response={canonical_response:#?}"
first_response={canonical_response:#?} \
second_response={new_canonical_response:#?}"
);
}
}
Expand Down Expand Up @@ -434,6 +437,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
})
}

pub(super) fn next_region_infer(&self) -> ty::Region<'tcx> {
self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP))
}

pub(super) fn next_const_infer(&self, ty: Ty<'tcx>) -> ty::Const<'tcx> {
self.infcx.next_const_var(
ty,
Expand Down
Loading