Skip to content

Commit 91b8f34

Browse files
committed
Auto merge of #104799 - pcc:linkage-fn, r=tmiasko
Support Option and similar enums as type of static variable with linkage attribute Compiler MCP: rust-lang/compiler-team#565
2 parents ec28f53 + b4278b0 commit 91b8f34

File tree

22 files changed

+157
-89
lines changed

22 files changed

+157
-89
lines changed

Diff for: compiler/rustc_codegen_gcc/src/consts.rs

+6-21
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@ use rustc_middle::mir::mono::MonoItem;
88
use rustc_middle::ty::{self, Instance, Ty};
99
use rustc_middle::ty::layout::LayoutOf;
1010
use rustc_middle::mir::interpret::{self, ConstAllocation, ErrorHandled, Scalar as InterpScalar, read_target_uint};
11-
use rustc_span::Span;
1211
use rustc_span::def_id::DefId;
1312
use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRange};
1413

1514
use crate::base;
1615
use crate::context::CodegenCx;
17-
use crate::errors::LinkageConstOrMutType;
1816
use crate::type_of::LayoutGccExt;
1917

2018
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
@@ -239,12 +237,12 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
239237
}
240238

241239
Node::ForeignItem(&hir::ForeignItem {
242-
span,
240+
span: _,
243241
kind: hir::ForeignItemKind::Static(..),
244242
..
245243
}) => {
246244
let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
247-
check_and_apply_linkage(&self, &fn_attrs, ty, sym, span)
245+
check_and_apply_linkage(&self, &fn_attrs, ty, sym)
248246
}
249247

250248
item => bug!("get_static: expected static, found {:?}", item),
@@ -257,8 +255,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
257255
//debug!("get_static: sym={} item_attr={:?}", sym, self.tcx.item_attrs(def_id));
258256

259257
let attrs = self.tcx.codegen_fn_attrs(def_id);
260-
let span = self.tcx.def_span(def_id);
261-
let global = check_and_apply_linkage(&self, &attrs, ty, sym, span);
258+
let global = check_and_apply_linkage(&self, &attrs, ty, sym);
262259

263260
let needs_dll_storage_attr = false; // TODO(antoyo)
264261

@@ -355,24 +352,12 @@ pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id
355352
Ok((const_alloc_to_gcc(cx, alloc), alloc))
356353
}
357354

358-
fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &CodegenFnAttrs, ty: Ty<'tcx>, sym: &str, span: Span) -> LValue<'gcc> {
355+
fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &CodegenFnAttrs, ty: Ty<'tcx>, sym: &str) -> LValue<'gcc> {
359356
let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL);
360357
let llty = cx.layout_of(ty).gcc_type(cx, true);
361-
if let Some(linkage) = attrs.linkage {
362-
// If this is a static with a linkage specified, then we need to handle
363-
// it a little specially. The typesystem prevents things like &T and
364-
// extern "C" fn() from being non-null, so we can't just declare a
365-
// static and call it a day. Some linkages (like weak) will make it such
366-
// that the static actually has a null value.
367-
let llty2 =
368-
if let ty::RawPtr(ref mt) = ty.kind() {
369-
cx.layout_of(mt.ty).gcc_type(cx, true)
370-
}
371-
else {
372-
cx.sess().emit_fatal(LinkageConstOrMutType { span: span })
373-
};
358+
if let Some(linkage) = attrs.import_linkage {
374359
// Declare a symbol `foo` with the desired linkage.
375-
let global1 = cx.declare_global_with_linkage(&sym, llty2, base::global_linkage_to_gcc(linkage));
360+
let global1 = cx.declare_global_with_linkage(&sym, cx.type_i8(), base::global_linkage_to_gcc(linkage));
376361

377362
// Declare an internal global `extern_with_linkage_foo` which
378363
// is initialized with the address of `foo`. If `foo` is

Diff for: compiler/rustc_codegen_gcc/src/errors.rs

-7
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,6 @@ pub(crate) struct InvalidMonomorphizationUnsupportedOperation<'a> {
211211
pub in_elem: Ty<'a>,
212212
}
213213

214-
#[derive(Diagnostic)]
215-
#[diag(codegen_gcc_linkage_const_or_mut_type)]
216-
pub(crate) struct LinkageConstOrMutType {
217-
#[primary_span]
218-
pub span: Span,
219-
}
220-
221214
#[derive(Diagnostic)]
222215
#[diag(codegen_gcc_lto_not_supported)]
223216
pub(crate) struct LTONotSupported;

Diff for: compiler/rustc_codegen_llvm/src/consts.rs

+4-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::base;
22
use crate::common::{self, CodegenCx};
33
use crate::debuginfo;
4-
use crate::errors::{InvalidMinimumAlignment, LinkageConstOrMutType, SymbolAlreadyDefined};
4+
use crate::errors::{InvalidMinimumAlignment, SymbolAlreadyDefined};
55
use crate::llvm::{self, True};
66
use crate::llvm_util;
77
use crate::type_::Type;
@@ -162,22 +162,12 @@ fn check_and_apply_linkage<'ll, 'tcx>(
162162
def_id: DefId,
163163
) -> &'ll Value {
164164
let llty = cx.layout_of(ty).llvm_type(cx);
165-
if let Some(linkage) = attrs.linkage {
165+
if let Some(linkage) = attrs.import_linkage {
166166
debug!("get_static: sym={} linkage={:?}", sym, linkage);
167167

168-
// If this is a static with a linkage specified, then we need to handle
169-
// it a little specially. The typesystem prevents things like &T and
170-
// extern "C" fn() from being non-null, so we can't just declare a
171-
// static and call it a day. Some linkages (like weak) will make it such
172-
// that the static actually has a null value.
173-
let llty2 = if let ty::RawPtr(ref mt) = ty.kind() {
174-
cx.layout_of(mt.ty).llvm_type(cx)
175-
} else {
176-
cx.sess().emit_fatal(LinkageConstOrMutType { span: cx.tcx.def_span(def_id) })
177-
};
178168
unsafe {
179169
// Declare a symbol `foo` with the desired linkage.
180-
let g1 = cx.declare_global(sym, llty2);
170+
let g1 = cx.declare_global(sym, cx.type_i8());
181171
llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage));
182172

183173
// Declare an internal global `extern_with_linkage_foo` which
@@ -195,7 +185,7 @@ fn check_and_apply_linkage<'ll, 'tcx>(
195185
})
196186
});
197187
llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
198-
llvm::LLVMSetInitializer(g2, g1);
188+
llvm::LLVMSetInitializer(g2, cx.const_ptrcast(g1, llty));
199189
g2
200190
}
201191
} else if cx.tcx.sess.target.arch == "x86" &&

Diff for: compiler/rustc_codegen_llvm/src/errors.rs

-7
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,6 @@ pub(crate) struct InvalidMinimumAlignment {
6161
pub err: String,
6262
}
6363

64-
#[derive(Diagnostic)]
65-
#[diag(codegen_llvm_linkage_const_or_mut_type)]
66-
pub(crate) struct LinkageConstOrMutType {
67-
#[primary_span]
68-
pub span: Span,
69-
}
70-
7164
#[derive(Diagnostic)]
7265
#[diag(codegen_llvm_sanitizer_memtag_requires_mte)]
7366
pub(crate) struct SanitizerMemtagRequiresMte;

Diff for: compiler/rustc_error_codes/src/error_codes.rs

+1
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,7 @@ E0786: include_str!("./error_codes/E0786.md"),
494494
E0787: include_str!("./error_codes/E0787.md"),
495495
E0788: include_str!("./error_codes/E0788.md"),
496496
E0790: include_str!("./error_codes/E0790.md"),
497+
E0791: include_str!("./error_codes/E0791.md"),
497498
;
498499
// E0006, // merged with E0005
499500
// E0008, // cannot bind by-move into a pattern guard

Diff for: compiler/rustc_error_codes/src/error_codes/E0791.md

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
Static variables with the `#[linkage]` attribute within external blocks
2+
must have one of the following types, which are equivalent to a nullable
3+
pointer in C:
4+
5+
* `*mut T` or `*const T`, where `T` may be any type.
6+
7+
* An enumerator type with no `#[repr]` attribute and with two variants, where
8+
one of the variants has no fields, and the other has a single field of one of
9+
the following non-nullable types:
10+
* Reference type
11+
* Function pointer type
12+
13+
The variants can appear in either order.
14+
15+
For example, the following declaration is invalid:
16+
17+
```compile_fail,E0791
18+
#![feature(linkage)]
19+
20+
extern "C" {
21+
#[linkage = "extern_weak"]
22+
static foo: i8;
23+
}
24+
```
25+
26+
The following declarations are valid:
27+
28+
```
29+
#![feature(linkage)]
30+
31+
extern "C" {
32+
#[linkage = "extern_weak"]
33+
static foo: Option<unsafe extern "C" fn()>;
34+
35+
#[linkage = "extern_weak"]
36+
static bar: Option<&'static i8>;
37+
38+
#[linkage = "extern_weak"]
39+
static baz: *mut i8;
40+
}
41+
```

Diff for: compiler/rustc_error_messages/locales/en-US/codegen_gcc.ftl

-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
codegen_gcc_linkage_const_or_mut_type =
2-
must have type `*const T` or `*mut T` due to `#[linkage]` attribute
3-
41
codegen_gcc_unwinding_inline_asm =
52
GCC backend does not support unwinding from inline asm
63

Diff for: compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl

-3
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,6 @@ codegen_llvm_branch_protection_requires_aarch64 =
2323
codegen_llvm_invalid_minimum_alignment =
2424
invalid minimum global alignment: {$err}
2525
26-
codegen_llvm_linkage_const_or_mut_type =
27-
must have type `*const T` or `*mut T` due to `#[linkage]` attribute
28-
2926
codegen_llvm_sanitizer_memtag_requires_mte =
3027
`-Zsanitizer=memtag` requires `-Ctarget-feature=+mte`
3128

Diff for: compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,6 @@ hir_analysis_const_bound_for_non_const_trait =
115115
hir_analysis_self_in_impl_self =
116116
`Self` is not valid in the self type of an impl block
117117
.note = replace `Self` with a different type
118+
119+
hir_analysis_linkage_type =
120+
invalid type for variable with `#[linkage]` attribute

Diff for: compiler/rustc_hir_analysis/src/check/check.rs

+34-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::check::intrinsicck::InlineAsmCtxt;
2+
use crate::errors::LinkageType;
23

34
use super::compare_method::check_type_bounds;
45
use super::compare_method::{compare_impl_method, compare_ty_impl};
@@ -20,7 +21,7 @@ use rustc_middle::middle::stability::EvalResult;
2021
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
2122
use rustc_middle::ty::subst::GenericArgKind;
2223
use rustc_middle::ty::util::{Discr, IntTypeExt};
23-
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
24+
use rustc_middle::ty::{self, AdtDef, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
2425
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
2526
use rustc_span::symbol::sym;
2627
use rustc_span::{self, Span};
@@ -478,6 +479,36 @@ fn check_opaque_meets_bounds<'tcx>(
478479
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
479480
}
480481

482+
fn is_enum_of_nonnullable_ptr<'tcx>(
483+
tcx: TyCtxt<'tcx>,
484+
adt_def: AdtDef<'tcx>,
485+
substs: SubstsRef<'tcx>,
486+
) -> bool {
487+
if adt_def.repr().inhibit_enum_layout_opt() {
488+
return false;
489+
}
490+
491+
let [var_one, var_two] = &adt_def.variants().raw[..] else {
492+
return false;
493+
};
494+
let (([], [field]) | ([field], [])) = (&var_one.fields[..], &var_two.fields[..]) else {
495+
return false;
496+
};
497+
matches!(field.ty(tcx, substs).kind(), ty::FnPtr(..) | ty::Ref(..))
498+
}
499+
500+
fn check_static_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
501+
if tcx.codegen_fn_attrs(def_id).import_linkage.is_some() {
502+
if match tcx.type_of(def_id).kind() {
503+
ty::RawPtr(_) => false,
504+
ty::Adt(adt_def, substs) => !is_enum_of_nonnullable_ptr(tcx, *adt_def, *substs),
505+
_ => true,
506+
} {
507+
tcx.sess.emit_err(LinkageType { span: tcx.def_span(def_id) });
508+
}
509+
}
510+
}
511+
481512
fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
482513
debug!(
483514
"check_item_type(it.def_id={:?}, it.name={})",
@@ -490,6 +521,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
490521
tcx.ensure().typeck(id.owner_id.def_id);
491522
maybe_check_static_with_link_section(tcx, id.owner_id.def_id);
492523
check_static_inhabited(tcx, id.owner_id.def_id);
524+
check_static_linkage(tcx, id.owner_id.def_id);
493525
}
494526
DefKind::Const => {
495527
tcx.ensure().typeck(id.owner_id.def_id);
@@ -627,6 +659,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
627659
}
628660
hir::ForeignItemKind::Static(..) => {
629661
check_static_inhabited(tcx, def_id);
662+
check_static_linkage(tcx, def_id);
630663
}
631664
_ => {}
632665
}

Diff for: compiler/rustc_hir_analysis/src/collect.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -1814,7 +1814,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
18141814
);
18151815
} else if attr.has_name(sym::linkage) {
18161816
if let Some(val) = attr.value_str() {
1817-
codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, did, val.as_str()));
1817+
let linkage = Some(linkage_by_name(tcx, did, val.as_str()));
1818+
if tcx.is_foreign_item(did) {
1819+
codegen_fn_attrs.import_linkage = linkage;
1820+
} else {
1821+
codegen_fn_attrs.linkage = linkage;
1822+
}
18181823
}
18191824
} else if attr.has_name(sym::link_section) {
18201825
if let Some(val) = attr.value_str() {

Diff for: compiler/rustc_hir_analysis/src/errors.rs

+7
Original file line numberDiff line numberDiff line change
@@ -289,3 +289,10 @@ pub struct SelfInImplSelf {
289289
#[note]
290290
pub note: (),
291291
}
292+
293+
#[derive(Diagnostic)]
294+
#[diag(hir_analysis_linkage_type, code = "E0791")]
295+
pub(crate) struct LinkageType {
296+
#[primary_span]
297+
pub span: Span,
298+
}

Diff for: compiler/rustc_middle/src/middle/codegen_fn_attrs.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ pub struct CodegenFnAttrs {
2626
/// The `#[target_feature(enable = "...")]` attribute and the enabled
2727
/// features (only enabled features are supported right now).
2828
pub target_features: Vec<Symbol>,
29-
/// The `#[linkage = "..."]` attribute and the value we found.
29+
/// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
3030
pub linkage: Option<Linkage>,
31+
/// The `#[linkage = "..."]` attribute on foreign items and the value we found.
32+
pub import_linkage: Option<Linkage>,
3133
/// The `#[link_section = "..."]` attribute, or what executable section this
3234
/// should be placed in.
3335
pub link_section: Option<Symbol>,
@@ -113,6 +115,7 @@ impl CodegenFnAttrs {
113115
link_ordinal: None,
114116
target_features: vec![],
115117
linkage: None,
118+
import_linkage: None,
116119
link_section: None,
117120
no_sanitize: SanitizerSet::empty(),
118121
instruction_set: None,

Diff for: library/std/src/sys/unix/weak.rs

+36-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,21 @@ use crate::ptr;
2929
use crate::sync::atomic::{self, AtomicPtr, Ordering};
3030

3131
// We can use true weak linkage on ELF targets.
32-
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
32+
#[cfg(all(not(any(target_os = "macos", target_os = "ios")), not(bootstrap)))]
33+
pub(crate) macro weak {
34+
(fn $name:ident($($t:ty),*) -> $ret:ty) => (
35+
let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
36+
extern "C" {
37+
#[linkage = "extern_weak"]
38+
static $name: Option<unsafe extern "C" fn($($t),*) -> $ret>;
39+
}
40+
#[allow(unused_unsafe)]
41+
ExternWeak::new(unsafe { $name })
42+
};
43+
)
44+
}
45+
46+
#[cfg(all(not(any(target_os = "macos", target_os = "ios")), bootstrap))]
3347
pub(crate) macro weak {
3448
(fn $name:ident($($t:ty),*) -> $ret:ty) => (
3549
let ref $name: ExternWeak<unsafe extern "C" fn($($t),*) -> $ret> = {
@@ -47,18 +61,39 @@ pub(crate) macro weak {
4761
#[cfg(any(target_os = "macos", target_os = "ios"))]
4862
pub(crate) use self::dlsym as weak;
4963

64+
#[cfg(not(bootstrap))]
65+
pub(crate) struct ExternWeak<F: Copy> {
66+
weak_ptr: Option<F>,
67+
}
68+
69+
#[cfg(not(bootstrap))]
70+
impl<F: Copy> ExternWeak<F> {
71+
#[inline]
72+
pub(crate) fn new(weak_ptr: Option<F>) -> Self {
73+
ExternWeak { weak_ptr }
74+
}
75+
76+
#[inline]
77+
pub(crate) fn get(&self) -> Option<F> {
78+
self.weak_ptr
79+
}
80+
}
81+
82+
#[cfg(bootstrap)]
5083
pub(crate) struct ExternWeak<F> {
5184
weak_ptr: *const libc::c_void,
5285
_marker: PhantomData<F>,
5386
}
5487

88+
#[cfg(bootstrap)]
5589
impl<F> ExternWeak<F> {
5690
#[inline]
5791
pub(crate) fn new(weak_ptr: *const libc::c_void) -> Self {
5892
ExternWeak { weak_ptr, _marker: PhantomData }
5993
}
6094
}
6195

96+
#[cfg(bootstrap)]
6297
impl<F> ExternWeak<F> {
6398
#[inline]
6499
pub(crate) fn get(&self) -> Option<F> {

Diff for: src/test/ui/feature-gates/feature-gate-linkage.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
extern "C" {
2-
#[linkage = "extern_weak"] static foo: isize;
2+
#[linkage = "extern_weak"] static foo: *mut isize;
33
//~^ ERROR: the `linkage` attribute is experimental and not portable
44
}
55

0 commit comments

Comments
 (0)