pub struct Program {Show 15 fields
pub unit_id: u64,
pub types: Types,
pub objects: Vec<Object>,
pub statics: Vec<StaticVar>,
pub externs: Vec<ObjectId>,
pub functions: Vec<Function>,
pub calls: Vec<CallEdge>,
pub typedefs: Vec<TypedefItem>,
pub enum_constants: Vec<Enumerator>,
pub strings: Vec<StrData>,
pub link_libraries: Vec<String>,
pub export: bool,
pub cpu_supports: Vec<SourceRange>,
pub no_std: bool,
pub crate_path: String,
}Expand description
Everything one translation unit generates.
Fields§
§unit_id: u64A hash of the invocation site, used to build the synthetic item names
that must not collide between two c99! blocks in one module.
types: TypesEvery derived and tagged type.
objects: Vec<Object>Every named object, indexed by ObjectId.
statics: Vec<StaticVar>The objects that become static mut items, in declaration order.
externs: Vec<ObjectId>The objects declared extern, in declaration order.
functions: Vec<Function>Every function, indexed by FuncId, in declaration order.
calls: Vec<CallEdge>Every direct call the unit’s bodies make; see CallEdge.
typedefs: Vec<TypedefItem>The file-scope typedefs, in declaration order.
enum_constants: Vec<Enumerator>The enum constants that become Rust const items, in order.
strings: Vec<StrData>Every string literal, indexed by StrId.
link_libraries: Vec<String>The libraries the unit must be linked against, named by
#pragma cinrs link "…".
Filled in after semantic analysis: it is the preprocessor that reads the pragma, and nothing about the program itself depends on it.
export: boolWhether #pragma cinrs export asked for every function and object with
external linkage to become a real C symbol.
Filled in after semantic analysis, for the same reason as
Program::link_libraries.
cpu_supports: Vec<SourceRange>Every __builtin_cpu_supports the unit wrote, by where it was written.
It becomes ::std::is_x86_feature_detected!, and core has no CPU
detection at all — so a unit that said #pragma cinrs no_std cannot
have one. The pragma is only known after semantic analysis, which is
why the sites are collected rather than checked where they are met; see
crate::sema::check_pragmas.
no_std: boolWhether #pragma cinrs no_std said the expansion goes into a
#![no_std] crate.
Everything generated is core-only except the storage a variable
length array and alloca need, which is a bump arena made
of Vecs; this decides whether they are spelled ::std::vec::Vec or
::alloc::vec::Vec. Filled in after semantic analysis, for the same
reason as Program::link_libraries.
crate_path: StringThe Rust path of the cinrs facade crate, which the generated code
names when it needs the runtime: ::cinrs unless
#pragma cinrs crate "…" said otherwise.
Only a unit that uses a complex type spells it at all. Filled in after
semantic analysis, for the same reason as Program::link_libraries.
Implementations§
Source§impl Program
impl Program
Sourcepub fn extern_object_name(&self, symbol: &str) -> String
pub fn extern_object_name(&self, symbol: &str) -> String
The hidden Rust name an externally linked object is declared under.
Only an object. A function the unit merely declares is generated under
its own C name, like everything else the unit spells, so that
#include <zlib.h> is enough for Rust to call crc32; an object is
not, and the difference is Rust’s rule for patterns rather than a
matter of taste.
A glob-imported function cannot change the meaning of Rust code
that does not mention it: a function is not a pattern, so let read = 1; beside a unit that declares read is still a new binding. A glob
imported static can. Rust resolves a binding pattern against the
value namespace first, and a static there is not a name a let may
shadow:
error[E0530]: let bindings cannot shadow statics— which is what let stdout = std::io::stdout(); would become next to a
block that includes <stdio.h>, and let timezone = … next to one that
includes glibc’s <time.h>. optarg, optind and environ are the
same story. So a declared-only object keeps a name of its own,
__cinrs_<unit>_<symbol>, and Rust reaches it the way C code does in
the same situation: through an accessor written in the block,
FILE *get_stdout(void) { return stdout; }.
The C code in the unit is unaffected either way — it refers to the object by its C name, and this is only the Rust side of that.
A module of its own for the extern block would have avoided the
question altogether, but a module cannot see the struct items of the
block it is written in, which an extern declaration taking a struct
needs.
A $ in the C name — an identifier character here, and one Rust has no
spelling for — is written crate::codegen::DOLLAR; the symbol the
declaration links by is a #[link_name] string and keeps the $.
Sourcepub fn has_externs(&self) -> bool
pub fn has_externs(&self) -> bool
Whether anything at all has to go into the extern block.
An x86 intrinsic does not count: it is declared like any
other function and generated as a call to core::arch, so a unit whose
only declarations came from <immintrin.h> needs no block at all.