From 5dd54fdfc48ecac5646c8ffc5a5a5321f0733f65 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 1 Mar 2023 15:52:29 +0000 Subject: [PATCH 01/14] lint/ctypes: ext. abi fn-ptr in internal abi fn Instead of skipping functions with internal ABIs, check that the signature doesn't contain any fn-ptr types with external ABIs that aren't FFI-safe. Signed-off-by: David Wood --- compiler/rustc_lint/src/types.rs | 75 +++++++++++++++---- tests/ui/abi/foreign/foreign-fn-with-byval.rs | 2 +- tests/ui/lint/lint-ctypes-94223.rs | 5 ++ tests/ui/lint/lint-ctypes-94223.stderr | 16 ++++ 4 files changed, 81 insertions(+), 17 deletions(-) create mode 100644 tests/ui/lint/lint-ctypes-94223.rs create mode 100644 tests/ui/lint/lint-ctypes-94223.stderr diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 85958c4170569..702d8c0cea334 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1230,17 +1230,40 @@ 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: &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>, + span: Span, + 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(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.. + if let Some(fn_ptr_ty) = this.find_fn_ptr_ty_with_external_abi(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.span, *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.span, sig.output(), true); } } @@ -1255,6 +1278,30 @@ 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` returns `extern "C" fn()` + fn find_fn_ptr_ty_with_external_abi(&self, ty: Ty<'tcx>) -> Option> { + struct FnPtrFinder<'parent, 'a, 'tcx>(&'parent ImproperCTypesVisitor<'a, 'tcx>); + impl<'vis, 'a, 'tcx> ty::visit::TypeVisitor> for FnPtrFinder<'vis, 'a, 'tcx> { + type BreakTy = Ty<'tcx>; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { + if let ty::FnPtr(sig) = ty.kind() && !self.0.is_internal_abi(sig.abi()) { + ControlFlow::Break(ty) + } else { + ty.super_visit_with(self) + } + } + } + + self.cx + .tcx + .normalize_erasing_regions(self.cx.param_env, ty) + .visit_with(&mut FnPtrFinder(&*self)) + .break_value() + } } impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations { @@ -1262,16 +1309,14 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations { 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 => (), } } } @@ -1295,9 +1340,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); } } diff --git a/tests/ui/abi/foreign/foreign-fn-with-byval.rs b/tests/ui/abi/foreign/foreign-fn-with-byval.rs index f366b6ee1bdd5..e20ee0da45d9d 100644 --- a/tests/ui/abi/foreign/foreign-fn-with-byval.rs +++ b/tests/ui/abi/foreign/foreign-fn-with-byval.rs @@ -1,5 +1,5 @@ // run-pass -#![allow(improper_ctypes)] +#![allow(improper_ctypes, improper_ctypes_definitions)] // ignore-wasm32-bare no libc to test ffi with diff --git a/tests/ui/lint/lint-ctypes-94223.rs b/tests/ui/lint/lint-ctypes-94223.rs new file mode 100644 index 0000000000000..ca7f3b73f66c5 --- /dev/null +++ b/tests/ui/lint/lint-ctypes-94223.rs @@ -0,0 +1,5 @@ +#![crate_type = "lib"] +#![deny(improper_ctypes_definitions)] + +pub fn bad(f: extern "C" fn([u8])) {} +//~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe diff --git a/tests/ui/lint/lint-ctypes-94223.stderr b/tests/ui/lint/lint-ctypes-94223.stderr new file mode 100644 index 0000000000000..f8afed34ea458 --- /dev/null +++ b/tests/ui/lint/lint-ctypes-94223.stderr @@ -0,0 +1,16 @@ +error: `extern` fn uses type `[u8]`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:4:15 + | +LL | pub fn bad(f: extern "C" fn([u8])) {} + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using a raw pointer instead + = note: slices have no C equivalent +note: the lint level is defined here + --> $DIR/lint-ctypes-94223.rs:2:9 + | +LL | #![deny(improper_ctypes_definitions)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From c1dcf2649e8a11b1990e999f3edf762c101d2b97 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 1 Mar 2023 15:55:09 +0000 Subject: [PATCH 02/14] abi: avoid ice for non-ffi-safe fn ptrs Remove an `unwrap` that assumed FFI-safe types in foreign fn-ptr types. Signed-off-by: David Wood --- compiler/rustc_target/src/abi/call/x86_64.rs | 10 ++++++---- tests/ui/abi/issue-94223.rs | 8 ++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 tests/ui/abi/issue-94223.rs diff --git a/compiler/rustc_target/src/abi/call/x86_64.rs b/compiler/rustc_target/src/abi/call/x86_64.rs index 9427f27d1b7bb..2470cdfebe225 100644 --- a/compiler/rustc_target/src/abi/call/x86_64.rs +++ b/compiler/rustc_target/src/abi/call/x86_64.rs @@ -153,9 +153,9 @@ fn reg_component(cls: &[Option], i: &mut usize, size: Size) -> Option], size: Size) -> CastTarget { +fn cast_target(cls: &[Option], size: Size) -> Option { 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 { @@ -164,7 +164,7 @@ fn cast_target(cls: &[Option], 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 @@ -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); } diff --git a/tests/ui/abi/issue-94223.rs b/tests/ui/abi/issue-94223.rs new file mode 100644 index 0000000000000..79d6b94031bc2 --- /dev/null +++ b/tests/ui/abi/issue-94223.rs @@ -0,0 +1,8 @@ +// check-pass +#![allow(improper_ctypes_definitions)] +#![crate_type = "lib"] + +// Check that computing the fn abi for `bad`, with a external ABI fn ptr that is not FFI-safe, does +// not ICE. + +pub fn bad(f: extern "C" fn([u8])) {} From 92ae35f53d73bcd006a99f22e7103f03ebdccc2e Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 2 Mar 2023 11:23:44 +0000 Subject: [PATCH 03/14] lint/ctypes: multiple external fn-ptrs in ty Extend previous commit's support for checking for external fn-ptrs in internal fn types to report errors for multiple found fn-ptrs. Signed-off-by: David Wood --- compiler/rustc_lint/src/types.rs | 63 ++++++++++++++++++-------- tests/ui/lint/lint-ctypes-94223.rs | 4 ++ tests/ui/lint/lint-ctypes-94223.stderr | 20 +++++++- 3 files changed, 68 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 702d8c0cea334..62d56931426ef 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1235,35 +1235,40 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { /// 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: &hir::FnDecl<'_>) { + 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>, - span: Span, + 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(span, ty, false, is_return_type); + 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.. - if let Some(fn_ptr_ty) = this.find_fn_ptr_ty_with_external_abi(ty) { + 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) { - check_ty(self, input_hir.span, *input_ty, false); + check_ty(self, input_hir, *input_ty, false); } if let hir::FnRetTy::Return(ref ret_hir) = decl.output { - check_ty(self, ret_hir.span, sig.output(), true); + check_ty(self, ret_hir, sig.output(), true); } } @@ -1282,30 +1287,52 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { /// Find any fn-ptr types with external ABIs in `ty`. /// /// For example, `Option` returns `extern "C" fn()` - fn find_fn_ptr_ty_with_external_abi(&self, ty: Ty<'tcx>) -> Option> { - struct FnPtrFinder<'parent, 'a, 'tcx>(&'parent ImproperCTypesVisitor<'a, 'tcx>); + 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, + tys: Vec>, + } + + 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> for FnPtrFinder<'vis, 'a, 'tcx> { type BreakTy = Ty<'tcx>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow { - if let ty::FnPtr(sig) = ty.kind() && !self.0.is_internal_abi(sig.abi()) { - ControlFlow::Break(ty) - } else { - ty.super_visit_with(self) + if let ty::FnPtr(sig) = ty.kind() && !self.visitor.is_internal_abi(sig.abi()) { + self.tys.push(ty); } + + ty.super_visit_with(self) } } - self.cx - .tcx - .normalize_erasing_regions(self.cx.param_env, ty) - .visit_with(&mut FnPtrFinder(&*self)) - .break_value() + let mut visitor = FnPtrFinder { visitor: &*self, spans: Vec::new(), tys: Vec::new() }; + self.cx.tcx.normalize_erasing_regions(self.cx.param_env, 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()); diff --git a/tests/ui/lint/lint-ctypes-94223.rs b/tests/ui/lint/lint-ctypes-94223.rs index ca7f3b73f66c5..98ccbd23a9ed8 100644 --- a/tests/ui/lint/lint-ctypes-94223.rs +++ b/tests/ui/lint/lint-ctypes-94223.rs @@ -3,3 +3,7 @@ pub fn bad(f: extern "C" fn([u8])) {} //~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe + +pub fn bad_twice(f: Result) {} +//~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe +//~^^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe diff --git a/tests/ui/lint/lint-ctypes-94223.stderr b/tests/ui/lint/lint-ctypes-94223.stderr index f8afed34ea458..e05d6197cb426 100644 --- a/tests/ui/lint/lint-ctypes-94223.stderr +++ b/tests/ui/lint/lint-ctypes-94223.stderr @@ -12,5 +12,23 @@ note: the lint level is defined here LL | #![deny(improper_ctypes_definitions)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: `extern` fn uses type `[u8]`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:7:28 + | +LL | pub fn bad_twice(f: Result) {} + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using a raw pointer instead + = note: slices have no C equivalent + +error: `extern` fn uses type `[u8]`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:7:49 + | +LL | pub fn bad_twice(f: Result) {} + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using a raw pointer instead + = note: slices have no C equivalent + +error: aborting due to 3 previous errors From 3e7ca3e8518c9a2c8837a07a505cd85e82c01c81 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 2 Mar 2023 11:54:37 +0000 Subject: [PATCH 04/14] lint/ctypes: check other types for ext. fn-ptr ty Extend previous checks for external ABI fn-ptrs to use in internal statics, constants, type aliases and algebraic data types. Signed-off-by: David Wood --- compiler/rustc_lint/src/types.rs | 64 +++++++++++++++++- tests/ui/hashmap/hashmap-memory.rs | 1 + tests/ui/lint/lint-ctypes-94223.rs | 33 +++++++++ tests/ui/lint/lint-ctypes-94223.stderr | 94 +++++++++++++++++++++++++- 4 files changed, 190 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 62d56931426ef..defd5206bc025 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1324,7 +1324,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } let mut visitor = FnPtrFinder { visitor: &*self, spans: Vec::new(), tys: Vec::new() }; - self.cx.tcx.normalize_erasing_regions(self.cx.param_env, ty).visit_with(&mut visitor); + 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() @@ -1348,7 +1352,65 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations { } } +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 "" fn` definitions are checked in the same way as the +/// `ImproperCtypesDeclarations` visitor checks functions if `` 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>, diff --git a/tests/ui/hashmap/hashmap-memory.rs b/tests/ui/hashmap/hashmap-memory.rs index 87f8b6ad5730b..bd364b349e263 100644 --- a/tests/ui/hashmap/hashmap-memory.rs +++ b/tests/ui/hashmap/hashmap-memory.rs @@ -1,5 +1,6 @@ // run-pass +#![allow(improper_ctypes_definitions)] #![allow(non_camel_case_types)] #![allow(dead_code)] #![allow(unused_mut)] diff --git a/tests/ui/lint/lint-ctypes-94223.rs b/tests/ui/lint/lint-ctypes-94223.rs index 98ccbd23a9ed8..70dd2a71f2675 100644 --- a/tests/ui/lint/lint-ctypes-94223.rs +++ b/tests/ui/lint/lint-ctypes-94223.rs @@ -7,3 +7,36 @@ pub fn bad(f: extern "C" fn([u8])) {} pub fn bad_twice(f: Result) {} //~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe //~^^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe + +struct BadStruct(extern "C" fn([u8])); +//~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe + +enum BadEnum { + A(extern "C" fn([u8])), + //~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe +} + +enum BadUnion { + A(extern "C" fn([u8])), + //~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe +} + +type Foo = extern "C" fn([u8]); +//~^ ERROR `extern` fn uses type `[u8]`, which is not FFI-safe + +pub struct FfiUnsafe; + +#[allow(improper_ctypes_definitions)] +extern "C" fn f(_: FfiUnsafe) { + unimplemented!() +} + +pub static BAD: extern "C" fn(FfiUnsafe) = f; +//~^ ERROR `extern` fn uses type `FfiUnsafe`, which is not FFI-safe + +pub static BAD_TWICE: Result = Ok(f); +//~^ ERROR `extern` fn uses type `FfiUnsafe`, which is not FFI-safe +//~^^ ERROR `extern` fn uses type `FfiUnsafe`, which is not FFI-safe + +pub const BAD_CONST: extern "C" fn(FfiUnsafe) = f; +//~^ ERROR `extern` fn uses type `FfiUnsafe`, which is not FFI-safe diff --git a/tests/ui/lint/lint-ctypes-94223.stderr b/tests/ui/lint/lint-ctypes-94223.stderr index e05d6197cb426..49e64ed5140c2 100644 --- a/tests/ui/lint/lint-ctypes-94223.stderr +++ b/tests/ui/lint/lint-ctypes-94223.stderr @@ -30,5 +30,97 @@ LL | pub fn bad_twice(f: Result) {} = help: consider using a raw pointer instead = note: slices have no C equivalent -error: aborting due to 3 previous errors +error: `extern` fn uses type `[u8]`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:11:18 + | +LL | struct BadStruct(extern "C" fn([u8])); + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using a raw pointer instead + = note: slices have no C equivalent + +error: `extern` fn uses type `[u8]`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:15:7 + | +LL | A(extern "C" fn([u8])), + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using a raw pointer instead + = note: slices have no C equivalent + +error: `extern` fn uses type `[u8]`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:20:7 + | +LL | A(extern "C" fn([u8])), + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using a raw pointer instead + = note: slices have no C equivalent + +error: `extern` fn uses type `[u8]`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:24:12 + | +LL | type Foo = extern "C" fn([u8]); + | ^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using a raw pointer instead + = note: slices have no C equivalent + +error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:34:17 + | +LL | pub static BAD: extern "C" fn(FfiUnsafe) = f; + | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout +note: the type is defined here + --> $DIR/lint-ctypes-94223.rs:27:1 + | +LL | pub struct FfiUnsafe; + | ^^^^^^^^^^^^^^^^^^^^ + +error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:37:30 + | +LL | pub static BAD_TWICE: Result = Ok(f); + | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout +note: the type is defined here + --> $DIR/lint-ctypes-94223.rs:27:1 + | +LL | pub struct FfiUnsafe; + | ^^^^^^^^^^^^^^^^^^^^ + +error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:37:56 + | +LL | pub static BAD_TWICE: Result = Ok(f); + | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout +note: the type is defined here + --> $DIR/lint-ctypes-94223.rs:27:1 + | +LL | pub struct FfiUnsafe; + | ^^^^^^^^^^^^^^^^^^^^ + +error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe + --> $DIR/lint-ctypes-94223.rs:41:22 + | +LL | pub const BAD_CONST: extern "C" fn(FfiUnsafe) = f; + | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout +note: the type is defined here + --> $DIR/lint-ctypes-94223.rs:27:1 + | +LL | pub struct FfiUnsafe; + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 11 previous errors From 1a7132d4f8dfb2ed6f9267b3bac5391a992d0775 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 14 Apr 2023 13:32:44 -0700 Subject: [PATCH 05/14] rustdoc-search: fix incorrect doc comment --- src/librustdoc/html/static/js/search.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 929dae81c8de4..9ef01b5d8927a 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -873,7 +873,7 @@ function initSearch(rawSearchIndex) { * * @param {Array} results_in_args * @param {Array} results_returned - * @param {Array} results_in_args + * @param {Array} results_others * @param {ParsedQuery} parsedQuery * * @return {ResultsTable} From 4c11822aebd9e9c3bbe798f14fa10ec6db3f3937 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 15 Apr 2023 11:53:50 -0700 Subject: [PATCH 06/14] rustdoc: restructure type search engine to pick-and-use IDs This change makes it so, instead of mixing string distance with type unification, function signature search works by mapping names to IDs at the start, reporting to the user any cases where it had to make corrections, and then matches with IDs when going through the items. This only changes function searches. Name searches are left alone, and corrections are only done when there's a single item in the search query. --- src/librustdoc/html/static/css/rustdoc.css | 4 + src/librustdoc/html/static/js/externs.js | 5 +- src/librustdoc/html/static/js/search.js | 414 +++++++++++---------- src/tools/rustdoc-js/tester.js | 54 ++- tests/rustdoc-gui/search-corrections.goml | 54 +++ tests/rustdoc-js/generics-trait.js | 27 ++ 6 files changed, 354 insertions(+), 204 deletions(-) create mode 100644 tests/rustdoc-gui/search-corrections.goml diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 6fbb4508662c7..a7d5f497756b5 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -1259,6 +1259,10 @@ a.tooltip:hover::after { background-color: var(--search-error-code-background-color); } +.search-corrections { + font-weight: normal; +} + #src-sidebar-toggle { position: sticky; top: 0; diff --git a/src/librustdoc/html/static/js/externs.js b/src/librustdoc/html/static/js/externs.js index 4c81a0979c1a7..8b931f74e600a 100644 --- a/src/librustdoc/html/static/js/externs.js +++ b/src/librustdoc/html/static/js/externs.js @@ -9,6 +9,7 @@ function initSearch(searchIndex){} /** * @typedef {{ * name: string, + * id: integer, * fullPath: Array, * pathWithoutLast: Array, * pathLast: string, @@ -36,6 +37,8 @@ let ParserState; * args: Array, * returned: Array, * foundElems: number, + * literalSearch: boolean, + * corrections: Array<{from: string, to: integer}>, * }} */ let ParsedQuery; @@ -139,7 +142,7 @@ let FunctionSearchType; /** * @typedef {{ - * name: (null|string), + * id: (null|number), * ty: (null|number), * generics: Array, * }} diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 9ef01b5d8927a..2d0a3f0192bd0 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -58,6 +58,7 @@ function printTab(nb) { } iter += 1; }); + const isTypeSearch = (nb > 0 || iter === 1); iter = 0; onEachLazy(document.getElementById("results").childNodes, elem => { if (nb === iter) { @@ -70,6 +71,13 @@ function printTab(nb) { }); if (foundCurrentTab && foundCurrentResultSet) { searchState.currentTab = nb; + // Corrections only kick in on type-based searches. + const correctionsElem = document.getElementsByClassName("search-corrections"); + if (isTypeSearch) { + removeClass(correctionsElem[0], "hidden"); + } else { + addClass(correctionsElem[0], "hidden"); + } } else if (nb !== 0) { printTab(0); } @@ -191,6 +199,13 @@ function initSearch(rawSearchIndex) { */ let searchIndex; let currentResults; + /** + * Map from normalized type names to integers. Used to make type search + * more efficient. + * + * @type {Map} + */ + let typeNameIdMap; const ALIASES = new Map(); function isWhitespace(c) { @@ -358,6 +373,7 @@ function initSearch(rawSearchIndex) { parserState.typeFilter = null; return { name: name, + id: -1, fullPath: pathSegments, pathWithoutLast: pathSegments.slice(0, pathSegments.length - 1), pathLast: pathSegments[pathSegments.length - 1], @@ -718,6 +734,7 @@ function initSearch(rawSearchIndex) { foundElems: 0, literalSearch: false, error: null, + correction: null, }; } @@ -1091,48 +1108,50 @@ function initSearch(rawSearchIndex) { * * @param {Row} row - The object to check. * @param {QueryElement} elem - The element from the parsed query. - * @param {integer} defaultDistance - This is the value to return in case there are no - * generics. * - * @return {integer} - Returns the best match (if any) or `maxEditDistance + 1`. + * @return {boolean} - Returns true if a match, false otherwise. */ - function checkGenerics(row, elem, defaultDistance, maxEditDistance) { - if (row.generics.length === 0) { - return elem.generics.length === 0 ? defaultDistance : maxEditDistance + 1; - } else if (row.generics.length > 0 && row.generics[0].name === null) { - return checkGenerics(row.generics[0], elem, defaultDistance, maxEditDistance); - } - // The names match, but we need to be sure that all generics kinda - // match as well. + function checkGenerics(row, elem) { + if (row.generics.length === 0 || elem.generics.length === 0) { + return false; + } + // This function is called if the names match, but we need to make + // sure that all generics match as well. + // + // This search engine implements order-agnostic unification. There + // should be no missing duplicates (generics have "bag semantics"), + // and the row is allowed to have extras. if (elem.generics.length > 0 && row.generics.length >= elem.generics.length) { const elems = new Map(); - for (const entry of row.generics) { - if (entry.name === "") { + const addEntryToElems = function addEntryToElems(entry) { + if (entry.id === -1) { // Pure generic, needs to check into it. - if (checkGenerics(entry, elem, maxEditDistance + 1, maxEditDistance) - !== 0) { - return maxEditDistance + 1; + for (const inner_entry of entry.generics) { + addEntryToElems(inner_entry); } - continue; + return; } let currentEntryElems; - if (elems.has(entry.name)) { - currentEntryElems = elems.get(entry.name); + if (elems.has(entry.id)) { + currentEntryElems = elems.get(entry.id); } else { currentEntryElems = []; - elems.set(entry.name, currentEntryElems); + elems.set(entry.id, currentEntryElems); } currentEntryElems.push(entry); + }; + for (const entry of row.generics) { + addEntryToElems(entry); } // We need to find the type that matches the most to remove it in order // to move forward. const handleGeneric = generic => { - if (!elems.has(generic.name)) { + if (!elems.has(generic.id)) { return false; } - const matchElems = elems.get(generic.name); + const matchElems = elems.get(generic.id); const matchIdx = matchElems.findIndex(tmp_elem => { - if (checkGenerics(tmp_elem, generic, 0, maxEditDistance) !== 0) { + if (generic.generics.length > 0 && !checkGenerics(tmp_elem, generic)) { return false; } return typePassesFilter(generic.typeFilter, tmp_elem.ty); @@ -1142,7 +1161,7 @@ function initSearch(rawSearchIndex) { } matchElems.splice(matchIdx, 1); if (matchElems.length === 0) { - elems.delete(generic.name); + elems.delete(generic.id); } return true; }; @@ -1152,17 +1171,17 @@ function initSearch(rawSearchIndex) { // own type. for (const generic of elem.generics) { if (generic.typeFilter !== -1 && !handleGeneric(generic)) { - return maxEditDistance + 1; + return false; } } for (const generic of elem.generics) { if (generic.typeFilter === -1 && !handleGeneric(generic)) { - return maxEditDistance + 1; + return false; } } - return 0; + return true; } - return maxEditDistance + 1; + return false; } /** @@ -1172,17 +1191,15 @@ function initSearch(rawSearchIndex) { * @param {Row} row * @param {QueryElement} elem - The element from the parsed query. * - * @return {integer} - Returns an edit distance to the best match. + * @return {boolean} - Returns true if found, false otherwise. */ - function checkIfInGenerics(row, elem, maxEditDistance) { - let dist = maxEditDistance + 1; + function checkIfInGenerics(row, elem) { for (const entry of row.generics) { - dist = Math.min(checkType(entry, elem, true, maxEditDistance), dist); - if (dist === 0) { - break; + if (checkType(entry, elem)) { + return true; } } - return dist; + return false; } /** @@ -1191,75 +1208,30 @@ function initSearch(rawSearchIndex) { * * @param {Row} row * @param {QueryElement} elem - The element from the parsed query. - * @param {boolean} literalSearch * - * @return {integer} - Returns an edit distance to the best match. If there is - * no match, returns `maxEditDistance + 1`. + * @return {boolean} - Returns true if the type matches, false otherwise. */ - function checkType(row, elem, literalSearch, maxEditDistance) { - if (row.name === null) { + function checkType(row, elem) { + if (row.id === -1) { // This is a pure "generic" search, no need to run other checks. - if (row.generics.length > 0) { - return checkIfInGenerics(row, elem, maxEditDistance); - } - return maxEditDistance + 1; + return row.generics.length > 0 ? checkIfInGenerics(row, elem) : false; } - let dist; - if (typePassesFilter(elem.typeFilter, row.ty)) { - dist = editDistance(row.name, elem.name, maxEditDistance); - } else { - dist = maxEditDistance + 1; - } - if (literalSearch) { - if (dist !== 0) { - // The name didn't match, let's try to check if the generics do. - if (elem.generics.length === 0) { - const checkGeneric = row.generics.length > 0; - if (checkGeneric && row.generics - .findIndex(tmp_elem => tmp_elem.name === elem.name && - typePassesFilter(elem.typeFilter, tmp_elem.ty)) !== -1) { - return 0; - } - } - return maxEditDistance + 1; - } else if (elem.generics.length > 0) { - return checkGenerics(row, elem, maxEditDistance + 1, maxEditDistance); - } - return 0; - } else if (row.generics.length > 0) { - if (elem.generics.length === 0) { - if (dist === 0) { - return 0; - } - // The name didn't match so we now check if the type we're looking for is inside - // the generics! - dist = Math.min(dist, checkIfInGenerics(row, elem, maxEditDistance)); - return dist; - } else if (dist > maxEditDistance) { - // So our item's name doesn't match at all and has generics. - // - // Maybe it's present in a sub generic? For example "f>>()", if we're - // looking for "B", we'll need to go down. - return checkIfInGenerics(row, elem, maxEditDistance); - } else { - // At this point, the name kinda match and we have generics to check, so - // let's go! - const tmp_dist = checkGenerics(row, elem, dist, maxEditDistance); - if (tmp_dist > maxEditDistance) { - return maxEditDistance + 1; - } - // We compute the median value of both checks and return it. - return (tmp_dist + dist) / 2; + if (row.id === elem.id && typePassesFilter(elem.typeFilter, row.ty)) { + if (elem.generics.length > 0) { + return checkGenerics(row, elem); } - } else if (elem.generics.length > 0) { - // In this case, we were expecting generics but there isn't so we simply reject this - // one. - return maxEditDistance + 1; + return true; + } + + // If the current item does not match, try [unboxing] the generic. + // [unboxing]: + // https://ndmitchell.com/downloads/slides-hoogle_fast_type_searching-09_aug_2008.pdf + if (checkIfInGenerics(row, elem)) { + return true; } - // No generics on our query or on the target type so we can return without doing - // anything else. - return dist; + + return false; } /** @@ -1267,17 +1239,11 @@ function initSearch(rawSearchIndex) { * * @param {Row} row * @param {QueryElement} elem - The element from the parsed query. - * @param {integer} maxEditDistance * @param {Array} skipPositions - Do not return one of these positions. * - * @return {dist: integer, position: integer} - Returns an edit distance to the best match. - * If there is no match, returns - * `maxEditDistance + 1` and position: -1. + * @return {integer} - Returns the position of the match, or -1 if none. */ - function findArg(row, elem, maxEditDistance, skipPositions) { - let dist = maxEditDistance + 1; - let position = -1; - + function findArg(row, elem, skipPositions) { if (row && row.type && row.type.inputs && row.type.inputs.length > 0) { let i = 0; for (const input of row.type.inputs) { @@ -1285,24 +1251,13 @@ function initSearch(rawSearchIndex) { i += 1; continue; } - const typeDist = checkType( - input, - elem, - parsedQuery.literalSearch, - maxEditDistance - ); - if (typeDist === 0) { - return {dist: 0, position: i}; - } - if (typeDist < dist) { - dist = typeDist; - position = i; + if (checkType(input, elem)) { + return i; } i += 1; } } - dist = parsedQuery.literalSearch ? maxEditDistance + 1 : dist; - return {dist, position}; + return -1; } /** @@ -1310,43 +1265,25 @@ function initSearch(rawSearchIndex) { * * @param {Row} row * @param {QueryElement} elem - The element from the parsed query. - * @param {integer} maxEditDistance * @param {Array} skipPositions - Do not return one of these positions. * - * @return {dist: integer, position: integer} - Returns an edit distance to the best match. - * If there is no match, returns - * `maxEditDistance + 1` and position: -1. + * @return {integer} - Returns the position of the matching item, or -1 if none. */ - function checkReturned(row, elem, maxEditDistance, skipPositions) { - let dist = maxEditDistance + 1; - let position = -1; - + function checkReturned(row, elem, skipPositions) { if (row && row.type && row.type.output.length > 0) { - const ret = row.type.output; let i = 0; - for (const ret_ty of ret) { + for (const ret_ty of row.type.output) { if (skipPositions.indexOf(i) !== -1) { i += 1; continue; } - const typeDist = checkType( - ret_ty, - elem, - parsedQuery.literalSearch, - maxEditDistance - ); - if (typeDist === 0) { - return {dist: 0, position: i}; - } - if (typeDist < dist) { - dist = typeDist; - position = i; + if (checkType(ret_ty, elem)) { + return i; } i += 1; } } - dist = parsedQuery.literalSearch ? maxEditDistance + 1 : dist; - return {dist, position}; + return -1; } function checkPath(contains, ty, maxEditDistance) { @@ -1543,17 +1480,20 @@ function initSearch(rawSearchIndex) { if (!row || (filterCrates !== null && row.crate !== filterCrates)) { return; } - let dist, index = -1, path_dist = 0; + let index = -1, path_dist = 0; const fullId = row.id; const searchWord = searchWords[pos]; - const in_args = findArg(row, elem, maxEditDistance, []); - const returned = checkReturned(row, elem, maxEditDistance, []); - - // path_dist is 0 because no parent path information is currently stored - // in the search index - addIntoResults(results_in_args, fullId, pos, -1, in_args.dist, 0, maxEditDistance); - addIntoResults(results_returned, fullId, pos, -1, returned.dist, 0, maxEditDistance); + const in_args = findArg(row, elem, []); + if (in_args !== -1) { + // path_dist is 0 because no parent path information is currently stored + // in the search index + addIntoResults(results_in_args, fullId, pos, -1, 0, 0, maxEditDistance); + } + const returned = checkReturned(row, elem, []); + if (returned !== -1) { + addIntoResults(results_returned, fullId, pos, -1, 0, 0, maxEditDistance); + } if (!typePassesFilter(elem.typeFilter, row.ty)) { return; @@ -1574,16 +1514,6 @@ function initSearch(rawSearchIndex) { index = row_index; } - // No need to check anything else if it's a "pure" generics search. - if (elem.name.length === 0) { - if (row.type !== null) { - dist = checkGenerics(row.type, elem, maxEditDistance + 1, maxEditDistance); - // path_dist is 0 because we know it's empty - addIntoResults(results_others, fullId, pos, index, dist, 0, maxEditDistance); - } - return; - } - if (elem.fullPath.length > 1) { path_dist = checkPath(elem.pathWithoutLast, row, maxEditDistance); if (path_dist > maxEditDistance) { @@ -1598,7 +1528,7 @@ function initSearch(rawSearchIndex) { return; } - dist = editDistance(searchWord, elem.pathLast, maxEditDistance); + const dist = editDistance(searchWord, elem.pathLast, maxEditDistance); if (index === -1 && dist + path_dist > maxEditDistance) { return; @@ -1616,28 +1546,22 @@ function initSearch(rawSearchIndex) { * @param {integer} pos - Position in the `searchIndex`. * @param {Object} results */ - function handleArgs(row, pos, results, maxEditDistance) { + function handleArgs(row, pos, results) { if (!row || (filterCrates !== null && row.crate !== filterCrates)) { return; } - let totalDist = 0; - let nbDist = 0; - // If the result is too "bad", we return false and it ends this search. function checkArgs(elems, callback) { const skipPositions = []; for (const elem of elems) { // There is more than one parameter to the query so all checks should be "exact" - const { dist, position } = callback( + const position = callback( row, elem, - maxEditDistance, skipPositions ); - if (dist <= 1) { - nbDist += 1; - totalDist += dist; + if (position !== -1) { skipPositions.push(position); } else { return false; @@ -1652,11 +1576,7 @@ function initSearch(rawSearchIndex) { return; } - if (nbDist === 0) { - return; - } - const dist = Math.round(totalDist / nbDist); - addIntoResults(results, row.id, pos, 0, dist, 0, maxEditDistance); + addIntoResults(results, row.id, pos, 0, 0, 0, Number.MAX_VALUE); } function innerRunQuery() { @@ -1671,6 +1591,50 @@ function initSearch(rawSearchIndex) { } const maxEditDistance = Math.floor(queryLen / 3); + /** + * Convert names to ids in parsed query elements. + * This is not used for the "In Names" tab, but is used for the + * "In Params", "In Returns", and "In Function Signature" tabs. + * + * If there is no matching item, but a close-enough match, this + * function also that correction. + * + * See `buildTypeMapIndex` for more information. + * + * @param {QueryElement} elem + */ + function convertNameToId(elem) { + if (typeNameIdMap.has(elem.name)) { + elem.id = typeNameIdMap.get(elem.name); + } else if (!parsedQuery.literalSearch) { + let match = -1; + let matchDist = maxEditDistance + 1; + let matchName = ""; + for (const [name, id] of typeNameIdMap) { + const dist = editDistance(name, elem.name, maxEditDistance); + if (dist <= matchDist && dist <= maxEditDistance) { + match = id; + matchDist = dist; + matchName = name; + } + } + if (match !== -1) { + parsedQuery.correction = matchName; + } + elem.id = match; + } + for (const elem2 of elem.generics) { + convertNameToId(elem2); + } + } + + for (const elem of parsedQuery.elems) { + convertNameToId(elem); + } + for (const elem of parsedQuery.returned) { + convertNameToId(elem); + } + if (parsedQuery.foundElems === 1) { if (parsedQuery.elems.length === 1) { elem = parsedQuery.elems[0]; @@ -1695,22 +1659,23 @@ function initSearch(rawSearchIndex) { in_returned = checkReturned( row, elem, - maxEditDistance, [] ); - addIntoResults( - results_others, - row.id, - i, - -1, - in_returned.dist, - maxEditDistance - ); + if (in_returned !== -1) { + addIntoResults( + results_others, + row.id, + i, + -1, + 0, + Number.MAX_VALUE + ); + } } } } else if (parsedQuery.foundElems > 0) { for (i = 0, nSearchWords = searchWords.length; i < nSearchWords; ++i) { - handleArgs(searchIndex[i], i, results_others, maxEditDistance); + handleArgs(searchIndex[i], i, results_others); } } } @@ -2030,6 +1995,11 @@ function initSearch(rawSearchIndex) { currentTab = 0; } + if (results.query.correction !== null) { + output += "

Showing results for " + + `"${results.query.correction}".

`; + } + const resultsElem = document.createElement("div"); resultsElem.id = "results"; resultsElem.appendChild(ret_others[0]); @@ -2108,6 +2078,34 @@ function initSearch(rawSearchIndex) { filterCrates); } + /** + * Add an item to the type Name->ID map, or, if one already exists, use it. + * Returns the number. If name is "" or null, return -1 (pure generic). + * + * This is effectively string interning, so that function matching can be + * done more quickly. Two types with the same name but different item kinds + * get the same ID. + * + * @param {Map} typeNameIdMap + * @param {string} name + * + * @returns {integer} + */ + function buildTypeMapIndex(typeNameIdMap, name) { + + if (name === "" || name === null) { + return -1; + } + + if (typeNameIdMap.has(name)) { + return typeNameIdMap.get(name); + } else { + const id = typeNameIdMap.size; + typeNameIdMap.set(name, id); + return id; + } + } + /** * Convert a list of RawFunctionType / ID to object-based FunctionType. * @@ -2126,7 +2124,7 @@ function initSearch(rawSearchIndex) { * * @return {Array} */ - function buildItemSearchTypeAll(types, lowercasePaths) { + function buildItemSearchTypeAll(types, lowercasePaths, typeNameIdMap) { const PATH_INDEX_DATA = 0; const GENERICS_DATA = 1; return types.map(type => { @@ -2136,11 +2134,17 @@ function initSearch(rawSearchIndex) { generics = []; } else { pathIndex = type[PATH_INDEX_DATA]; - generics = buildItemSearchTypeAll(type[GENERICS_DATA], lowercasePaths); + generics = buildItemSearchTypeAll( + type[GENERICS_DATA], + lowercasePaths, + typeNameIdMap + ); } return { // `0` is used as a sentinel because it's fewer bytes than `null` - name: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].name, + id: pathIndex === 0 + ? -1 + : buildTypeMapIndex(typeNameIdMap, lowercasePaths[pathIndex - 1].name), ty: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].ty, generics: generics, }; @@ -2159,10 +2163,11 @@ function initSearch(rawSearchIndex) { * * @param {RawFunctionSearchType} functionSearchType * @param {Array<{name: string, ty: number}>} lowercasePaths + * @param {Map} * * @return {null|FunctionSearchType} */ - function buildFunctionSearchType(functionSearchType, lowercasePaths) { + function buildFunctionSearchType(functionSearchType, lowercasePaths, typeNameIdMap) { const INPUTS_DATA = 0; const OUTPUT_DATA = 1; // `0` is used as a sentinel because it's fewer bytes than `null` @@ -2173,23 +2178,35 @@ function initSearch(rawSearchIndex) { if (typeof functionSearchType[INPUTS_DATA] === "number") { const pathIndex = functionSearchType[INPUTS_DATA]; inputs = [{ - name: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].name, + id: pathIndex === 0 + ? -1 + : buildTypeMapIndex(typeNameIdMap, lowercasePaths[pathIndex - 1].name), ty: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].ty, generics: [], }]; } else { - inputs = buildItemSearchTypeAll(functionSearchType[INPUTS_DATA], lowercasePaths); + inputs = buildItemSearchTypeAll( + functionSearchType[INPUTS_DATA], + lowercasePaths, + typeNameIdMap + ); } if (functionSearchType.length > 1) { if (typeof functionSearchType[OUTPUT_DATA] === "number") { const pathIndex = functionSearchType[OUTPUT_DATA]; output = [{ - name: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].name, + id: pathIndex === 0 + ? -1 + : buildTypeMapIndex(typeNameIdMap, lowercasePaths[pathIndex - 1].name), ty: pathIndex === 0 ? null : lowercasePaths[pathIndex - 1].ty, generics: [], }]; } else { - output = buildItemSearchTypeAll(functionSearchType[OUTPUT_DATA], lowercasePaths); + output = buildItemSearchTypeAll( + functionSearchType[OUTPUT_DATA], + lowercasePaths, + typeNameIdMap + ); } } else { output = []; @@ -2202,9 +2219,12 @@ function initSearch(rawSearchIndex) { function buildIndex(rawSearchIndex) { searchIndex = []; /** + * List of normalized search words (ASCII lowercased, and undescores removed). + * * @type {Array} */ const searchWords = []; + typeNameIdMap = new Map(); const charA = "A".charCodeAt(0); let currentIndex = 0; let id = 0; @@ -2337,7 +2357,11 @@ function initSearch(rawSearchIndex) { path: itemPaths.has(i) ? itemPaths.get(i) : lastPath, desc: itemDescs[i], parent: itemParentIdxs[i] > 0 ? paths[itemParentIdxs[i] - 1] : undefined, - type: buildFunctionSearchType(itemFunctionSearchTypes[i], lowercasePaths), + type: buildFunctionSearchType( + itemFunctionSearchTypes[i], + lowercasePaths, + typeNameIdMap + ), id: id, normalizedName: word.indexOf("_") === -1 ? word : word.replace(/_/g, ""), deprecated: deprecatedItems.has(i), diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 6b9a9b66a7d9e..270704ebffde6 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -226,6 +226,24 @@ function runSearch(query, expected, doSearch, loadedFile, queryName) { return error_text; } +function runCorrections(query, corrections, getCorrections, loadedFile) { + const qc = getCorrections(query, loadedFile.FILTER_CRATE); + const error_text = []; + + if (corrections === null) { + if (qc !== null) { + error_text.push(`==> expected = null, found = ${qc}`); + } + return error_text; + } + + if (qc !== corrections.toLowerCase()) { + error_text.push(`==> expected = ${corrections}, found = ${qc}`); + } + + return error_text; +} + function checkResult(error_text, loadedFile, displaySuccess) { if (error_text.length === 0 && loadedFile.should_fail === true) { console.log("FAILED"); @@ -272,9 +290,10 @@ function runCheck(loadedFile, key, callback) { return 0; } -function runChecks(testFile, doSearch, parseQuery) { +function runChecks(testFile, doSearch, parseQuery, getCorrections) { let checkExpected = false; let checkParsed = false; + let checkCorrections = false; let testFileContent = readFile(testFile) + "exports.QUERY = QUERY;"; if (testFileContent.indexOf("FILTER_CRATE") !== -1) { @@ -291,9 +310,13 @@ function runChecks(testFile, doSearch, parseQuery) { testFileContent += "exports.PARSED = PARSED;"; checkParsed = true; } - if (!checkParsed && !checkExpected) { + if (testFileContent.indexOf("\nconst CORRECTIONS") !== -1) { + testFileContent += "exports.CORRECTIONS = CORRECTIONS;"; + checkCorrections = true; + } + if (!checkParsed && !checkExpected && !checkCorrections) { console.log("FAILED"); - console.log("==> At least `PARSED` or `EXPECTED` is needed!"); + console.log("==> At least `PARSED`, `EXPECTED`, or `CORRECTIONS` is needed!"); return 1; } @@ -310,6 +333,11 @@ function runChecks(testFile, doSearch, parseQuery) { return runParser(query, expected, parseQuery, text); }); } + if (checkCorrections) { + res += runCheck(loadedFile, "CORRECTIONS", (query, expected) => { + return runCorrections(query, expected, getCorrections, loadedFile); + }); + } return res; } @@ -318,9 +346,10 @@ function runChecks(testFile, doSearch, parseQuery) { * * @param {string} doc_folder - Path to a folder generated by running rustdoc * @param {string} resource_suffix - Version number between filename and .js, e.g. "1.59.0" - * @returns {Object} - Object containing two keys: `doSearch`, which runs a search - * with the loaded index and returns a table of results; and `parseQuery`, which is the - * `parseQuery` function exported from the search module. + * @returns {Object} - Object containing keys: `doSearch`, which runs a search + * with the loaded index and returns a table of results; `parseQuery`, which is the + * `parseQuery` function exported from the search module; and `getCorrections`, which runs + * a search but returns type name corrections instead of results. */ function loadSearchJS(doc_folder, resource_suffix) { const searchIndexJs = path.join(doc_folder, "search-index" + resource_suffix + ".js"); @@ -336,6 +365,12 @@ function loadSearchJS(doc_folder, resource_suffix) { return searchModule.execQuery(searchModule.parseQuery(queryStr), searchWords, filterCrate, currentCrate); }, + getCorrections: function(queryStr, filterCrate, currentCrate) { + const parsedQuery = searchModule.parseQuery(queryStr); + searchModule.execQuery(parsedQuery, searchWords, + filterCrate, currentCrate); + return parsedQuery.correction; + }, parseQuery: searchModule.parseQuery, }; } @@ -417,11 +452,14 @@ function main(argv) { const doSearch = function(queryStr, filterCrate) { return parseAndSearch.doSearch(queryStr, filterCrate, opts["crate_name"]); }; + const getCorrections = function(queryStr, filterCrate) { + return parseAndSearch.getCorrections(queryStr, filterCrate, opts["crate_name"]); + }; if (opts["test_file"].length !== 0) { opts["test_file"].forEach(file => { process.stdout.write(`Testing ${file} ... `); - errors += runChecks(file, doSearch, parseAndSearch.parseQuery); + errors += runChecks(file, doSearch, parseAndSearch.parseQuery, getCorrections); }); } else if (opts["test_folder"].length !== 0) { fs.readdirSync(opts["test_folder"]).forEach(file => { @@ -430,7 +468,7 @@ function main(argv) { } process.stdout.write(`Testing ${file} ... `); errors += runChecks(path.join(opts["test_folder"], file), doSearch, - parseAndSearch.parseQuery); + parseAndSearch.parseQuery, getCorrections); }); } return errors > 0 ? 1 : 0; diff --git a/tests/rustdoc-gui/search-corrections.goml b/tests/rustdoc-gui/search-corrections.goml new file mode 100644 index 0000000000000..832aa15305468 --- /dev/null +++ b/tests/rustdoc-gui/search-corrections.goml @@ -0,0 +1,54 @@ +// Checks that the search tab result tell the user about corrections +// First, try a search-by-name +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +// Intentionally wrong spelling of "NotableStructWithLongName" +write: (".search-input", "NotableStructWithLongNamr") +// To be SURE that the search will be run. +press-key: 'Enter' +// Waiting for the search results to appear... +wait-for: "#search-tabs" + +// Corrections aren't shown on the "In Names" tab. +assert: "#search-tabs button.selected:first-child" +assert-css: (".search-corrections", { + "display": "none" +}) + +// Corrections do get shown on the "In Parameters" tab. +click: "#search-tabs button:nth-child(2)" +assert: "#search-tabs button.selected:nth-child(2)" +assert-css: (".search-corrections", { + "display": "block" +}) +assert-text: ( + ".search-corrections", + "Showing results for \"notablestructwithlongname\"." +) + +// Corrections do get shown on the "In Return Type" tab. +click: "#search-tabs button:nth-child(3)" +assert: "#search-tabs button.selected:nth-child(3)" +assert-css: (".search-corrections", { + "display": "block" +}) +assert-text: ( + ".search-corrections", + "Showing results for \"notablestructwithlongname\"." +) + +// Now, explicit return values +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +// Intentionally wrong spelling of "NotableStructWithLongName" +write: (".search-input", "-> NotableStructWithLongNamr") +// To be SURE that the search will be run. +press-key: 'Enter' +// Waiting for the search results to appear... +wait-for: "#search-tabs" + +assert-css: (".search-corrections", { + "display": "block" +}) +assert-text: ( + ".search-corrections", + "Showing results for \"notablestructwithlongname\"." +) diff --git a/tests/rustdoc-js/generics-trait.js b/tests/rustdoc-js/generics-trait.js index 7876622435b60..0e84751603ed6 100644 --- a/tests/rustdoc-js/generics-trait.js +++ b/tests/rustdoc-js/generics-trait.js @@ -1,9 +1,21 @@ +// exact-check + const QUERY = [ 'Result', + 'Result', + 'OtherThingxxxxxxxx', + 'OtherThingxxxxxxxy', +]; + +const CORRECTIONS = [ + null, + null, + null, 'OtherThingxxxxxxxx', ]; const EXPECTED = [ + // Result { 'in_args': [ { 'path': 'generics_trait', 'name': 'beta' }, @@ -12,6 +24,21 @@ const EXPECTED = [ { 'path': 'generics_trait', 'name': 'bet' }, ], }, + // Result + { + 'in_args': [], + 'returned': [], + }, + // OtherThingxxxxxxxx + { + 'in_args': [ + { 'path': 'generics_trait', 'name': 'alpha' }, + ], + 'returned': [ + { 'path': 'generics_trait', 'name': 'alef' }, + ], + }, + // OtherThingxxxxxxxy { 'in_args': [ { 'path': 'generics_trait', 'name': 'alpha' }, From 1ece1ea48c0d9e4c8414abf872626f7a54747976 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Mon, 27 Mar 2023 10:42:22 -0700 Subject: [PATCH 07/14] Stablize raw-dylib, link_ordinal and -Cdlltool --- compiler/rustc_codegen_llvm/messages.ftl | 2 +- .../rustc_codegen_llvm/src/back/archive.rs | 12 ++++--- compiler/rustc_codegen_llvm/src/errors.rs | 3 +- .../rustc_codegen_ssa/src/codegen_attrs.rs | 9 ----- compiler/rustc_feature/src/accepted.rs | 2 ++ compiler/rustc_feature/src/active.rs | 2 -- compiler/rustc_interface/src/tests.rs | 2 +- compiler/rustc_metadata/src/native_libs.rs | 18 ---------- compiler/rustc_session/src/options.rs | 4 +-- src/doc/rustc/src/codegen-options/index.md | 8 +++++ .../src/language-features/raw-dylib.md | 34 ------------------ src/tools/compiletest/src/header/needs.rs | 36 ++++++++++++++++--- .../raw-dylib-alt-calling-convention/lib.rs | 1 - tests/run-make/raw-dylib-c/lib.rs | 2 -- .../raw-dylib-cross-compilation/lib.rs | 1 - .../raw-dylib-custom-dlltool/Makefile | 11 ++++++ .../run-make/raw-dylib-custom-dlltool/lib.rs | 10 ++++++ .../raw-dylib-custom-dlltool/output.txt | 1 + .../raw-dylib-custom-dlltool/script.cmd | 2 ++ .../raw-dylib-import-name-type/driver.rs | 1 - .../raw-dylib-inline-cross-dylib/driver.rs | 2 -- .../raw-dylib-inline-cross-dylib/lib.rs | 2 -- tests/run-make/raw-dylib-link-ordinal/lib.rs | 2 -- .../run-make/raw-dylib-stdcall-ordinal/lib.rs | 2 -- .../feature-gates/feature-gate-raw-dylib-2.rs | 12 ------- .../feature-gate-raw-dylib-2.stderr | 21 ----------- ...feature-gate-raw-dylib-import-name-type.rs | 8 ----- ...ure-gate-raw-dylib-import-name-type.stderr | 21 ----------- .../feature-gates/feature-gate-raw-dylib.rs | 7 ---- .../feature-gate-raw-dylib.stderr | 12 ------- tests/ui/rfc-2627-raw-dylib/dlltool-failed.rs | 19 ++++++++++ .../rfc-2627-raw-dylib/dlltool-failed.stderr | 5 +++ .../import-name-type-invalid-format.rs | 2 -- .../import-name-type-invalid-format.stderr | 2 +- .../import-name-type-multiple.rs | 2 -- .../import-name-type-multiple.stderr | 2 +- .../import-name-type-unknown-value.rs | 2 -- .../import-name-type-unknown-value.stderr | 2 +- .../import-name-type-unsupported-link-kind.rs | 2 -- ...ort-name-type-unsupported-link-kind.stderr | 4 +-- .../ui/rfc-2627-raw-dylib/invalid-dlltool.rs | 13 +++++++ .../rfc-2627-raw-dylib/invalid-dlltool.stderr | 4 +++ .../link-ordinal-and-name.rs | 2 -- .../link-ordinal-and-name.stderr | 4 +-- .../link-ordinal-invalid-format.rs | 2 -- .../link-ordinal-invalid-format.stderr | 4 +-- .../link-ordinal-missing-argument.rs | 2 -- .../link-ordinal-missing-argument.stderr | 4 +-- .../link-ordinal-multiple.rs | 2 -- .../link-ordinal-multiple.stderr | 8 ++--- .../link-ordinal-not-foreign-fn.rs | 2 -- .../link-ordinal-not-foreign-fn.stderr | 6 ++-- .../link-ordinal-too-large.rs | 2 -- .../link-ordinal-too-large.stderr | 4 +-- .../link-ordinal-too-many-arguments.rs | 2 -- .../link-ordinal-too-many-arguments.stderr | 4 +-- .../link-ordinal-unsupported-link-kind.rs | 2 -- .../link-ordinal-unsupported-link-kind.stderr | 4 +-- .../multiple-declarations.rs | 1 - .../multiple-declarations.stderr | 2 +- .../raw-dylib-windows-only.rs | 1 - .../raw-dylib-windows-only.stderr | 2 +- 62 files changed, 146 insertions(+), 223 deletions(-) delete mode 100644 src/doc/unstable-book/src/language-features/raw-dylib.md create mode 100644 tests/run-make/raw-dylib-custom-dlltool/Makefile create mode 100644 tests/run-make/raw-dylib-custom-dlltool/lib.rs create mode 100644 tests/run-make/raw-dylib-custom-dlltool/output.txt create mode 100644 tests/run-make/raw-dylib-custom-dlltool/script.cmd delete mode 100644 tests/ui/feature-gates/feature-gate-raw-dylib-2.rs delete mode 100644 tests/ui/feature-gates/feature-gate-raw-dylib-2.stderr delete mode 100644 tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs delete mode 100644 tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr delete mode 100644 tests/ui/feature-gates/feature-gate-raw-dylib.rs delete mode 100644 tests/ui/feature-gates/feature-gate-raw-dylib.stderr create mode 100644 tests/ui/rfc-2627-raw-dylib/dlltool-failed.rs create mode 100644 tests/ui/rfc-2627-raw-dylib/dlltool-failed.stderr create mode 100644 tests/ui/rfc-2627-raw-dylib/invalid-dlltool.rs create mode 100644 tests/ui/rfc-2627-raw-dylib/invalid-dlltool.stderr diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index b6d7484bccefd..2e3adc0866931 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -24,7 +24,7 @@ codegen_llvm_error_writing_def_file = Error writing .DEF file: {$error} codegen_llvm_error_calling_dlltool = - Error calling dlltool: {$error} + Error calling dlltool '{$dlltool_path}': {$error} codegen_llvm_dlltool_fail_import_library = Dlltool could not create import library: {$stdout} diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 12da21dc47772..a6416e9540cc0 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -198,7 +198,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { "arm" => ("arm", "--32"), _ => panic!("unsupported arch {}", sess.target.arch), }; - let result = std::process::Command::new(dlltool) + let result = std::process::Command::new(&dlltool) .args([ "-d", def_file_path.to_str().unwrap(), @@ -218,9 +218,13 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { match result { Err(e) => { - sess.emit_fatal(ErrorCallingDllTool { error: e }); + sess.emit_fatal(ErrorCallingDllTool { + dlltool_path: dlltool.to_string_lossy(), + error: e, + }); } - Ok(output) if !output.status.success() => { + // dlltool returns '0' on failure, so check for error output instead. + Ok(output) if !output.stderr.is_empty() => { sess.emit_fatal(DlltoolFailImportLibrary { stdout: String::from_utf8_lossy(&output.stdout), stderr: String::from_utf8_lossy(&output.stderr), @@ -431,7 +435,7 @@ fn string_to_io_error(s: String) -> io::Error { fn find_binutils_dlltool(sess: &Session) -> OsString { assert!(sess.target.options.is_like_windows && !sess.target.options.is_like_msvc); - if let Some(dlltool_path) = &sess.opts.unstable_opts.dlltool { + if let Some(dlltool_path) = &sess.opts.cg.dlltool { return dlltool_path.clone().into_os_string(); } diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index bae88d942934c..672087de31555 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -67,7 +67,8 @@ pub(crate) struct ErrorWritingDEFFile { #[derive(Diagnostic)] #[diag(codegen_llvm_error_calling_dlltool)] -pub(crate) struct ErrorCallingDllTool { +pub(crate) struct ErrorCallingDllTool<'a> { + pub dlltool_path: Cow<'a, str>, pub error: std::io::Error, } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 8542bab689d6d..87d42a89a8207 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -594,15 +594,6 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool { fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option { use rustc_ast::{LitIntType, LitKind, MetaItemLit}; - if !tcx.features().raw_dylib && tcx.sess.target.arch == "x86" { - feature_err( - &tcx.sess.parse_sess, - sym::raw_dylib, - attr.span, - "`#[link_ordinal]` is unstable on x86", - ) - .emit(); - } let meta_item_list = attr.meta_item_list(); let meta_item_list = meta_item_list.as_deref(); let sole_meta_list = match meta_item_list { diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 3d644de166526..1c9ef342fecc3 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -278,6 +278,8 @@ declare_features! ( (accepted, pub_restricted, "1.18.0", Some(32409), None), /// Allows use of the postfix `?` operator in expressions. (accepted, question_mark, "1.13.0", Some(31436), None), + /// Allows the use of raw-dylibs (RFC 2627). + (accepted, raw_dylib, "CURRENT_RUSTC_VERSION", Some(58713), None), /// Allows keywords to be escaped for use as identifiers. (accepted, raw_identifiers, "1.30.0", Some(48589), None), /// Allows relaxing the coherence rules such that diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 48f5bd1cb5048..68f511cf8b848 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -485,8 +485,6 @@ declare_features! ( (active, precise_pointer_size_matching, "1.32.0", Some(56354), None), /// Allows macro attributes on expressions, statements and non-inline modules. (active, proc_macro_hygiene, "1.30.0", Some(54727), None), - /// Allows the use of raw-dylibs (RFC 2627). - (active, raw_dylib, "1.65.0", Some(58713), None), /// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions. (active, raw_ref_op, "1.41.0", Some(64490), None), /// Allows using the `#[register_tool]` attribute. diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 10dfd32d418a2..efac621d947e4 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -547,6 +547,7 @@ fn test_codegen_options_tracking_hash() { untracked!(ar, String::from("abc")); untracked!(codegen_units, Some(42)); untracked!(default_linker_libraries, true); + untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe"))); untracked!(extra_filename, String::from("extra-filename")); untracked!(incremental, Some(String::from("abc"))); // `link_arg` is omitted because it just forwards to `link_args`. @@ -651,7 +652,6 @@ fn test_unstable_options_tracking_hash() { untracked!(assert_incr_state, Some(String::from("loaded"))); untracked!(deduplicate_diagnostics, false); untracked!(dep_tasks, true); - untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe"))); untracked!(dont_buffer_diagnostics, true); untracked!(dump_dep_graph, true); untracked!(dump_drop_tracking_cfg, Some("cfg.dot".to_string())); diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index b855c8e433266..d3ad32752c62f 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -161,14 +161,6 @@ impl<'tcx> Collector<'tcx> { "raw-dylib" => { if !sess.target.is_like_windows { sess.emit_err(errors::FrameworkOnlyWindows { span }); - } else if !features.raw_dylib && sess.target.arch == "x86" { - feature_err( - &sess.parse_sess, - sym::raw_dylib, - span, - "link kind `raw-dylib` is unstable on x86", - ) - .emit(); } NativeLibKind::RawDylib } @@ -251,16 +243,6 @@ impl<'tcx> Collector<'tcx> { continue; } }; - if !features.raw_dylib { - let span = item.name_value_literal_span().unwrap(); - feature_err( - &sess.parse_sess, - sym::raw_dylib, - span, - "import name type is unstable", - ) - .emit(); - } import_name_type = Some((link_import_name_type, item.span())); } _ => { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 631dd0a2146e8..d43e87f795006 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1235,6 +1235,8 @@ options! { line-tables-only, limited, or full; default: 0)"), default_linker_libraries: bool = (false, parse_bool, [UNTRACKED], "allow the linker to link its default libraries (default: no)"), + dlltool: Option = (None, parse_opt_pathbuf, [UNTRACKED], + "import library generation tool (ignored except when targeting windows-gnu)"), embed_bitcode: bool = (true, parse_bool, [TRACKED], "emit bitcode in rlibs (default: yes)"), extra_filename: String = (String::new(), parse_string, [UNTRACKED], @@ -1391,8 +1393,6 @@ options! { (default: no)"), diagnostic_width: Option = (None, parse_opt_number, [UNTRACKED], "set the current output width for diagnostic truncation"), - dlltool: Option = (None, parse_opt_pathbuf, [UNTRACKED], - "import library generation tool (windows-gnu only)"), dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED], "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) \ (default: no)"), diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index d7c6a884fc8fb..b7fa7243cc1c0 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -90,6 +90,14 @@ It takes one of the following values: For example, for gcc flavor linkers, this issues the `-nodefaultlibs` flag to the linker. +## dlltool + +On `windows-gnu` targets, this flag controls which dlltool `rustc` invokes to +generate import libraries when using the [`raw-dylib` link kind](../../reference/items/external-blocks.md#the-link-attribute). +It takes a path to [the dlltool executable](https://sourceware.org/binutils/docs/binutils/dlltool.html). +If this flag is not specified, a dlltool executable will be inferred based on +the host environment and target. + ## embed-bitcode This flag controls whether or not the compiler embeds LLVM bitcode into object diff --git a/src/doc/unstable-book/src/language-features/raw-dylib.md b/src/doc/unstable-book/src/language-features/raw-dylib.md deleted file mode 100644 index 5fd208ae7571c..0000000000000 --- a/src/doc/unstable-book/src/language-features/raw-dylib.md +++ /dev/null @@ -1,34 +0,0 @@ -# `raw_dylib` - -The tracking issue for this feature is: [#58713] - -[#58713]: https://github.com/rust-lang/rust/issues/58713 - ------------------------- - -The `raw_dylib` feature allows you to link against the implementations of functions in an `extern` -block without, on Windows, linking against an import library. - -```rust,ignore (partial-example) -#![feature(raw_dylib)] - -#[link(name="library", kind="raw-dylib")] -extern { - fn extern_function(x: i32); -} - -fn main() { - unsafe { - extern_function(14); - } -} -``` - -## Limitations - -This feature is unstable for the `x86` architecture, and stable for all other architectures. - -This feature is only supported on Windows. - -On the `x86` architecture, this feature supports only the `cdecl`, `stdcall`, `system`, `fastcall`, and -`vectorcall` calling conventions. diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs index 81179480ed810..4a57c61406ce4 100644 --- a/src/tools/compiletest/src/header/needs.rs +++ b/src/tools/compiletest/src/header/needs.rs @@ -115,6 +115,11 @@ pub(super) fn handle_needs( condition: cache.x86_64_dlltool, ignore_reason: "ignored when dlltool for x86_64 is not present", }, + Need { + name: "needs-dlltool", + condition: cache.dlltool, + ignore_reason: "ignored when dlltool for the current architecture is not present", + }, Need { name: "needs-git-hash", condition: config.git_hash, @@ -183,6 +188,7 @@ pub(super) struct CachedNeedsConditions { rust_lld: bool, i686_dlltool: bool, x86_64_dlltool: bool, + dlltool: bool, } impl CachedNeedsConditions { @@ -190,6 +196,17 @@ impl CachedNeedsConditions { let path = std::env::var_os("PATH").expect("missing PATH environment variable"); let path = std::env::split_paths(&path).collect::>(); + // On Windows, dlltool.exe is used for all architectures. + #[cfg(windows)] + let dlltool = path.iter().any(|dir| dir.join("dlltool.exe").is_file()); + + // For non-Windows, there are architecture specific dlltool binaries. + #[cfg(not(windows))] + let i686_dlltool = path.iter().any(|dir| dir.join("i686-w64-mingw32-dlltool").is_file()); + #[cfg(not(windows))] + let x86_64_dlltool = + path.iter().any(|dir| dir.join("x86_64-w64-mingw32-dlltool").is_file()); + let target = &&*config.target; Self { sanitizer_support: std::env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(), @@ -225,17 +242,26 @@ impl CachedNeedsConditions { .join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" }) .exists(), - // On Windows, dlltool.exe is used for all architectures. #[cfg(windows)] - i686_dlltool: path.iter().any(|dir| dir.join("dlltool.exe").is_file()), + i686_dlltool: dlltool, #[cfg(windows)] - x86_64_dlltool: path.iter().any(|dir| dir.join("dlltool.exe").is_file()), + x86_64_dlltool: dlltool, + #[cfg(windows)] + dlltool, // For non-Windows, there are architecture specific dlltool binaries. #[cfg(not(windows))] - i686_dlltool: path.iter().any(|dir| dir.join("i686-w64-mingw32-dlltool").is_file()), + i686_dlltool, + #[cfg(not(windows))] + x86_64_dlltool, #[cfg(not(windows))] - x86_64_dlltool: path.iter().any(|dir| dir.join("x86_64-w64-mingw32-dlltool").is_file()), + dlltool: if config.matches_arch("x86") { + i686_dlltool + } else if config.matches_arch("x86_64") { + x86_64_dlltool + } else { + false + }, } } } diff --git a/tests/run-make/raw-dylib-alt-calling-convention/lib.rs b/tests/run-make/raw-dylib-alt-calling-convention/lib.rs index 22f222c12c39b..dcb5fee9ecc76 100644 --- a/tests/run-make/raw-dylib-alt-calling-convention/lib.rs +++ b/tests/run-make/raw-dylib-alt-calling-convention/lib.rs @@ -1,5 +1,4 @@ #![feature(abi_vectorcall)] -#![cfg_attr(target_arch = "x86", feature(raw_dylib))] #[repr(C)] #[derive(Clone)] diff --git a/tests/run-make/raw-dylib-c/lib.rs b/tests/run-make/raw-dylib-c/lib.rs index 5fb1204037c93..f17125f308c20 100644 --- a/tests/run-make/raw-dylib-c/lib.rs +++ b/tests/run-make/raw-dylib-c/lib.rs @@ -1,5 +1,3 @@ -#![feature(raw_dylib)] - #[link(name = "extern_1.dll", kind = "raw-dylib", modifiers = "+verbatim")] extern { fn extern_fn_1(); diff --git a/tests/run-make/raw-dylib-cross-compilation/lib.rs b/tests/run-make/raw-dylib-cross-compilation/lib.rs index 51bf2ec6b6e11..3338ac0a0b50f 100644 --- a/tests/run-make/raw-dylib-cross-compilation/lib.rs +++ b/tests/run-make/raw-dylib-cross-compilation/lib.rs @@ -1,4 +1,3 @@ -#![feature(raw_dylib)] #![feature(no_core, lang_items)] #![no_std] #![no_core] diff --git a/tests/run-make/raw-dylib-custom-dlltool/Makefile b/tests/run-make/raw-dylib-custom-dlltool/Makefile new file mode 100644 index 0000000000000..f5d5360a3fbe8 --- /dev/null +++ b/tests/run-make/raw-dylib-custom-dlltool/Makefile @@ -0,0 +1,11 @@ +# Test using -Cdlltool to change where raw-dylib looks for the dlltool binary. + +# only-windows +# only-gnu +# needs-dlltool + +include ../tools.mk + +all: + $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs -Cdlltool=$(CURDIR)/script.cmd + $(DIFF) output.txt "$(TMPDIR)"/output.txt diff --git a/tests/run-make/raw-dylib-custom-dlltool/lib.rs b/tests/run-make/raw-dylib-custom-dlltool/lib.rs new file mode 100644 index 0000000000000..2f3f497a00de1 --- /dev/null +++ b/tests/run-make/raw-dylib-custom-dlltool/lib.rs @@ -0,0 +1,10 @@ +#[link(name = "extern_1", kind = "raw-dylib")] +extern { + fn extern_fn_1(); +} + +pub fn library_function() { + unsafe { + extern_fn_1(); + } +} diff --git a/tests/run-make/raw-dylib-custom-dlltool/output.txt b/tests/run-make/raw-dylib-custom-dlltool/output.txt new file mode 100644 index 0000000000000..6dd9466d26ddc --- /dev/null +++ b/tests/run-make/raw-dylib-custom-dlltool/output.txt @@ -0,0 +1 @@ +Called dlltool via script.cmd diff --git a/tests/run-make/raw-dylib-custom-dlltool/script.cmd b/tests/run-make/raw-dylib-custom-dlltool/script.cmd new file mode 100644 index 0000000000000..95f85c61c67d2 --- /dev/null +++ b/tests/run-make/raw-dylib-custom-dlltool/script.cmd @@ -0,0 +1,2 @@ +echo Called dlltool via script.cmd> %TMPDIR%\output.txt +dlltool.exe %* diff --git a/tests/run-make/raw-dylib-import-name-type/driver.rs b/tests/run-make/raw-dylib-import-name-type/driver.rs index 9a3cd9ebe1b4b..6c1c212f187b7 100644 --- a/tests/run-make/raw-dylib-import-name-type/driver.rs +++ b/tests/run-make/raw-dylib-import-name-type/driver.rs @@ -1,4 +1,3 @@ -#![feature(raw_dylib)] #![feature(abi_vectorcall)] #[link(name = "extern", kind = "raw-dylib", import_name_type = "undecorated")] diff --git a/tests/run-make/raw-dylib-inline-cross-dylib/driver.rs b/tests/run-make/raw-dylib-inline-cross-dylib/driver.rs index f72ded7d9f638..0c3125be6f596 100644 --- a/tests/run-make/raw-dylib-inline-cross-dylib/driver.rs +++ b/tests/run-make/raw-dylib-inline-cross-dylib/driver.rs @@ -1,5 +1,3 @@ -#![feature(raw_dylib)] - extern crate raw_dylib_test; extern crate raw_dylib_test_wrapper; diff --git a/tests/run-make/raw-dylib-inline-cross-dylib/lib.rs b/tests/run-make/raw-dylib-inline-cross-dylib/lib.rs index 00c2c1c42d15f..4877cb80aea5e 100644 --- a/tests/run-make/raw-dylib-inline-cross-dylib/lib.rs +++ b/tests/run-make/raw-dylib-inline-cross-dylib/lib.rs @@ -1,5 +1,3 @@ -#![feature(raw_dylib)] - #[link(name = "extern_1", kind = "raw-dylib")] extern { fn extern_fn_1(); diff --git a/tests/run-make/raw-dylib-link-ordinal/lib.rs b/tests/run-make/raw-dylib-link-ordinal/lib.rs index bb25ac64c613b..1bbb45bbc7725 100644 --- a/tests/run-make/raw-dylib-link-ordinal/lib.rs +++ b/tests/run-make/raw-dylib-link-ordinal/lib.rs @@ -1,5 +1,3 @@ -#![cfg_attr(target_arch = "x86", feature(raw_dylib))] - #[link(name = "exporter", kind = "raw-dylib")] extern { #[link_ordinal(13)] diff --git a/tests/run-make/raw-dylib-stdcall-ordinal/lib.rs b/tests/run-make/raw-dylib-stdcall-ordinal/lib.rs index b7921396a0f4d..74c5c7f8250b2 100644 --- a/tests/run-make/raw-dylib-stdcall-ordinal/lib.rs +++ b/tests/run-make/raw-dylib-stdcall-ordinal/lib.rs @@ -1,5 +1,3 @@ -#![cfg_attr(target_arch = "x86", feature(raw_dylib))] - #[link(name = "exporter", kind = "raw-dylib")] extern "stdcall" { #[link_ordinal(15)] diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib-2.rs b/tests/ui/feature-gates/feature-gate-raw-dylib-2.rs deleted file mode 100644 index fc47a9061d3c0..0000000000000 --- a/tests/ui/feature-gates/feature-gate-raw-dylib-2.rs +++ /dev/null @@ -1,12 +0,0 @@ -// only-x86 -#[link(name = "foo")] -extern "C" { - #[link_ordinal(42)] - //~^ ERROR: `#[link_ordinal]` is unstable on x86 - fn foo(); - #[link_ordinal(5)] - //~^ ERROR: `#[link_ordinal]` is unstable on x86 - static mut imported_variable: i32; -} - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib-2.stderr b/tests/ui/feature-gates/feature-gate-raw-dylib-2.stderr deleted file mode 100644 index 0e900760d245e..0000000000000 --- a/tests/ui/feature-gates/feature-gate-raw-dylib-2.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0658]: `#[link_ordinal]` is unstable on x86 - --> $DIR/feature-gate-raw-dylib-2.rs:4:5 - | -LL | #[link_ordinal(42)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #58713 for more information - = help: add `#![feature(raw_dylib)]` to the crate attributes to enable - -error[E0658]: `#[link_ordinal]` is unstable on x86 - --> $DIR/feature-gate-raw-dylib-2.rs:7:5 - | -LL | #[link_ordinal(5)] - | ^^^^^^^^^^^^^^^^^^ - | - = note: see issue #58713 for more information - = help: add `#![feature(raw_dylib)]` to the crate attributes to enable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs b/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs deleted file mode 100644 index 295f502d6a3e5..0000000000000 --- a/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.rs +++ /dev/null @@ -1,8 +0,0 @@ -// only-windows -// only-x86 -#[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")] -//~^ ERROR link kind `raw-dylib` is unstable on x86 -//~| ERROR import name type is unstable -extern "C" {} - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr b/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr deleted file mode 100644 index d6b165b7610a5..0000000000000 --- a/tests/ui/feature-gates/feature-gate-raw-dylib-import-name-type.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error[E0658]: link kind `raw-dylib` is unstable on x86 - --> $DIR/feature-gate-raw-dylib-import-name-type.rs:3:29 - | -LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")] - | ^^^^^^^^^^^ - | - = note: see issue #58713 for more information - = help: add `#![feature(raw_dylib)]` to the crate attributes to enable - -error[E0658]: import name type is unstable - --> $DIR/feature-gate-raw-dylib-import-name-type.rs:3:61 - | -LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated")] - | ^^^^^^^^^^^ - | - = note: see issue #58713 for more information - = help: add `#![feature(raw_dylib)]` to the crate attributes to enable - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib.rs b/tests/ui/feature-gates/feature-gate-raw-dylib.rs deleted file mode 100644 index 291cca8fd2573..0000000000000 --- a/tests/ui/feature-gates/feature-gate-raw-dylib.rs +++ /dev/null @@ -1,7 +0,0 @@ -// only-windows -// only-x86 -#[link(name = "foo", kind = "raw-dylib")] -//~^ ERROR: link kind `raw-dylib` is unstable on x86 -extern "C" {} - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-raw-dylib.stderr b/tests/ui/feature-gates/feature-gate-raw-dylib.stderr deleted file mode 100644 index f02241e4908c0..0000000000000 --- a/tests/ui/feature-gates/feature-gate-raw-dylib.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: link kind `raw-dylib` is unstable on x86 - --> $DIR/feature-gate-raw-dylib.rs:3:29 - | -LL | #[link(name = "foo", kind = "raw-dylib")] - | ^^^^^^^^^^^ - | - = note: see issue #58713 for more information - = help: add `#![feature(raw_dylib)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/rfc-2627-raw-dylib/dlltool-failed.rs b/tests/ui/rfc-2627-raw-dylib/dlltool-failed.rs new file mode 100644 index 0000000000000..d7a418959bf51 --- /dev/null +++ b/tests/ui/rfc-2627-raw-dylib/dlltool-failed.rs @@ -0,0 +1,19 @@ +// Tests that dlltool failing to generate an import library will raise an error. + +// only-gnu +// only-windows +// needs-dlltool +// compile-flags: --crate-type lib --emit link +// normalize-stderr-test: "[^ ']*/dlltool.exe" -> "$$DLLTOOL" +// normalize-stderr-test: "[^ ]*/foo.def" -> "$$DEF_FILE" +#[link(name = "foo", kind = "raw-dylib")] +extern "C" { + // `@1` is an invalid name to export, as it usually indicates that something + // is being exported via ordinal. + #[link_name = "@1"] + fn f(x: i32); +} + +pub fn lib_main() { + unsafe { f(42); } +} diff --git a/tests/ui/rfc-2627-raw-dylib/dlltool-failed.stderr b/tests/ui/rfc-2627-raw-dylib/dlltool-failed.stderr new file mode 100644 index 0000000000000..020ac6a2b670b --- /dev/null +++ b/tests/ui/rfc-2627-raw-dylib/dlltool-failed.stderr @@ -0,0 +1,5 @@ +error: Dlltool could not create import library: + $DLLTOOL: Syntax error in def file $DEF_FILE:1 + +error: aborting due to previous error + diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs b/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs index 22d57f8bedddc..7bc44d65be9e5 100644 --- a/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs +++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.rs @@ -1,7 +1,5 @@ // only-windows // only-x86 -#![feature(raw_dylib)] - #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] //~^ ERROR import name type must be of the form `import_name_type = "string"` extern "C" { } diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr b/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr index 0e95fec29d257..fb70b987fc7d9 100644 --- a/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr +++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-invalid-format.stderr @@ -1,5 +1,5 @@ error: import name type must be of the form `import_name_type = "string"` - --> $DIR/import-name-type-invalid-format.rs:5:42 + --> $DIR/import-name-type-invalid-format.rs:3:42 | LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs b/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs index 7ccb0082fb976..b96f61a26da8b 100644 --- a/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs +++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.rs @@ -1,8 +1,6 @@ // ignore-tidy-linelength // only-windows // only-x86 -#![feature(raw_dylib)] - #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")] //~^ ERROR multiple `import_name_type` arguments in a single `#[link]` attribute extern "C" { } diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr b/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr index 7c0e0be911f73..9533061892fee 100644 --- a/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr +++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-multiple.stderr @@ -1,5 +1,5 @@ error: multiple `import_name_type` arguments in a single `#[link]` attribute - --> $DIR/import-name-type-multiple.rs:6:74 + --> $DIR/import-name-type-multiple.rs:4:74 | LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "decorated", import_name_type = "decorated")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs b/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs index f728a578d3b8a..067e82a17fdc5 100644 --- a/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs +++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.rs @@ -1,7 +1,5 @@ // only-windows // only-x86 -#![feature(raw_dylib)] - #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] //~^ ERROR unknown import name type `unknown`, expected one of: decorated, noprefix, undecorated extern "C" { } diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr b/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr index 2b299f2fea316..2bce9758e997c 100644 --- a/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr +++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-unknown-value.stderr @@ -1,5 +1,5 @@ error: unknown import name type `unknown`, expected one of: decorated, noprefix, undecorated - --> $DIR/import-name-type-unknown-value.rs:5:42 + --> $DIR/import-name-type-unknown-value.rs:3:42 | LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = "unknown")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs b/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs index ae9207864a2ae..34e907bde839a 100644 --- a/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs +++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.rs @@ -1,7 +1,5 @@ // only-windows // only-x86 -#![feature(raw_dylib)] - #[link(name = "foo", import_name_type = "decorated")] //~^ ERROR import name type can only be used with link kind `raw-dylib` extern "C" { } diff --git a/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr b/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr index 5898cd875a1c8..75cadc471c437 100644 --- a/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr +++ b/tests/ui/rfc-2627-raw-dylib/import-name-type-unsupported-link-kind.stderr @@ -1,11 +1,11 @@ error: import name type can only be used with link kind `raw-dylib` - --> $DIR/import-name-type-unsupported-link-kind.rs:5:22 + --> $DIR/import-name-type-unsupported-link-kind.rs:3:22 | LL | #[link(name = "foo", import_name_type = "decorated")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: import name type can only be used with link kind `raw-dylib` - --> $DIR/import-name-type-unsupported-link-kind.rs:9:39 + --> $DIR/import-name-type-unsupported-link-kind.rs:7:39 | LL | #[link(name = "bar", kind = "static", import_name_type = "decorated")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.rs b/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.rs new file mode 100644 index 0000000000000..a07be9d92b4ed --- /dev/null +++ b/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.rs @@ -0,0 +1,13 @@ +// Tests that failing to run dlltool will raise an error. + +// only-gnu +// only-windows +// compile-flags: --crate-type lib --emit link -Cdlltool=does_not_exit.exe +#[link(name = "foo", kind = "raw-dylib")] +extern "C" { + fn f(x: i32); +} + +pub fn lib_main() { + unsafe { f(42); } +} diff --git a/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.stderr b/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.stderr new file mode 100644 index 0000000000000..3ae901e0dbc94 --- /dev/null +++ b/tests/ui/rfc-2627-raw-dylib/invalid-dlltool.stderr @@ -0,0 +1,4 @@ +error: Error calling dlltool 'does_not_exit.exe': program not found + +error: aborting due to previous error + diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs index 1a128c87a0c30..b04c2facbcdf3 100644 --- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs +++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs @@ -1,5 +1,3 @@ -#![cfg_attr(target_arch = "x86", feature(raw_dylib))] - #[link(name="foo")] extern "C" { #[link_name="foo"] diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr index 481a06d2797d5..f1e54d37827c0 100644 --- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr +++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr @@ -1,11 +1,11 @@ error: cannot use `#[link_name]` with `#[link_ordinal]` - --> $DIR/link-ordinal-and-name.rs:6:5 + --> $DIR/link-ordinal-and-name.rs:4:5 | LL | #[link_ordinal(42)] | ^^^^^^^^^^^^^^^^^^^ error: cannot use `#[link_name]` with `#[link_ordinal]` - --> $DIR/link-ordinal-and-name.rs:10:5 + --> $DIR/link-ordinal-and-name.rs:8:5 | LL | #[link_ordinal(5)] | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs index 7c8da050cf624..9b7e8d70743b7 100644 --- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs +++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs @@ -1,5 +1,3 @@ -#![cfg_attr(target_arch = "x86", feature(raw_dylib))] - #[link(name = "foo")] extern "C" { #[link_ordinal("JustMonika")] diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr index 55cdcad75a4ad..6341e57a0be53 100644 --- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr +++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr @@ -1,5 +1,5 @@ error: illegal ordinal format in `link_ordinal` - --> $DIR/link-ordinal-invalid-format.rs:5:5 + --> $DIR/link-ordinal-invalid-format.rs:3:5 | LL | #[link_ordinal("JustMonika")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[link_ordinal("JustMonika")] = note: an unsuffixed integer value, e.g., `1`, is expected error: illegal ordinal format in `link_ordinal` - --> $DIR/link-ordinal-invalid-format.rs:8:5 + --> $DIR/link-ordinal-invalid-format.rs:6:5 | LL | #[link_ordinal("JustMonika")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs index 9feed39411046..6b8cd49566dfe 100644 --- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs +++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs @@ -1,5 +1,3 @@ -#![cfg_attr(target_arch = "x86", feature(raw_dylib))] - #[link(name = "foo")] extern "C" { #[link_ordinal()] diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr index 853cdad8c1c54..1b04bb228e76a 100644 --- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr +++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr @@ -1,5 +1,5 @@ error: incorrect number of arguments to `#[link_ordinal]` - --> $DIR/link-ordinal-missing-argument.rs:5:5 + --> $DIR/link-ordinal-missing-argument.rs:3:5 | LL | #[link_ordinal()] | ^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[link_ordinal()] = note: the attribute requires exactly one argument error: incorrect number of arguments to `#[link_ordinal]` - --> $DIR/link-ordinal-missing-argument.rs:8:5 + --> $DIR/link-ordinal-missing-argument.rs:6:5 | LL | #[link_ordinal()] | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs index 631c363d4ba15..8842cb944045f 100644 --- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs +++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs @@ -1,6 +1,4 @@ // only-windows -#![cfg_attr(target_arch = "x86", feature(raw_dylib))] - #[link(name = "foo", kind = "raw-dylib")] extern "C" { #[link_ordinal(1)] //~ ERROR multiple `link_ordinal` attributes diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr index c0453d2bf0118..2e6cf3761c2f0 100644 --- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr +++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr @@ -1,23 +1,23 @@ error: multiple `link_ordinal` attributes - --> $DIR/link-ordinal-multiple.rs:6:5 + --> $DIR/link-ordinal-multiple.rs:4:5 | LL | #[link_ordinal(1)] | ^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/link-ordinal-multiple.rs:7:5 + --> $DIR/link-ordinal-multiple.rs:5:5 | LL | #[link_ordinal(2)] | ^^^^^^^^^^^^^^^^^^ error: multiple `link_ordinal` attributes - --> $DIR/link-ordinal-multiple.rs:9:5 + --> $DIR/link-ordinal-multiple.rs:7:5 | LL | #[link_ordinal(1)] | ^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here - --> $DIR/link-ordinal-multiple.rs:10:5 + --> $DIR/link-ordinal-multiple.rs:8:5 | LL | #[link_ordinal(2)] | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs index 54e614164b3a5..f33a3d62e2688 100644 --- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs +++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs @@ -1,5 +1,3 @@ -#![cfg_attr(target_arch = "x86", feature(raw_dylib))] - #[link_ordinal(123)] //~^ ERROR attribute should be applied to a foreign function or static struct Foo {} diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr index ec4104fbe5000..8f279508720ce 100644 --- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr +++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr @@ -1,17 +1,17 @@ error: attribute should be applied to a foreign function or static - --> $DIR/link-ordinal-not-foreign-fn.rs:3:1 + --> $DIR/link-ordinal-not-foreign-fn.rs:1:1 | LL | #[link_ordinal(123)] | ^^^^^^^^^^^^^^^^^^^^ error: attribute should be applied to a foreign function or static - --> $DIR/link-ordinal-not-foreign-fn.rs:7:1 + --> $DIR/link-ordinal-not-foreign-fn.rs:5:1 | LL | #[link_ordinal(123)] | ^^^^^^^^^^^^^^^^^^^^ error: attribute should be applied to a foreign function or static - --> $DIR/link-ordinal-not-foreign-fn.rs:11:1 + --> $DIR/link-ordinal-not-foreign-fn.rs:9:1 | LL | #[link_ordinal(42)] | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs index 46731581ebcb0..9d741630fc9da 100644 --- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs +++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs @@ -1,5 +1,3 @@ -#![cfg_attr(target_arch = "x86", feature(raw_dylib))] - #[link(name = "foo")] extern "C" { #[link_ordinal(72436)] diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr index fef6de6aedfe4..811145e77ee46 100644 --- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr +++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr @@ -1,5 +1,5 @@ error: ordinal value in `link_ordinal` is too large: `72436` - --> $DIR/link-ordinal-too-large.rs:5:5 + --> $DIR/link-ordinal-too-large.rs:3:5 | LL | #[link_ordinal(72436)] | ^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[link_ordinal(72436)] = note: the value may not exceed `u16::MAX` error: ordinal value in `link_ordinal` is too large: `72436` - --> $DIR/link-ordinal-too-large.rs:8:5 + --> $DIR/link-ordinal-too-large.rs:6:5 | LL | #[link_ordinal(72436)] | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs index 71e0ac9f3ee4b..9988115fd8b0d 100644 --- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs +++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs @@ -1,5 +1,3 @@ -#![cfg_attr(target_arch = "x86", feature(raw_dylib))] - #[link(name = "foo")] extern "C" { #[link_ordinal(3, 4)] diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr index 7e0fcd845cbde..d5ce8aff34f20 100644 --- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr +++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr @@ -1,5 +1,5 @@ error: incorrect number of arguments to `#[link_ordinal]` - --> $DIR/link-ordinal-too-many-arguments.rs:5:5 + --> $DIR/link-ordinal-too-many-arguments.rs:3:5 | LL | #[link_ordinal(3, 4)] | ^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[link_ordinal(3, 4)] = note: the attribute requires exactly one argument error: incorrect number of arguments to `#[link_ordinal]` - --> $DIR/link-ordinal-too-many-arguments.rs:8:5 + --> $DIR/link-ordinal-too-many-arguments.rs:6:5 | LL | #[link_ordinal(3, 4)] | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs b/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs index 329c93fc19637..14e915d602aaa 100644 --- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs +++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs @@ -1,5 +1,3 @@ -#![cfg_attr(target_arch = "x86", feature(raw_dylib))] - #[link(name = "foo")] extern "C" { #[link_ordinal(3)] diff --git a/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr b/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr index 5fbffbda570af..200b8f6287465 100644 --- a/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr +++ b/tests/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr @@ -1,11 +1,11 @@ error: `#[link_ordinal]` is only supported if link kind is `raw-dylib` - --> $DIR/link-ordinal-unsupported-link-kind.rs:5:5 + --> $DIR/link-ordinal-unsupported-link-kind.rs:3:5 | LL | #[link_ordinal(3)] | ^^^^^^^^^^^^^^^^^^ error: `#[link_ordinal]` is only supported if link kind is `raw-dylib` - --> $DIR/link-ordinal-unsupported-link-kind.rs:12:5 + --> $DIR/link-ordinal-unsupported-link-kind.rs:10:5 | LL | #[link_ordinal(3)] | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rfc-2627-raw-dylib/multiple-declarations.rs b/tests/ui/rfc-2627-raw-dylib/multiple-declarations.rs index 6542faad26412..b4173f3b60bce 100644 --- a/tests/ui/rfc-2627-raw-dylib/multiple-declarations.rs +++ b/tests/ui/rfc-2627-raw-dylib/multiple-declarations.rs @@ -2,7 +2,6 @@ // only-windows // compile-flags: --crate-type lib --emit link #![allow(clashing_extern_declarations)] -#![feature(raw_dylib)] #[link(name = "foo", kind = "raw-dylib")] extern "C" { fn f(x: i32); diff --git a/tests/ui/rfc-2627-raw-dylib/multiple-declarations.stderr b/tests/ui/rfc-2627-raw-dylib/multiple-declarations.stderr index c6808bec7b5c5..5101084054882 100644 --- a/tests/ui/rfc-2627-raw-dylib/multiple-declarations.stderr +++ b/tests/ui/rfc-2627-raw-dylib/multiple-declarations.stderr @@ -1,5 +1,5 @@ error: multiple declarations of external function `f` from library `foo.dll` have different calling conventions - --> $DIR/multiple-declarations.rs:14:9 + --> $DIR/multiple-declarations.rs:13:9 | LL | fn f(x: i32); | ^^^^^^^^^^^^^ diff --git a/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs b/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs index 4efffbd532e13..d4c6658a33024 100644 --- a/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs +++ b/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.rs @@ -1,6 +1,5 @@ // ignore-windows // compile-flags: --crate-type lib -#![cfg_attr(target_arch = "x86", feature(raw_dylib))] #[link(name = "foo", kind = "raw-dylib")] //~^ ERROR: link kind `raw-dylib` is only supported on Windows targets extern "C" {} diff --git a/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr b/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr index 14e791f1fb9a1..b635a09afba4e 100644 --- a/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr +++ b/tests/ui/rfc-2627-raw-dylib/raw-dylib-windows-only.stderr @@ -1,5 +1,5 @@ error[E0455]: link kind `raw-dylib` is only supported on Windows targets - --> $DIR/raw-dylib-windows-only.rs:4:29 + --> $DIR/raw-dylib-windows-only.rs:3:29 | LL | #[link(name = "foo", kind = "raw-dylib")] | ^^^^^^^^^^^ From b6f81e04347d9dbd29e59e7dbca3f9289ddb2fe3 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Wed, 19 Apr 2023 10:16:14 -0700 Subject: [PATCH 08/14] rustdoc-search: give longer notification for type corrections --- src/librustdoc/html/static/js/search.js | 9 +++++++-- tests/rustdoc-gui/search-corrections.goml | 6 +++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 2d0a3f0192bd0..1bee6987739a4 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1996,8 +1996,13 @@ function initSearch(rawSearchIndex) { } if (results.query.correction !== null) { - output += "

Showing results for " + - `"${results.query.correction}".

`; + const orig = results.query.returned.length > 0 + ? results.query.returned[0].name + : results.query.elems[0].name; + output += "

" + + `Type "${orig}" not found. ` + + "Showing results for " + + `"${results.query.correction}" instead.

`; } const resultsElem = document.createElement("div"); diff --git a/tests/rustdoc-gui/search-corrections.goml b/tests/rustdoc-gui/search-corrections.goml index 832aa15305468..323dd658426c1 100644 --- a/tests/rustdoc-gui/search-corrections.goml +++ b/tests/rustdoc-gui/search-corrections.goml @@ -22,7 +22,7 @@ assert-css: (".search-corrections", { }) assert-text: ( ".search-corrections", - "Showing results for \"notablestructwithlongname\"." + "Type \"notablestructwithlongnamr\" not found. Showing results for \"notablestructwithlongname\" instead." ) // Corrections do get shown on the "In Return Type" tab. @@ -33,7 +33,7 @@ assert-css: (".search-corrections", { }) assert-text: ( ".search-corrections", - "Showing results for \"notablestructwithlongname\"." + "Type \"notablestructwithlongnamr\" not found. Showing results for \"notablestructwithlongname\" instead." ) // Now, explicit return values @@ -50,5 +50,5 @@ assert-css: (".search-corrections", { }) assert-text: ( ".search-corrections", - "Showing results for \"notablestructwithlongname\"." + "Type \"notablestructwithlongnamr\" not found. Showing results for \"notablestructwithlongname\" instead." ) From e0a7462d2f6a14c15c77950539b127f7e4f3c4f6 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 20 Apr 2023 12:17:43 -0700 Subject: [PATCH 09/14] rustdoc-search: clean up `checkIfInGenerics` call at end of `checkType` --- src/librustdoc/html/static/js/search.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 1bee6987739a4..74d9af14fa7c5 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1227,11 +1227,7 @@ function initSearch(rawSearchIndex) { // If the current item does not match, try [unboxing] the generic. // [unboxing]: // https://ndmitchell.com/downloads/slides-hoogle_fast_type_searching-09_aug_2008.pdf - if (checkIfInGenerics(row, elem)) { - return true; - } - - return false; + return checkIfInGenerics(row, elem); } /** From 7529d874075df61209d3aa61b7072ba1714f4a17 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 20 Apr 2023 12:34:17 -0700 Subject: [PATCH 10/14] rustdoc-search: make type name correction choice deterministic --- src/librustdoc/html/static/js/search.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 74d9af14fa7c5..71568cd700c2d 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -1609,6 +1609,9 @@ function initSearch(rawSearchIndex) { for (const [name, id] of typeNameIdMap) { const dist = editDistance(name, elem.name, maxEditDistance); if (dist <= matchDist && dist <= maxEditDistance) { + if (dist === matchDist && matchName > name) { + continue; + } match = id; matchDist = dist; matchName = name; From 395840cd5e0d349ff33a2b0adb01d13848de4d0f Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 20 Apr 2023 14:32:02 -0700 Subject: [PATCH 11/14] rustdoc-search: use more descriptive "x not found; y instead" message --- src/librustdoc/html/static/js/search.js | 2 +- tests/rustdoc-gui/search-corrections.goml | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 71568cd700c2d..92e5f4089366f 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2000,7 +2000,7 @@ function initSearch(rawSearchIndex) { : results.query.elems[0].name; output += "

" + `Type "${orig}" not found. ` + - "Showing results for " + + "Showing results for closest type name " + `"${results.query.correction}" instead.

`; } diff --git a/tests/rustdoc-gui/search-corrections.goml b/tests/rustdoc-gui/search-corrections.goml index 323dd658426c1..5d1b83b35c5ee 100644 --- a/tests/rustdoc-gui/search-corrections.goml +++ b/tests/rustdoc-gui/search-corrections.goml @@ -1,3 +1,5 @@ +// ignore-tidy-linelength + // Checks that the search tab result tell the user about corrections // First, try a search-by-name go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" @@ -22,7 +24,7 @@ assert-css: (".search-corrections", { }) assert-text: ( ".search-corrections", - "Type \"notablestructwithlongnamr\" not found. Showing results for \"notablestructwithlongname\" instead." + "Type \"notablestructwithlongnamr\" not found. Showing results for closest type name \"notablestructwithlongname\" instead." ) // Corrections do get shown on the "In Return Type" tab. @@ -33,7 +35,7 @@ assert-css: (".search-corrections", { }) assert-text: ( ".search-corrections", - "Type \"notablestructwithlongnamr\" not found. Showing results for \"notablestructwithlongname\" instead." + "Type \"notablestructwithlongnamr\" not found. Showing results for closest type name \"notablestructwithlongname\" instead." ) // Now, explicit return values @@ -50,5 +52,5 @@ assert-css: (".search-corrections", { }) assert-text: ( ".search-corrections", - "Type \"notablestructwithlongnamr\" not found. Showing results for \"notablestructwithlongname\" instead." + "Type \"notablestructwithlongnamr\" not found. Showing results for closest type name \"notablestructwithlongname\" instead." ) From d5e7ac53c7c4034f31cfc2fa4f0f7bded19ec8d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Apr 2023 14:27:17 +0200 Subject: [PATCH 12/14] avoid duplicating TLS state between test std and realstd --- .../std/src/sys/common/thread_local/mod.rs | 5 +++ .../src/sys/common/thread_local/os_local.rs | 2 +- library/std/src/thread/mod.rs | 32 +++++++++---------- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/library/std/src/sys/common/thread_local/mod.rs b/library/std/src/sys/common/thread_local/mod.rs index a7528c06c9de2..17c085cc92ccb 100644 --- a/library/std/src/sys/common/thread_local/mod.rs +++ b/library/std/src/sys/common/thread_local/mod.rs @@ -1,5 +1,10 @@ #![unstable(feature = "thread_local_internals", reason = "should not be necessary", issue = "none")] +// There are three thread-local implementations: "static", "fast", "OS". +// The "OS" thread local key type is accessed via platform-specific API calls and is slow, while the +// "fast" key type is accessed via code generated via LLVM, where TLS keys are set up by the linker. +// "static" is for single-threaded platforms where a global static is sufficient. + cfg_if::cfg_if! { if #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))] { #[doc(hidden)] diff --git a/library/std/src/sys/common/thread_local/os_local.rs b/library/std/src/sys/common/thread_local/os_local.rs index e9516f9983f2a..6b01f6e44d38b 100644 --- a/library/std/src/sys/common/thread_local/os_local.rs +++ b/library/std/src/sys/common/thread_local/os_local.rs @@ -18,7 +18,7 @@ pub macro thread_local_inner { ) -> $crate::option::Option<&'static $t> { const INIT_EXPR: $t = $init; - // On platforms without `#[thread_local]` we fall back to the + // On platforms without `#[thread_local]` we fall back to the // same implementation as below for os thread locals. #[inline] const fn __init() -> $t { INIT_EXPR } diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 9cdc17a287c96..f712c872708ac 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -193,22 +193,22 @@ pub use scoped::{scope, Scope, ScopedJoinHandle}; #[macro_use] mod local; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::local::{AccessError, LocalKey}; - -// Provide the type used by the thread_local! macro to access TLS keys. This -// needs to be kept in sync with the macro itself (in `local.rs`). -// There are three types: "static", "fast", "OS". The "OS" thread local key -// type is accessed via platform-specific API calls and is slow, while the "fast" -// key type is accessed via code generated via LLVM, where TLS keys are set up -// by the elf linker. "static" is for single-threaded platforms where a global -// static is sufficient. - -// Implementation details used by the thread_local!{} macro. -#[doc(hidden)] -#[unstable(feature = "thread_local_internals", issue = "none")] -pub mod local_impl { - pub use crate::sys::common::thread_local::{thread_local_inner, Key}; +cfg_if::cfg_if! { + if #[cfg(test)] { + // Avoid duplicating the global state assoicated with thread-locals between this crate and + // realstd. Miri relies on this. + pub use realstd::thread::{local_impl, AccessError, LocalKey}; + } else { + #[stable(feature = "rust1", since = "1.0.0")] + pub use self::local::{AccessError, LocalKey}; + + // Implementation details used by the thread_local!{} macro. + #[doc(hidden)] + #[unstable(feature = "thread_local_internals", issue = "none")] + pub mod local_impl { + pub use crate::sys::common::thread_local::{thread_local_inner, Key}; + } + } } //////////////////////////////////////////////////////////////////////////////// From ed468eebf6e852b80eeed6997c67444268795faa Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 30 Apr 2023 21:52:35 +0000 Subject: [PATCH 13/14] Encode def span for foreign RPITITs --- compiler/rustc_metadata/src/rmeta/encoder.rs | 3 ++- tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs | 4 ++-- tests/ui/impl-trait/in-trait/foreign-dyn-error.rs | 8 ++++++++ .../impl-trait/in-trait/foreign-dyn-error.stderr | 15 +++++++++++++++ tests/ui/impl-trait/in-trait/foreign.rs | 9 +++++---- 5 files changed, 32 insertions(+), 7 deletions(-) create mode 100644 tests/ui/impl-trait/in-trait/foreign-dyn-error.rs create mode 100644 tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index f5ffdd27cae3f..479bac9b2aaeb 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -837,11 +837,12 @@ fn should_encode_span(def_kind: DefKind) -> bool { | DefKind::AnonConst | DefKind::InlineConst | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder | DefKind::Field | DefKind::Impl { .. } | DefKind::Closure | DefKind::Generator => true, - DefKind::ForeignMod | DefKind::ImplTraitPlaceholder | DefKind::GlobalAsm => false, + DefKind::ForeignMod | DefKind::GlobalAsm => false, } } diff --git a/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs index ffeabe5c2edab..776006124dccf 100644 --- a/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs +++ b/tests/ui/impl-trait/in-trait/auxiliary/rpitit.rs @@ -5,10 +5,10 @@ use std::ops::Deref; pub trait Foo { - fn bar() -> impl Deref; + fn bar(self) -> impl Deref; } pub struct Foreign; impl Foo for Foreign { - fn bar() -> &'static () { &() } + fn bar(self) -> &'static () { &() } } diff --git a/tests/ui/impl-trait/in-trait/foreign-dyn-error.rs b/tests/ui/impl-trait/in-trait/foreign-dyn-error.rs new file mode 100644 index 0000000000000..ecb5e62c433a0 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/foreign-dyn-error.rs @@ -0,0 +1,8 @@ +// aux-build: rpitit.rs + +extern crate rpitit; + +fn main() { + let _: &dyn rpitit::Foo = todo!(); + //~^ ERROR the trait `Foo` cannot be made into an object +} diff --git a/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr b/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr new file mode 100644 index 0000000000000..6eef392c05f01 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr @@ -0,0 +1,15 @@ +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/foreign-dyn-error.rs:6:12 + | +LL | let _: &dyn rpitit::Foo = todo!(); + | ^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/auxiliary/rpitit.rs:8:21 + | +LL | fn bar(self) -> impl Deref; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait cannot be made into an object because method `bar` references an `impl Trait` type in its return type + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/impl-trait/in-trait/foreign.rs b/tests/ui/impl-trait/in-trait/foreign.rs index f4972d948b246..98417b343a11e 100644 --- a/tests/ui/impl-trait/in-trait/foreign.rs +++ b/tests/ui/impl-trait/in-trait/foreign.rs @@ -5,17 +5,18 @@ extern crate rpitit; +use rpitit::{Foo, Foreign}; use std::sync::Arc; // Implement an RPITIT from another crate. struct Local; -impl rpitit::Foo for Local { - fn bar() -> Arc { Arc::new(String::new()) } +impl Foo for Local { + fn bar(self) -> Arc { Arc::new(String::new()) } } fn main() { // Witness an RPITIT from another crate. - let &() = ::bar(); + let &() = Foreign.bar(); - let x: Arc = ::bar(); + let x: Arc = Local.bar(); } From bc68de94c87537edd43f22606d84e8a2ad48e413 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Mon, 1 May 2023 18:36:30 +0300 Subject: [PATCH 14/14] remove pointless `FIXME` in `bootstrap::download` The suggestion given by `FIXME` to use `CompilerMetadata` for `download_toolchain` in `bootstrap::download` can result in more confusion. This is because `stamp_key` is not always a date; it can also be a commit hash. Additionally, unlike in `download_beta_toolchain`, in the `download_ci_rustc` function, `version` and `commit` values are calculated separately. Signed-off-by: ozkanonur --- src/bootstrap/download.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs index c1cf9b93fb356..3e82a381a1b2d 100644 --- a/src/bootstrap/download.rs +++ b/src/bootstrap/download.rs @@ -427,7 +427,6 @@ impl Config { fn download_toolchain( &self, - // FIXME(ozkanonur) use CompilerMetadata instead of `version: &str` version: &str, sysroot: &str, stamp_key: &str,