From 6005619bde6abacfdce096d1f67437323b63d8dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 24 Jan 2025 01:06:14 +0000 Subject: [PATCH 01/14] In "specify type" suggestion, skip type params that are already known When we suggest specifying a type for an expression or pattern, like in a `let` binding, we previously would print the entire type as the type system knew it. We now look at the params that have *no* inference variables, so they are fully known to the type system which means that they don't need to be specified. This helps in suggestions for types that are really long, because we can usually skip most of the type params and make the annotation as short as possible: ``` error[E0282]: type annotations needed for `Result<_, ((..., ..., ..., ...), ..., ..., ...)>` --> $DIR/really-long-type-in-let-binding-without-sufficient-type-info.rs:7:9 | LL | let y = Err(x); | ^ ------ type must be known at this point | help: consider giving `y` an explicit type, where the type for type parameter `T` is specified | LL | let y: Result = Err(x); | ++++++++++++++ ``` --- .../error_reporting/infer/need_type_info.rs | 84 ++++++++++++++++--- .../cannot-infer-closure-circular.stderr | 4 +- .../erase-type-params-in-label.stderr | 8 +- tests/ui/inference/issue-104649.stderr | 4 +- tests/ui/inference/issue-83606.stderr | 4 +- ...et-binding-without-sufficient-type-info.rs | 10 +++ ...inding-without-sufficient-type-info.stderr | 14 ++++ .../or_else-multiple-type-params.stderr | 4 +- 8 files changed, 108 insertions(+), 24 deletions(-) create mode 100644 tests/ui/inference/really-long-type-in-let-binding-without-sufficient-type-info.rs create mode 100644 tests/ui/inference/really-long-type-in-let-binding-without-sufficient-type-info.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 99b70c87ccd..61fb7bcbc9a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -18,6 +18,7 @@ use rustc_middle::ty::{ TypeFoldable, TypeFolder, TypeSuperFoldable, TypeckResults, }; use rustc_span::{BytePos, DUMMY_SP, FileName, Ident, Span, sym}; +use rustc_type_ir::visit::TypeVisitableExt; use tracing::{debug, instrument, warn}; use super::nice_region_error::placeholder_error::Highlighted; @@ -155,26 +156,85 @@ impl UnderspecifiedArgKind { } } -struct ClosureEraser<'tcx> { - tcx: TyCtxt<'tcx>, +struct ClosureEraser<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, + // When recursing into types, if an ADT has type parameters with a default type we do *not* + // want to replace that type parameter with `_`, as it will cause the normally hidden type + // parameter to be rendered. The best example of this is `Vec`, which we want to + // render as `Vec` and not `Vec` when `T` is unknown. + do_not_hide_nested_type: bool, } -impl<'tcx> TypeFolder> for ClosureEraser<'tcx> { +impl<'a, 'tcx> ClosureEraser<'a, 'tcx> { + fn new_infer(&mut self) -> Ty<'tcx> { + self.infcx.next_ty_var(DUMMY_SP) + } +} + +impl<'a, 'tcx> TypeFolder> for ClosureEraser<'a, 'tcx> { fn cx(&self) -> TyCtxt<'tcx> { - self.tcx + self.infcx.tcx } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.kind() { + let prev = self.do_not_hide_nested_type; + let ty = match ty.kind() { ty::Closure(_, args) => { + // For a closure type, we turn it into a function pointer so that it gets rendered + // as `fn(args) -> Ret`. let closure_sig = args.as_closure().sig(); Ty::new_fn_ptr( - self.tcx, - self.tcx.signature_unclosure(closure_sig, hir::Safety::Safe), + self.cx(), + self.cx().signature_unclosure(closure_sig, hir::Safety::Safe), ) } - _ => ty.super_fold_with(self), - } + ty::Adt(def, _) => { + let generics = self.cx().generics_of(def.did()); + if generics.own_params.iter().any(|param| param.default_value(self.cx()).is_some()) + { + // We have a type that has default types, like the allocator in Vec. We decided + // to show `Vec` itself, because it hasn't yet been replaced by an `_` `Infer`, + // but we want to ensure that the type parameter with default types does *not* + // get replaced with `_` because then we'd end up with `Vec<_, _>`, instead of + // `Vec<_>`. + self.do_not_hide_nested_type = true; + ty.super_fold_with(self) + } else if ty.has_infer() || self.do_not_hide_nested_type { + // This type has an unsubstituted type variable, meaning that this type has a + // (potentially deeply nested) type parameter from the corresponding type's + // definition. We have explicitly asked this type to not be hidden. In either + // case, we keep the type and don't substitute with `_` just yet. + ty.super_fold_with(self) + } else { + // When we have a type that doesn't have any inference variables, so we replace + // the whole thing with `_`. The type system already knows about this type in + // its entirety and it is redundant to specify it for the user. The user only + // needs to specify the type parameters that we *couldn't* figure out. + self.new_infer() + } + } + _ if ty.has_infer() || self.do_not_hide_nested_type => { + // This type has a (potentially nested) type parameter that we couldn't figure out. + // We will print this depth of type, so at least the type name and at least one of + // its type parameters. We unset `do_not_hide_nested_type` because this type can't + // have type parameter defaults until next type we hit an ADT. + self.do_not_hide_nested_type = false; + ty.super_fold_with(self) + } + // We don't have an unknown type parameter anywhere, replace with `_`. + _ => self.new_infer(), + }; + self.do_not_hide_nested_type = prev; + ty + } + + fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { + let prev = self.do_not_hide_nested_type; + // Avoid accidentally erasing the type of the const. + self.do_not_hide_nested_type = true; + let c = c.super_fold_with(self); + self.do_not_hide_nested_type = prev; + c } } @@ -219,9 +279,9 @@ fn ty_to_string<'tcx>( ) -> String { let mut printer = fmt_printer(infcx, Namespace::TypeNS); let ty = infcx.resolve_vars_if_possible(ty); - // We use `fn` ptr syntax for closures, but this only works when the closure - // does not capture anything. - let ty = ty.fold_with(&mut ClosureEraser { tcx: infcx.tcx }); + // We use `fn` ptr syntax for closures, but this only works when the closure does not capture + // anything. We also remove all type parameters that are fully known to the type system. + let ty = ty.fold_with(&mut ClosureEraser { infcx, do_not_hide_nested_type: false }); match (ty.kind(), called_method_def_id) { // We don't want the regular output for `fn`s because it includes its path in diff --git a/tests/ui/inference/cannot-infer-closure-circular.stderr b/tests/ui/inference/cannot-infer-closure-circular.stderr index a16e832f8ef..ee17f7737cf 100644 --- a/tests/ui/inference/cannot-infer-closure-circular.stderr +++ b/tests/ui/inference/cannot-infer-closure-circular.stderr @@ -9,8 +9,8 @@ LL | Ok(v) | help: consider giving this closure parameter an explicit type, where the type for type parameter `E` is specified | -LL | let x = |r: Result<(), E>| { - | +++++++++++++++ +LL | let x = |r: Result<_, E>| { + | ++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/inference/erase-type-params-in-label.stderr b/tests/ui/inference/erase-type-params-in-label.stderr index 4e9a74c1e40..1ec8a33eb82 100644 --- a/tests/ui/inference/erase-type-params-in-label.stderr +++ b/tests/ui/inference/erase-type-params-in-label.stderr @@ -12,8 +12,8 @@ LL | fn foo(t: T, k: K) -> Foo { | ^^^^^^^ required by this bound in `foo` help: consider giving `foo` an explicit type, where the type for type parameter `W` is specified | -LL | let foo: Foo = foo(1, ""); - | ++++++++++++++++++++++ +LL | let foo: Foo<_, &_, W, Z> = foo(1, ""); + | ++++++++++++++++++ error[E0283]: type annotations needed for `Bar` --> $DIR/erase-type-params-in-label.rs:5:9 @@ -29,8 +29,8 @@ LL | fn bar(t: T, k: K) -> Bar { | ^^^^^^^ required by this bound in `bar` help: consider giving `bar` an explicit type, where the type for type parameter `Z` is specified | -LL | let bar: Bar = bar(1, ""); - | +++++++++++++++++++ +LL | let bar: Bar<_, &_, Z> = bar(1, ""); + | +++++++++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/inference/issue-104649.stderr b/tests/ui/inference/issue-104649.stderr index 391ed16f349..27382e30134 100644 --- a/tests/ui/inference/issue-104649.stderr +++ b/tests/ui/inference/issue-104649.stderr @@ -6,8 +6,8 @@ LL | let a = A(Result::Ok(Result::Ok(()))); | help: consider giving `a` an explicit type, where the type for type parameter `E` is specified | -LL | let a: A, Error>> = A(Result::Ok(Result::Ok(()))); - | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +LL | let a: A, _>> = A(Result::Ok(Result::Ok(()))); + | ++++++++++++++++++++++++++++++++++++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/inference/issue-83606.stderr b/tests/ui/inference/issue-83606.stderr index 69d1d71ef3c..97ccad9e785 100644 --- a/tests/ui/inference/issue-83606.stderr +++ b/tests/ui/inference/issue-83606.stderr @@ -11,8 +11,8 @@ LL | fn foo(_: impl std::fmt::Display) -> [usize; N] { | ^^^^^^^^^^^^^^ required by this const generic parameter in `foo` help: consider giving this pattern a type, where the value of const parameter `N` is specified | -LL | let _: [usize; N] = foo("foo"); - | ++++++++++++ +LL | let _: [_; N] = foo("foo"); + | ++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/inference/really-long-type-in-let-binding-without-sufficient-type-info.rs b/tests/ui/inference/really-long-type-in-let-binding-without-sufficient-type-info.rs new file mode 100644 index 00000000000..4fd15eea9e0 --- /dev/null +++ b/tests/ui/inference/really-long-type-in-let-binding-without-sufficient-type-info.rs @@ -0,0 +1,10 @@ +type A = (i32, i32, i32, i32); +type B = (A, A, A, A); +type C = (B, B, B, B); +type D = (C, C, C, C); + +fn foo(x: D) { + let y = Err(x); //~ ERROR type annotations needed for `Result<_ +} + +fn main() {} diff --git a/tests/ui/inference/really-long-type-in-let-binding-without-sufficient-type-info.stderr b/tests/ui/inference/really-long-type-in-let-binding-without-sufficient-type-info.stderr new file mode 100644 index 00000000000..65fe2ffcb7f --- /dev/null +++ b/tests/ui/inference/really-long-type-in-let-binding-without-sufficient-type-info.stderr @@ -0,0 +1,14 @@ +error[E0282]: type annotations needed for `Result<_, ((((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32))), (((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32))), (((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32))), (((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32)), ((i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32), (i32, i32, i32, i32))))>` + --> $DIR/really-long-type-in-let-binding-without-sufficient-type-info.rs:7:9 + | +LL | let y = Err(x); + | ^ ------ type must be known at this point + | +help: consider giving `y` an explicit type, where the type for type parameter `T` is specified + | +LL | let y: Result = Err(x); + | ++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/type-inference/or_else-multiple-type-params.stderr b/tests/ui/type-inference/or_else-multiple-type-params.stderr index 3176a2d490e..9bcd07f8bf1 100644 --- a/tests/ui/type-inference/or_else-multiple-type-params.stderr +++ b/tests/ui/type-inference/or_else-multiple-type-params.stderr @@ -6,8 +6,8 @@ LL | .or_else(|err| { | help: try giving this closure an explicit return type | -LL | .or_else(|err| -> Result { - | +++++++++++++++++++ +LL | .or_else(|err| -> Result<_, F> { + | +++++++++++++++ error: aborting due to 1 previous error From 576db131a38ccb53f9fbbe314e6bce37503c0050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 30 Jan 2025 18:26:31 +0000 Subject: [PATCH 02/14] Simplify recursive logic --- .../error_reporting/infer/need_type_info.rs | 93 ++++++++++--------- 1 file changed, 50 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 61fb7bcbc9a..9e7e96dddd7 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -18,6 +18,7 @@ use rustc_middle::ty::{ TypeFoldable, TypeFolder, TypeSuperFoldable, TypeckResults, }; use rustc_span::{BytePos, DUMMY_SP, FileName, Ident, Span, sym}; +use rustc_type_ir::inherent::*; use rustc_type_ir::visit::TypeVisitableExt; use tracing::{debug, instrument, warn}; @@ -158,11 +159,6 @@ impl UnderspecifiedArgKind { struct ClosureEraser<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, - // When recursing into types, if an ADT has type parameters with a default type we do *not* - // want to replace that type parameter with `_`, as it will cause the normally hidden type - // parameter to be rendered. The best example of this is `Vec`, which we want to - // render as `Vec` and not `Vec` when `T` is unknown. - do_not_hide_nested_type: bool, } impl<'a, 'tcx> ClosureEraser<'a, 'tcx> { @@ -177,8 +173,7 @@ impl<'a, 'tcx> TypeFolder> for ClosureEraser<'a, 'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - let prev = self.do_not_hide_nested_type; - let ty = match ty.kind() { + match ty.kind() { ty::Closure(_, args) => { // For a closure type, we turn it into a function pointer so that it gets rendered // as `fn(args) -> Ret`. @@ -188,52 +183,64 @@ impl<'a, 'tcx> TypeFolder> for ClosureEraser<'a, 'tcx> { self.cx().signature_unclosure(closure_sig, hir::Safety::Safe), ) } - ty::Adt(def, _) => { - let generics = self.cx().generics_of(def.did()); - if generics.own_params.iter().any(|param| param.default_value(self.cx()).is_some()) - { - // We have a type that has default types, like the allocator in Vec. We decided - // to show `Vec` itself, because it hasn't yet been replaced by an `_` `Infer`, - // but we want to ensure that the type parameter with default types does *not* - // get replaced with `_` because then we'd end up with `Vec<_, _>`, instead of - // `Vec<_>`. - self.do_not_hide_nested_type = true; - ty.super_fold_with(self) - } else if ty.has_infer() || self.do_not_hide_nested_type { - // This type has an unsubstituted type variable, meaning that this type has a - // (potentially deeply nested) type parameter from the corresponding type's - // definition. We have explicitly asked this type to not be hidden. In either - // case, we keep the type and don't substitute with `_` just yet. - ty.super_fold_with(self) - } else { - // When we have a type that doesn't have any inference variables, so we replace - // the whole thing with `_`. The type system already knows about this type in - // its entirety and it is redundant to specify it for the user. The user only - // needs to specify the type parameters that we *couldn't* figure out. - self.new_infer() - } + ty::Adt(_, args) if !args.iter().any(|a| a.has_infer()) => { + // We have a type that doesn't have any inference variables, so we replace + // the whole thing with `_`. The type system already knows about this type in + // its entirety and it is redundant to specify it for the user. The user only + // needs to specify the type parameters that we *couldn't* figure out. + self.new_infer() } - _ if ty.has_infer() || self.do_not_hide_nested_type => { + ty::Adt(def, args) => { + let generics = self.cx().generics_of(def.did()); + let generics: Vec = generics + .own_params + .iter() + .map(|param| param.default_value(self.cx()).is_some()) + .collect(); + let ty = Ty::new_adt( + self.cx(), + *def, + self.cx().mk_args_from_iter(generics.into_iter().zip(args.iter()).map( + |(has_default, arg)| { + if arg.has_infer() { + // This param has an unsubstituted type variable, meaning that this + // type has a (potentially deeply nested) type parameter from the + // corresponding type's definition. We have explicitly asked this + // type to not be hidden. In either case, we keep the type and don't + // substitute with `_` just yet. + arg.fold_with(self) + } else if has_default { + // We have a type param that has a default type, like the allocator + // in Vec. We decided to show `Vec` itself, because it hasn't yet + // been replaced by an `_` `Infer`, but we want to ensure that the + // type parameter with default types does *not* get replaced with + // `_` because then we'd end up with `Vec<_, _>`, instead of + // `Vec<_>`. + arg + } else if let GenericArgKind::Type(_) = arg.kind() { + // We don't replace lifetime or const params, only type params. + self.new_infer().into() + } else { + arg.fold_with(self) + } + }, + )), + ); + ty + } + _ if ty.has_infer() => { // This type has a (potentially nested) type parameter that we couldn't figure out. // We will print this depth of type, so at least the type name and at least one of - // its type parameters. We unset `do_not_hide_nested_type` because this type can't - // have type parameter defaults until next type we hit an ADT. - self.do_not_hide_nested_type = false; + // its type parameters. ty.super_fold_with(self) } // We don't have an unknown type parameter anywhere, replace with `_`. _ => self.new_infer(), - }; - self.do_not_hide_nested_type = prev; - ty + } } fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { - let prev = self.do_not_hide_nested_type; // Avoid accidentally erasing the type of the const. - self.do_not_hide_nested_type = true; - let c = c.super_fold_with(self); - self.do_not_hide_nested_type = prev; c } } @@ -281,7 +288,7 @@ fn ty_to_string<'tcx>( let ty = infcx.resolve_vars_if_possible(ty); // We use `fn` ptr syntax for closures, but this only works when the closure does not capture // anything. We also remove all type parameters that are fully known to the type system. - let ty = ty.fold_with(&mut ClosureEraser { infcx, do_not_hide_nested_type: false }); + let ty = ty.fold_with(&mut ClosureEraser { infcx }); match (ty.kind(), called_method_def_id) { // We don't want the regular output for `fn`s because it includes its path in From 644c6948d01c66b744d8d7b8d06ea131a75e8311 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 24 Jan 2025 15:57:13 +0000 Subject: [PATCH 03/14] Add ffi tests for pattern types --- tests/ui/lint/clashing-extern-fn.rs | 41 ++++++++- tests/ui/lint/clashing-extern-fn.stderr | 116 +++++++++++++++++++++++- tests/ui/lint/lint-ctypes-enum.rs | 1 + tests/ui/lint/lint-ctypes-enum.stderr | 49 ++++++---- 4 files changed, 185 insertions(+), 22 deletions(-) diff --git a/tests/ui/lint/clashing-extern-fn.rs b/tests/ui/lint/clashing-extern-fn.rs index 9bbb20246df..0464299348b 100644 --- a/tests/ui/lint/clashing-extern-fn.rs +++ b/tests/ui/lint/clashing-extern-fn.rs @@ -1,7 +1,7 @@ //@ check-pass //@ aux-build:external_extern_fn.rs #![crate_type = "lib"] - +#![feature(pattern_type_macro, pattern_types)] mod redeclared_different_signature { mod a { extern "C" { @@ -490,3 +490,42 @@ mod hidden_niche { } } } + +mod pattern_types { + mod a { + use std::pat::pattern_type; + #[repr(transparent)] + struct NonZeroUsize(pattern_type!(usize is 1..)); + extern "C" { + fn pt_non_zero_usize() -> pattern_type!(usize is 1..); + //~^ WARN not FFI-safe + fn pt_non_zero_usize_opt() -> Option; + //~^ WARN not FFI-safe + fn pt_non_zero_usize_opt_full_range() -> Option; + //~^ WARN not FFI-safe + fn pt_non_null_ptr() -> pattern_type!(usize is 1..); + //~^ WARN not FFI-safe + fn pt_non_zero_usize_wrapper() -> NonZeroUsize; + //~^ WARN not FFI-safe + fn pt_non_zero_usize_wrapper_opt() -> Option; + //~^ WARN not FFI-safe + } + } + mod b { + extern "C" { + // If there's a clash in either of these cases you're either gaining an incorrect + // invariant that the value is non-zero, or you're missing out on that invariant. Both + // cases are warning for, from both a caller-convenience and optimisation perspective. + fn pt_non_zero_usize() -> usize; + //~^ WARN `pt_non_zero_usize` redeclared with a different signature + fn pt_non_zero_usize_opt() -> usize; + //~^ WARN `pt_non_zero_usize_opt` redeclared with a different signature + fn pt_non_null_ptr() -> *const (); + //~^ WARN `pt_non_null_ptr` redeclared with a different signature + fn pt_non_zero_usize_wrapper() -> usize; + //~^ WARN `pt_non_zero_usize_wrapper` redeclared with a different signature + fn pt_non_zero_usize_wrapper_opt() -> usize; + //~^ WARN `pt_non_zero_usize_wrapper_opt` redeclared with a different signature + } + } +} diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index 48dd1adbc1f..acf31a1f5dd 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -17,6 +17,60 @@ LL | fn hidden_niche_unsafe_cell() -> Option $DIR/clashing-extern-fn.rs:500:39 + | +LL | fn pt_non_zero_usize() -> pattern_type!(usize is 1..); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using the base type instead + = note: pattern types have no C equivalent + +warning: `extern` block uses type `Option<(usize) is 1..=>`, which is not FFI-safe + --> $DIR/clashing-extern-fn.rs:502:43 + | +LL | fn pt_non_zero_usize_opt() -> Option; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + +warning: `extern` block uses type `Option<(usize) is 0..=>`, which is not FFI-safe + --> $DIR/clashing-extern-fn.rs:504:54 + | +LL | fn pt_non_zero_usize_opt_full_range() -> Option; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + +warning: `extern` block uses type `(usize) is 1..=`, which is not FFI-safe + --> $DIR/clashing-extern-fn.rs:506:37 + | +LL | fn pt_non_null_ptr() -> pattern_type!(usize is 1..); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider using the base type instead + = note: pattern types have no C equivalent + +warning: `extern` block uses type `(usize) is 1..=`, which is not FFI-safe + --> $DIR/clashing-extern-fn.rs:508:47 + | +LL | fn pt_non_zero_usize_wrapper() -> NonZeroUsize; + | ^^^^^^^^^^^^ not FFI-safe + | + = help: consider using the base type instead + = note: pattern types have no C equivalent + +warning: `extern` block uses type `Option`, which is not FFI-safe + --> $DIR/clashing-extern-fn.rs:510:51 + | +LL | fn pt_non_zero_usize_wrapper_opt() -> Option; + | ^^^^^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + warning: `clash` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:13:13 | @@ -258,5 +312,65 @@ LL | fn hidden_niche_unsafe_cell() -> Option usize` found `unsafe extern "C" fn() -> Option>>` -warning: 22 warnings emitted +warning: `pt_non_zero_usize` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:519:13 + | +LL | fn pt_non_zero_usize() -> pattern_type!(usize is 1..); + | ------------------------------------------------------ `pt_non_zero_usize` previously declared here +... +LL | fn pt_non_zero_usize() -> usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn() -> (usize) is 1..=` + found `unsafe extern "C" fn() -> usize` + +warning: `pt_non_zero_usize_opt` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:521:13 + | +LL | fn pt_non_zero_usize_opt() -> Option; + | ------------------------------------------------------------------ `pt_non_zero_usize_opt` previously declared here +... +LL | fn pt_non_zero_usize_opt() -> usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn() -> Option<(usize) is 1..=>` + found `unsafe extern "C" fn() -> usize` + +warning: `pt_non_null_ptr` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:523:13 + | +LL | fn pt_non_null_ptr() -> pattern_type!(usize is 1..); + | ---------------------------------------------------- `pt_non_null_ptr` previously declared here +... +LL | fn pt_non_null_ptr() -> *const (); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn() -> (usize) is 1..=` + found `unsafe extern "C" fn() -> *const ()` + +warning: `pt_non_zero_usize_wrapper` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:525:13 + | +LL | fn pt_non_zero_usize_wrapper() -> NonZeroUsize; + | ----------------------------------------------- `pt_non_zero_usize_wrapper` previously declared here +... +LL | fn pt_non_zero_usize_wrapper() -> usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn() -> NonZeroUsize` + found `unsafe extern "C" fn() -> usize` + +warning: `pt_non_zero_usize_wrapper_opt` redeclared with a different signature + --> $DIR/clashing-extern-fn.rs:527:13 + | +LL | fn pt_non_zero_usize_wrapper_opt() -> Option; + | ----------------------------------------------------------- `pt_non_zero_usize_wrapper_opt` previously declared here +... +LL | fn pt_non_zero_usize_wrapper_opt() -> usize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration + | + = note: expected `unsafe extern "C" fn() -> Option` + found `unsafe extern "C" fn() -> usize` + +warning: 33 warnings emitted diff --git a/tests/ui/lint/lint-ctypes-enum.rs b/tests/ui/lint/lint-ctypes-enum.rs index 19af1de9576..0d19d5b5347 100644 --- a/tests/ui/lint/lint-ctypes-enum.rs +++ b/tests/ui/lint/lint-ctypes-enum.rs @@ -94,6 +94,7 @@ extern "C" { fn option_transparent_union(x: Option>>); //~^ ERROR `extern` block uses type fn option_repr_rust(x: Option>>); //~ ERROR `extern` block uses type + fn option_u8(x: Option); //~ ERROR `extern` block uses type fn result_ref_t(x: Result<&'static u8, ()>); fn result_fn_t(x: Result); diff --git a/tests/ui/lint/lint-ctypes-enum.stderr b/tests/ui/lint/lint-ctypes-enum.stderr index 8e92e7e6946..a491bd19605 100644 --- a/tests/ui/lint/lint-ctypes-enum.stderr +++ b/tests/ui/lint/lint-ctypes-enum.stderr @@ -79,8 +79,17 @@ LL | fn option_repr_rust(x: Option>>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint +error: `extern` block uses type `Option`, which is not FFI-safe + --> $DIR/lint-ctypes-enum.rs:97:21 + | +LL | fn option_u8(x: Option); + | ^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint + error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:106:33 + --> $DIR/lint-ctypes-enum.rs:107:33 | LL | fn result_nonzero_u128_t(x: Result, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -88,7 +97,7 @@ LL | fn result_nonzero_u128_t(x: Result, ()>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:113:33 + --> $DIR/lint-ctypes-enum.rs:114:33 | LL | fn result_nonzero_i128_t(x: Result, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -96,7 +105,7 @@ LL | fn result_nonzero_i128_t(x: Result, ()>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `Result>, ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:118:38 + --> $DIR/lint-ctypes-enum.rs:119:38 | LL | fn result_transparent_union_t(x: Result>, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -105,7 +114,7 @@ LL | fn result_transparent_union_t(x: Result>, ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:120:30 + --> $DIR/lint-ctypes-enum.rs:121:30 | LL | fn result_repr_rust_t(x: Result>, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -114,7 +123,7 @@ LL | fn result_repr_rust_t(x: Result>, ()>); = note: enum has no representation hint error: `extern` block uses type `Result, U>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:124:51 + --> $DIR/lint-ctypes-enum.rs:125:51 | LL | fn result_1zst_exhaustive_single_variant_t(x: Result, U>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -123,7 +132,7 @@ LL | fn result_1zst_exhaustive_single_variant_t(x: Result, = note: enum has no representation hint error: `extern` block uses type `Result, B>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:126:53 + --> $DIR/lint-ctypes-enum.rs:127:53 | LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result, B>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -132,7 +141,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_t(x: Result = note: enum has no representation hint error: `extern` block uses type `Result, NonExhaustive>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:128:51 + --> $DIR/lint-ctypes-enum.rs:129:51 | LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result, NonExhaustive>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -141,7 +150,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_t(x: Result, = note: enum has no representation hint error: `extern` block uses type `Result, Field>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:131:49 + --> $DIR/lint-ctypes-enum.rs:132:49 | LL | fn result_1zst_exhaustive_single_field_t(x: Result, Field>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -150,7 +159,7 @@ LL | fn result_1zst_exhaustive_single_field_t(x: Result, Fi = note: enum has no representation hint error: `extern` block uses type `Result>, ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:133:30 + --> $DIR/lint-ctypes-enum.rs:134:30 | LL | fn result_cascading_t(x: Result>, ()>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -159,7 +168,7 @@ LL | fn result_cascading_t(x: Result>, ()>); = note: enum has no representation hint error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:144:33 + --> $DIR/lint-ctypes-enum.rs:145:33 | LL | fn result_nonzero_u128_e(x: Result<(), num::NonZero>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -167,7 +176,7 @@ LL | fn result_nonzero_u128_e(x: Result<(), num::NonZero>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:151:33 + --> $DIR/lint-ctypes-enum.rs:152:33 | LL | fn result_nonzero_i128_e(x: Result<(), num::NonZero>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -175,7 +184,7 @@ LL | fn result_nonzero_i128_e(x: Result<(), num::NonZero>); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `Result<(), TransparentUnion>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:156:38 + --> $DIR/lint-ctypes-enum.rs:157:38 | LL | fn result_transparent_union_e(x: Result<(), TransparentUnion>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -184,7 +193,7 @@ LL | fn result_transparent_union_e(x: Result<(), TransparentUnion>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:158:30 + --> $DIR/lint-ctypes-enum.rs:159:30 | LL | fn result_repr_rust_e(x: Result<(), Rust>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -193,7 +202,7 @@ LL | fn result_repr_rust_e(x: Result<(), Rust>>); = note: enum has no representation hint error: `extern` block uses type `Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:162:51 + --> $DIR/lint-ctypes-enum.rs:163:51 | LL | fn result_1zst_exhaustive_single_variant_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -202,7 +211,7 @@ LL | fn result_1zst_exhaustive_single_variant_e(x: Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:164:53 + --> $DIR/lint-ctypes-enum.rs:165:53 | LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -211,7 +220,7 @@ LL | fn result_1zst_exhaustive_multiple_variant_e(x: Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:166:51 + --> $DIR/lint-ctypes-enum.rs:167:51 | LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -220,7 +229,7 @@ LL | fn result_1zst_non_exhaustive_no_variant_e(x: Result>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:169:49 + --> $DIR/lint-ctypes-enum.rs:170:49 | LL | fn result_1zst_exhaustive_single_field_e(x: Result>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -229,7 +238,7 @@ LL | fn result_1zst_exhaustive_single_field_e(x: Result>>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:171:30 + --> $DIR/lint-ctypes-enum.rs:172:30 | LL | fn result_cascading_e(x: Result<(), Result<(), num::NonZero>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -238,7 +247,7 @@ LL | fn result_cascading_e(x: Result<(), Result<(), num::NonZero>>); = note: enum has no representation hint error: `extern` block uses type `Result<(), ()>`, which is not FFI-safe - --> $DIR/lint-ctypes-enum.rs:173:27 + --> $DIR/lint-ctypes-enum.rs:174:27 | LL | fn result_unit_t_e(x: Result<(), ()>); | ^^^^^^^^^^^^^^ not FFI-safe @@ -246,5 +255,5 @@ LL | fn result_unit_t_e(x: Result<(), ()>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint -error: aborting due to 26 previous errors +error: aborting due to 27 previous errors From 473352da311f79bfaadb90c02c6458d02b1fb119 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 24 Jan 2025 15:57:13 +0000 Subject: [PATCH 04/14] Correctly handle pattern types in FFI safety --- compiler/rustc_lint/messages.ftl | 3 -- compiler/rustc_lint/src/types.rs | 8 ++--- tests/ui/lint/clashing-extern-fn.rs | 3 -- tests/ui/lint/clashing-extern-fn.stderr | 45 +++++-------------------- 4 files changed, 12 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 55c6a122d35..480d97e377a 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -390,9 +390,6 @@ lint_improper_ctypes_only_phantomdata = composed only of `PhantomData` lint_improper_ctypes_opaque = opaque types have no C equivalent -lint_improper_ctypes_pat_help = consider using the base type instead - -lint_improper_ctypes_pat_reason = pattern types have no C equivalent lint_improper_ctypes_slice_help = consider using a raw pointer instead lint_improper_ctypes_slice_reason = slices have no C equivalent diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 601d2fbfb67..0dccb8d336d 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1256,11 +1256,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { help: Some(fluent::lint_improper_ctypes_char_help), }, - ty::Pat(..) => FfiUnsafe { - ty, - reason: fluent::lint_improper_ctypes_pat_reason, - help: Some(fluent::lint_improper_ctypes_pat_help), - }, + // It's just extra invariants on the type that you need to uphold, + // but only the base type is relevant for being representable in FFI. + ty::Pat(base, ..) => self.check_type_for_ffi(acc, base), ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => { FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_128bit, help: None } diff --git a/tests/ui/lint/clashing-extern-fn.rs b/tests/ui/lint/clashing-extern-fn.rs index 0464299348b..012eda761f4 100644 --- a/tests/ui/lint/clashing-extern-fn.rs +++ b/tests/ui/lint/clashing-extern-fn.rs @@ -498,15 +498,12 @@ mod pattern_types { struct NonZeroUsize(pattern_type!(usize is 1..)); extern "C" { fn pt_non_zero_usize() -> pattern_type!(usize is 1..); - //~^ WARN not FFI-safe fn pt_non_zero_usize_opt() -> Option; //~^ WARN not FFI-safe fn pt_non_zero_usize_opt_full_range() -> Option; //~^ WARN not FFI-safe fn pt_non_null_ptr() -> pattern_type!(usize is 1..); - //~^ WARN not FFI-safe fn pt_non_zero_usize_wrapper() -> NonZeroUsize; - //~^ WARN not FFI-safe fn pt_non_zero_usize_wrapper_opt() -> Option; //~^ WARN not FFI-safe } diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index acf31a1f5dd..16d251c1d7a 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -17,17 +17,8 @@ LL | fn hidden_niche_unsafe_cell() -> Option $DIR/clashing-extern-fn.rs:500:39 - | -LL | fn pt_non_zero_usize() -> pattern_type!(usize is 1..); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider using the base type instead - = note: pattern types have no C equivalent - warning: `extern` block uses type `Option<(usize) is 1..=>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:502:43 + --> $DIR/clashing-extern-fn.rs:501:43 | LL | fn pt_non_zero_usize_opt() -> Option; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -36,7 +27,7 @@ LL | fn pt_non_zero_usize_opt() -> Option`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:504:54 + --> $DIR/clashing-extern-fn.rs:503:54 | LL | fn pt_non_zero_usize_opt_full_range() -> Option; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -44,26 +35,8 @@ LL | fn pt_non_zero_usize_opt_full_range() -> Option $DIR/clashing-extern-fn.rs:506:37 - | -LL | fn pt_non_null_ptr() -> pattern_type!(usize is 1..); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider using the base type instead - = note: pattern types have no C equivalent - -warning: `extern` block uses type `(usize) is 1..=`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:508:47 - | -LL | fn pt_non_zero_usize_wrapper() -> NonZeroUsize; - | ^^^^^^^^^^^^ not FFI-safe - | - = help: consider using the base type instead - = note: pattern types have no C equivalent - warning: `extern` block uses type `Option`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:510:51 + --> $DIR/clashing-extern-fn.rs:507:51 | LL | fn pt_non_zero_usize_wrapper_opt() -> Option; | ^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -313,7 +286,7 @@ LL | fn hidden_niche_unsafe_cell() -> Option Option>>` warning: `pt_non_zero_usize` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:519:13 + --> $DIR/clashing-extern-fn.rs:516:13 | LL | fn pt_non_zero_usize() -> pattern_type!(usize is 1..); | ------------------------------------------------------ `pt_non_zero_usize` previously declared here @@ -325,7 +298,7 @@ LL | fn pt_non_zero_usize() -> usize; found `unsafe extern "C" fn() -> usize` warning: `pt_non_zero_usize_opt` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:521:13 + --> $DIR/clashing-extern-fn.rs:518:13 | LL | fn pt_non_zero_usize_opt() -> Option; | ------------------------------------------------------------------ `pt_non_zero_usize_opt` previously declared here @@ -337,7 +310,7 @@ LL | fn pt_non_zero_usize_opt() -> usize; found `unsafe extern "C" fn() -> usize` warning: `pt_non_null_ptr` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:523:13 + --> $DIR/clashing-extern-fn.rs:520:13 | LL | fn pt_non_null_ptr() -> pattern_type!(usize is 1..); | ---------------------------------------------------- `pt_non_null_ptr` previously declared here @@ -349,7 +322,7 @@ LL | fn pt_non_null_ptr() -> *const (); found `unsafe extern "C" fn() -> *const ()` warning: `pt_non_zero_usize_wrapper` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:525:13 + --> $DIR/clashing-extern-fn.rs:522:13 | LL | fn pt_non_zero_usize_wrapper() -> NonZeroUsize; | ----------------------------------------------- `pt_non_zero_usize_wrapper` previously declared here @@ -361,7 +334,7 @@ LL | fn pt_non_zero_usize_wrapper() -> usize; found `unsafe extern "C" fn() -> usize` warning: `pt_non_zero_usize_wrapper_opt` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:527:13 + --> $DIR/clashing-extern-fn.rs:524:13 | LL | fn pt_non_zero_usize_wrapper_opt() -> Option; | ----------------------------------------------------------- `pt_non_zero_usize_wrapper_opt` previously declared here @@ -372,5 +345,5 @@ LL | fn pt_non_zero_usize_wrapper_opt() -> usize; = note: expected `unsafe extern "C" fn() -> Option` found `unsafe extern "C" fn() -> usize` -warning: 33 warnings emitted +warning: 30 warnings emitted From 5bae8ca77c3f6a0050a58b1bc96ee3d51d3feb32 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 24 Jan 2025 15:57:13 +0000 Subject: [PATCH 05/14] Correctly handle pattern types in FFI redeclaration lints --- compiler/rustc_lint/src/foreign_modules.rs | 9 +- compiler/rustc_lint/src/types.rs | 113 +++++++++++---------- tests/ui/lint/clashing-extern-fn.rs | 2 - tests/ui/lint/clashing-extern-fn.stderr | 32 +----- 4 files changed, 66 insertions(+), 90 deletions(-) diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index 45b188205d2..636779fe9b4 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -241,10 +241,7 @@ fn structurally_same_type_impl<'tcx>( if let ty::Adt(def, args) = *ty.kind() { let is_transparent = def.repr().transparent(); let is_non_null = types::nonnull_optimization_guaranteed(tcx, def); - debug!( - "non_transparent_ty({:?}) -- type is transparent? {}, type is non-null? {}", - ty, is_transparent, is_non_null - ); + debug!(?ty, is_transparent, is_non_null); if is_transparent && !is_non_null { debug_assert_eq!(def.variants().len(), 1); let v = &def.variant(FIRST_VARIANT); @@ -378,14 +375,14 @@ fn structurally_same_type_impl<'tcx>( // An Adt and a primitive or pointer type. This can be FFI-safe if non-null // enum layout optimisation is being applied. - (Adt(..), _) if is_primitive_or_pointer(b) => { + (Adt(..) | Pat(..), _) if is_primitive_or_pointer(b) => { if let Some(a_inner) = types::repr_nullable_ptr(tcx, typing_env, a, ckind) { a_inner == b } else { false } } - (_, Adt(..)) if is_primitive_or_pointer(a) => { + (_, Adt(..) | Pat(..)) if is_primitive_or_pointer(a) => { if let Some(b_inner) = types::repr_nullable_ptr(tcx, typing_env, b, ckind) { b_inner == a } else { diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 0dccb8d336d..47ceb4b7d28 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -907,9 +907,8 @@ fn get_nullable_type<'tcx>( }; return get_nullable_type(tcx, typing_env, inner_field_ty); } - ty::Int(ty) => Ty::new_int(tcx, ty), - ty::Uint(ty) => Ty::new_uint(tcx, ty), - ty::RawPtr(ty, mutbl) => Ty::new_ptr(tcx, ty, mutbl), + ty::Pat(base, ..) => return get_nullable_type(tcx, typing_env, base), + ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => ty, // As these types are always non-null, the nullable equivalent of // `Option` of these types are their raw pointer counterparts. ty::Ref(_region, ty, mutbl) => Ty::new_ptr(tcx, ty, mutbl), @@ -965,63 +964,69 @@ pub(crate) fn repr_nullable_ptr<'tcx>( ckind: CItemKind, ) -> Option> { debug!("is_repr_nullable_ptr(tcx, ty = {:?})", ty); - if let ty::Adt(ty_def, args) = ty.kind() { - let field_ty = match &ty_def.variants().raw[..] { - [var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) { - ([], [field]) | ([field], []) => field.ty(tcx, args), - ([field1], [field2]) => { - let ty1 = field1.ty(tcx, args); - let ty2 = field2.ty(tcx, args); + match ty.kind() { + ty::Adt(ty_def, args) => { + let field_ty = match &ty_def.variants().raw[..] { + [var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) { + ([], [field]) | ([field], []) => field.ty(tcx, args), + ([field1], [field2]) => { + let ty1 = field1.ty(tcx, args); + let ty2 = field2.ty(tcx, args); - if is_niche_optimization_candidate(tcx, typing_env, ty1) { - ty2 - } else if is_niche_optimization_candidate(tcx, typing_env, ty2) { - ty1 - } else { - return None; + if is_niche_optimization_candidate(tcx, typing_env, ty1) { + ty2 + } else if is_niche_optimization_candidate(tcx, typing_env, ty2) { + ty1 + } else { + return None; + } } - } + _ => return None, + }, _ => return None, - }, - _ => return None, - }; - - if !ty_is_known_nonnull(tcx, typing_env, field_ty, ckind) { - return None; - } - - // At this point, the field's type is known to be nonnull and the parent enum is Option-like. - // If the computed size for the field and the enum are different, the nonnull optimization isn't - // being applied (and we've got a problem somewhere). - let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, typing_env).ok(); - if !compute_size_skeleton(ty)?.same_size(compute_size_skeleton(field_ty)?) { - bug!("improper_ctypes: Option nonnull optimization not applied?"); - } - - // Return the nullable type this Option-like enum can be safely represented with. - let field_ty_layout = tcx.layout_of(typing_env.as_query_input(field_ty)); - if field_ty_layout.is_err() && !field_ty.has_non_region_param() { - bug!("should be able to compute the layout of non-polymorphic type"); - } - - let field_ty_abi = &field_ty_layout.ok()?.backend_repr; - if let BackendRepr::Scalar(field_ty_scalar) = field_ty_abi { - match field_ty_scalar.valid_range(&tcx) { - WrappingRange { start: 0, end } - if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 => - { - return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap()); - } - WrappingRange { start: 1, .. } => { - return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap()); - } - WrappingRange { start, end } => { - unreachable!("Unhandled start and end range: ({}, {})", start, end) - } }; + + if !ty_is_known_nonnull(tcx, typing_env, field_ty, ckind) { + return None; + } + + // At this point, the field's type is known to be nonnull and the parent enum is Option-like. + // If the computed size for the field and the enum are different, the nonnull optimization isn't + // being applied (and we've got a problem somewhere). + let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, typing_env).ok(); + if !compute_size_skeleton(ty)?.same_size(compute_size_skeleton(field_ty)?) { + bug!("improper_ctypes: Option nonnull optimization not applied?"); + } + + // Return the nullable type this Option-like enum can be safely represented with. + let field_ty_layout = tcx.layout_of(typing_env.as_query_input(field_ty)); + if field_ty_layout.is_err() && !field_ty.has_non_region_param() { + bug!("should be able to compute the layout of non-polymorphic type"); + } + + let field_ty_abi = &field_ty_layout.ok()?.backend_repr; + if let BackendRepr::Scalar(field_ty_scalar) = field_ty_abi { + match field_ty_scalar.valid_range(&tcx) { + WrappingRange { start: 0, end } + if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 => + { + return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap()); + } + WrappingRange { start: 1, .. } => { + return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap()); + } + WrappingRange { start, end } => { + unreachable!("Unhandled start and end range: ({}, {})", start, end) + } + }; + } + None } + ty::Pat(base, pat) => match **pat { + ty::PatternKind::Range { .. } => get_nullable_type(tcx, typing_env, *base), + }, + _ => None, } - None } impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { diff --git a/tests/ui/lint/clashing-extern-fn.rs b/tests/ui/lint/clashing-extern-fn.rs index 012eda761f4..1d1c07b66b2 100644 --- a/tests/ui/lint/clashing-extern-fn.rs +++ b/tests/ui/lint/clashing-extern-fn.rs @@ -514,13 +514,11 @@ mod pattern_types { // invariant that the value is non-zero, or you're missing out on that invariant. Both // cases are warning for, from both a caller-convenience and optimisation perspective. fn pt_non_zero_usize() -> usize; - //~^ WARN `pt_non_zero_usize` redeclared with a different signature fn pt_non_zero_usize_opt() -> usize; //~^ WARN `pt_non_zero_usize_opt` redeclared with a different signature fn pt_non_null_ptr() -> *const (); //~^ WARN `pt_non_null_ptr` redeclared with a different signature fn pt_non_zero_usize_wrapper() -> usize; - //~^ WARN `pt_non_zero_usize_wrapper` redeclared with a different signature fn pt_non_zero_usize_wrapper_opt() -> usize; //~^ WARN `pt_non_zero_usize_wrapper_opt` redeclared with a different signature } diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index 16d251c1d7a..a2fc9e77492 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -285,20 +285,8 @@ LL | fn hidden_niche_unsafe_cell() -> Option usize` found `unsafe extern "C" fn() -> Option>>` -warning: `pt_non_zero_usize` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:516:13 - | -LL | fn pt_non_zero_usize() -> pattern_type!(usize is 1..); - | ------------------------------------------------------ `pt_non_zero_usize` previously declared here -... -LL | fn pt_non_zero_usize() -> usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration - | - = note: expected `unsafe extern "C" fn() -> (usize) is 1..=` - found `unsafe extern "C" fn() -> usize` - warning: `pt_non_zero_usize_opt` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:518:13 + --> $DIR/clashing-extern-fn.rs:517:13 | LL | fn pt_non_zero_usize_opt() -> Option; | ------------------------------------------------------------------ `pt_non_zero_usize_opt` previously declared here @@ -310,7 +298,7 @@ LL | fn pt_non_zero_usize_opt() -> usize; found `unsafe extern "C" fn() -> usize` warning: `pt_non_null_ptr` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:520:13 + --> $DIR/clashing-extern-fn.rs:519:13 | LL | fn pt_non_null_ptr() -> pattern_type!(usize is 1..); | ---------------------------------------------------- `pt_non_null_ptr` previously declared here @@ -321,20 +309,8 @@ LL | fn pt_non_null_ptr() -> *const (); = note: expected `unsafe extern "C" fn() -> (usize) is 1..=` found `unsafe extern "C" fn() -> *const ()` -warning: `pt_non_zero_usize_wrapper` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:522:13 - | -LL | fn pt_non_zero_usize_wrapper() -> NonZeroUsize; - | ----------------------------------------------- `pt_non_zero_usize_wrapper` previously declared here -... -LL | fn pt_non_zero_usize_wrapper() -> usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration - | - = note: expected `unsafe extern "C" fn() -> NonZeroUsize` - found `unsafe extern "C" fn() -> usize` - warning: `pt_non_zero_usize_wrapper_opt` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:524:13 + --> $DIR/clashing-extern-fn.rs:522:13 | LL | fn pt_non_zero_usize_wrapper_opt() -> Option; | ----------------------------------------------------------- `pt_non_zero_usize_wrapper_opt` previously declared here @@ -345,5 +321,5 @@ LL | fn pt_non_zero_usize_wrapper_opt() -> usize; = note: expected `unsafe extern "C" fn() -> Option` found `unsafe extern "C" fn() -> usize` -warning: 30 warnings emitted +warning: 28 warnings emitted From 6d7ce4e893003cc652428ec02eb752bba63645e2 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 6 Feb 2025 13:48:12 +0000 Subject: [PATCH 06/14] Add a TyPat in the AST to reuse the generic arg lowering logic --- compiler/rustc_ast/src/ast.rs | 23 ++++- compiler/rustc_ast/src/mut_visit.rs | 20 ++++- compiler/rustc_ast/src/visit.rs | 17 +++- compiler/rustc_ast_lowering/src/pat.rs | 80 +++-------------- compiler/rustc_ast_pretty/src/pprust/state.rs | 24 ++++- .../rustc_builtin_macros/src/pattern_type.rs | 18 +++- compiler/rustc_resolve/src/late.rs | 15 ++++ src/tools/rustfmt/src/patterns.rs | 87 +++++++++++-------- src/tools/rustfmt/src/spanned.rs | 2 +- src/tools/rustfmt/src/types.rs | 16 ++++ .../pattern_types/assoc_const.default.stderr | 83 +++++------------- tests/ui/type/pattern_types/assoc_const.rs | 12 +-- .../bad_const_generics_args_on_const_param.rs | 2 +- ..._const_generics_args_on_const_param.stderr | 11 ++- tests/ui/type/pattern_types/const_block.rs | 2 +- .../ui/type/pattern_types/const_block.stderr | 72 --------------- .../feature-gate-pattern_types.rs | 1 + .../feature-gate-pattern_types.stderr | 8 +- .../feature-gate-pattern_types2.rs | 2 +- .../feature-gate-pattern_types2.stderr | 8 ++ tests/ui/unpretty/expanded-exhaustive.stdout | 2 +- 21 files changed, 241 insertions(+), 264 deletions(-) delete mode 100644 tests/ui/type/pattern_types/const_block.stderr create mode 100644 tests/ui/type/pattern_types/feature-gate-pattern_types2.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index deee3a597ae..29c1d34a125 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2249,7 +2249,7 @@ pub enum TyKind { CVarArgs, /// Pattern types like `pattern_type!(u32 is 1..=)`, which is the same as `NonZero`, /// just as part of the type system. - Pat(P, P), + Pat(P, P), /// Sometimes we need a dummy value when no error has occurred. Dummy, /// Placeholder for a kind that has failed to be defined. @@ -2277,6 +2277,27 @@ impl TyKind { } } +/// A pattern type pattern. +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct TyPat { + pub id: NodeId, + pub kind: TyPatKind, + pub span: Span, + pub tokens: Option, +} + +/// All the different flavors of pattern that Rust recognizes. +// +// Adding a new variant? Please update `test_pat` in `tests/ui/macros/stringify.rs`. +#[derive(Clone, Encodable, Decodable, Debug)] +pub enum TyPatKind { + /// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`). + Range(Option>, Option>, Spanned), + + /// Placeholder for a pattern that wasn't syntactically well formed in some way. + Err(ErrorGuaranteed), +} + /// Syntax used to declare a trait object. #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] #[repr(u8)] diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index a9961cca583..de9f049704a 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -210,6 +210,10 @@ pub trait MutVisitor: Sized { walk_ty(self, t); } + fn visit_ty_pat(&mut self, t: &mut P) { + walk_ty_pat(self, t); + } + fn visit_lifetime(&mut self, l: &mut Lifetime) { walk_lifetime(self, l); } @@ -570,7 +574,7 @@ pub fn walk_ty(vis: &mut T, ty: &mut P) { TyKind::Paren(ty) => vis.visit_ty(ty), TyKind::Pat(ty, pat) => { vis.visit_ty(ty); - vis.visit_pat(pat); + vis.visit_ty_pat(pat); } TyKind::Path(qself, path) => { vis.visit_qself(qself); @@ -594,6 +598,20 @@ pub fn walk_ty(vis: &mut T, ty: &mut P) { vis.visit_span(span); } +pub fn walk_ty_pat(vis: &mut T, ty: &mut P) { + let TyPat { id, kind, span, tokens } = ty.deref_mut(); + vis.visit_id(id); + match kind { + TyPatKind::Range(start, end, _include_end) => { + visit_opt(start, |c| vis.visit_anon_const(c)); + visit_opt(end, |c| vis.visit_anon_const(c)); + } + TyPatKind::Err(_) => {} + } + visit_lazy_tts(vis, tokens); + vis.visit_span(span); +} + fn walk_foreign_mod(vis: &mut T, foreign_mod: &mut ForeignMod) { let ForeignMod { extern_span: _, safety, abi: _, items } = foreign_mod; visit_safety(vis, safety); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 714b074f930..3242d414595 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -179,6 +179,9 @@ pub trait Visitor<'ast>: Sized { fn visit_ty(&mut self, t: &'ast Ty) -> Self::Result { walk_ty(self, t) } + fn visit_ty_pat(&mut self, t: &'ast TyPat) -> Self::Result { + walk_ty_pat(self, t) + } fn visit_generic_param(&mut self, param: &'ast GenericParam) -> Self::Result { walk_generic_param(self, param) } @@ -534,7 +537,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { } TyKind::Pat(ty, pat) => { try_visit!(visitor.visit_ty(ty)); - try_visit!(visitor.visit_pat(pat)); + try_visit!(visitor.visit_ty_pat(pat)); } TyKind::Array(ty, length) => { try_visit!(visitor.visit_ty(ty)); @@ -555,6 +558,18 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { V::Result::output() } +pub fn walk_ty_pat<'a, V: Visitor<'a>>(visitor: &mut V, tp: &'a TyPat) -> V::Result { + let TyPat { id: _, kind, span: _, tokens: _ } = tp; + match kind { + TyPatKind::Range(start, end, _include_end) => { + visit_opt!(visitor, visit_anon_const, start); + visit_opt!(visitor, visit_anon_const, end); + } + TyPatKind::Err(_) => {} + } + V::Result::output() +} + fn walk_qself<'a, V: Visitor<'a>>(visitor: &mut V, qself: &'a Option>) -> V::Result { if let Some(qself) = qself { let QSelf { ty, path_span: _, position: _ } = &**qself; diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index bb9b2a13185..e1f3afbcf59 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -4,10 +4,10 @@ use rustc_ast::ptr::P; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; -use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def::Res; use rustc_middle::span_bug; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{Ident, Span, kw}; +use rustc_span::{Ident, Span}; use super::errors::{ ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding, @@ -430,78 +430,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc(hir::PatExpr { hir_id: self.lower_node_id(expr.id), span, kind }) } - pub(crate) fn lower_ty_pat(&mut self, pattern: &Pat) -> &'hir hir::TyPat<'hir> { + pub(crate) fn lower_ty_pat(&mut self, pattern: &TyPat) -> &'hir hir::TyPat<'hir> { self.arena.alloc(self.lower_ty_pat_mut(pattern)) } - fn lower_ty_pat_mut(&mut self, mut pattern: &Pat) -> hir::TyPat<'hir> { + fn lower_ty_pat_mut(&mut self, pattern: &TyPat) -> hir::TyPat<'hir> { // loop here to avoid recursion let pat_hir_id = self.lower_node_id(pattern.id); - let node = loop { - match &pattern.kind { - PatKind::Range(e1, e2, Spanned { node: end, .. }) => { - // FIXME(pattern_types): remove this closure and call `lower_const_arg` instead. - // That requires first modifying the AST to have const args here. - let mut lower_expr = |e: &Expr| -> &_ { - if let ExprKind::Path(None, path) = &e.kind - && let Some(res) = self - .resolver - .get_partial_res(e.id) - .and_then(|partial_res| partial_res.full_res()) - { - self.lower_const_path_to_const_arg(path, res, e.id, e.span) - } else { - let node_id = self.next_node_id(); - let def_id = self.create_def( - self.current_hir_id_owner.def_id, - node_id, - kw::Empty, - DefKind::AnonConst, - e.span, - ); - let hir_id = self.lower_node_id(node_id); - let ac = self.arena.alloc(hir::AnonConst { - def_id, - hir_id, - body: self.lower_const_body(pattern.span, Some(e)), - span: self.lower_span(pattern.span), - }); - self.arena.alloc(hir::ConstArg { - hir_id: self.next_id(), - kind: hir::ConstArgKind::Anon(ac), - }) - } - }; - break hir::TyPatKind::Range( - e1.as_deref().map(|e| lower_expr(e)), - e2.as_deref().map(|e| lower_expr(e)), - self.lower_range_end(end, e2.is_some()), - ); - } - // return inner to be processed in next loop - PatKind::Paren(inner) => pattern = inner, - PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span), - PatKind::Err(guar) => break hir::TyPatKind::Err(*guar), - PatKind::Deref(..) - | PatKind::Box(..) - | PatKind::Or(..) - | PatKind::Struct(..) - | PatKind::TupleStruct(..) - | PatKind::Tuple(..) - | PatKind::Ref(..) - | PatKind::Expr(..) - | PatKind::Guard(..) - | PatKind::Slice(_) - | PatKind::Ident(..) - | PatKind::Path(..) - | PatKind::Wild - | PatKind::Never - | PatKind::Rest => { - break hir::TyPatKind::Err( - self.dcx().span_err(pattern.span, "pattern not supported in pattern types"), - ); - } - } + let node = match &pattern.kind { + TyPatKind::Range(e1, e2, Spanned { node: end, .. }) => hir::TyPatKind::Range( + e1.as_deref().map(|e| self.lower_anon_const_to_const_arg(e)), + e2.as_deref().map(|e| self.lower_anon_const_to_const_arg(e)), + self.lower_range_end(end, e2.is_some()), + ), + TyPatKind::Err(guar) => hir::TyPatKind::Err(*guar), }; hir::TyPat { hir_id: pat_hir_id, kind: node, span: self.lower_span(pattern.span) } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index eeec24e5ea4..0bf5de3ef89 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1148,6 +1148,28 @@ impl<'a> State<'a> { } } + pub fn print_ty_pat(&mut self, pat: &ast::TyPat) { + match &pat.kind { + rustc_ast::TyPatKind::Range(start, end, include_end) => { + if let Some(start) = start { + self.print_expr_anon_const(start, &[]); + } + self.word(".."); + if let Some(end) = end { + if let RangeEnd::Included(_) = include_end.node { + self.word("="); + } + self.print_expr_anon_const(end, &[]); + } + } + rustc_ast::TyPatKind::Err(_) => { + self.popen(); + self.word("/*ERROR*/"); + self.pclose(); + } + } + } + pub fn print_type(&mut self, ty: &ast::Ty) { self.maybe_print_comment(ty.span.lo()); self.ibox(0); @@ -1252,7 +1274,7 @@ impl<'a> State<'a> { ast::TyKind::Pat(ty, pat) => { self.print_type(ty); self.word(" is "); - self.print_pat(pat); + self.print_ty_pat(pat); } } self.end(); diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs index a600a9f316a..a55c7e962d0 100644 --- a/compiler/rustc_builtin_macros/src/pattern_type.rs +++ b/compiler/rustc_builtin_macros/src/pattern_type.rs @@ -1,6 +1,6 @@ use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{Pat, Ty, ast}; +use rustc_ast::{AnonConst, DUMMY_NODE_ID, Ty, TyPat, TyPatKind, ast}; use rustc_errors::PResult; use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; use rustc_parse::exp; @@ -21,12 +21,24 @@ pub(crate) fn expand<'cx>( ExpandResult::Ready(base::MacEager::ty(cx.ty(sp, ast::TyKind::Pat(ty, pat)))) } -fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P, P)> { +fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P, P)> { let mut parser = cx.new_parser_from_tts(stream); let ty = parser.parse_ty()?; parser.expect_keyword(exp!(Is))?; - let pat = parser.parse_pat_no_top_alt(None, None)?; + let pat = parser.parse_pat_no_top_alt(None, None)?.into_inner(); + + let kind = match pat.kind { + ast::PatKind::Range(start, end, include_end) => TyPatKind::Range( + start.map(|value| P(AnonConst { id: DUMMY_NODE_ID, value })), + end.map(|value| P(AnonConst { id: DUMMY_NODE_ID, value })), + include_end, + ), + ast::PatKind::Err(guar) => TyPatKind::Err(guar), + _ => TyPatKind::Err(cx.dcx().span_err(pat.span, "pattern not supported in pattern types")), + }; + + let pat = P(TyPat { id: pat.id, kind, span: pat.span, tokens: pat.tokens }); Ok((ty, pat)) } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 508bd831ccb..03aeb8720ca 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -923,6 +923,21 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r self.diag_metadata.current_trait_object = prev; self.diag_metadata.current_type_path = prev_ty; } + + fn visit_ty_pat(&mut self, t: &'ast TyPat) -> Self::Result { + match &t.kind { + TyPatKind::Range(start, end, _) => { + if let Some(start) = start { + self.resolve_anon_const(start, AnonConstKind::ConstArg(IsRepeatExpr::No)); + } + if let Some(end) = end { + self.resolve_anon_const(end, AnonConstKind::ConstArg(IsRepeatExpr::No)); + } + } + TyPatKind::Err(_) => {} + } + } + fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef) { let span = tref.span.shrink_to_lo().to(tref.trait_ref.path.span.shrink_to_lo()); self.with_generic_param_rib( diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index 1d88726d945..bafed41e39f 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -75,12 +75,12 @@ fn is_short_pattern_inner(context: &RewriteContext<'_>, pat: &ast::Pat) -> bool } } -pub(crate) struct RangeOperand<'a> { - operand: &'a Option>, - pub(crate) span: Span, +pub(crate) struct RangeOperand<'a, T> { + pub operand: &'a Option>, + pub span: Span, } -impl<'a> Rewrite for RangeOperand<'a> { +impl<'a, T: Rewrite> Rewrite for RangeOperand<'a, T> { fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { self.rewrite_result(context, shape).ok() } @@ -259,40 +259,7 @@ impl Rewrite for Pat { } PatKind::Never => Err(RewriteError::Unknown), PatKind::Range(ref lhs, ref rhs, ref end_kind) => { - let infix = match end_kind.node { - RangeEnd::Included(RangeSyntax::DotDotDot) => "...", - RangeEnd::Included(RangeSyntax::DotDotEq) => "..=", - RangeEnd::Excluded => "..", - }; - let infix = if context.config.spaces_around_ranges() { - let lhs_spacing = match lhs { - None => "", - Some(_) => " ", - }; - let rhs_spacing = match rhs { - None => "", - Some(_) => " ", - }; - format!("{lhs_spacing}{infix}{rhs_spacing}") - } else { - infix.to_owned() - }; - let lspan = self.span.with_hi(end_kind.span.lo()); - let rspan = self.span.with_lo(end_kind.span.hi()); - rewrite_pair( - &RangeOperand { - operand: lhs, - span: lspan, - }, - &RangeOperand { - operand: rhs, - span: rspan, - }, - PairParts::infix(&infix), - context, - shape, - SeparatorPlace::Front, - ) + rewrite_range_pat(context, shape, lhs, rhs, end_kind, self.span) } PatKind::Ref(ref pat, mutability) => { let prefix = format!("&{}", format_mutability(mutability)); @@ -359,6 +326,50 @@ impl Rewrite for Pat { } } +pub fn rewrite_range_pat( + context: &RewriteContext<'_>, + shape: Shape, + lhs: &Option>, + rhs: &Option>, + end_kind: &rustc_span::source_map::Spanned, + span: Span, +) -> RewriteResult { + let infix = match end_kind.node { + RangeEnd::Included(RangeSyntax::DotDotDot) => "...", + RangeEnd::Included(RangeSyntax::DotDotEq) => "..=", + RangeEnd::Excluded => "..", + }; + let infix = if context.config.spaces_around_ranges() { + let lhs_spacing = match lhs { + None => "", + Some(_) => " ", + }; + let rhs_spacing = match rhs { + None => "", + Some(_) => " ", + }; + format!("{lhs_spacing}{infix}{rhs_spacing}") + } else { + infix.to_owned() + }; + let lspan = span.with_hi(end_kind.span.lo()); + let rspan = span.with_lo(end_kind.span.hi()); + rewrite_pair( + &RangeOperand { + operand: lhs, + span: lspan, + }, + &RangeOperand { + operand: rhs, + span: rspan, + }, + PairParts::infix(&infix), + context, + shape, + SeparatorPlace::Front, + ) +} + fn rewrite_struct_pat( qself: &Option>, path: &ast::Path, diff --git a/src/tools/rustfmt/src/spanned.rs b/src/tools/rustfmt/src/spanned.rs index 6b3e40b9115..e93eb53cd87 100644 --- a/src/tools/rustfmt/src/spanned.rs +++ b/src/tools/rustfmt/src/spanned.rs @@ -211,7 +211,7 @@ impl Spanned for ast::PreciseCapturingArg { } } -impl<'a> Spanned for RangeOperand<'a> { +impl<'a, T> Spanned for RangeOperand<'a, T> { fn span(&self) -> Span { self.span } diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index f8b713117f4..0009490e86f 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -18,6 +18,7 @@ use crate::lists::{ use crate::macros::{MacroPosition, rewrite_macro}; use crate::overflow; use crate::pairs::{PairParts, rewrite_pair}; +use crate::patterns::rewrite_range_pat; use crate::rewrite::{Rewrite, RewriteContext, RewriteError, RewriteErrorExt, RewriteResult}; use crate::shape::Shape; use crate::source_map::SpanUtils; @@ -1045,6 +1046,21 @@ impl Rewrite for ast::Ty { } } +impl Rewrite for ast::TyPat { + fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option { + self.rewrite_result(context, shape).ok() + } + + fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult { + match self.kind { + ast::TyPatKind::Range(ref lhs, ref rhs, ref end_kind) => { + rewrite_range_pat(context, shape, lhs, rhs, end_kind, self.span) + } + ast::TyPatKind::Err(_) => Err(RewriteError::Unknown), + } + } +} + fn rewrite_bare_fn( bare_fn: &ast::BareFnTy, span: Span, diff --git a/tests/ui/type/pattern_types/assoc_const.default.stderr b/tests/ui/type/pattern_types/assoc_const.default.stderr index c5d9691a029..8cff0cee7b9 100644 --- a/tests/ui/type/pattern_types/assoc_const.default.stderr +++ b/tests/ui/type/pattern_types/assoc_const.default.stderr @@ -1,79 +1,38 @@ -error[E0658]: wraparound pattern type ranges cause monomorphization time errors - --> $DIR/assoc_const.rs:17:19 +error: generic parameters may not be used in const operations + --> $DIR/assoc_const.rs:17:41 | LL | fn foo(_: pattern_type!(u32 is ::START..=::END)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ cannot perform const operation using `T` | - = note: see issue #136574 for more information - = help: add `#![feature(generic_pattern_types)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: type parameters may not be used in const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions -error[E0658]: wraparound pattern type ranges cause monomorphization time errors - --> $DIR/assoc_const.rs:17:19 +error: generic parameters may not be used in const operations + --> $DIR/assoc_const.rs:17:61 | LL | fn foo(_: pattern_type!(u32 is ::START..=::END)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ cannot perform const operation using `T` | - = note: see issue #136574 for more information - = help: add `#![feature(generic_pattern_types)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + = note: type parameters may not be used in const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions -error: constant expression depends on a generic parameter - --> $DIR/assoc_const.rs:17:19 - | -LL | fn foo(_: pattern_type!(u32 is ::START..=::END)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this may fail depending on what value the parameter takes - -error: constant expression depends on a generic parameter - --> $DIR/assoc_const.rs:17:19 - | -LL | fn foo(_: pattern_type!(u32 is ::START..=::END)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this may fail depending on what value the parameter takes - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0658]: wraparound pattern type ranges cause monomorphization time errors - --> $DIR/assoc_const.rs:22:19 +error: generic parameters may not be used in const operations + --> $DIR/assoc_const.rs:20:40 | LL | fn bar(_: pattern_type!(u32 is T::START..=T::END)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^ cannot perform const operation using `T` | - = note: see issue #136574 for more information - = help: add `#![feature(generic_pattern_types)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: type parameters may not be used in const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions -error[E0658]: wraparound pattern type ranges cause monomorphization time errors - --> $DIR/assoc_const.rs:22:19 +error: generic parameters may not be used in const operations + --> $DIR/assoc_const.rs:20:51 | LL | fn bar(_: pattern_type!(u32 is T::START..=T::END)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ cannot perform const operation using `T` | - = note: see issue #136574 for more information - = help: add `#![feature(generic_pattern_types)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + = note: type parameters may not be used in const expressions + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions -error: constant expression depends on a generic parameter - --> $DIR/assoc_const.rs:22:19 - | -LL | fn bar(_: pattern_type!(u32 is T::START..=T::END)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this may fail depending on what value the parameter takes +error: aborting due to 4 previous errors -error: constant expression depends on a generic parameter - --> $DIR/assoc_const.rs:22:19 - | -LL | fn bar(_: pattern_type!(u32 is T::START..=T::END)) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this may fail depending on what value the parameter takes - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 8 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/type/pattern_types/assoc_const.rs b/tests/ui/type/pattern_types/assoc_const.rs index 87886587d51..90508801990 100644 --- a/tests/ui/type/pattern_types/assoc_const.rs +++ b/tests/ui/type/pattern_types/assoc_const.rs @@ -15,14 +15,10 @@ trait Foo { } fn foo(_: pattern_type!(u32 is ::START..=::END)) {} -//[default]~^ ERROR: constant expression depends on a generic parameter -//[default]~| ERROR: constant expression depends on a generic parameter -//[default]~| ERROR: wraparound pattern type ranges cause monomorphization time errors -//[default]~| ERROR: wraparound pattern type ranges cause monomorphization time errors +//[default]~^ ERROR: generic parameters may not be used in const operations +//[default]~| ERROR: generic parameters may not be used in const operations fn bar(_: pattern_type!(u32 is T::START..=T::END)) {} -//[default]~^ ERROR: constant expression depends on a generic parameter -//[default]~| ERROR: constant expression depends on a generic parameter -//[default]~| ERROR: wraparound pattern type ranges cause monomorphization time errors -//[default]~| ERROR: wraparound pattern type ranges cause monomorphization time errors +//[default]~^ ERROR: generic parameters may not be used in const operations +//[default]~| ERROR: generic parameters may not be used in const operations fn main() {} diff --git a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs index 0f10bf8ce62..c28fda6f91a 100644 --- a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs +++ b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs @@ -5,7 +5,7 @@ //@ normalize-stderr: "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: " //@ rustc-env:RUST_BACKTRACE=0 -#![feature(pattern_types, pattern_type_macro)] +#![feature(pattern_types, pattern_type_macro, generic_const_exprs)] #![allow(internal_features)] type Pat = diff --git a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr index fbe80a19863..ffc6068eb17 100644 --- a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr +++ b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr @@ -1,4 +1,11 @@ -error: internal compiler error: compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs:LL:CC: try_lower_anon_const_lit: received const param which shouldn't be possible +warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/bad_const_generics_args_on_const_param.rs:8:47 + | +LL | #![feature(pattern_types, pattern_type_macro, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #76560 for more information + = error: internal compiler error: compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs:LL:CC: try_lower_anon_const_lit: received const param which shouldn't be possible --> $DIR/bad_const_generics_args_on_const_param.rs:12:36 | LL | std::pat::pattern_type!(u32 is START::<(), i32, 2>..=END::<_, Assoc = ()>); @@ -10,5 +17,5 @@ query stack during panic: #0 [type_of] expanding type alias `Pat` #1 [check_well_formed] checking that `Pat` is well-formed ... and 2 other queries... use `env RUST_BACKTRACE=1` to see the full query stack -error: aborting due to 1 previous error +error: aborting due to 1 previous error; 1 warning emitted diff --git a/tests/ui/type/pattern_types/const_block.rs b/tests/ui/type/pattern_types/const_block.rs index 49c87f4fa0d..ed19b10671a 100644 --- a/tests/ui/type/pattern_types/const_block.rs +++ b/tests/ui/type/pattern_types/const_block.rs @@ -1,10 +1,10 @@ #![feature(pattern_types)] #![feature(pattern_type_macro)] #![feature(inline_const_pat)] +//@ check-pass use std::pat::pattern_type; fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} -//~^ ERROR: cycle fn main() {} diff --git a/tests/ui/type/pattern_types/const_block.stderr b/tests/ui/type/pattern_types/const_block.stderr deleted file mode 100644 index 82b616105af..00000000000 --- a/tests/ui/type/pattern_types/const_block.stderr +++ /dev/null @@ -1,72 +0,0 @@ -error[E0391]: cycle detected when evaluating type-level constant - --> $DIR/const_block.rs:7:36 - | -LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} - | ^^^^^^^^^^^^^^ - | -note: ...which requires const-evaluating + checking `bar::{constant#2}`... - --> $DIR/const_block.rs:7:36 - | -LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} - | ^^^^^^^^^^^^^^ -note: ...which requires caching mir of `bar::{constant#2}` for CTFE... - --> $DIR/const_block.rs:7:36 - | -LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} - | ^^^^^^^^^^^^^^ -note: ...which requires elaborating drops for `bar::{constant#2}`... - --> $DIR/const_block.rs:7:36 - | -LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} - | ^^^^^^^^^^^^^^ -note: ...which requires borrow-checking `bar::{constant#2}`... - --> $DIR/const_block.rs:7:36 - | -LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} - | ^^^^^^^^^^^^^^ -note: ...which requires borrow-checking `bar::{constant#0}`... - --> $DIR/const_block.rs:7:41 - | -LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} - | ^^^^^^^^^ -note: ...which requires promoting constants in MIR for `bar::{constant#0}`... - --> $DIR/const_block.rs:7:41 - | -LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} - | ^^^^^^^^^ -note: ...which requires const checking `bar::{constant#0}`... - --> $DIR/const_block.rs:7:41 - | -LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} - | ^^^^^^^^^ -note: ...which requires building MIR for `bar::{constant#0}`... - --> $DIR/const_block.rs:7:41 - | -LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} - | ^^^^^^^^^ -note: ...which requires match-checking `bar::{constant#0}`... - --> $DIR/const_block.rs:7:41 - | -LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} - | ^^^^^^^^^ -note: ...which requires type-checking `bar::{constant#0}`... - --> $DIR/const_block.rs:7:41 - | -LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} - | ^^^^^^^^^ -note: ...which requires type-checking `bar`... - --> $DIR/const_block.rs:7:1 - | -LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires evaluating type-level constant, completing the cycle -note: cycle used when checking that `bar` is well-formed - --> $DIR/const_block.rs:7:1 - | -LL | fn bar(x: pattern_type!(u32 is 0..=const{ 5 + 5 })) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types.rs b/tests/ui/type/pattern_types/feature-gate-pattern_types.rs index b90ba478402..b4f4bd656f5 100644 --- a/tests/ui/type/pattern_types/feature-gate-pattern_types.rs +++ b/tests/ui/type/pattern_types/feature-gate-pattern_types.rs @@ -12,3 +12,4 @@ type Positive = pattern_type!(i32 is 0..); //~^ use of unstable library feature `pattern_type_macro` type Always = pattern_type!(Option is Some(_)); //~^ use of unstable library feature `pattern_type_macro` +//~| ERROR pattern not supported in pattern types diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr b/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr index 69239d68bdc..12508bcb54a 100644 --- a/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr +++ b/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr @@ -48,6 +48,12 @@ LL | type Always = pattern_type!(Option is Some(_)); = help: add `#![feature(pattern_type_macro)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 5 previous errors +error: pattern not supported in pattern types + --> $DIR/feature-gate-pattern_types.rs:13:44 + | +LL | type Always = pattern_type!(Option is Some(_)); + | ^^^^^^^ + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs b/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs index 50c355c8de6..c6b4b325fa3 100644 --- a/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs +++ b/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs @@ -1,5 +1,4 @@ //@ compile-flags: -Zno-analysis -//@ check-pass #![feature(pattern_type_macro)] @@ -10,3 +9,4 @@ type Percent = pattern_type!(u32 is 0..=100); type Negative = pattern_type!(i32 is ..=0); type Positive = pattern_type!(i32 is 0..); type Always = pattern_type!(Option is Some(_)); +//~^ ERROR: pattern not supported in pattern types diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types2.stderr b/tests/ui/type/pattern_types/feature-gate-pattern_types2.stderr new file mode 100644 index 00000000000..81bf9dea0e2 --- /dev/null +++ b/tests/ui/type/pattern_types/feature-gate-pattern_types2.stderr @@ -0,0 +1,8 @@ +error: pattern not supported in pattern types + --> $DIR/feature-gate-pattern_types2.rs:11:44 + | +LL | type Always = pattern_type!(Option is Some(_)); + | ^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout index 11066c90edb..19ae66f7a07 100644 --- a/tests/ui/unpretty/expanded-exhaustive.stdout +++ b/tests/ui/unpretty/expanded-exhaustive.stdout @@ -678,7 +678,7 @@ mod types { /*! FIXME: todo */ } /// TyKind::Pat - fn ty_pat() { let _: u32 is 1..; } + fn ty_pat() { let _: u32 is const 1..; } } mod visibilities { /// VisibilityKind::Public From f1f996a4d590e3d75eb5c5dab5098b7ae2ebf7eb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 28 Jan 2025 11:08:22 +0000 Subject: [PATCH 07/14] Handle pattern types wrapped in `Option` in FFI checks --- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint/src/types.rs | 31 ++++++++++++++++ tests/ui/lint/clashing-extern-fn.rs | 4 --- tests/ui/lint/clashing-extern-fn.stderr | 48 ++----------------------- 4 files changed, 35 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index d89e615e14a..c8de5e87753 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -33,6 +33,7 @@ #![feature(let_chains)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] +#![feature(try_blocks)] #![warn(unreachable_pub)] // tidy-alphabetical-end diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 47ceb4b7d28..68b1f435a4c 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -877,6 +877,37 @@ fn ty_is_known_nonnull<'tcx>( .filter_map(|variant| transparent_newtype_field(tcx, variant)) .any(|field| ty_is_known_nonnull(tcx, typing_env, field.ty(tcx, args), mode)) } + ty::Pat(base, pat) => { + ty_is_known_nonnull(tcx, typing_env, *base, mode) + || Option::unwrap_or_default( + try { + match **pat { + ty::PatternKind::Range { start, end, include_end } => { + match (start, end) { + (Some(start), None) => { + start.try_to_value()?.try_to_bits(tcx, typing_env)? > 0 + } + (Some(start), Some(end)) => { + let start = + start.try_to_value()?.try_to_bits(tcx, typing_env)?; + let end = + end.try_to_value()?.try_to_bits(tcx, typing_env)?; + + if include_end { + // This also works for negative numbers, as we just need + // to ensure we aren't wrapping over zero. + start > 0 && end >= start + } else { + start > 0 && end > start + } + } + _ => false, + } + } + } + }, + ) + } _ => false, } } diff --git a/tests/ui/lint/clashing-extern-fn.rs b/tests/ui/lint/clashing-extern-fn.rs index 1d1c07b66b2..e4477c96202 100644 --- a/tests/ui/lint/clashing-extern-fn.rs +++ b/tests/ui/lint/clashing-extern-fn.rs @@ -499,13 +499,11 @@ mod pattern_types { extern "C" { fn pt_non_zero_usize() -> pattern_type!(usize is 1..); fn pt_non_zero_usize_opt() -> Option; - //~^ WARN not FFI-safe fn pt_non_zero_usize_opt_full_range() -> Option; //~^ WARN not FFI-safe fn pt_non_null_ptr() -> pattern_type!(usize is 1..); fn pt_non_zero_usize_wrapper() -> NonZeroUsize; fn pt_non_zero_usize_wrapper_opt() -> Option; - //~^ WARN not FFI-safe } } mod b { @@ -515,12 +513,10 @@ mod pattern_types { // cases are warning for, from both a caller-convenience and optimisation perspective. fn pt_non_zero_usize() -> usize; fn pt_non_zero_usize_opt() -> usize; - //~^ WARN `pt_non_zero_usize_opt` redeclared with a different signature fn pt_non_null_ptr() -> *const (); //~^ WARN `pt_non_null_ptr` redeclared with a different signature fn pt_non_zero_usize_wrapper() -> usize; fn pt_non_zero_usize_wrapper_opt() -> usize; - //~^ WARN `pt_non_zero_usize_wrapper_opt` redeclared with a different signature } } } diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index a2fc9e77492..118b18b224c 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -17,17 +17,8 @@ LL | fn hidden_niche_unsafe_cell() -> Option`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:501:43 - | -LL | fn pt_non_zero_usize_opt() -> Option; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - warning: `extern` block uses type `Option<(usize) is 0..=>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:503:54 + --> $DIR/clashing-extern-fn.rs:502:54 | LL | fn pt_non_zero_usize_opt_full_range() -> Option; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -35,15 +26,6 @@ LL | fn pt_non_zero_usize_opt_full_range() -> Option`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:507:51 - | -LL | fn pt_non_zero_usize_wrapper_opt() -> Option; - | ^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum - = note: enum has no representation hint - warning: `clash` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:13:13 | @@ -285,20 +267,8 @@ LL | fn hidden_niche_unsafe_cell() -> Option usize` found `unsafe extern "C" fn() -> Option>>` -warning: `pt_non_zero_usize_opt` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:517:13 - | -LL | fn pt_non_zero_usize_opt() -> Option; - | ------------------------------------------------------------------ `pt_non_zero_usize_opt` previously declared here -... -LL | fn pt_non_zero_usize_opt() -> usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration - | - = note: expected `unsafe extern "C" fn() -> Option<(usize) is 1..=>` - found `unsafe extern "C" fn() -> usize` - warning: `pt_non_null_ptr` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:519:13 + --> $DIR/clashing-extern-fn.rs:516:13 | LL | fn pt_non_null_ptr() -> pattern_type!(usize is 1..); | ---------------------------------------------------- `pt_non_null_ptr` previously declared here @@ -309,17 +279,5 @@ LL | fn pt_non_null_ptr() -> *const (); = note: expected `unsafe extern "C" fn() -> (usize) is 1..=` found `unsafe extern "C" fn() -> *const ()` -warning: `pt_non_zero_usize_wrapper_opt` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:522:13 - | -LL | fn pt_non_zero_usize_wrapper_opt() -> Option; - | ----------------------------------------------------------- `pt_non_zero_usize_wrapper_opt` previously declared here -... -LL | fn pt_non_zero_usize_wrapper_opt() -> usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration - | - = note: expected `unsafe extern "C" fn() -> Option` - found `unsafe extern "C" fn() -> usize` - -warning: 28 warnings emitted +warning: 24 warnings emitted From b2cd1b8ead95530e61ad108a3113c588e590187a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 14 Jan 2025 12:25:16 +0000 Subject: [PATCH 08/14] Remove an unsafe closure invariant by inlining the closure wrapper into the called function --- compiler/rustc_codegen_llvm/src/back/write.rs | 130 +++++++----------- 1 file changed, 50 insertions(+), 80 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index ae4c4d5876e..6a7b6996347 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -40,7 +40,7 @@ use crate::errors::{ WithLlvmError, WriteBytecode, }; use crate::llvm::diagnostic::OptimizationDiagnosticKind::*; -use crate::llvm::{self, DiagnosticInfo, PassManager}; +use crate::llvm::{self, DiagnosticInfo}; use crate::type_::Type; use crate::{LlvmCodegenBackend, ModuleLlvm, base, common, llvm_util}; @@ -54,7 +54,7 @@ pub(crate) fn llvm_err<'a>(dcx: DiagCtxtHandle<'_>, err: LlvmError<'a>) -> Fatal fn write_output_file<'ll>( dcx: DiagCtxtHandle<'_>, target: &'ll llvm::TargetMachine, - pm: &llvm::PassManager<'ll>, + no_builtins: bool, m: &'ll llvm::Module, output: &Path, dwo_output: Option<&Path>, @@ -63,16 +63,19 @@ fn write_output_file<'ll>( verify_llvm_ir: bool, ) -> Result<(), FatalError> { debug!("write_output_file output={:?} dwo_output={:?}", output, dwo_output); - unsafe { - let output_c = path_to_c_string(output); - let dwo_output_c; - let dwo_output_ptr = if let Some(dwo_output) = dwo_output { - dwo_output_c = path_to_c_string(dwo_output); - dwo_output_c.as_ptr() - } else { - std::ptr::null() - }; - let result = llvm::LLVMRustWriteOutputFile( + let output_c = path_to_c_string(output); + let dwo_output_c; + let dwo_output_ptr = if let Some(dwo_output) = dwo_output { + dwo_output_c = path_to_c_string(dwo_output); + dwo_output_c.as_ptr() + } else { + std::ptr::null() + }; + let result = unsafe { + let pm = llvm::LLVMCreatePassManager(); + llvm::LLVMAddAnalysisPasses(target, pm); + llvm::LLVMRustAddLibraryInfo(pm, m, no_builtins); + llvm::LLVMRustWriteOutputFile( target, pm, m, @@ -80,22 +83,22 @@ fn write_output_file<'ll>( dwo_output_ptr, file_type, verify_llvm_ir, - ); + ) + }; - // Record artifact sizes for self-profiling - if result == llvm::LLVMRustResult::Success { - let artifact_kind = match file_type { - llvm::FileType::ObjectFile => "object_file", - llvm::FileType::AssemblyFile => "assembly_file", - }; - record_artifact_size(self_profiler_ref, artifact_kind, output); - if let Some(dwo_file) = dwo_output { - record_artifact_size(self_profiler_ref, "dwo_file", dwo_file); - } + // Record artifact sizes for self-profiling + if result == llvm::LLVMRustResult::Success { + let artifact_kind = match file_type { + llvm::FileType::ObjectFile => "object_file", + llvm::FileType::AssemblyFile => "assembly_file", + }; + record_artifact_size(self_profiler_ref, artifact_kind, output); + if let Some(dwo_file) = dwo_output { + record_artifact_size(self_profiler_ref, "dwo_file", dwo_file); } - - result.into_result().map_err(|()| llvm_err(dcx, LlvmError::WriteOutput { path: output })) } + + result.into_result().map_err(|()| llvm_err(dcx, LlvmError::WriteOutput { path: output })) } pub(crate) fn create_informational_target_machine( @@ -755,31 +758,6 @@ pub(crate) unsafe fn codegen( create_msvc_imps(cgcx, llcx, llmod); } - // A codegen-specific pass manager is used to generate object - // files for an LLVM module. - // - // Apparently each of these pass managers is a one-shot kind of - // thing, so we create a new one for each type of output. The - // pass manager passed to the closure should be ensured to not - // escape the closure itself, and the manager should only be - // used once. - unsafe fn with_codegen<'ll, F, R>( - tm: &'ll llvm::TargetMachine, - llmod: &'ll llvm::Module, - no_builtins: bool, - f: F, - ) -> R - where - F: FnOnce(&'ll mut PassManager<'ll>) -> R, - { - unsafe { - let cpm = llvm::LLVMCreatePassManager(); - llvm::LLVMAddAnalysisPasses(tm, cpm); - llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); - f(cpm) - } - } - // Note that if object files are just LLVM bitcode we write bitcode, // copy it to the .o file, and delete the bitcode if it wasn't // otherwise requested. @@ -898,21 +876,17 @@ pub(crate) unsafe fn codegen( } else { llmod }; - unsafe { - with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file( - dcx, - tm, - cpm, - llmod, - &path, - None, - llvm::FileType::AssemblyFile, - &cgcx.prof, - config.verify_llvm_ir, - ) - })?; - } + write_output_file( + dcx, + tm, + config.no_builtins, + llmod, + &path, + None, + llvm::FileType::AssemblyFile, + &cgcx.prof, + config.verify_llvm_ir, + )?; } match config.emit_obj { @@ -936,21 +910,17 @@ pub(crate) unsafe fn codegen( (_, SplitDwarfKind::Split) => Some(dwo_out.as_path()), }; - unsafe { - with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file( - dcx, - tm, - cpm, - llmod, - &obj_out, - dwo_out, - llvm::FileType::ObjectFile, - &cgcx.prof, - config.verify_llvm_ir, - ) - })?; - } + write_output_file( + dcx, + tm, + config.no_builtins, + llmod, + &obj_out, + dwo_out, + llvm::FileType::ObjectFile, + &cgcx.prof, + config.verify_llvm_ir, + )?; } EmitObj::Bitcode => { From 4b83038d637c1664df94895c82cb8b26716bad1d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 14 Jan 2025 12:25:16 +0000 Subject: [PATCH 09/14] Add a safe wrapper for `WriteBitcodeToFile` --- compiler/rustc_codegen_llvm/src/back/write.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 6a7b6996347..39aa3a033dc 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -328,13 +328,17 @@ pub(crate) fn save_temp_bitcode( if !cgcx.save_temps { return; } + let ext = format!("{name}.bc"); + let cgu = Some(&module.name[..]); + let path = cgcx.output_filenames.temp_path_ext(&ext, cgu); + write_bitcode_to_file(module, &path) +} + +fn write_bitcode_to_file(module: &ModuleCodegen, path: &Path) { unsafe { - let ext = format!("{name}.bc"); - let cgu = Some(&module.name[..]); - let path = cgcx.output_filenames.temp_path_ext(&ext, cgu); - let cstr = path_to_c_string(&path); + let path = path_to_c_string(&path); let llmod = module.module_llvm.llmod(); - llvm::LLVMWriteBitcodeToFile(llmod, cstr.as_ptr()); + llvm::LLVMWriteBitcodeToFile(llmod, path.as_ptr()); } } @@ -679,7 +683,6 @@ pub(crate) unsafe fn optimize( ) -> Result<(), FatalError> { let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_optimize", &*module.name); - let llmod = module.module_llvm.llmod(); let llcx = &*module.module_llvm.llcx; let _handlers = DiagnosticHandlers::new(cgcx, dcx, llcx, module, CodegenDiagnosticsStage::Opt); @@ -688,8 +691,7 @@ pub(crate) unsafe fn optimize( if config.emit_no_opt_bc { let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name); - let out = path_to_c_string(&out); - unsafe { llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()) }; + write_bitcode_to_file(module, &out) } // FIXME(ZuseZ4): support SanitizeHWAddress and prevent illegal/unsupported opts From dcf1e4d72b4dbda592050dcde7d7972414b05d3c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 14 Jan 2025 12:25:16 +0000 Subject: [PATCH 10/14] Document some safety constraints and use more safe wrappers --- compiler/rustc_codegen_llvm/src/allocator.rs | 4 +- .../rustc_codegen_llvm/src/back/archive.rs | 11 ++-- compiler/rustc_codegen_llvm/src/back/write.rs | 64 ++++++++----------- compiler/rustc_codegen_llvm/src/common.rs | 2 +- compiler/rustc_codegen_llvm/src/consts.rs | 6 +- compiler/rustc_codegen_llvm/src/context.rs | 10 ++- .../rustc_codegen_llvm/src/debuginfo/gdb.rs | 2 +- compiler/rustc_codegen_llvm/src/declare.rs | 2 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 2 +- compiler/rustc_codegen_llvm/src/llvm/mod.rs | 4 ++ 11 files changed, 50 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 149ded28356..66723cbf882 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -81,13 +81,13 @@ pub(crate) unsafe fn codegen( llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); let val = tcx.sess.opts.unstable_opts.oom.should_panic(); let llval = llvm::LLVMConstInt(i8, val as u64, False); - llvm::LLVMSetInitializer(ll_g, llval); + llvm::set_initializer(ll_g, llval); let name = NO_ALLOC_SHIM_IS_UNSTABLE; let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8); llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); let llval = llvm::LLVMConstInt(i8, 0, False); - llvm::LLVMSetInitializer(ll_g, llval); + llvm::set_initializer(ll_g, llval); } if tcx.sess.opts.debuginfo != DebugInfo::None { diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 33a956e552f..93553f3f364 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -11,7 +11,7 @@ use rustc_codegen_ssa::back::archive::{ use rustc_session::Session; use crate::llvm::archive_ro::{ArchiveRO, Child}; -use crate::llvm::{self, ArchiveKind}; +use crate::llvm::{self, ArchiveKind, last_error}; /// Helper for adding many files to an archive. #[must_use = "must call build() to finish building the archive"] @@ -169,6 +169,8 @@ impl<'a> LlvmArchiveBuilder<'a> { .unwrap_or_else(|kind| self.sess.dcx().emit_fatal(UnknownArchiveKind { kind })); let mut additions = mem::take(&mut self.additions); + // Values in the `members` list below will contain pointers to the strings allocated here. + // So they need to get dropped after all elements of `members` get freed. let mut strings = Vec::new(); let mut members = Vec::new(); @@ -229,12 +231,7 @@ impl<'a> LlvmArchiveBuilder<'a> { self.sess.target.arch == "arm64ec", ); let ret = if r.into_result().is_err() { - let err = llvm::LLVMRustGetLastError(); - let msg = if err.is_null() { - "failed to write archive".into() - } else { - String::from_utf8_lossy(CStr::from_ptr(err).to_bytes()) - }; + let msg = last_error().unwrap_or_else(|| "failed to write archive".into()); Err(io::Error::new(io::ErrorKind::Other, msg)) } else { Ok(!members.is_empty()) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 39aa3a033dc..58933a77e53 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -1049,24 +1049,18 @@ unsafe fn embed_bitcode( { // We don't need custom section flags, create LLVM globals. let llconst = common::bytes_in_context(llcx, bitcode); - let llglobal = llvm::LLVMAddGlobal( - llmod, - common::val_ty(llconst), - c"rustc.embedded.module".as_ptr(), - ); - llvm::LLVMSetInitializer(llglobal, llconst); + let llglobal = + llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.module"); + llvm::set_initializer(llglobal, llconst); llvm::set_section(llglobal, bitcode_section_name(cgcx)); llvm::set_linkage(llglobal, llvm::Linkage::PrivateLinkage); llvm::LLVMSetGlobalConstant(llglobal, llvm::True); let llconst = common::bytes_in_context(llcx, cmdline.as_bytes()); - let llglobal = llvm::LLVMAddGlobal( - llmod, - common::val_ty(llconst), - c"rustc.embedded.cmdline".as_ptr(), - ); - llvm::LLVMSetInitializer(llglobal, llconst); + let llglobal = + llvm::add_global(llmod, common::val_ty(llconst), c"rustc.embedded.cmdline"); + llvm::set_initializer(llglobal, llconst); let section = if cgcx.target_is_like_osx { c"__LLVM,__cmdline" } else if cgcx.target_is_like_aix { @@ -1106,31 +1100,29 @@ fn create_msvc_imps( // underscores added in front). let prefix = if cgcx.target_arch == "x86" { "\x01__imp__" } else { "\x01__imp_" }; - unsafe { - let ptr_ty = Type::ptr_llcx(llcx); - let globals = base::iter_globals(llmod) - .filter(|&val| { - llvm::get_linkage(val) == llvm::Linkage::ExternalLinkage - && llvm::LLVMIsDeclaration(val) == 0 - }) - .filter_map(|val| { - // Exclude some symbols that we know are not Rust symbols. - let name = llvm::get_value_name(val); - if ignored(name) { None } else { Some((val, name)) } - }) - .map(move |(val, name)| { - let mut imp_name = prefix.as_bytes().to_vec(); - imp_name.extend(name); - let imp_name = CString::new(imp_name).unwrap(); - (imp_name, val) - }) - .collect::>(); + let ptr_ty = Type::ptr_llcx(llcx); + let globals = base::iter_globals(llmod) + .filter(|&val| { + llvm::get_linkage(val) == llvm::Linkage::ExternalLinkage && !llvm::is_declaration(val) + }) + .filter_map(|val| { + // Exclude some symbols that we know are not Rust symbols. + let name = llvm::get_value_name(val); + if ignored(name) { None } else { Some((val, name)) } + }) + .map(move |(val, name)| { + let mut imp_name = prefix.as_bytes().to_vec(); + imp_name.extend(name); + let imp_name = CString::new(imp_name).unwrap(); + (imp_name, val) + }) + .collect::>(); - for (imp_name, val) in globals { - let imp = llvm::LLVMAddGlobal(llmod, ptr_ty, imp_name.as_ptr()); - llvm::LLVMSetInitializer(imp, val); - llvm::set_linkage(imp, llvm::Linkage::ExternalLinkage); - } + for (imp_name, val) in globals { + let imp = llvm::add_global(llmod, ptr_ty, &imp_name); + + llvm::set_initializer(imp, val); + llvm::set_linkage(imp, llvm::Linkage::ExternalLinkage); } // Use this function to exclude certain symbols from `__imp` generation. diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 8c94a46ebf3..78b3a7f8541 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -219,8 +219,8 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { let g = self.define_global(&sym, self.val_ty(sc)).unwrap_or_else(|| { bug!("symbol `{}` is already defined", sym); }); + llvm::set_initializer(g, sc); unsafe { - llvm::LLVMSetInitializer(g, sc); llvm::LLVMSetGlobalConstant(g, True); llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global); } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index c6855dd42e5..4a5491ec7a1 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -191,7 +191,7 @@ fn check_and_apply_linkage<'ll, 'tcx>( }) }); llvm::set_linkage(g2, llvm::Linkage::InternalLinkage); - unsafe { llvm::LLVMSetInitializer(g2, g1) }; + llvm::set_initializer(g2, g1); g2 } else if cx.tcx.sess.target.arch == "x86" && common::is_mingw_gnu_toolchain(&cx.tcx.sess.target) @@ -235,7 +235,7 @@ impl<'ll> CodegenCx<'ll, '_> { } _ => self.define_private_global(self.val_ty(cv)), }; - unsafe { llvm::LLVMSetInitializer(gv, cv) }; + llvm::set_initializer(gv, cv); set_global_alignment(self, gv, align); llvm::SetUnnamedAddress(gv, llvm::UnnamedAddr::Global); gv @@ -458,7 +458,7 @@ impl<'ll> CodegenCx<'ll, '_> { new_g }; set_global_alignment(self, g, alloc.align); - llvm::LLVMSetInitializer(g, v); + llvm::set_initializer(g, v); if self.should_assume_dso_local(g, true) { llvm::LLVMRustSetDSOLocal(g, true); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index ba4fd75fb94..7fe527a4c07 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -616,12 +616,10 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { pub(crate) fn create_used_variable_impl(&self, name: &'static CStr, values: &[&'ll Value]) { let array = self.const_array(self.type_ptr(), values); - unsafe { - let g = llvm::LLVMAddGlobal(self.llmod, self.val_ty(array), name.as_ptr()); - llvm::LLVMSetInitializer(g, array); - llvm::set_linkage(g, llvm::Linkage::AppendingLinkage); - llvm::set_section(g, c"llvm.metadata"); - } + let g = llvm::add_global(self.llmod, self.val_ty(array), name); + llvm::set_initializer(g, array); + llvm::set_linkage(g, llvm::Linkage::AppendingLinkage); + llvm::set_section(g, c"llvm.metadata"); } } impl<'ll> SimpleCx<'ll> { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 2c9f1cda13a..54c5d445f66 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -73,7 +73,7 @@ pub(crate) fn get_or_insert_gdb_debug_scripts_section_global<'ll>( .define_global(section_var_name, llvm_type) .unwrap_or_else(|| bug!("symbol `{}` is already defined", section_var_name)); llvm::set_section(section_var, c".debug_gdb_scripts"); - llvm::LLVMSetInitializer(section_var, cx.const_bytes(section_contents)); + llvm::set_initializer(section_var, cx.const_bytes(section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); llvm::LLVMSetUnnamedAddress(section_var, llvm::UnnamedAddr::Global); llvm::set_linkage(section_var, llvm::Linkage::LinkOnceODRLinkage); diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index bdc83267cca..cebceef1b93 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -235,7 +235,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { /// name. pub(crate) fn get_defined_value(&self, name: &str) -> Option<&'ll Value> { self.get_declared_value(name).and_then(|val| { - let declaration = unsafe { llvm::LLVMIsDeclaration(val) != 0 }; + let declaration = llvm::is_declaration(val); if !declaration { Some(val) } else { None } }) } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 3200c94d977..8b976885904 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -824,7 +824,7 @@ fn codegen_msvc_try<'ll>( if bx.cx.tcx.sess.target.supports_comdat() { llvm::SetUniqueComdat(bx.llmod, tydesc); } - unsafe { llvm::LLVMSetInitializer(tydesc, type_info) }; + llvm::set_initializer(tydesc, type_info); // The flag value of 8 indicates that we are catching the exception by // reference instead of by value. We can't use catch by value because diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 4d6a76b23ea..441d144ce50 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2359,7 +2359,7 @@ unsafe extern "C" { ); pub fn LLVMRustWriteOutputFile<'a>( T: &'a TargetMachine, - PM: &PassManager<'a>, + PM: *mut PassManager<'a>, M: &'a Module, Output: *const c_char, DwoOutput: *const c_char, diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 707aeba22cc..7becba4ccd4 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -241,6 +241,10 @@ pub fn set_linkage(llglobal: &Value, linkage: Linkage) { } } +pub fn is_declaration(llglobal: &Value) -> bool { + unsafe { LLVMIsDeclaration(llglobal) == ffi::True } +} + pub fn get_visibility(llglobal: &Value) -> Visibility { unsafe { LLVMGetVisibility(llglobal) }.to_rust() } From e32f79583c3709644567b55db7b6fcb9c425e787 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 11 Feb 2025 16:08:08 +0000 Subject: [PATCH 11/14] Change the issue number for `likely_unlikely` and `cold_path` These currently point to rust-lang/rust#26179, which is nearly a decade old and has a lot of outdated discussion. Move these features to a new tracking issue specifically for the recently added API. New tracking issue: https://github.com/rust-lang/rust/issues/136873 --- library/core/src/hint.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index e5c1a64c12e..520b9941ae4 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -646,7 +646,7 @@ pub const fn must_use(value: T) -> T { /// ``` /// /// -#[unstable(feature = "likely_unlikely", issue = "26179")] +#[unstable(feature = "likely_unlikely", issue = "136873")] #[inline(always)] pub const fn likely(b: bool) -> bool { crate::intrinsics::likely(b) @@ -696,7 +696,7 @@ pub const fn likely(b: bool) -> bool { /// } /// } /// ``` -#[unstable(feature = "likely_unlikely", issue = "26179")] +#[unstable(feature = "likely_unlikely", issue = "136873")] #[inline(always)] pub const fn unlikely(b: bool) -> bool { crate::intrinsics::unlikely(b) @@ -729,7 +729,7 @@ pub const fn unlikely(b: bool) -> bool { /// } /// } /// ``` -#[unstable(feature = "cold_path", issue = "26179")] +#[unstable(feature = "cold_path", issue = "136873")] #[inline(always)] pub const fn cold_path() { crate::intrinsics::cold_path() From f0cb746480830d585768c03f8447c0e5f9817b52 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 11 Feb 2025 19:16:12 +0000 Subject: [PATCH 12/14] Lower fn items as ZST valtrees and delay a bug --- .../src/hir_ty_lowering/mod.rs | 14 +++++++++----- compiler/rustc_middle/src/ty/print/pretty.rs | 13 +++++++++---- .../mgca/unexpected-fn-item-in-array.rs | 13 +++++++++++++ .../mgca/unexpected-fn-item-in-array.stderr | 19 +++++++++++++++++++ 4 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 tests/ui/const-generics/mgca/unexpected-fn-item-in-array.rs create mode 100644 tests/ui/const-generics/mgca/unexpected-fn-item-in-array.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index ffddf6f73aa..e58cb2ff592 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2154,11 +2154,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span_bug!(span, "use of bare `static` ConstArgKind::Path's not yet supported") } // FIXME(const_generics): create real const to allow fn items as const paths - Res::Def(DefKind::Fn | DefKind::AssocFn, _) => ty::Const::new_error_with_message( - tcx, - span, - "fn items cannot be used as const args", - ), + Res::Def(DefKind::Fn | DefKind::AssocFn, did) => { + self.dcx().span_delayed_bug(span, "function items cannot be used as const args"); + let args = self.lower_generic_args_of_path_segment( + span, + did, + path.segments.last().unwrap(), + ); + ty::Const::new_value(tcx, ty::ValTree::zst(), Ty::new_fn_def(tcx, did, args)) + } // Exhaustive match to be clear about what exactly we're considering to be // an invalid Res for a const path. diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index feae8ea312e..5a88e315b39 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1800,7 +1800,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } let u8_type = self.tcx().types.u8; - match (cv.valtree, cv.ty.kind()) { + match (cv.valtree, *cv.ty.kind()) { (ty::ValTree::Branch(_), ty::Ref(_, inner_ty, _)) => match inner_ty.kind() { ty::Slice(t) if *t == u8_type => { let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| { @@ -1820,13 +1820,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { return Ok(()); } _ => { - let cv = ty::Value { valtree: cv.valtree, ty: *inner_ty }; + let cv = ty::Value { valtree: cv.valtree, ty: inner_ty }; p!("&"); p!(pretty_print_const_valtree(cv, print_ty)); return Ok(()); } }, - (ty::ValTree::Branch(_), ty::Array(t, _)) if *t == u8_type => { + (ty::ValTree::Branch(_), ty::Array(t, _)) if t == u8_type => { let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| { bug!("expected to convert valtree to raw bytes for type {:?}", t) }); @@ -1893,11 +1893,16 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } (ty::ValTree::Leaf(leaf), ty::Ref(_, inner_ty, _)) => { p!(write("&")); - return self.pretty_print_const_scalar_int(leaf, *inner_ty, print_ty); + return self.pretty_print_const_scalar_int(leaf, inner_ty, print_ty); } (ty::ValTree::Leaf(leaf), _) => { return self.pretty_print_const_scalar_int(leaf, cv.ty, print_ty); } + (_, ty::FnDef(def_id, args)) => { + // Never allowed today, but we still encounter them in invalid const args. + p!(print_value_path(def_id, args)); + return Ok(()); + } // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading // their fields instead of just dumping the memory. _ => {} diff --git a/tests/ui/const-generics/mgca/unexpected-fn-item-in-array.rs b/tests/ui/const-generics/mgca/unexpected-fn-item-in-array.rs new file mode 100644 index 00000000000..1c3274f6a37 --- /dev/null +++ b/tests/ui/const-generics/mgca/unexpected-fn-item-in-array.rs @@ -0,0 +1,13 @@ +// Make sure we don't ICE when encountering an fn item during lowering in mGCA. + +#![feature(min_generic_const_args)] +//~^ WARN the feature `min_generic_const_args` is incomplete + +trait A {} + +impl A<[usize; fn_item]> for () {} +//~^ ERROR the constant `fn_item` is not of type `usize` + +fn fn_item() {} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/unexpected-fn-item-in-array.stderr b/tests/ui/const-generics/mgca/unexpected-fn-item-in-array.stderr new file mode 100644 index 00000000000..89fc8270e3e --- /dev/null +++ b/tests/ui/const-generics/mgca/unexpected-fn-item-in-array.stderr @@ -0,0 +1,19 @@ +warning: the feature `min_generic_const_args` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/unexpected-fn-item-in-array.rs:3:12 + | +LL | #![feature(min_generic_const_args)] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #132980 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: the constant `fn_item` is not of type `usize` + --> $DIR/unexpected-fn-item-in-array.rs:8:6 + | +LL | impl A<[usize; fn_item]> for () {} + | ^^^^^^^^^^^^^^^^^^^ expected `usize`, found fn item + | + = note: the length of array `[usize; fn_item]` must be type `usize` + +error: aborting due to 1 previous error; 1 warning emitted + From 9d8ffe47e73c12b48c8790249f6494253301ffde Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 11 Feb 2025 20:37:01 +0100 Subject: [PATCH 13/14] i686-linux-android: increase CPU baseline to Pentium 4 (without an actual change) --- compiler/rustc_target/src/spec/targets/i686_linux_android.rs | 2 +- src/doc/rustc/src/platform-support.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/i686_linux_android.rs b/compiler/rustc_target/src/spec/targets/i686_linux_android.rs index dcf9b6b4460..1b8f4c1be2d 100644 --- a/compiler/rustc_target/src/spec/targets/i686_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/i686_linux_android.rs @@ -9,7 +9,7 @@ pub(crate) fn target() -> Target { base.max_atomic_width = Some(64); // https://developer.android.com/ndk/guides/abis.html#x86 - base.cpu = "pentiumpro".into(); + base.cpu = "pentium4".into(); base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".into(); base.stack_probes = StackProbeType::Inline; diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 05555f537c9..a086498fcbd 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -165,7 +165,7 @@ target | std | notes `i586-pc-windows-msvc` | * | 32-bit Windows (original Pentium) [^x86_32-floats-x87] `i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2, glibc 2.17, original Pentium) [^x86_32-floats-x87] `i586-unknown-linux-musl` | ✓ | 32-bit Linux (musl 1.2.3, original Pentium) [^x86_32-floats-x87] -[`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android ([PentiumPro with SSE](https://developer.android.com/ndk/guides/abis.html#x86)) [^x86_32-floats-return-ABI] +[`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android ([Pentium 4 plus various extensions](https://developer.android.com/ndk/guides/abis.html#x86)) [^x86_32-floats-return-ABI] [`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+, Pentium 4), LLVM ABI [^x86_32-floats-return-ABI] [`i686-unknown-freebsd`](platform-support/freebsd.md) | ✓ | 32-bit x86 FreeBSD (Pentium 4) [^x86_32-floats-return-ABI] `i686-unknown-linux-musl` | ✓ | 32-bit Linux with musl 1.2.3 (Pentium 4) [^x86_32-floats-return-ABI] From 6ffe6dd826d737daf363c1251621b7da362a437d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 11 Feb 2025 22:59:50 +0000 Subject: [PATCH 14/14] Check sig for errors before checking for unconstrained anonymous lifetime --- .../src/hir_ty_lowering/mod.rs | 42 ++++++++++--------- .../ui/async-await/unconstrained-lifetimes.rs | 9 ++++ .../unconstrained-lifetimes.stderr | 9 ++++ 3 files changed, 40 insertions(+), 20 deletions(-) create mode 100644 tests/ui/async-await/unconstrained-lifetimes.rs create mode 100644 tests/ui/async-await/unconstrained-lifetimes.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index ffddf6f73aa..1ef0cbb39eb 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2557,27 +2557,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // reject function types that violate cmse ABI requirements cmse::validate_cmse_abi(self.tcx(), self.dcx(), hir_id, abi, bare_fn_ty); - // Find any late-bound regions declared in return type that do - // not appear in the arguments. These are not well-formed. - // - // Example: - // for<'a> fn() -> &'a str <-- 'a is bad - // for<'a> fn(&'a String) -> &'a str <-- 'a is ok - let inputs = bare_fn_ty.inputs(); - let late_bound_in_args = - tcx.collect_constrained_late_bound_regions(inputs.map_bound(|i| i.to_owned())); - let output = bare_fn_ty.output(); - let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(output); + if !bare_fn_ty.references_error() { + // Find any late-bound regions declared in return type that do + // not appear in the arguments. These are not well-formed. + // + // Example: + // for<'a> fn() -> &'a str <-- 'a is bad + // for<'a> fn(&'a String) -> &'a str <-- 'a is ok + let inputs = bare_fn_ty.inputs(); + let late_bound_in_args = + tcx.collect_constrained_late_bound_regions(inputs.map_bound(|i| i.to_owned())); + let output = bare_fn_ty.output(); + let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(output); - self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| { - struct_span_code_err!( - self.dcx(), - decl.output.span(), - E0581, - "return type references {}, which is not constrained by the fn input types", - br_name - ) - }); + self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| { + struct_span_code_err!( + self.dcx(), + decl.output.span(), + E0581, + "return type references {}, which is not constrained by the fn input types", + br_name + ) + }); + } bare_fn_ty } diff --git a/tests/ui/async-await/unconstrained-lifetimes.rs b/tests/ui/async-await/unconstrained-lifetimes.rs new file mode 100644 index 00000000000..50ab7bae73d --- /dev/null +++ b/tests/ui/async-await/unconstrained-lifetimes.rs @@ -0,0 +1,9 @@ +//@ edition: 2021 + +// Make sure we don't complain about the implicit `-> impl Future` capturing an +// unconstrained anonymous lifetime. + +async fn foo(_: Missing<'_>) {} +//~^ ERROR cannot find type `Missing` in this scope + +fn main() {} diff --git a/tests/ui/async-await/unconstrained-lifetimes.stderr b/tests/ui/async-await/unconstrained-lifetimes.stderr new file mode 100644 index 00000000000..18a46a3b555 --- /dev/null +++ b/tests/ui/async-await/unconstrained-lifetimes.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `Missing` in this scope + --> $DIR/unconstrained-lifetimes.rs:6:17 + | +LL | async fn foo(_: Missing<'_>) {} + | ^^^^^^^ not found in this scope + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0412`.