diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 1e86d159668..31a709c36d4 100644 --- a/compiler/rustc_error_codes/src/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -494,6 +494,7 @@ E0786: include_str!("./error_codes/E0786.md"), E0787: include_str!("./error_codes/E0787.md"), E0788: include_str!("./error_codes/E0788.md"), E0790: include_str!("./error_codes/E0790.md"), +E0791: include_str!("./error_codes/E0791.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/compiler/rustc_error_codes/src/error_codes/E0791.md b/compiler/rustc_error_codes/src/error_codes/E0791.md new file mode 100644 index 00000000000..61d2f511a34 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0791.md @@ -0,0 +1,41 @@ +Static variables with the `#[linkage]` attribute within external blocks +must have one of the following types, which are equivalent to a nullable +pointer in C: + +* `*mut T` or `*const T`, where `T` may be any type. + +* An enumerator type with no `#[repr]` attribute and with two variants, where + one of the variants has no fields, and the other has a single field of one of + the following non-nullable types: + * Reference type + * Function pointer type + + The variants can appear in either order. + +For example, the following declaration is invalid: + +```compile_fail,E0791 +#![feature(linkage)] + +extern "C" { + #[linkage = "extern_weak"] + static foo: i8; +} +``` + +The following declarations are valid: + +``` +#![feature(linkage)] + +extern "C" { + #[linkage = "extern_weak"] + static foo: Option; + + #[linkage = "extern_weak"] + static bar: Option<&'static i8>; + + #[linkage = "extern_weak"] + static baz: *mut i8; +} +``` diff --git a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl index 86a51b2d310..a4910dacd5f 100644 --- a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl +++ b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl @@ -115,4 +115,4 @@ hir_analysis_self_in_impl_self = .note = replace `Self` with a different type hir_analysis_linkage_type = - must have type `*const T` or `*mut T` due to `#[linkage]` attribute + invalid type for variable with `#[linkage]` attribute diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 7345e604d0b..fc0ca62090d 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -21,7 +21,7 @@ use rustc_middle::middle::stability::EvalResult; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::util::{Discr, IntTypeExt}; -use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; +use rustc_middle::ty::{self, AdtDef, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable}; use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS}; use rustc_span::symbol::sym; use rustc_span::{self, Span}; @@ -479,10 +479,29 @@ fn check_opaque_meets_bounds<'tcx>( let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types(); } +fn is_enum_of_nonnullable_ptr<'tcx>( + tcx: TyCtxt<'tcx>, + adt_def: AdtDef<'tcx>, + substs: SubstsRef<'tcx>, +) -> bool { + if adt_def.repr().inhibit_enum_layout_opt() { + return false; + } + + let [var_one, var_two] = &adt_def.variants().raw[..] else { + return false; + }; + let (([], [field]) | ([field], [])) = (&var_one.fields[..], &var_two.fields[..]) else { + return false; + }; + matches!(field.ty(tcx, substs).kind(), ty::FnPtr(..) | ty::Ref(..)) +} + fn check_static_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) { if tcx.codegen_fn_attrs(def_id).import_linkage.is_some() { if match tcx.type_of(def_id).kind() { ty::RawPtr(_) => false, + ty::Adt(adt_def, substs) => !is_enum_of_nonnullable_ptr(tcx, *adt_def, *substs), _ => true, } { tcx.sess.emit_err(LinkageType { span: tcx.def_span(def_id) }); diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 02943e7b887..1ac53fb6ddf 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -287,7 +287,7 @@ pub struct SelfInImplSelf { } #[derive(Diagnostic)] -#[diag(hir_analysis_linkage_type)] +#[diag(hir_analysis_linkage_type, code = "E0791")] pub(crate) struct LinkageType { #[primary_span] pub span: Span, diff --git a/src/test/ui/linkage-attr/linkage2.rs b/src/test/ui/linkage-attr/linkage2.rs index 3bc6634f18a..aa42874f7ba 100644 --- a/src/test/ui/linkage-attr/linkage2.rs +++ b/src/test/ui/linkage-attr/linkage2.rs @@ -5,7 +5,7 @@ extern "C" { #[linkage = "extern_weak"] static foo: i32; -//~^ ERROR: must have type `*const T` or `*mut T` due to `#[linkage]` attribute +//~^ ERROR: invalid type for variable with `#[linkage]` attribute } fn main() { diff --git a/src/test/ui/linkage-attr/linkage2.stderr b/src/test/ui/linkage-attr/linkage2.stderr index 44e8eaaef51..7265f711fd0 100644 --- a/src/test/ui/linkage-attr/linkage2.stderr +++ b/src/test/ui/linkage-attr/linkage2.stderr @@ -1,4 +1,4 @@ -error: must have type `*const T` or `*mut T` due to `#[linkage]` attribute +error[E0791]: invalid type for variable with `#[linkage]` attribute --> $DIR/linkage2.rs:7:5 | LL | static foo: i32; @@ -6,3 +6,4 @@ LL | static foo: i32; error: aborting due to previous error +For more information about this error, try `rustc --explain E0791`.