Skip to content

Commit

Permalink
Support Option and similar enums as type of static variable with link…
Browse files Browse the repository at this point in the history
…age attribute.

Compiler MCP:
rust-lang/compiler-team#565
  • Loading branch information
pcc committed Dec 5, 2022
1 parent 5873ebe commit f44a015
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 5 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_error_codes/src/error_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
41 changes: 41 additions & 0 deletions compiler/rustc_error_codes/src/error_codes/E0791.md
Original file line number Diff line number Diff line change
@@ -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<unsafe extern "C" fn()>;
#[linkage = "extern_weak"]
static bar: Option<&'static i8>;
#[linkage = "extern_weak"]
static baz: *mut i8;
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -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
21 changes: 20 additions & 1 deletion compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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) });
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/linkage-attr/linkage2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
3 changes: 2 additions & 1 deletion src/test/ui/linkage-attr/linkage2.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
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;
| ^^^^^^^^^^^^^^^

error: aborting due to previous error

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

0 comments on commit f44a015

Please sign in to comment.