Skip to content

Rollup of 5 pull requests #83897

New issue

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

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

Already on GitHub? Sign in to your account

Closed
wants to merge 14 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions compiler/rustc_errors/src/diagnostic_builder.rs
Original file line number Diff line number Diff line change
@@ -45,9 +45,6 @@ macro_rules! forward {
pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)?) -> &Self
) => {
$(#[$attrs])*
// we always document with --document-private-items
#[cfg_attr(not(bootstrap), allow(rustdoc::private_intra_doc_links))]
#[cfg_attr(bootstrap, allow(private_intra_doc_links))]
#[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")]
pub fn $n(&self, $($name: $ty),*) -> &Self {
self.diagnostic.$n($($name),*);
@@ -62,9 +59,6 @@ macro_rules! forward {
) => {
$(#[$attrs])*
#[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")]
// we always document with --document-private-items
#[cfg_attr(not(bootstrap), allow(rustdoc::private_intra_doc_links))]
#[cfg_attr(bootstrap, allow(private_intra_doc_links))]
pub fn $n(&mut self, $($name: $ty),*) -> &mut Self {
self.0.diagnostic.$n($($name),*);
self
@@ -82,9 +76,6 @@ macro_rules! forward {
) => {
$(#[$attrs])*
#[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")]
// we always document with --document-private-items
#[cfg_attr(not(bootstrap), allow(rustdoc::private_intra_doc_links))]
#[cfg_attr(bootstrap, allow(private_intra_doc_links))]
pub fn $n<$($generic: $bound),*>(&mut self, $($name: $ty),*) -> &mut Self {
self.0.diagnostic.$n($($name),*);
self
1 change: 1 addition & 0 deletions compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@
#![feature(nll)]
#![cfg_attr(bootstrap, feature(or_patterns))]
#![recursion_limit = "256"]
#![allow(rustdoc::private_intra_doc_links)]

pub use rustc_hir::def::{Namespace, PerNS};

13 changes: 13 additions & 0 deletions library/panic_abort/src/lib.rs
Original file line number Diff line number Diff line change
@@ -116,6 +116,19 @@ pub mod personalities {
)))]
pub extern "C" fn rust_eh_personality() {}

// On *-pc-windows-msvc we need such a symbol to make linker happy.
#[allow(non_snake_case)]
#[no_mangle]
#[cfg(all(target_os = "windows", target_env = "msvc"))]
pub extern "C" fn __CxxFrameHandler3(
_record: usize,
_frame: usize,
_context: usize,
_dispatcher: usize,
) -> u32 {
1
}

// On x86_64-pc-windows-gnu we use our own personality function that needs
// to return `ExceptionContinueSearch` as we're passing on all our frames.
#[rustc_std_internal_symbol]
3 changes: 1 addition & 2 deletions src/bootstrap/defaults/config.compiler.toml
Original file line number Diff line number Diff line change
@@ -8,6 +8,5 @@ debug-logging = true
incremental = true

[llvm]
# Will download LLVM from CI if available on your platform (Linux only for now)
# https://github.com/rust-lang/rust/issues/77084 tracks support for more platforms
# Will download LLVM from CI if available on your platform.
download-ci-llvm = "if-available"
16 changes: 16 additions & 0 deletions src/bootstrap/defaults/config.tools.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# These defaults are meant for contributors to tools which build on the
# compiler, but do not modify it directly.
[rust]
# This enables `RUSTC_LOG=debug`, avoiding confusing situations
# where adding `debug!()` appears to do nothing.
# However, it makes running the compiler slightly slower.
debug-logging = true
# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
incremental = true
# Download rustc from CI instead of building it from source.
# This cuts compile times by almost 60x, but means you can't modify the compiler.
download-rustc = "if-unchanged"

[llvm]
# Will download LLVM from CI if available on your platform.
download-ci-llvm = "if-available"
2 changes: 2 additions & 0 deletions src/bootstrap/doc.rs
Original file line number Diff line number Diff line change
@@ -549,6 +549,8 @@ impl Step for Rustc {
// Build cargo command.
let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "doc");
cargo.rustdocflag("--document-private-items");
// Since we always pass --document-private-items, there's no need to warn about linking to private items.
cargo.rustdocflag("-Arustdoc::private-intra-doc-links");
cargo.rustdocflag("--enable-index-page");
cargo.rustdocflag("-Zunstable-options");
cargo.rustdocflag("-Znormalize-docs");
20 changes: 17 additions & 3 deletions src/bootstrap/setup.rs
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ pub enum Profile {
Compiler,
Codegen,
Library,
Tools,
User,
}

@@ -24,15 +25,16 @@ impl Profile {
pub fn all() -> impl Iterator<Item = Self> {
use Profile::*;
// N.B. these are ordered by how they are displayed, not alphabetically
[Library, Compiler, Codegen, User].iter().copied()
[Library, Compiler, Codegen, Tools, User].iter().copied()
}

pub fn purpose(&self) -> String {
use Profile::*;
match self {
Library => "Contribute to the standard library",
Compiler => "Contribute to the compiler or rustdoc",
Compiler => "Contribute to the compiler itself",
Codegen => "Contribute to the compiler, and also modify LLVM or codegen",
Tools => "Contribute to tools which depend on the compiler, but do not modify it directly (e.g. rustdoc, clippy, miri)",
User => "Install Rust from source",
}
.to_string()
@@ -53,9 +55,12 @@ impl FromStr for Profile {
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"lib" | "library" => Ok(Profile::Library),
"compiler" | "rustdoc" => Ok(Profile::Compiler),
"compiler" => Ok(Profile::Compiler),
"llvm" | "codegen" => Ok(Profile::Codegen),
"maintainer" | "user" => Ok(Profile::User),
"tools" | "tool" | "rustdoc" | "clippy" | "miri" | "rustfmt" | "rls" => {
Ok(Profile::Tools)
}
_ => Err(format!("unknown profile: '{}'", s)),
}
}
@@ -68,6 +73,7 @@ impl fmt::Display for Profile {
Profile::Codegen => write!(f, "codegen"),
Profile::Library => write!(f, "library"),
Profile::User => write!(f, "user"),
Profile::Tools => write!(f, "tools"),
}
}
}
@@ -103,6 +109,14 @@ pub fn setup(src_path: &Path, profile: Profile) {

let suggestions = match profile {
Profile::Codegen | Profile::Compiler => &["check", "build", "test"][..],
Profile::Tools => &[
"check",
"build",
"test src/test/rustdoc*",
"test src/tools/clippy",
"test src/tools/miri",
"test src/tools/rustfmt",
],
Profile::Library => &["check", "build", "test library/std", "doc"],
Profile::User => &["dist", "build"],
};
237 changes: 102 additions & 135 deletions src/librustdoc/passes/collect_intra_doc_links.rs
Original file line number Diff line number Diff line change
@@ -368,55 +368,28 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
}

/// Given a primitive type, try to resolve an associated item.
///
/// HACK(jynelson): `item_str` is passed in instead of derived from `item_name` so the
/// lifetimes on `&'path` will work.
fn resolve_primitive_associated_item(
&self,
prim_ty: PrimitiveType,
ns: Namespace,
module_id: DefId,
item_name: Symbol,
item_str: &'path str,
) -> Result<(Res, Option<String>), ErrorKind<'path>> {
) -> Option<(Res, String, Option<(DefKind, DefId)>)> {
let tcx = self.cx.tcx;

prim_ty
.impls(tcx)
.into_iter()
.find_map(|&impl_| {
tcx.associated_items(impl_)
.find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, impl_)
.map(|item| {
let kind = item.kind;
self.kind_side_channel.set(Some((kind.as_def_kind(), item.def_id)));
match kind {
ty::AssocKind::Fn => "method",
ty::AssocKind::Const => "associatedconstant",
ty::AssocKind::Type => "associatedtype",
}
})
.map(|out| {
(
Res::Primitive(prim_ty),
Some(format!("{}#{}.{}", prim_ty.as_str(), out, item_str)),
)
})
})
.ok_or_else(|| {
debug!(
"returning primitive error for {}::{} in {} namespace",
prim_ty.as_str(),
item_name,
ns.descr()
);
ResolutionFailure::NotResolved {
module_id,
partial_res: Some(Res::Primitive(prim_ty)),
unresolved: item_str.into(),
}
.into()
})
prim_ty.impls(tcx).into_iter().find_map(|&impl_| {
tcx.associated_items(impl_)
.find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, impl_)
.map(|item| {
let kind = item.kind;
let out = match kind {
ty::AssocKind::Fn => "method",
ty::AssocKind::Const => "associatedconstant",
ty::AssocKind::Type => "associatedtype",
};
let fragment = format!("{}#{}.{}", prim_ty.as_str(), out, item_name);
(Res::Primitive(prim_ty), fragment, Some((kind.as_def_kind(), item.def_id)))
})
})
}

/// Resolves a string as a macro.
@@ -490,8 +463,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
module_id: DefId,
extra_fragment: &Option<String>,
) -> Result<(Res, Option<String>), ErrorKind<'path>> {
let tcx = self.cx.tcx;

if let Some(res) = self.resolve_path(path_str, ns, module_id) {
match res {
// FIXME(#76467): make this fallthrough to lookup the associated
@@ -534,29 +505,58 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
}
})?;

// FIXME: are these both necessary?
let ty_res = if let Some(ty_res) = resolve_primitive(&path_root, TypeNS)
// FIXME(#83862): this arbitrarily gives precedence to primitives over modules to support
// links to primitives when `#[doc(primitive)]` is present. It should give an ambiguity
// error instead and special case *only* modules with `#[doc(primitive)]`, not all
// primitives.
resolve_primitive(&path_root, TypeNS)
.or_else(|| self.resolve_path(&path_root, TypeNS, module_id))
{
ty_res
} else {
// FIXME: this is duplicated on the end of this function.
return if ns == Namespace::ValueNS {
self.variant_field(path_str, module_id)
} else {
Err(ResolutionFailure::NotResolved {
module_id,
partial_res: None,
unresolved: path_root.into(),
.and_then(|ty_res| {
let (res, fragment, side_channel) =
self.resolve_associated_item(ty_res, item_name, ns, module_id)?;
let result = if extra_fragment.is_some() {
let diag_res = side_channel.map_or(res, |(k, r)| Res::Def(k, r));
Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(diag_res)))
} else {
// HACK(jynelson): `clean` expects the type, not the associated item
// but the disambiguator logic expects the associated item.
// Store the kind in a side channel so that only the disambiguator logic looks at it.
if let Some((kind, id)) = side_channel {
self.kind_side_channel.set(Some((kind, id)));
}
Ok((res, Some(fragment)))
};
Some(result)
})
.unwrap_or_else(|| {
if ns == Namespace::ValueNS {
self.variant_field(path_str, module_id)
} else {
Err(ResolutionFailure::NotResolved {
module_id,
partial_res: None,
unresolved: path_root.into(),
}
.into())
}
.into())
};
};
})
}

/// Returns:
/// - None if no associated item was found
/// - Some((_, _, Some(_))) if an item was found and should go through a side channel
/// - Some((_, _, None)) otherwise
fn resolve_associated_item(
&mut self,
root_res: Res,
item_name: Symbol,
ns: Namespace,
module_id: DefId,
) -> Option<(Res, String, Option<(DefKind, DefId)>)> {
let tcx = self.cx.tcx;

let res = match ty_res {
Res::Primitive(prim) => Some(
self.resolve_primitive_associated_item(prim, ns, module_id, item_name, item_str),
),
match root_res {
Res::Primitive(prim) => self.resolve_primitive_associated_item(prim, ns, item_name),
Res::Def(
DefKind::Struct
| DefKind::Union
@@ -599,59 +599,42 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
ty::AssocKind::Const => "associatedconstant",
ty::AssocKind::Type => "associatedtype",
};
Some(if extra_fragment.is_some() {
Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res)))
} else {
// HACK(jynelson): `clean` expects the type, not the associated item
// but the disambiguator logic expects the associated item.
// Store the kind in a side channel so that only the disambiguator logic looks at it.
self.kind_side_channel.set(Some((kind.as_def_kind(), id)));
Ok((ty_res, Some(format!("{}.{}", out, item_str))))
})
} else if ns == Namespace::ValueNS {
debug!("looking for variants or fields named {} for {:?}", item_name, did);
// FIXME(jynelson): why is this different from
// `variant_field`?
match tcx.type_of(did).kind() {
ty::Adt(def, _) => {
let field = if def.is_enum() {
def.all_fields().find(|item| item.ident.name == item_name)
} else {
def.non_enum_variant()
.fields
.iter()
.find(|item| item.ident.name == item_name)
};
field.map(|item| {
if extra_fragment.is_some() {
let res = Res::Def(
if def.is_enum() {
DefKind::Variant
} else {
DefKind::Field
},
item.did,
);
Err(ErrorKind::AnchorFailure(
AnchorFailure::RustdocAnchorConflict(res),
))
} else {
Ok((
ty_res,
Some(format!(
"{}.{}",
if def.is_enum() { "variant" } else { "structfield" },
item.ident
)),
))
}
})
}
_ => None,
}
} else {
None
// HACK(jynelson): `clean` expects the type, not the associated item
// but the disambiguator logic expects the associated item.
// Store the kind in a side channel so that only the disambiguator logic looks at it.
return Some((
root_res,
format!("{}.{}", out, item_name),
Some((kind.as_def_kind(), id)),
));
}

if ns != Namespace::ValueNS {
return None;
}
debug!("looking for variants or fields named {} for {:?}", item_name, did);
// FIXME: this doesn't really belong in `associated_item` (maybe `variant_field` is better?)
// NOTE: it's different from variant_field because it resolves fields and variants,
// not variant fields (2 path segments, not 3).
let def = match tcx.type_of(did).kind() {
ty::Adt(def, _) => def,
_ => return None,
};
let field = if def.is_enum() {
def.all_fields().find(|item| item.ident.name == item_name)
} else {
def.non_enum_variant().fields.iter().find(|item| item.ident.name == item_name)
}?;
let kind = if def.is_enum() { DefKind::Variant } else { DefKind::Field };
Some((
root_res,
format!(
"{}.{}",
if def.is_enum() { "variant" } else { "structfield" },
field.ident
),
Some((kind, field.did)),
))
}
Res::Def(DefKind::Trait, did) => tcx
.associated_items(did)
@@ -669,27 +652,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
}
};

if extra_fragment.is_some() {
Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res)))
} else {
let res = Res::Def(item.kind.as_def_kind(), item.def_id);
Ok((res, Some(format!("{}.{}", kind, item_str))))
}
let res = Res::Def(item.kind.as_def_kind(), item.def_id);
(res, format!("{}.{}", kind, item_name), None)
}),
_ => None,
};
res.unwrap_or_else(|| {
if ns == Namespace::ValueNS {
self.variant_field(path_str, module_id)
} else {
Err(ResolutionFailure::NotResolved {
module_id,
partial_res: Some(ty_res),
unresolved: item_str.into(),
}
.into())
}
})
}
}

/// Used for reporting better errors.
18 changes: 13 additions & 5 deletions src/test/rustdoc-ui/intra-doc/private.private.stderr
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
warning: public documentation for `DocMe` links to private item `DontDocMe`
--> $DIR/private.rs:5:11
--> $DIR/private.rs:7:11
|
LL | /// docs [DontDocMe] [DontDocMe::f]
LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
| ^^^^^^^^^ this item is private
|
= note: `#[warn(rustdoc::private_intra_doc_links)]` on by default
= note: this link resolves only because you passed `--document-private-items`, but will break without

warning: public documentation for `DocMe` links to private item `DontDocMe::f`
--> $DIR/private.rs:5:23
--> $DIR/private.rs:7:23
|
LL | /// docs [DontDocMe] [DontDocMe::f]
LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
| ^^^^^^^^^^^^ this item is private
|
= note: this link resolves only because you passed `--document-private-items`, but will break without

warning: 2 warnings emitted
warning: public documentation for `DocMe` links to private item `DontDocMe::x`
--> $DIR/private.rs:7:38
|
LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
| ^^^^^^^^^^^^ this item is private
|
= note: this link resolves only because you passed `--document-private-items`, but will break without

warning: 3 warnings emitted

18 changes: 13 additions & 5 deletions src/test/rustdoc-ui/intra-doc/private.public.stderr
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
warning: public documentation for `DocMe` links to private item `DontDocMe`
--> $DIR/private.rs:5:11
--> $DIR/private.rs:7:11
|
LL | /// docs [DontDocMe] [DontDocMe::f]
LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
| ^^^^^^^^^ this item is private
|
= note: `#[warn(rustdoc::private_intra_doc_links)]` on by default
= note: this link will resolve properly if you pass `--document-private-items`

warning: public documentation for `DocMe` links to private item `DontDocMe::f`
--> $DIR/private.rs:5:23
--> $DIR/private.rs:7:23
|
LL | /// docs [DontDocMe] [DontDocMe::f]
LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
| ^^^^^^^^^^^^ this item is private
|
= note: this link will resolve properly if you pass `--document-private-items`

warning: 2 warnings emitted
warning: public documentation for `DocMe` links to private item `DontDocMe::x`
--> $DIR/private.rs:7:38
|
LL | /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
| ^^^^^^^^^^^^ this item is private
|
= note: this link will resolve properly if you pass `--document-private-items`

warning: 3 warnings emitted

10 changes: 7 additions & 3 deletions src/test/rustdoc-ui/intra-doc/private.rs
Original file line number Diff line number Diff line change
@@ -2,12 +2,16 @@
// revisions: public private
// [private]compile-flags: --document-private-items

/// docs [DontDocMe] [DontDocMe::f]
// make sure to update `rustdoc/intra-doc/private.rs` if you update this file

/// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
//~^ WARNING public documentation for `DocMe` links to private item `DontDocMe`
//~| WARNING public documentation for `DocMe` links to private item `DontDocMe::x`
//~| WARNING public documentation for `DocMe` links to private item `DontDocMe::f`
// FIXME: for [private] we should also make sure the link was actually generated
pub struct DocMe;
struct DontDocMe;
struct DontDocMe {
x: usize,
}

impl DontDocMe {
fn f() {}
15 changes: 13 additions & 2 deletions src/test/rustdoc/intra-doc/private.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
#![crate_name = "private"]
// compile-flags: --document-private-items
/// docs [DontDocMe]

// make sure to update `rustdoc-ui/intra-doc/private.rs` if you update this file

/// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
// @has private/struct.DocMe.html '//*a[@href="../private/struct.DontDocMe.html"]' 'DontDocMe'
// @has private/struct.DocMe.html '//*a[@href="../private/struct.DontDocMe.html#method.f"]' 'DontDocMe::f'
// @has private/struct.DocMe.html '//*a[@href="../private/struct.DontDocMe.html#structfield.x"]' 'DontDocMe::x'
pub struct DocMe;
struct DontDocMe;
struct DontDocMe {
x: usize,
}

impl DontDocMe {
fn f() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// build-pass
// compile-flags: -C panic=abort -C target-feature=+crt-static
// aux-build:exit-success-if-unwind-msvc-no-std.rs
// only-msvc
// Test that `no_std` with `panic=abort` under MSVC toolchain
// doesn't cause error when linking to libcmt.
// We don't run this executable because it will hang in `rust_begin_unwind`

#![no_std]
#![no_main]

extern crate exit_success_if_unwind_msvc_no_std;

use core::panic::PanicInfo;

#[panic_handler]
fn handle_panic(_: &PanicInfo) -> ! {
loop {}
}

#[link(name = "libcmt")]
extern "C" {}

#[no_mangle]
pub extern "C" fn main() -> i32 {
exit_success_if_unwind_msvc_no_std::bar(do_panic);
0
}

fn do_panic() {
panic!();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// build-pass
// compile-flags: -C panic=abort
// aux-build:exit-success-if-unwind-msvc-no-std.rs
// only-msvc
// Test that `no_std` with `panic=abort` under MSVC toolchain
// doesn't cause error when linking to msvcrt.
// We don't run this executable because it will hang in `rust_begin_unwind`

#![no_std]
#![no_main]

extern crate exit_success_if_unwind_msvc_no_std;

use core::panic::PanicInfo;

#[panic_handler]
fn handle_panic(_: &PanicInfo) -> ! {
loop {}
}

#[link(name = "msvcrt")]
extern "C" {}

#[no_mangle]
pub extern "C" fn main() -> i32 {
exit_success_if_unwind_msvc_no_std::bar(do_panic);
0
}

fn do_panic() {
panic!();
}
54 changes: 54 additions & 0 deletions src/test/ui/panic-runtime/abort-link-to-unwind-msvc-no-std.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// build-pass
// compile-flags:-C panic=abort
// aux-build:exit-success-if-unwind-msvc-no-std.rs
// no-prefer-dynamic
// only-msvc
// We don't run this executable because it will hang in `rust_begin_unwind`

#![no_std]
#![no_main]
#![windows_subsystem = "console"]
#![feature(panic_abort)]

extern crate exit_success_if_unwind_msvc_no_std;
extern crate panic_abort;

use core::panic::PanicInfo;

#[panic_handler]
fn handle_panic(_: &PanicInfo) -> ! {
loop {}
}

#[no_mangle]
pub unsafe extern "C" fn memcpy(dest: *mut u8, _src: *const u8, _n: usize) -> *mut u8 {
dest
}

#[no_mangle]
pub unsafe extern "C" fn memmove(dest: *mut u8, _src: *const u8, _n: usize) -> *mut u8 {
dest
}

#[no_mangle]
pub unsafe extern "C" fn memset(mem: *mut u8, _val: i32, _n: usize) -> *mut u8 {
mem
}

#[no_mangle]
pub unsafe extern "C" fn memcmp(_mem1: *const u8, _mem2: *const u8, _n: usize) -> i32 {
0
}

#[no_mangle]
#[used]
static _fltused: i32 = 0;

#[no_mangle]
pub extern "C" fn mainCRTStartup() {
exit_success_if_unwind_msvc_no_std::bar(main);
}

fn main() {
panic!();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// compile-flags:-C panic=unwind
// no-prefer-dynamic

#![no_std]
#![crate_type = "rlib"]

struct Bomb;

impl Drop for Bomb {
fn drop(&mut self) {
#[link(name = "kernel32")]
extern "C" {
fn ExitProcess(code: u32) -> !;
}
unsafe {
ExitProcess(0);
}
}
}

pub fn bar(f: fn()) {
let _bomb = Bomb;
f();
}
47 changes: 47 additions & 0 deletions src/test/ui/panic-runtime/unwind-msvc-no-std-link-to-libcmt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// build-pass
// compile-flags: -C panic=unwind -C target-feature=+crt-static
// only-msvc
// Test that `no_std` with `panic=unwind` under MSVC toolchain
// doesn't cause error when linking to libcmt.

#![no_std]
#![no_main]
#![feature(alloc_error_handler)]
#![feature(panic_unwind)]

use core::alloc::{GlobalAlloc, Layout};

struct DummyAllocator;

unsafe impl GlobalAlloc for DummyAllocator {
unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
core::ptr::null_mut()
}

unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
}

#[global_allocator]
static ALLOC: DummyAllocator = DummyAllocator;

#[alloc_error_handler]
fn rust_oom(_layout: Layout) -> ! {
panic!()
}

extern crate panic_unwind;

use core::panic::PanicInfo;

#[panic_handler]
fn handle_panic(_: &PanicInfo) -> ! {
loop {}
}

#[link(name = "libcmt")]
extern "C" {}

#[no_mangle]
pub extern "C" fn main() -> i32 {
panic!();
}
47 changes: 47 additions & 0 deletions src/test/ui/panic-runtime/unwind-msvc-no-std-link-to-msvcrt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// build-pass
// compile-flags: -C panic=unwind
// only-msvc
// Test that `no_std` with `panic=unwind` under MSVC toolchain
// doesn't cause error when linking to msvcrt.

#![no_std]
#![no_main]
#![feature(alloc_error_handler)]
#![feature(panic_unwind)]

use core::alloc::{GlobalAlloc, Layout};

struct DummyAllocator;

unsafe impl GlobalAlloc for DummyAllocator {
unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
core::ptr::null_mut()
}

unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
}

#[global_allocator]
static ALLOC: DummyAllocator = DummyAllocator;

#[alloc_error_handler]
fn rust_oom(_layout: Layout) -> ! {
panic!()
}

extern crate panic_unwind;

use core::panic::PanicInfo;

#[panic_handler]
fn handle_panic(_: &PanicInfo) -> ! {
loop {}
}

#[link(name = "msvcrt")]
extern "C" {}

#[no_mangle]
pub extern "C" fn main() -> i32 {
panic!();
}
2 changes: 1 addition & 1 deletion src/tools/rust-analyzer