Skip to content

Commit 5873ebe

Browse files
committed
Move linkage type check to HIR analysis and fix semantics issues.
This ensures that the error is printed even for unused variables, as well as unifying the handling between the LLVM and GCC backends. This also fixes unusual behavior around exported Rust-defined variables with linkage attributes. With the previous behavior, it appears to be impossible to define such a variable such that it can actually be imported and used by another crate. This is because on the importing side, the variable is required to be a pointer, but on the exporting side, the type checker rejects static variables of pointer type because they do not implement `Sync`. Even if it were possible to import such a type, it appears that code generation on the importing side would add an unexpected additional level of pointer indirection, which would break type safety. This highlighted that the semantics of linkage on Rust-defined variables is different to linkage on foreign items. As such, we now model the difference with two different codegen attributes: linkage for Rust-defined variables, and import_linkage for foreign items. This change gives semantics to the test src/test/ui/linkage-attr/auxiliary/def_illtyped_external.rs which was previously expected to fail to compile. Therefore, convert it into a test that is expected to successfully compile. The update to the GCC backend is speculative and untested.
1 parent e1d8195 commit 5873ebe

File tree

19 files changed

+56
-85
lines changed

19 files changed

+56
-85
lines changed

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

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;

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" &&

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;

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

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

compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,6 @@ hir_analysis_const_bound_for_non_const_trait =
113113
hir_analysis_self_in_impl_self =
114114
`Self` is not valid in the self type of an impl block
115115
.note = replace `Self` with a different type
116+
117+
hir_analysis_linkage_type =
118+
must have type `*const T` or `*mut T` due to `#[linkage]` attribute

compiler/rustc_hir_analysis/src/check/check.rs

+14
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};
@@ -478,6 +479,17 @@ fn check_opaque_meets_bounds<'tcx>(
478479
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
479480
}
480481

482+
fn check_static_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
483+
if tcx.codegen_fn_attrs(def_id).import_linkage.is_some() {
484+
if match tcx.type_of(def_id).kind() {
485+
ty::RawPtr(_) => false,
486+
_ => true,
487+
} {
488+
tcx.sess.emit_err(LinkageType { span: tcx.def_span(def_id) });
489+
}
490+
}
491+
}
492+
481493
fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
482494
debug!(
483495
"check_item_type(it.def_id={:?}, it.name={})",
@@ -490,6 +502,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
490502
tcx.ensure().typeck(id.owner_id.def_id);
491503
maybe_check_static_with_link_section(tcx, id.owner_id.def_id);
492504
check_static_inhabited(tcx, id.owner_id.def_id);
505+
check_static_linkage(tcx, id.owner_id.def_id);
493506
}
494507
DefKind::Const => {
495508
tcx.ensure().typeck(id.owner_id.def_id);
@@ -627,6 +640,7 @@ fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
627640
}
628641
hir::ForeignItemKind::Static(..) => {
629642
check_static_inhabited(tcx, def_id);
643+
check_static_linkage(tcx, def_id);
630644
}
631645
_ => {}
632646
}

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() {

compiler/rustc_hir_analysis/src/errors.rs

+7
Original file line numberDiff line numberDiff line change
@@ -285,3 +285,10 @@ pub struct SelfInImplSelf {
285285
#[note]
286286
pub note: (),
287287
}
288+
289+
#[derive(Diagnostic)]
290+
#[diag(hir_analysis_linkage_type)]
291+
pub(crate) struct LinkageType {
292+
#[primary_span]
293+
pub span: Span,
294+
}

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,

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

src/test/ui/feature-gates/feature-gate-linkage.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
error[E0658]: the `linkage` attribute is experimental and not portable across platforms
22
--> $DIR/feature-gate-linkage.rs:2:5
33
|
4-
LL | #[linkage = "extern_weak"] static foo: isize;
4+
LL | #[linkage = "extern_weak"] static foo: *mut isize;
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
77
= note: see issue #29603 <https://github.com/rust-lang/rust/issues/29603> for more information
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// build-pass
2+
// aux-build:def_external.rs
3+
4+
extern crate def_external as dep;
5+
6+
fn main() {
7+
println!("{:p}", &dep::EXTERN);
8+
}

src/test/ui/linkage-attr/linkage-requires-raw-ptr.rs

-11
This file was deleted.

src/test/ui/linkage-attr/linkage-requires-raw-ptr.stderr

-8
This file was deleted.

src/test/ui/linkage-attr/linkage2.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
// FIXME https://github.com/rust-lang/rust/issues/59774
2-
3-
// build-fail
4-
// normalize-stderr-test "thread.*panicked.*Metadata module not compiled.*\n" -> ""
5-
// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> ""
6-
// ignore-sgx no weak linkages permitted
1+
// check-fail
72

83
#![feature(linkage)]
94

src/test/ui/linkage-attr/linkage2.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: must have type `*const T` or `*mut T` due to `#[linkage]` attribute
2-
--> $DIR/linkage2.rs:12:5
2+
--> $DIR/linkage2.rs:7:5
33
|
44
LL | static foo: i32;
55
| ^^^^^^^^^^^^^^^

0 commit comments

Comments
 (0)