Skip to content

Commit f44a015

Browse files
committed
Support Option and similar enums as type of static variable with linkage attribute.
Compiler MCP: rust-lang/compiler-team#565
1 parent 5873ebe commit f44a015

File tree

7 files changed

+67
-5
lines changed

7 files changed

+67
-5
lines changed

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
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+
```

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,4 @@ hir_analysis_self_in_impl_self =
115115
.note = replace `Self` with a different type
116116
117117
hir_analysis_linkage_type =
118-
must have type `*const T` or `*mut T` due to `#[linkage]` attribute
118+
invalid type for variable with `#[linkage]` attribute

compiler/rustc_hir_analysis/src/check/check.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use rustc_middle::middle::stability::EvalResult;
2121
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
2222
use rustc_middle::ty::subst::GenericArgKind;
2323
use rustc_middle::ty::util::{Discr, IntTypeExt};
24-
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
24+
use rustc_middle::ty::{self, AdtDef, ParamEnv, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
2525
use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
2626
use rustc_span::symbol::sym;
2727
use rustc_span::{self, Span};
@@ -479,10 +479,29 @@ fn check_opaque_meets_bounds<'tcx>(
479479
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
480480
}
481481

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+
482500
fn check_static_linkage<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
483501
if tcx.codegen_fn_attrs(def_id).import_linkage.is_some() {
484502
if match tcx.type_of(def_id).kind() {
485503
ty::RawPtr(_) => false,
504+
ty::Adt(adt_def, substs) => !is_enum_of_nonnullable_ptr(tcx, *adt_def, *substs),
486505
_ => true,
487506
} {
488507
tcx.sess.emit_err(LinkageType { span: tcx.def_span(def_id) });

compiler/rustc_hir_analysis/src/errors.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ pub struct SelfInImplSelf {
287287
}
288288

289289
#[derive(Diagnostic)]
290-
#[diag(hir_analysis_linkage_type)]
290+
#[diag(hir_analysis_linkage_type, code = "E0791")]
291291
pub(crate) struct LinkageType {
292292
#[primary_span]
293293
pub span: Span,

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
extern "C" {
66
#[linkage = "extern_weak"]
77
static foo: i32;
8-
//~^ ERROR: must have type `*const T` or `*mut T` due to `#[linkage]` attribute
8+
//~^ ERROR: invalid type for variable with `#[linkage]` attribute
99
}
1010

1111
fn main() {
+2-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
error: must have type `*const T` or `*mut T` due to `#[linkage]` attribute
1+
error[E0791]: invalid type for variable with `#[linkage]` attribute
22
--> $DIR/linkage2.rs:7:5
33
|
44
LL | static foo: i32;
55
| ^^^^^^^^^^^^^^^
66

77
error: aborting due to previous error
88

9+
For more information about this error, try `rustc --explain E0791`.

0 commit comments

Comments
 (0)