Skip to content

Commit

Permalink
Auto merge of #115290 - compiler-errors:ctor-unsafe, r=cjgillot
Browse files Browse the repository at this point in the history
`rustc_layout_scalar_valid_range` makes ctors unsafe

We already validate this when we use the ctor in a call, e.g. `Variant(1)`, but not if we use the ctor as a fn ptr, e.g. `.map(Variant)`. The easiest way to fix the latter is (afaict) is by marking the ctor as unsafe itself.

Fixes #115284
  • Loading branch information
bors committed Aug 31, 2023
2 parents 2bd8131 + bf66723 commit 784916c
Show file tree
Hide file tree
Showing 21 changed files with 65 additions and 30 deletions.
17 changes: 9 additions & 8 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
use rustc_trait_selection::traits::ObligationCtxt;
use std::iter;
use std::ops::Bound;

mod generics_of;
mod item_bounds;
Expand Down Expand Up @@ -1144,15 +1145,15 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<
}

Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor().is_some() => {
let ty = tcx.type_of(tcx.hir().get_parent_item(hir_id)).instantiate_identity();
let adt_def_id = tcx.hir().get_parent_item(hir_id).def_id.to_def_id();
let ty = tcx.type_of(adt_def_id).instantiate_identity();
let inputs = data.fields().iter().map(|f| tcx.type_of(f.def_id).instantiate_identity());
ty::Binder::dummy(tcx.mk_fn_sig(
inputs,
ty,
false,
hir::Unsafety::Normal,
abi::Abi::Rust,
))
// constructors for structs with `layout_scalar_valid_range` are unsafe to call
let safety = match tcx.layout_scalar_valid_range(adt_def_id) {
(Bound::Unbounded, Bound::Unbounded) => hir::Unsafety::Normal,
_ => hir::Unsafety::Unsafe,
};
ty::Binder::dummy(tcx.mk_fn_sig(inputs, ty, false, safety, abi::Abi::Rust))
}

Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,12 +266,10 @@ impl<T> Trait<T> for X {
}
}
}
(ty::FnPtr(_), ty::FnDef(def, _))
if let hir::def::DefKind::Fn = tcx.def_kind(def) => {
diag.note(
"when the arguments and return types match, functions can be coerced \
to function pointers",
);
(ty::FnPtr(sig), ty::FnDef(def_id, _)) | (ty::FnDef(def_id, _), ty::FnPtr(sig)) => {
if tcx.fn_sig(*def_id).skip_binder().unsafety() < sig.unsafety() {
diag.note("unsafe functions cannot be coerced into safe function pointers");
}
}
_ => {}
}
Expand Down
1 change: 0 additions & 1 deletion tests/ui/argument-suggestions/two-mismatch-notes.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ LL | foo(f, w);
| ^
= note: expected fn pointer `fn(i32)`
found fn item `fn(u32) {f}`
= note: when the arguments and return types match, functions can be coerced to function pointers
note: expected `Wrapper<i32>`, found `Wrapper<isize>`
--> $DIR/two-mismatch-notes.rs:10:12
|
Expand Down
2 changes: 0 additions & 2 deletions tests/ui/c-variadic/variadic-ffi-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ LL | let x: unsafe extern "C" fn(f: isize, x: u8) = foo;
|
= note: expected fn pointer `unsafe extern "C" fn(_, _)`
found fn item `unsafe extern "C" fn(_, _, ...) {foo}`
= note: when the arguments and return types match, functions can be coerced to function pointers

error[E0308]: mismatched types
--> $DIR/variadic-ffi-1.rs:26:54
Expand All @@ -58,7 +57,6 @@ LL | let y: extern "C" fn(f: isize, x: u8, ...) = bar;
|
= note: expected fn pointer `extern "C" fn(_, _, ...)`
found fn item `extern "C" fn(_, _) {bar}`
= note: when the arguments and return types match, functions can be coerced to function pointers

error[E0617]: can't pass `f32` to variadic function
--> $DIR/variadic-ffi-1.rs:28:19
Expand Down
1 change: 0 additions & 1 deletion tests/ui/fn/fn-pointer-mismatch.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ LL | let e: &fn(u32) -> u32 = &foo;
= note: expected reference `&fn(u32) -> u32`
found reference `&fn(u32) -> u32 {foo}`
= note: fn items are distinct from fn pointers
= note: when the arguments and return types match, functions can be coerced to function pointers
help: consider casting to a fn pointer
|
LL | let e: &fn(u32) -> u32 = &(foo as fn(u32) -> u32);
Expand Down
1 change: 0 additions & 1 deletion tests/ui/fn/signature-error-reporting-under-verbose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,4 @@ fn main() {
//~| NOTE expected fn pointer, found fn item
//~| NOTE expected fn pointer `fn(i32, u32)`
//~| NOTE arguments to this function are incorrect
//~| NOTE when the arguments and return types match, functions can be coerced to function pointers
}
1 change: 0 additions & 1 deletion tests/ui/fn/signature-error-reporting-under-verbose.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ LL | needs_ptr(foo);
|
= note: expected fn pointer `fn(i32, u32)`
found fn item `fn(i32, i32) {foo}`
= note: when the arguments and return types match, functions can be coerced to function pointers
note: function defined here
--> $DIR/signature-error-reporting-under-verbose.rs:5:4
|
Expand Down
1 change: 0 additions & 1 deletion tests/ui/issues/issue-10764.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ LL | fn main() { f(bar) }
|
= note: expected fn pointer `fn()`
found fn item `extern "C" fn() {bar}`
= note: when the arguments and return types match, functions can be coerced to function pointers
note: function defined here
--> $DIR/issue-10764.rs:1:4
|
Expand Down
1 change: 0 additions & 1 deletion tests/ui/mismatched_types/normalize-fn-sig.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ LL | needs_i32_ref_fn(foo::<()>);
|
= note: expected fn pointer `fn(&'static i32, i32)`
found fn item `fn(i32, &'static i32) {foo::<()>}`
= note: when the arguments and return types match, functions can be coerced to function pointers
note: function defined here
--> $DIR/normalize-fn-sig.rs:11:4
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ LL | let _: fn(&mut &isize, &mut &isize) = a;
|
= note: expected fn pointer `for<'a, 'b, 'c, 'd> fn(&'a mut &'b isize, &'c mut &'d isize)`
found fn item `for<'a, 'b> fn(&'a mut &isize, &'b mut &isize) {a::<'_, '_>}`
= note: when the arguments and return types match, functions can be coerced to function pointers

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ LL | let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
|
= note: expected fn pointer `for<'a, 'b, 'c, 'd, 'e, 'f> fn(&'a mut &'b isize, &'c mut &'d isize, &'e mut &'f isize)`
found fn item `for<'a, 'b, 'c> fn(&'a mut &isize, &'b mut &isize, &'c mut &isize) {a::<'_, '_, '_>}`
= note: when the arguments and return types match, functions can be coerced to function pointers

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ LL | want_G(baz);
|
= note: expected fn pointer `for<'cx> fn(&'cx S) -> &'static S`
found fn item `for<'a> fn(&'a S) -> &'a S {baz}`
= note: when the arguments and return types match, functions can be coerced to function pointers
note: function defined here
--> $DIR/regions-fn-subtyping-return-static-fail.rs:20:4
|
Expand Down
1 change: 0 additions & 1 deletion tests/ui/regions/regions-lifetime-bounds-on-fns.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ LL | let _: fn(&mut &isize, &mut &isize) = a;
|
= note: expected fn pointer `for<'a, 'b, 'c, 'd> fn(&'a mut &'b isize, &'c mut &'d isize)`
found fn item `for<'a, 'b> fn(&'a mut &isize, &'b mut &isize) {a::<'_, '_>}`
= note: when the arguments and return types match, functions can be coerced to function pointers

error: aborting due to previous error

Expand Down
1 change: 0 additions & 1 deletion tests/ui/reify-intrinsic.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ LL | let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::tr
|
= note: expected fn pointer `unsafe extern "rust-intrinsic" fn(isize) -> usize`
found fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}`
= note: when the arguments and return types match, functions can be coerced to function pointers

error[E0606]: casting `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid
--> $DIR/reify-intrinsic.rs:11:13
Expand Down
1 change: 0 additions & 1 deletion tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ LL | let foo: fn() = foo;
found fn item `fn() {foo}`
= note: fn items are distinct from fn pointers
= note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers
= note: when the arguments and return types match, functions can be coerced to function pointers
help: consider casting to a fn pointer
|
LL | let foo: fn() = foo as fn();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ LL | let foo: fn() = foo;
found fn item `fn() {foo}`
= note: fn items are distinct from fn pointers
= note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers
= note: when the arguments and return types match, functions can be coerced to function pointers
help: consider casting to a fn pointer
|
LL | let foo: fn() = foo as fn();
Expand Down
1 change: 0 additions & 1 deletion tests/ui/static/static-reference-to-fn-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ LL | func: &foo,
= note: expected reference `&fn() -> Option<isize>`
found reference `&fn() -> Option<isize> {foo}`
= note: fn items are distinct from fn pointers
= note: when the arguments and return types match, functions can be coerced to function pointers
help: consider casting to a fn pointer
|
LL | func: &(foo as fn() -> Option<isize>),
Expand Down
11 changes: 11 additions & 0 deletions tests/ui/unsafe/initializing-ranged-via-ctor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#![feature(rustc_attrs)]
#![allow(internal_features)]

#[derive(Debug)]
#[rustc_layout_scalar_valid_range_start(2)]
struct NonZeroAndOneU8(u8);

fn main() {
println!("{:?}", Some(1).map(NonZeroAndOneU8).unwrap());
//~^ ERROR found `unsafe fn(u8) -> NonZeroAndOneU8 {NonZeroAndOneU8}`
}
16 changes: 16 additions & 0 deletions tests/ui/unsafe/initializing-ranged-via-ctor.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error[E0277]: expected a `FnOnce<({integer},)>` closure, found `unsafe fn(u8) -> NonZeroAndOneU8 {NonZeroAndOneU8}`
--> $DIR/initializing-ranged-via-ctor.rs:9:34
|
LL | println!("{:?}", Some(1).map(NonZeroAndOneU8).unwrap());
| --- ^^^^^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
| |
| required by a bound introduced by this call
|
= help: the trait `FnOnce<({integer},)>` is not implemented for fn item `unsafe fn(u8) -> NonZeroAndOneU8 {NonZeroAndOneU8}`
= note: unsafe function cannot be called generically without an unsafe block
note: required by a bound in `Option::<T>::map`
--> $SRC_DIR/core/src/option.rs:LL:COL

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
10 changes: 10 additions & 0 deletions tests/ui/unsafe/ranged-ctor-as-fn-ptr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#![feature(rustc_attrs)]

#[derive(Debug)]
#[rustc_layout_scalar_valid_range_start(2)]
struct NonZeroAndOneU8(u8);

fn main() {
let x: fn(u8) -> NonZeroAndOneU8 = NonZeroAndOneU8;
//~^ ERROR mismatched types
}
15 changes: 15 additions & 0 deletions tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
error[E0308]: mismatched types
--> $DIR/ranged-ctor-as-fn-ptr.rs:8:40
|
LL | let x: fn(u8) -> NonZeroAndOneU8 = NonZeroAndOneU8;
| ------------------------- ^^^^^^^^^^^^^^^ expected normal fn, found unsafe fn
| |
| expected due to this
|
= note: expected fn pointer `fn(_) -> NonZeroAndOneU8`
found struct constructor `unsafe fn(_) -> NonZeroAndOneU8 {NonZeroAndOneU8}`
= note: unsafe functions cannot be coerced into safe function pointers

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.

0 comments on commit 784916c

Please sign in to comment.