diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index 111bfeb1322..ea8ab761146 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -8,13 +8,11 @@ use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::mir::interpret::{self, ConstAllocation, ErrorHandled, Scalar as InterpScalar, read_target_uint}; -use rustc_span::Span; use rustc_span::def_id::DefId; use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRange}; use crate::base; use crate::context::CodegenCx; -use crate::errors::LinkageConstOrMutType; use crate::type_of::LayoutGccExt; impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { @@ -239,12 +237,12 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } Node::ForeignItem(&hir::ForeignItem { - span, + span: _, kind: hir::ForeignItemKind::Static(..), .. }) => { let fn_attrs = self.tcx.codegen_fn_attrs(def_id); - check_and_apply_linkage(&self, &fn_attrs, ty, sym, span) + check_and_apply_linkage(&self, &fn_attrs, ty, sym) } item => bug!("get_static: expected static, found {:?}", item), @@ -257,8 +255,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { //debug!("get_static: sym={} item_attr={:?}", sym, self.tcx.item_attrs(def_id)); let attrs = self.tcx.codegen_fn_attrs(def_id); - let span = self.tcx.def_span(def_id); - let global = check_and_apply_linkage(&self, &attrs, ty, sym, span); + let global = check_and_apply_linkage(&self, &attrs, ty, sym); let needs_dll_storage_attr = false; // TODO(antoyo) @@ -355,24 +352,12 @@ pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id Ok((const_alloc_to_gcc(cx, alloc), alloc)) } -fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &CodegenFnAttrs, ty: Ty<'tcx>, sym: &str, span: Span) -> LValue<'gcc> { +fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &CodegenFnAttrs, ty: Ty<'tcx>, sym: &str) -> LValue<'gcc> { let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); let llty = cx.layout_of(ty).gcc_type(cx, true); - if let Some(linkage) = attrs.linkage { - // If this is a static with a linkage specified, then we need to handle - // it a little specially. The typesystem prevents things like &T and - // extern "C" fn() from being non-null, so we can't just declare a - // static and call it a day. Some linkages (like weak) will make it such - // that the static actually has a null value. - let llty2 = - if let ty::RawPtr(ref mt) = ty.kind() { - cx.layout_of(mt.ty).gcc_type(cx, true) - } - else { - cx.sess().emit_fatal(LinkageConstOrMutType { span: span }) - }; + if let Some(linkage) = attrs.import_linkage { // Declare a symbol `foo` with the desired linkage. - let global1 = cx.declare_global_with_linkage(&sym, llty2, base::global_linkage_to_gcc(linkage)); + let global1 = cx.declare_global_with_linkage(&sym, cx.type_i8(), base::global_linkage_to_gcc(linkage)); // Declare an internal global `extern_with_linkage_foo` which // is initialized with the address of `foo`. If `foo` is diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index 89fed7be131..d0ba7e24791 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs @@ -211,13 +211,6 @@ pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> { pub in_elem: Ty<'a>, } -#[derive(Diagnostic)] -#[diag(codegen_gcc_linkage_const_or_mut_type)] -pub(crate) struct LinkageConstOrMutType { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(codegen_gcc_lto_not_supported)] pub(crate) struct LTONotSupported; diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 3c324359565..3626aa901c0 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -1,7 +1,7 @@ use crate::base; use crate::common::{self, CodegenCx}; use crate::debuginfo; -use crate::errors::{InvalidMinimumAlignment, LinkageConstOrMutType, SymbolAlreadyDefined}; +use crate::errors::{InvalidMinimumAlignment, SymbolAlreadyDefined}; use crate::llvm::{self, True}; use crate::llvm_util; use crate::type_::Type; @@ -162,22 +162,12 @@ fn check_and_apply_linkage<'ll, 'tcx>( def_id: DefId, ) -> &'ll Value { let llty = cx.layout_of(ty).llvm_type(cx); - if let Some(linkage) = attrs.linkage { + if let Some(linkage) = attrs.import_linkage { debug!("get_static: sym={} linkage={:?}", sym, linkage); - // If this is a static with a linkage specified, then we need to handle - // it a little specially. The typesystem prevents things like &T and - // extern "C" fn() from being non-null, so we can't just declare a - // static and call it a day. Some linkages (like weak) will make it such - // that the static actually has a null value. - let llty2 = if let ty::RawPtr(ref mt) = ty.kind() { - cx.layout_of(mt.ty).llvm_type(cx) - } else { - cx.sess().emit_fatal(LinkageConstOrMutType { span: cx.tcx.def_span(def_id) }) - }; unsafe { // Declare a symbol `foo` with the desired linkage. - let g1 = cx.declare_global(sym, llty2); + let g1 = cx.declare_global(sym, cx.type_i8()); llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage)); // Declare an internal global `extern_with_linkage_foo` which @@ -195,7 +185,7 @@ fn check_and_apply_linkage<'ll, 'tcx>( }) }); llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage); - llvm::LLVMSetInitializer(g2, g1); + llvm::LLVMSetInitializer(g2, cx.const_ptrcast(g1, llty)); g2 } } else if cx.tcx.sess.target.arch == "x86" && diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index fddfbb23c67..af9f31fc324 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -61,13 +61,6 @@ pub(crate) struct InvalidMinimumAlignment { pub err: String, } -#[derive(Diagnostic)] -#[diag(codegen_llvm_linkage_const_or_mut_type)] -pub(crate) struct LinkageConstOrMutType { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(codegen_llvm_sanitizer_memtag_requires_mte)] pub(crate) struct SanitizerMemtagRequiresMte; 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/codegen_gcc.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl index a1b7afeb709..08ce5172574 100644 --- a/compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl +++ b/compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl @@ -1,6 +1,3 @@ -codegen_gcc_linkage_const_or_mut_type = - must have type `*const T` or `*mut T` due to `#[linkage]` attribute - codegen_gcc_unwinding_inline_asm = GCC backend does not support unwinding from inline asm diff --git a/compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl b/compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl index e273476b60b..97198cb4be2 100644 --- a/compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl +++ b/compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl @@ -23,9 +23,6 @@ codegen_llvm_branch_protection_requires_aarch64 = codegen_llvm_invalid_minimum_alignment = invalid minimum global alignment: {$err} -codegen_llvm_linkage_const_or_mut_type = - must have type `*const T` or `*mut T` due to `#[linkage]` attribute - codegen_llvm_sanitizer_memtag_requires_mte = `-Zsanitizer=memtag` requires `-Ctarget-feature=+mte` 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 a5cb8a88819..a9ea161b93e 100644 --- a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl +++ b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl @@ -115,3 +115,6 @@ hir_analysis_const_bound_for_non_const_trait = hir_analysis_self_in_impl_self = `Self` is not valid in the self type of an impl block .note = replace `Self` with a different type + +hir_analysis_linkage_type = + 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 069b405423c..fc0ca62090d 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1,4 +1,5 @@ use crate::check::intrinsicck::InlineAsmCtxt; +use crate::errors::LinkageType; use super::compare_method::check_type_bounds; use super::compare_method::{compare_impl_method, compare_ty_impl}; @@ -20,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}; @@ -478,6 +479,36 @@ 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) }); + } + } +} + fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { debug!( "check_item_type(it.def_id={:?}, it.name={})", @@ -490,6 +521,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { tcx.ensure().typeck(id.owner_id.def_id); maybe_check_static_with_link_section(tcx, id.owner_id.def_id); check_static_inhabited(tcx, id.owner_id.def_id); + check_static_linkage(tcx, id.owner_id.def_id); } DefKind::Const => { tcx.ensure().typeck(id.owner_id.def_id); @@ -627,6 +659,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) { } hir::ForeignItemKind::Static(..) => { check_static_inhabited(tcx, def_id); + check_static_linkage(tcx, def_id); } _ => {} } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index b7084303aaf..945361ef43a 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1814,7 +1814,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { ); } else if attr.has_name(sym::linkage) { if let Some(val) = attr.value_str() { - codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, did, val.as_str())); + let linkage = Some(linkage_by_name(tcx, did, val.as_str())); + if tcx.is_foreign_item(did) { + codegen_fn_attrs.import_linkage = linkage; + } else { + codegen_fn_attrs.linkage = linkage; + } } } else if attr.has_name(sym::link_section) { if let Some(val) = attr.value_str() { diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 5156d432b5b..c92ab749bc1 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -289,3 +289,10 @@ pub struct SelfInImplSelf { #[note] pub note: (), } + +#[derive(Diagnostic)] +#[diag(hir_analysis_linkage_type, code = "E0791")] +pub(crate) struct LinkageType { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 45d33a1659f..bea884c856a 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -26,8 +26,10 @@ pub struct CodegenFnAttrs { /// The `#[target_feature(enable = "...")]` attribute and the enabled /// features (only enabled features are supported right now). pub target_features: Vec, - /// The `#[linkage = "..."]` attribute and the value we found. + /// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found. pub linkage: Option, + /// The `#[linkage = "..."]` attribute on foreign items and the value we found. + pub import_linkage: Option, /// The `#[link_section = "..."]` attribute, or what executable section this /// should be placed in. pub link_section: Option, @@ -113,6 +115,7 @@ impl CodegenFnAttrs { link_ordinal: None, target_features: vec![], linkage: None, + import_linkage: None, link_section: None, no_sanitize: SanitizerSet::empty(), instruction_set: None, diff --git a/library/std/src/sys/unix/weak.rs b/library/std/src/sys/unix/weak.rs index e4ff21b25bd..f5a4ce929b2 100644 --- a/library/std/src/sys/unix/weak.rs +++ b/library/std/src/sys/unix/weak.rs @@ -29,7 +29,21 @@ use crate::ptr; use crate::sync::atomic::{self, AtomicPtr, Ordering}; // We can use true weak linkage on ELF targets. -#[cfg(not(any(target_os = "macos", target_os = "ios")))] +#[cfg(all(not(any(target_os = "macos", target_os = "ios")), not(bootstrap)))] +pub(crate) macro weak { + (fn $name:ident($($t:ty),*) -> $ret:ty) => ( + let ref $name: ExternWeak $ret> = { + extern "C" { + #[linkage = "extern_weak"] + static $name: Option $ret>; + } + #[allow(unused_unsafe)] + ExternWeak::new(unsafe { $name }) + }; + ) +} + +#[cfg(all(not(any(target_os = "macos", target_os = "ios")), bootstrap))] pub(crate) macro weak { (fn $name:ident($($t:ty),*) -> $ret:ty) => ( let ref $name: ExternWeak $ret> = { @@ -47,11 +61,31 @@ pub(crate) macro weak { #[cfg(any(target_os = "macos", target_os = "ios"))] pub(crate) use self::dlsym as weak; +#[cfg(not(bootstrap))] +pub(crate) struct ExternWeak { + weak_ptr: Option, +} + +#[cfg(not(bootstrap))] +impl ExternWeak { + #[inline] + pub(crate) fn new(weak_ptr: Option) -> Self { + ExternWeak { weak_ptr } + } + + #[inline] + pub(crate) fn get(&self) -> Option { + self.weak_ptr + } +} + +#[cfg(bootstrap)] pub(crate) struct ExternWeak { weak_ptr: *const libc::c_void, _marker: PhantomData, } +#[cfg(bootstrap)] impl ExternWeak { #[inline] pub(crate) fn new(weak_ptr: *const libc::c_void) -> Self { @@ -59,6 +93,7 @@ impl ExternWeak { } } +#[cfg(bootstrap)] impl ExternWeak { #[inline] pub(crate) fn get(&self) -> Option { diff --git a/src/test/ui/feature-gates/feature-gate-linkage.rs b/src/test/ui/feature-gates/feature-gate-linkage.rs index 15b8d442aeb..505f31ec638 100644 --- a/src/test/ui/feature-gates/feature-gate-linkage.rs +++ b/src/test/ui/feature-gates/feature-gate-linkage.rs @@ -1,5 +1,5 @@ extern "C" { - #[linkage = "extern_weak"] static foo: isize; + #[linkage = "extern_weak"] static foo: *mut isize; //~^ ERROR: the `linkage` attribute is experimental and not portable } diff --git a/src/test/ui/feature-gates/feature-gate-linkage.stderr b/src/test/ui/feature-gates/feature-gate-linkage.stderr index 3e5b79bfd41..a1c73e555ef 100644 --- a/src/test/ui/feature-gates/feature-gate-linkage.stderr +++ b/src/test/ui/feature-gates/feature-gate-linkage.stderr @@ -1,7 +1,7 @@ error[E0658]: the `linkage` attribute is experimental and not portable across platforms --> $DIR/feature-gate-linkage.rs:2:5 | -LL | #[linkage = "extern_weak"] static foo: isize; +LL | #[linkage = "extern_weak"] static foo: *mut isize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #29603 for more information diff --git a/src/test/ui/linkage-attr/auxiliary/def_illtyped_external.rs b/src/test/ui/linkage-attr/auxiliary/def_external.rs similarity index 100% rename from src/test/ui/linkage-attr/auxiliary/def_illtyped_external.rs rename to src/test/ui/linkage-attr/auxiliary/def_external.rs diff --git a/src/test/ui/linkage-attr/linkage-import.rs b/src/test/ui/linkage-attr/linkage-import.rs new file mode 100644 index 00000000000..f754ddc6e08 --- /dev/null +++ b/src/test/ui/linkage-attr/linkage-import.rs @@ -0,0 +1,8 @@ +// build-pass +// aux-build:def_external.rs + +extern crate def_external as dep; + +fn main() { + println!("{:p}", &dep::EXTERN); +} diff --git a/src/test/ui/linkage-attr/linkage-requires-raw-ptr.rs b/src/test/ui/linkage-attr/linkage-requires-raw-ptr.rs deleted file mode 100644 index 93afc537f7c..00000000000 --- a/src/test/ui/linkage-attr/linkage-requires-raw-ptr.rs +++ /dev/null @@ -1,11 +0,0 @@ -// rust-lang/rust#59548: We used to ICE when trying to use a static -// with a type that violated its own `#[linkage]`. - -// build-fail -// aux-build:def_illtyped_external.rs - -extern crate def_illtyped_external as dep; - -fn main() { - println!("{:p}", &dep::EXTERN); -} diff --git a/src/test/ui/linkage-attr/linkage-requires-raw-ptr.stderr b/src/test/ui/linkage-attr/linkage-requires-raw-ptr.stderr deleted file mode 100644 index 5abbe745c6a..00000000000 --- a/src/test/ui/linkage-attr/linkage-requires-raw-ptr.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: must have type `*const T` or `*mut T` due to `#[linkage]` attribute - --> $DIR/auxiliary/def_illtyped_external.rs:5:1 - | -LL | pub static EXTERN: u32 = 0; - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/linkage-attr/linkage2.rs b/src/test/ui/linkage-attr/linkage2.rs index a7be1985286..aa42874f7ba 100644 --- a/src/test/ui/linkage-attr/linkage2.rs +++ b/src/test/ui/linkage-attr/linkage2.rs @@ -1,16 +1,11 @@ -// FIXME https://github.com/rust-lang/rust/issues/59774 - -// build-fail -// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> "" -// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" -// ignore-sgx no weak linkages permitted +// check-fail #![feature(linkage)] 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 a6ac0aad077..7265f711fd0 100644 --- a/src/test/ui/linkage-attr/linkage2.stderr +++ b/src/test/ui/linkage-attr/linkage2.stderr @@ -1,8 +1,9 @@ -error: must have type `*const T` or `*mut T` due to `#[linkage]` attribute - --> $DIR/linkage2.rs:12:5 +error[E0791]: invalid type for variable with `#[linkage]` attribute + --> $DIR/linkage2.rs:7:5 | LL | static foo: i32; | ^^^^^^^^^^^^^^^ error: aborting due to previous error +For more information about this error, try `rustc --explain E0791`.