Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Rollup of 6 pull requests #103685

Closed
wants to merge 26 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
328f817
Make `CStr::from_ptr` `const`.
reitermarkus Oct 12, 2022
36dbb07
Update docs for `CStr::from_ptr`.
reitermarkus Oct 12, 2022
4accf83
Note scope of TAIT more accurately
compiler-errors Oct 22, 2022
8b984e5
fake capture if min_captures empty
ouz-a Aug 11, 2022
e521a8d
Prevent foreign Rust exceptions from being caught
nbdd0121 Oct 5, 2022
86c65d2
Implement Rust foreign exception protection for EMCC and SEH
nbdd0121 Oct 5, 2022
daf3063
Add test case for foreign Rust exceptions
nbdd0121 Oct 5, 2022
979d1a2
Apply suggestion
nbdd0121 Oct 11, 2022
4e6d60c
Fix alloc size
nbdd0121 Oct 12, 2022
c9cca33
Fix windows compilation
nbdd0121 Oct 23, 2022
8b494f4
Allow `impl Fn() -> impl Trait` in return position
WaffleLapkin Feb 2, 2022
7a4ba2f
Add more tests for `impl Fn() -> impl Trait`
WaffleLapkin Jun 23, 2022
00f2277
Add even more tests for `impl Fn() -> impl Trait`
WaffleLapkin Jun 23, 2022
cc752f5
Feature gate `impl_trait_in_fn_trait_return`
WaffleLapkin Jul 24, 2022
d116859
--bless
WaffleLapkin Jul 28, 2022
690e037
add a test for gate `impl_trait_in_fn_trait_return`
WaffleLapkin Jul 28, 2022
e93982a
adopt to compiler changes
WaffleLapkin Oct 25, 2022
bfac2da
Ignore test on mingw32
nbdd0121 Oct 26, 2022
92b314b
add test for issue 98634
Rageking8 Oct 21, 2022
b3f9277
Remove unneeded attribute.
reitermarkus Oct 28, 2022
38abbcf
Rollup merge of #93582 - WaffleLapkin:rpitirpit, r=compiler-errors
Dylan-DPC Oct 28, 2022
eb6cd05
Rollup merge of #100452 - ouz-a:issue-93242, r=jackh726
Dylan-DPC Oct 28, 2022
28ece5a
Rollup merge of #102721 - nbdd0121:panic, r=Amanieu
Dylan-DPC Oct 28, 2022
6db281a
Rollup merge of #102961 - reitermarkus:const-cstr-from-ptr, r=oli-obk
Dylan-DPC Oct 28, 2022
ccc10a4
Rollup merge of #103342 - Rageking8:add-test-for-issue-98634, r=compi…
Dylan-DPC Oct 28, 2022
e7fb356
Rollup merge of #103383 - compiler-errors:tait-scope, r=oli-obk
Dylan-DPC Oct 28, 2022
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
16 changes: 15 additions & 1 deletion compiler/rustc_ast_lowering/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
}
GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
ParenthesizedGenericArgs::Ok => {
self.lower_parenthesized_parameter_data(data, itctx)
}
ParenthesizedGenericArgs::Err => {
// Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>`
let sub = if !data.inputs.is_empty() {
Expand Down Expand Up @@ -344,6 +346,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn lower_parenthesized_parameter_data(
&mut self,
data: &ParenthesizedArgs,
itctx: &ImplTraitContext,
) -> (GenericArgsCtor<'hir>, bool) {
// Switch to `PassThrough` mode for anonymous lifetimes; this
// means that we permit things like `&Ref<T>`, where `Ref` has
Expand All @@ -355,6 +358,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.lower_ty_direct(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
}));
let output_ty = match output {
// Only allow `impl Trait` in return position. i.e.:
// ```rust
// fn f(_: impl Fn() -> impl Debug) -> impl Fn() -> impl Debug
// // disallowed --^^^^^^^^^^ allowed --^^^^^^^^^^
// ```
FnRetTy::Ty(ty)
if matches!(itctx, ImplTraitContext::ReturnPositionOpaqueTy { .. })
&& self.tcx.features().impl_trait_in_fn_trait_return =>
{
self.lower_ty(&ty, itctx)
}
FnRetTy::Ty(ty) => {
self.lower_ty(&ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ hir_analysis_expected_default_return_type = expected `()` because of default ret
hir_analysis_expected_return_type = expected `{$expected}` because of return type

hir_analysis_unconstrained_opaque_type = unconstrained opaque type
.note = `{$name}` must be used in combination with a concrete type within the same module
.note = `{$name}` must be used in combination with a concrete type within the same {$what}

hir_analysis_missing_type_params =
the type {$parameterCount ->
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,8 @@ declare_features! (
(active, half_open_range_patterns_in_slices, "CURRENT_RUSTC_VERSION", Some(67264), None),
/// Allows `if let` guard in match arms.
(active, if_let_guard, "1.47.0", Some(51114), None),
/// Allows `impl Trait` as output type in `Fn` traits in return position of functions.
(active, impl_trait_in_fn_trait_return, "1.64.0", Some(99697), None),
/// Allows using imported `main` function
(active, imported_main, "1.53.0", Some(28937), None),
/// Allows associated types in inherent impls.
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_hir_analysis/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,12 @@ fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> T
tcx.sess.emit_err(UnconstrainedOpaqueType {
span: tcx.def_span(def_id),
name: tcx.item_name(tcx.local_parent(def_id).to_def_id()),
what: match tcx.hir().get(scope) {
_ if scope == hir::CRATE_HIR_ID => "module",
Node::Item(hir::Item { kind: hir::ItemKind::Mod(_), .. }) => "module",
Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => "impl",
_ => "item",
},
});
return tcx.ty_error();
};
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ pub struct UnconstrainedOpaqueType {
#[primary_span]
pub span: Span,
pub name: Symbol,
pub what: &'static str,
}

pub struct MissingTypeParams {
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_hir_typeck/src/upvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

// We now fake capture information for all variables that are mentioned within the closure
// We do this after handling migrations so that min_captures computes before
if !enable_precise_capture(self.tcx, span) {
if !enable_precise_capture(self.tcx, span)
// (ouz-a) #93242 - ICE happens because closure_min_captures is empty with
// 2021 edition, because it sets `enable_precise_capture` to true, which won't allow us
// fake capture information this check sidesteps that and avoids the ICE.
|| (infer_kind == None && self.typeck_results.borrow().closure_min_captures.is_empty())
{
let mut capture_information: InferredCaptureInformation<'tcx> = Default::default();

if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,7 @@ symbols! {
impl_lint_pass,
impl_macros,
impl_trait_in_bindings,
impl_trait_in_fn_trait_return,
implied_by,
import,
import_name_type,
Expand Down
48 changes: 37 additions & 11 deletions library/core/src/ffi/c_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,7 @@ impl CStr {
/// # Examples
///
/// ```ignore (extern-declaration)
/// # fn main() {
/// use std::ffi::CStr;
/// use std::os::raw::c_char;
/// use std::ffi::{c_char, CStr};
///
/// extern "C" {
/// fn my_string() -> *const c_char;
Expand All @@ -233,14 +231,26 @@ impl CStr {
/// let slice = CStr::from_ptr(my_string());
/// println!("string returned: {}", slice.to_str().unwrap());
/// }
/// # }
/// ```
///
/// ```
/// #![feature(const_cstr_methods)]
///
/// use std::ffi::{c_char, CStr};
///
/// const HELLO_PTR: *const c_char = {
/// const BYTES: &[u8] = b"Hello, world!\0";
/// BYTES.as_ptr().cast()
/// };
/// const HELLO: &CStr = unsafe { CStr::from_ptr(HELLO_PTR) };
/// ```
///
/// [valid]: core::ptr#safety
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
#[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
// SAFETY: The caller has provided a pointer that points to a valid C
// string with a NUL terminator of size less than `isize::MAX`, whose
// content remain valid and doesn't change for the lifetime of the
Expand All @@ -252,13 +262,29 @@ impl CStr {
//
// The cast from c_char to u8 is ok because a c_char is always one byte.
unsafe {
extern "C" {
/// Provided by libc or compiler_builtins.
fn strlen(s: *const c_char) -> usize;
const fn strlen_ct(s: *const c_char) -> usize {
let mut len = 0;

// SAFETY: Outer caller has provided a pointer to a valid C string.
while unsafe { *s.add(len) } != 0 {
len += 1;
}

len
}
let len = strlen(ptr);
let ptr = ptr as *const u8;
CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))

fn strlen_rt(s: *const c_char) -> usize {
extern "C" {
/// Provided by libc or compiler_builtins.
fn strlen(s: *const c_char) -> usize;
}

// SAFETY: Outer caller has provided a pointer to a valid C string.
unsafe { strlen(s) }
}

let len = intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt);
Self::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr.cast(), len + 1))
}
}

Expand Down
40 changes: 28 additions & 12 deletions library/panic_unwind/src/emcc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ static EXCEPTION_TYPE_INFO: TypeInfo = TypeInfo {
name: b"rust_panic\0".as_ptr(),
};

// NOTE(nbdd0121): The `canary` field will be part of stable ABI after `c_unwind` stabilization.
#[repr(C)]
struct Exception {
// See `gcc.rs` on why this is present. We already have a static here so just use it.
canary: *const TypeInfo,

// This is necessary because C++ code can capture our exception with
// std::exception_ptr and rethrow it multiple times, possibly even in
// another thread.
Expand All @@ -70,27 +75,38 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
let catch_data = &*(ptr as *mut CatchData);

let adjusted_ptr = __cxa_begin_catch(catch_data.ptr as *mut libc::c_void) as *mut Exception;
let out = if catch_data.is_rust_panic {
let was_caught = (*adjusted_ptr).caught.swap(true, Ordering::SeqCst);
if was_caught {
// Since cleanup() isn't allowed to panic, we just abort instead.
intrinsics::abort();
}
(*adjusted_ptr).data.take().unwrap()
} else {
if !catch_data.is_rust_panic {
super::__rust_foreign_exception();
};
}

let canary = ptr::addr_of!((*adjusted_ptr).canary).read();
if !ptr::eq(canary, &EXCEPTION_TYPE_INFO) {
super::__rust_foreign_exception();
}

let was_caught = (*adjusted_ptr).caught.swap(true, Ordering::SeqCst);
if was_caught {
// Since cleanup() isn't allowed to panic, we just abort instead.
intrinsics::abort();
}
let out = (*adjusted_ptr).data.take().unwrap();
__cxa_end_catch();
out
}

pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
let sz = mem::size_of_val(&data);
let exception = __cxa_allocate_exception(sz) as *mut Exception;
let exception = __cxa_allocate_exception(mem::size_of::<Exception>()) as *mut Exception;
if exception.is_null() {
return uw::_URC_FATAL_PHASE1_ERROR as u32;
}
ptr::write(exception, Exception { caught: AtomicBool::new(false), data: Some(data) });
ptr::write(
exception,
Exception {
canary: &EXCEPTION_TYPE_INFO,
caught: AtomicBool::new(false),
data: Some(data),
},
);
__cxa_throw(exception as *mut _, &EXCEPTION_TYPE_INFO, exception_cleanup);
}

Expand Down
30 changes: 27 additions & 3 deletions library/panic_unwind/src/gcc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,23 @@

use alloc::boxed::Box;
use core::any::Any;
use core::ptr;

use unwind as uw;

// In case where multiple copies of std exist in a single process,
// we use address of this static variable to distinguish an exception raised by
// this copy and some other copy (which needs to be treated as foreign exception).
static CANARY: u8 = 0;

// NOTE(nbdd0121)
// Once `c_unwind` feature is stabilized, there will be ABI stability requirement
// on this struct. The first two field must be `_Unwind_Exception` and `canary`,
// as it may be accessed by a different version of the std with a different compiler.
#[repr(C)]
struct Exception {
_uwe: uw::_Unwind_Exception,
canary: *const u8,
cause: Box<dyn Any + Send>,
}

Expand All @@ -54,6 +65,7 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
exception_cleanup,
private: [0; uw::unwinder_private_data_size],
},
canary: &CANARY,
cause: data,
});
let exception_param = Box::into_raw(exception) as *mut uw::_Unwind_Exception;
Expand All @@ -75,10 +87,22 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
if (*exception).exception_class != rust_exception_class() {
uw::_Unwind_DeleteException(exception);
super::__rust_foreign_exception();
} else {
let exception = Box::from_raw(exception as *mut Exception);
exception.cause
}

let exception = exception.cast::<Exception>();
// Just access the canary field, avoid accessing the entire `Exception` as
// it can be a foreign Rust exception.
let canary = ptr::addr_of!((*exception).canary).read();
if !ptr::eq(canary, &CANARY) {
// A foreign Rust exception, treat it slightly differently from other
// foreign exceptions, because call into `_Unwind_DeleteException` will
// call into `__rust_drop_panic` which produces a confusing
// "Rust panic must be rethrown" message.
super::__rust_foreign_exception();
}

let exception = Box::from_raw(exception as *mut Exception);
exception.cause
}

// Rust's exception class identifier. This is used by personality routines to
Expand Down
20 changes: 15 additions & 5 deletions library/panic_unwind/src/seh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,15 @@
use alloc::boxed::Box;
use core::any::Any;
use core::mem::{self, ManuallyDrop};
use core::ptr;
use libc::{c_int, c_uint, c_void};

// NOTE(nbdd0121): The `canary` field will be part of stable ABI after `c_unwind` stabilization.
#[repr(C)]
struct Exception {
// See `gcc.rs` on why this is present. We already have a static here so just use it.
canary: *const _TypeDescriptor,

// This needs to be an Option because we catch the exception by reference
// and its destructor is executed by the C++ runtime. When we take the Box
// out of the exception, we need to leave the exception in a valid state
Expand Down Expand Up @@ -235,7 +241,7 @@ static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor {
macro_rules! define_cleanup {
($abi:tt $abi2:tt) => {
unsafe extern $abi fn exception_cleanup(e: *mut Exception) {
if let Exception { data: Some(b) } = e.read() {
if let Exception { data: Some(b), .. } = e.read() {
drop(b);
super::__rust_drop_panic();
}
Expand Down Expand Up @@ -265,7 +271,7 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
// The ManuallyDrop is needed here since we don't want Exception to be
// dropped when unwinding. Instead it will be dropped by exception_cleanup
// which is invoked by the C++ runtime.
let mut exception = ManuallyDrop::new(Exception { data: Some(data) });
let mut exception = ManuallyDrop::new(Exception { canary: &TYPE_DESCRIPTOR, data: Some(data) });
let throw_ptr = &mut exception as *mut _ as *mut _;

// This... may seems surprising, and justifiably so. On 32-bit MSVC the
Expand Down Expand Up @@ -321,8 +327,12 @@ pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> {
// __rust_try. This happens when a non-Rust foreign exception is caught.
if payload.is_null() {
super::__rust_foreign_exception();
} else {
let exception = &mut *(payload as *mut Exception);
exception.data.take().unwrap()
}
let exception = payload as *mut Exception;
let canary = ptr::addr_of!((*exception).canary).read();
if !ptr::eq(canary, &TYPE_DESCRIPTOR) {
// A foreign Rust exception.
super::__rust_foreign_exception();
}
(*exception).data.take().unwrap()
}
11 changes: 11 additions & 0 deletions src/test/run-make-fulldeps/foreign-rust-exceptions/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# ignore-i686-pc-windows-gnu

# This test doesn't work on 32-bit MinGW as cdylib has its own copy of unwinder
# so cross-DLL unwinding does not work.

include ../tools.mk

all:
$(RUSTC) bar.rs --crate-type=cdylib
$(RUSTC) foo.rs
$(call RUN,foo) 2>&1 | $(CGREP) "Rust cannot catch foreign exceptions"
7 changes: 7 additions & 0 deletions src/test/run-make-fulldeps/foreign-rust-exceptions/bar.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#![crate_type = "cdylib"]
#![feature(c_unwind)]

#[no_mangle]
extern "C-unwind" fn panic() {
panic!();
}
13 changes: 13 additions & 0 deletions src/test/run-make-fulldeps/foreign-rust-exceptions/foo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#![feature(c_unwind)]

#[cfg_attr(not(windows), link(name = "bar"))]
#[cfg_attr(windows, link(name = "bar.dll"))]
extern "C-unwind" {
fn panic();
}

fn main() {
let _ = std::panic::catch_unwind(|| {
unsafe { panic() };
});
}
Loading