diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 334e0541c765d..01e40c62a8bff 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -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; @@ -1144,15 +1145,15 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder { - 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 { .. }, .. }) => { diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index 372539d73b130..445f68160d286 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -266,12 +266,10 @@ impl Trait 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"); + } } _ => {} } diff --git a/tests/ui/argument-suggestions/two-mismatch-notes.stderr b/tests/ui/argument-suggestions/two-mismatch-notes.stderr index 38cf23ddc3895..70cc60255c717 100644 --- a/tests/ui/argument-suggestions/two-mismatch-notes.stderr +++ b/tests/ui/argument-suggestions/two-mismatch-notes.stderr @@ -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`, found `Wrapper` --> $DIR/two-mismatch-notes.rs:10:12 | diff --git a/tests/ui/c-variadic/variadic-ffi-1.stderr b/tests/ui/c-variadic/variadic-ffi-1.stderr index c7899338197d8..4beea83d8a528 100644 --- a/tests/ui/c-variadic/variadic-ffi-1.stderr +++ b/tests/ui/c-variadic/variadic-ffi-1.stderr @@ -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 @@ -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 diff --git a/tests/ui/fn/fn-pointer-mismatch.stderr b/tests/ui/fn/fn-pointer-mismatch.stderr index a674babcb324b..87ece845b83a8 100644 --- a/tests/ui/fn/fn-pointer-mismatch.stderr +++ b/tests/ui/fn/fn-pointer-mismatch.stderr @@ -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); diff --git a/tests/ui/fn/signature-error-reporting-under-verbose.rs b/tests/ui/fn/signature-error-reporting-under-verbose.rs index 12ff113c91347..d00cbd8a0f242 100644 --- a/tests/ui/fn/signature-error-reporting-under-verbose.rs +++ b/tests/ui/fn/signature-error-reporting-under-verbose.rs @@ -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 } diff --git a/tests/ui/fn/signature-error-reporting-under-verbose.stderr b/tests/ui/fn/signature-error-reporting-under-verbose.stderr index f4498db7259e3..067ee824d5d84 100644 --- a/tests/ui/fn/signature-error-reporting-under-verbose.stderr +++ b/tests/ui/fn/signature-error-reporting-under-verbose.stderr @@ -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 | diff --git a/tests/ui/issues/issue-10764.stderr b/tests/ui/issues/issue-10764.stderr index fcb45affe2c18..4d8a85a139715 100644 --- a/tests/ui/issues/issue-10764.stderr +++ b/tests/ui/issues/issue-10764.stderr @@ -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 | diff --git a/tests/ui/mismatched_types/normalize-fn-sig.stderr b/tests/ui/mismatched_types/normalize-fn-sig.stderr index e3a0646550cb2..252e56387ba8b 100644 --- a/tests/ui/mismatched_types/normalize-fn-sig.stderr +++ b/tests/ui/mismatched_types/normalize-fn-sig.stderr @@ -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 | diff --git a/tests/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr b/tests/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr index f2328cf3b24c6..a9a92b7a695eb 100644 --- a/tests/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr +++ b/tests/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr @@ -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 diff --git a/tests/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr b/tests/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr index 9c5004981d59b..e96559937d421 100644 --- a/tests/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr +++ b/tests/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr @@ -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 diff --git a/tests/ui/regions/regions-fn-subtyping-return-static-fail.stderr b/tests/ui/regions/regions-fn-subtyping-return-static-fail.stderr index 766a3d0337c06..8d82ff958ff3a 100644 --- a/tests/ui/regions/regions-fn-subtyping-return-static-fail.stderr +++ b/tests/ui/regions/regions-fn-subtyping-return-static-fail.stderr @@ -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 | diff --git a/tests/ui/regions/regions-lifetime-bounds-on-fns.stderr b/tests/ui/regions/regions-lifetime-bounds-on-fns.stderr index 2fab2986567b7..53a5612d24f25 100644 --- a/tests/ui/regions/regions-lifetime-bounds-on-fns.stderr +++ b/tests/ui/regions/regions-lifetime-bounds-on-fns.stderr @@ -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 diff --git a/tests/ui/reify-intrinsic.stderr b/tests/ui/reify-intrinsic.stderr index 9f9034a30c736..310b6c224e0e7 100644 --- a/tests/ui/reify-intrinsic.stderr +++ b/tests/ui/reify-intrinsic.stderr @@ -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 diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr index b0ac5dc44ad9a..e08ffe42d6aab 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr @@ -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(); diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr index b0ac5dc44ad9a..e08ffe42d6aab 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr @@ -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(); diff --git a/tests/ui/static/static-reference-to-fn-1.stderr b/tests/ui/static/static-reference-to-fn-1.stderr index b68352b518314..86c4eaa7eb432 100644 --- a/tests/ui/static/static-reference-to-fn-1.stderr +++ b/tests/ui/static/static-reference-to-fn-1.stderr @@ -7,7 +7,6 @@ LL | func: &foo, = note: expected reference `&fn() -> Option` found reference `&fn() -> Option {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), diff --git a/tests/ui/unsafe/initializing-ranged-via-ctor.rs b/tests/ui/unsafe/initializing-ranged-via-ctor.rs new file mode 100644 index 0000000000000..ca44fa7e4e756 --- /dev/null +++ b/tests/ui/unsafe/initializing-ranged-via-ctor.rs @@ -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}` +} diff --git a/tests/ui/unsafe/initializing-ranged-via-ctor.stderr b/tests/ui/unsafe/initializing-ranged-via-ctor.stderr new file mode 100644 index 0000000000000..d34554c6641a9 --- /dev/null +++ b/tests/ui/unsafe/initializing-ranged-via-ctor.stderr @@ -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::::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`. diff --git a/tests/ui/unsafe/ranged-ctor-as-fn-ptr.rs b/tests/ui/unsafe/ranged-ctor-as-fn-ptr.rs new file mode 100644 index 0000000000000..a91e579510d4d --- /dev/null +++ b/tests/ui/unsafe/ranged-ctor-as-fn-ptr.rs @@ -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 +} diff --git a/tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr b/tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr new file mode 100644 index 0000000000000..660c4070451a8 --- /dev/null +++ b/tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr @@ -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`.