This introduces the concept of a "weak global name" into translate-c.
translate-c consists of two passes. The first is important, because it
discovers all global names, which are used to prevent naming conflicts:
whenever we see an identifier in the second pass, we can mangle it if it
conflicts with any global or any other in-scope identifier.
Unfortunately, this is a bit tricky for structs, unions, and enums. In
C, these types are not represented by normal identifers, but by separate
tags - `struct foo` does not prevent an unrelated identifier `foo`
existing. In general, we want to translate type names to user-friendly
ones such as `struct_foo` and `foo` where possible, but we can't
guarantee such names will not conflict with real variable names.
This is where weak global names come in. In the initial pass, when a
global type declaration is seen, `struct_foo` and `foo` are both added
as weak global names. This essentially means that we will use these
names for the type *if possible*, but if there is another global with
the same name, we will mangle the type name instead. Then, when actually
translating the declaration, we check whether there's a "true" global
with a conflicting name, in which case we mangle our name. If the
user-friendly alias `foo` conflicts, we do not attempt to mangle it: we
just don't emit it, because a mangled alias isn't particularly helpful.
AstGen emits an error when a closure over a known-runtime value crosses
a namespace boundary. This usually makes sense: however, this usage is
actually valid if the capture is within a `@TypeOf` operand. Sema
already has a special case to allow such closure within `@TypeOf` when
AstGen could not determine a value to be runtime-known. This commit
simply introduces analagous logic to AstGen to allow `var`s to cross
namespace boundaries within `@TypeOf`.
Superceeds PR #12735 (now supporting all packed structs in GNU C)
Fixes issue #12733
This stops translating C packed struct as a Zig packed struct.
Instead use a regular `extern struct` with `align(1)`.
This is because (as @Vexu explained) Zig packed structs are really just integers (not structs).
Alignment issue is more complicated. I think @ifreund was the
first to notice it in his comment on PR #12735
Justification of my interpretion of the C(lang) behavior
comes from a careful reading of the GCC docs for type & variable attributes:
(clang emulates gnu's packed attribute here)
The final line of the documentation for __attribute__ ((aligned)) [on types] says:
> When used on a struct, or struct member, *the aligned attribute can only increase the alignment*; in order to decrease it, the packed attribute must be specified as well.
This implies that GCC uses the `packed` attribute for alignment purposes
in addition to eliminating padding.
The documentation for __attribute__((packed)) [on types], states:
> This attribute, attached to a struct, union, or C++ class type definition, specifies that each of its members (other than zero-width bit-fields) is placed to minimize the memory required. **This is equivalent to specifying the packed attribute on each of the members**.
The key is resolving this indirection, and looking at the documentation
for __attribute__((packed)) [on fields (wierdly under "variables" section)]:
> The packed attribute specifies that a **structure member should have the smallest possible alignment** — one bit for a bit-field and one byte otherwise, unless a larger value is specified with the aligned attribute. The attribute does not apply to non-member objects.
Furthermore, alignment is the only effect of the packed attribute mentioned in the GCC docs (for "common" architecture).
Based on this, it seems safe to completely substitute C 'packed' with Zig 'align(1)'.
Target-specific or undocumented behavior potentially changes this.
Unfortunately, the current implementation of `translate-c` translates as
`packed struct` without alignment info.
Because Zig packed structs are really integers (as mentioned above),
they are the wrong interpretation and we should be using 'extern struct'.
Running `translate-c` on the following code:
```c
struct foo {
char a;
int b;
} __attribute__((packed));
struct bar {
char a;
int b;
short c;
__attribute__((aligned(8))) long d;
} __attribute__((packed));
```
Previously used a 'packed struct' (which was not FFI-safe on stage1).
After applying this change, the translated structures have align(1)
explicitly applied to all of their fields AS EXPECTED (unless explicitly overriden).
This makes Zig behavior for `tranlsate-c` consistent with clang/GCC.
Here is the newly produced (correct) output for the above example:
```zig
pub const struct_foo = extern struct {
a: u8 align(1),
b: c_int align(1),
};
pub const struct_bar = extern struct {
a: u8 align(1),
b: c_int align(1),
c: c_short align(1),
d: c_long align(8),
};
```
Also note for reference: Since the last stable release (0.9.1),
there was a change in the language spec
related to the alignment of packed structures.
The docs for Zig 0.9.1 read:
> Packed structs have 1-byte alignment.
So the old behavior of translate-c (not specifying any alignment) was possibly correct back then.
However the current docs read:
> Packed structs have the same alignment as their backing integer
Suggsestive both to the change to an integer-backed representation
which is incompatible with C's notation.
Use `@` syntax to escape `_` when used as an identifier.
Remove the stage1 astgen prohibition against assigning from `_`
Note: there a few stage1 bugs preventing `_` from being used as an identifier
for a local variable or function parameter; these will be fixed by stage2.
They are unlikely to arise in real C code since identifiers starting with
underscore are reserved for the implementation.
Translate enum types as the underlying integer type. Translate enum constants
as top-level integer constants of the correct type (which does not necessarily
match the enum integer type).
If an enum constant's type cannot be translated for some reason, omit it.
See discussion https://github.com/ziglang/zig/issues/2115#issuecomment-827968279Fixes#9153
Don't move static local variables into the top-level scope since this
can cause name clashes if subsequently-defined variables or parameters
in different scopes share the name.
Instead, use a variable within a struct so that the variable's lexical
scope does not change. This solution was suggested by @LemonBoy
Note that a similar name-shadowing problem exists with `extern` variables
declared within block scope, but a different solution will be needed since
they do need to be moved to the top-level scope and we can't rename them.
In std.meta.cast when casting to an enum type from an integer type, first
do a C-style cast from the source value to the tag type of the enum.
This ensures that we don't get an error due to the source value not being
representable by the enum.
In transCCast() use std.meta.cast instead of directly emitting the cast
operation since the enum's underlying type may not be known at translation
time due to an MSVC bug, see https://github.com/ziglang/zig/issues/8003Fixes#6011
This allows `break` statements to be directly translated from the original C.
Add a break statement as the last statement of the while loop to ensure we
don't have an infinite loop if no breaks / returns are hit in the switch.
Fixes#8387
Ensures that if an assignment statement is the sole statement within a
C if statement, for loop, do loop, or do while loop, then when translated
it resides within a block, even though it does not in the original C.
Fixes the following invalid translation:
`if (1) if (1) 2;` -> `if (true) if (true) _ = @as(c_int, 2);`
To this:
```zig
if (true) if (true) {
_ = @as(c_int, 2);
};
```
Fixes#8159