-
Notifications
You must be signed in to change notification settings - Fork 13.3k
"extern type" should use opaque
type in LLVM
#59095
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
If you use those words precisely in the sense LLVM documentation does, then that should do the trick. The easiest way to be sure would be to look at |
From the assertion it appears that something somewhere is doing a GEP(i) on a pointer to an opaque type (a different thing from a |
I suspect it's caused by compiling code working with this: Lines 591 to 607 in aa97448
However, that would just be just "tail-opaque" and its overall size shouldn't matter. |
As @eddyb suspected, the #![feature(extern_types)]
#![allow(dead_code)]
extern "C" {
pub type Opaque;
}
pub struct TailOpaque {
a: usize,
opaque: Opaque,
}
pub fn foo(v: &TailOpaque) -> &Opaque {
&v.opaque
} #![feature(extern_types)]
#![allow(dead_code)]
extern "C" {
pub type Opaque;
}
pub struct TailOpaque {
a: usize,
b: usize,
opaque: Opaque,
}
pub fn foo(v: &TailOpaque) -> usize {
v.b
} It seems that accessing or referencing any field of a tail-opaque struct past the first element triggers the assertion failure. |
Okay, digging further into this I have come to a few conclusions: The rustc issue leading to the assertion failure is our attempt to generate a getelementptr instruction, which is invalid for unsized types. By commenting out a few sanity checks, I could get LLVM to emit IR with such an instruction, but it would then fail at a later step. At this point, I was wondering why the issue only affects "extern type" (with PR #58271), and not all unsized types, for example a struct with a That leaves me with the question if there is a fundamental difference between "extern type" and existing unsized types which would require us to use |
One more data point, which may be relevant for unsized statics: clang (tested with 10.0.0) emits externals of unknown size as "size 0" as well: extern const char foo[]; turns into @foo = external global [0 x i8], align 1 My interpretation of this is that using an empty struct and not Unless someone has a different interpretation, I propose we go with one of the following options, so we can move to stabilize external types:
|
So the argument seems to be: clang doesn't use that pattern for opaque types, but it uses it for something, and thus the pattern is probably legal? That seems reasonable. Before we rely on this, could someone file an LLVM bug asking them to state this explicitly in their LangRef (that |
@RalfJung I don't think we ever use I would actually have expected that regular slices are a bigger problem, as pub struct Foo(usize, str);
pub fn foo(v: &Foo) -> &u8 {
unsafe { &v.1.as_bytes().get_unchecked(1) }
} But there is no problem in this case either, as we emit slices as length 0 arrays - and the handling of this case is explained in detail here: https://llvm.org/docs/GetElementPtr.html#what-happens-if-an-array-index-is-out-of-bounds |
The issue is with cases like extern {
type Foo;
static mut BAR: Foo;
} At least after cross-crate inlining (LTO, maybe even cross-language LTO), there can well be actual accesses to |
Okay, in that case we should switch over to |
FWIW, I don't think that page really addresses the concern. It tells us that static type information of the pointer or GEP is irrelevant and the actual allocation size matters, but the type of global variables in fact determines the actual allocation size. Certainly with |
I see. I can make a request for clarification over at the LLVM bug tracker as soon as my account is approved. |
Can https://bugs.llvm.org/show_bug.cgi?id=45681 be closed now that https://reviews.llvm.org/D78952 was merged? And are there any other clarifications required before Rust can use |
@mjbshaw I think the LLVM bug can be closed. As I understand it, the result of the merge is the opposite though for Rust: With the clarified LLVM spec, there should be no reason for Rust to use (@RalfJung Please correct me if any of this is inaccurate) |
Yeah that sounds right, the LLVM patch seems pretty clear about this. Thanks for pushing this through on the LLVM side! |
Currently, in a situation like
we generate a zero-sized struct as the LLVM type for
Foo
. LLVM might use this to assume thatBAR
has size 0, which would be fatal. And anyway it seems prudent for extern types, that should match C's declared-but-not-defined types, to match what Clang does for the corresponding C types -- which is to useopaque
.See #58271 for an attempt to fix this, which ran into LLVM assertion failures.
Cc @eddyb
The text was updated successfully, but these errors were encountered: