Zig Version
0.16.0
Steps to Reproduce and Observed Behavior
Somewhat related: https://github.com/ziglang/zig/issues/7639
- Build a shared library using GCC (not clang), then build and run a Zig program linked to it using the LLVM codegen backend:
func.c:
// gcc func.c -o libfunc.so -fpic -shared
#include <stdbool.h>#include <stdio.h>#include <inttypes.h>
void func(bool v) {
printf("func: %" PRIu32 "\n", (uint32_t)v);
}
main.zig:
// zig run main.zig -L. -lfunc -lc -fllvmconststd=@import("std");externfnfunc(v:bool)void;pubconstEdges=packedstruct(u32){top:bool=false,bottom:bool=false,left:bool=false,right:bool=false,_:u28=0,};pubfnmain(init:std.process.Init)void{// avoid comptime shenanigansconstn=init.minimal.args.vector.len;constedges:Edges=.{.top=n!=10,.bottom=n!=11,.left=n!=12,.right=n!=13,};func(edges.top);func(edges.bottom);func(edges.left);func(edges.right);}- Observe that
func()reports invalidboolvalues, which is UB in C:
func: 15
func: 7
func: 3
func: 1
The emitted IR declares and calls func() without any parameter attributes:
$ rg 'call void @func' < main.ll
declare void @func(i1) #0 align 1
call void @func(i1 %54), !dbg !82391
call void @func(i1 %57), !dbg !82393
call void @func(i1 %60), !dbg !82395
call void @func(i1 %63), !dbg !82397
In comparison, clang uses zeroext when emitting IR for a C program equivalent to main.zig:
$ rg 'void @func' < main.ll
call void @func(i1 noundef zeroext %39)
call void @func(i1 noundef zeroext %43)
call void @func(i1 noundef zeroext %47)
call void @func(i1 noundef zeroext %51)
declare void @func(i1 noundef zeroext) #1
Expected Behavior
Expected output:
func: 1
func: 1
func: 1
func: 1
### Zig Version
0.16.0
### Steps to Reproduce and Observed Behavior
Somewhat related: https://github.com/ziglang/zig/issues/7639
---
1. Build a shared library using GCC (not clang), then build and run a Zig program linked to it using the LLVM codegen backend:
`func.c`:
```c
// gcc func.c -o libfunc.so -fpic -shared
#include <stdbool.h>
#include <stdio.h>
#include <inttypes.h>
void func(bool v) {
printf("func: %" PRIu32 "\n", (uint32_t)v);
}
```
`main.zig`:
```zig
// zig run main.zig -L. -lfunc -lc -fllvm
const std = @import("std");
extern fn func(v: bool) void;
pub const Edges = packed struct(u32) {
top: bool = false,
bottom: bool = false,
left: bool = false,
right: bool = false,
_: u28 = 0,
};
pub fn main(init: std.process.Init) void {
// avoid comptime shenanigans
const n = init.minimal.args.vector.len;
const edges: Edges = .{
.top = n != 10,
.bottom = n != 11,
.left = n != 12,
.right = n != 13,
};
func(edges.top);
func(edges.bottom);
func(edges.left);
func(edges.right);
}
```
2. Observe that `func()` reports invalid `bool` values, which is UB in C:
```plain
func: 15
func: 7
func: 3
func: 1
```
The emitted IR declares and calls `func()` without any parameter attributes:
```plain
$ rg 'call void @func' < main.ll
declare void @func(i1) #0 align 1
call void @func(i1 %54), !dbg !82391
call void @func(i1 %57), !dbg !82393
call void @func(i1 %60), !dbg !82395
call void @func(i1 %63), !dbg !82397
```
In comparison, clang uses `zeroext` when emitting IR for a C program equivalent to `main.zig`:
```plain
$ rg 'void @func' < main.ll
call void @func(i1 noundef zeroext %39)
call void @func(i1 noundef zeroext %43)
call void @func(i1 noundef zeroext %47)
call void @func(i1 noundef zeroext %51)
declare void @func(i1 noundef zeroext) #1
```
### Expected Behavior
Expected output:
```plain
func: 1
func: 1
func: 1
func: 1
```