mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
Merge remote-tracking branch 'origin/master' into llvm15
This commit is contained in:
commit
b7900de168
3
.github/CODEOWNERS
vendored
3
.github/CODEOWNERS
vendored
@ -1,3 +1,4 @@
|
||||
# Autodoc
|
||||
/src/Autodoc.zig @kristoff-it
|
||||
/lib/docs/* @kristoff-it
|
||||
/src/autodoc/* @kristoff-it
|
||||
/lib/docs/* @kristoff-it
|
||||
|
||||
@ -52,6 +52,7 @@ stage3-release/bin/zig build test docs \
|
||||
--zig-lib-dir "$(pwd)/../lib" \
|
||||
-Denable-macos-sdk \
|
||||
-Dstatic-llvm \
|
||||
-Dskip-non-native \
|
||||
--search-prefix "$PREFIX"
|
||||
|
||||
if [ "${BUILD_REASON}" != "PullRequest" ]; then
|
||||
|
||||
@ -16,4 +16,4 @@ $ZIG build test-universal-libc -Dskip-non-native --zig-lib-dir lib
|
||||
$ZIG build test-stack-traces -Dskip-non-native --zig-lib-dir lib
|
||||
$ZIG build test-cli -Dskip-non-native --zig-lib-dir lib
|
||||
$ZIG build test-asm-link -Dskip-non-native --zig-lib-dir lib
|
||||
$ZIG build test-translate-c -Dskip-non-native --zig-lib-dir lib
|
||||
# $ZIG build test-translate-c -Dskip-non-native --zig-lib-dir lib
|
||||
|
||||
@ -101,32 +101,48 @@ CIDIR="$(pwd)"
|
||||
|
||||
cd "$HOME"
|
||||
|
||||
# Upload new stdlib autodocs
|
||||
mkdir -p docs_to_upload/documentation/master/std/
|
||||
gzip -c -9 "$ZIGDIR/docs/std/index.html" > docs_to_upload/documentation/master/std/index.html
|
||||
gzip -c -9 "$ZIGDIR/docs/std/data.js" > docs_to_upload/documentation/master/std/data.js
|
||||
gzip -c -9 "$ZIGDIR/docs/std/main.js" > docs_to_upload/documentation/master/std/main.js
|
||||
gzip -c -9 "$LANGREF" > docs_to_upload/documentation/master/index.html
|
||||
$S3CMD put -P --no-mime-magic --recursive --add-header="Content-Encoding:gzip" --add-header="Cache-Control: max-age=0, must-revalidate" "docs_to_upload/" s3://ziglang.org/
|
||||
# Update autodocs and langref directly to S3 in order to prevent the
|
||||
# www.ziglang.org git repo from growing too big.
|
||||
|
||||
mkdir -p docs_src_to_upload/documentation/master/std/
|
||||
cp -r "$ZIGDIR/docs/std/src" docs_src_to_upload/documentation/master/std/
|
||||
$S3CMD put -P --no-mime-magic --recursive --add-header:"Content-Type:text/html" --add-header="Cache-Control: max-age=0, must-revalidate" "docs_src_to_upload/" s3://ziglang.org/
|
||||
# Please do not edit this script to pre-compress the artifacts before they hit
|
||||
# S3. This prevents the website from working on browsers that do not support gzip
|
||||
# encoding. Cloudfront will automatically compress files if they are less than
|
||||
# 9.5 MiB, and the client advertises itself as capable of decompressing.
|
||||
# The data.js file is currently 16 MiB. In order to fix this problem, we need to do
|
||||
# one of the following things:
|
||||
# * Reduce the size of data.js to less than 9.5 MiB.
|
||||
# * Figure out how to adjust the Cloudfront settings to increase the max size for
|
||||
# auto-compressed objects.
|
||||
# * Migrate to fastly.
|
||||
$S3CMD put -P --no-mime-magic \
|
||||
--add-header="Cache-Control: max-age=0, must-revalidate" \
|
||||
"$LANGREF" s3://ziglang.org/documentation/master/index.html
|
||||
|
||||
## Copy without compression:
|
||||
# mkdir -p docs_to_upload/documentation/master/std/
|
||||
# cp "$ZIGDIR/docs/std/index.html" docs_to_upload/documentation/master/std/index.html
|
||||
# cp "$ZIGDIR/docs/std/data.js" docs_to_upload/documentation/master/std/data.js
|
||||
# cp "$ZIGDIR/docs/std/main.js" docs_to_upload/documentation/master/std/main.js
|
||||
# cp "$LANGREF" docs_to_upload/documentation/master/index.html
|
||||
# $S3CMD put -P --no-mime-magic --recursive --add-header="Cache-Control: max-age=0, must-revalidate" "docs_to_upload/" s3://ziglang.org/
|
||||
$S3CMD put -P --no-mime-magic \
|
||||
--add-header="Cache-Control: max-age=0, must-revalidate" \
|
||||
"$ZIGDIR/docs/std/index.html" s3://ziglang.org/documentation/master/std/index.html
|
||||
|
||||
$S3CMD put -P --no-mime-magic \
|
||||
--add-header="Cache-Control: max-age=0, must-revalidate" \
|
||||
"$ZIGDIR/docs/std/main.js" s3://ziglang.org/documentation/master/std/main.js
|
||||
|
||||
$S3CMD put -P --no-mime-magic \
|
||||
--add-header="Cache-Control: max-age=0, must-revalidate" \
|
||||
"$ZIGDIR/docs/std/data.js" s3://ziglang.org/documentation/master/std/data.js
|
||||
|
||||
$S3CMD put -P --no-mime-magic --recursive \
|
||||
--add-header="Cache-Control: max-age=0, must-revalidate" \
|
||||
-m "text/html" \
|
||||
"$ZIGDIR/docs/std/src/" s3://ziglang.org/documentation/master/std/src/
|
||||
|
||||
$S3CMD put -P --no-mime-magic \
|
||||
--add-header="cache-control: public, max-age=31536000, immutable" \
|
||||
"$HOME/$SRC_TARBALL" s3://ziglang.org/builds/
|
||||
|
||||
git clone --depth 1 git@github.com:ziglang/www.ziglang.org.git
|
||||
cd www.ziglang.org
|
||||
WWWDIR="$(pwd)"
|
||||
|
||||
$S3CMD put -P --no-mime-magic --add-header="cache-control: public, max-age=31536000, immutable" "$HOME/$SRC_TARBALL" s3://ziglang.org/builds/
|
||||
|
||||
cd "$WWWDIR"
|
||||
cp "$CIDIR/out/index.json" data/releases.json
|
||||
git add data/releases.json
|
||||
|
||||
@ -75,6 +75,11 @@ steps:
|
||||
depends_on:
|
||||
- macos_package
|
||||
- linux_package
|
||||
when:
|
||||
branch:
|
||||
- master
|
||||
event:
|
||||
- push
|
||||
image: ci/debian-amd64:11.1-9
|
||||
environment:
|
||||
SRHT_OAUTH_TOKEN:
|
||||
|
||||
@ -29,7 +29,7 @@ tar cfJ "$TARBALL" "$BASENAME"
|
||||
SHASUM=$(sha256sum $TARBALL | cut '-d ' -f1)
|
||||
BYTESIZE=$(wc -c < $TARBALL)
|
||||
|
||||
MANIFEST="manifest.json"
|
||||
MANIFEST="manifest-$TARGET.json"
|
||||
touch $MANIFEST
|
||||
echo "{\"tarball\": \"$TARBALL\"," >>$MANIFEST
|
||||
echo "\"shasum\": \"$SHASUM\"," >>$MANIFEST
|
||||
|
||||
@ -33,7 +33,7 @@ tar cfJ "$TARBALL" "$BASENAME"
|
||||
SHASUM=$(sha256sum $TARBALL | cut '-d ' -f1)
|
||||
BYTESIZE=$(wc -c < $TARBALL)
|
||||
|
||||
MANIFEST="manifest.json"
|
||||
MANIFEST="manifest-$TARGET.json"
|
||||
touch $MANIFEST
|
||||
echo "{\"tarball\": \"$TARBALL\"," >>$MANIFEST
|
||||
echo "\"shasum\": \"$SHASUM\"," >>$MANIFEST
|
||||
|
||||
@ -2631,7 +2631,7 @@ test "Conversion between vectors, arrays, and slices" {
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>{#syntax#}[]T{#endsyntax#} - pointer to runtime-known number of items.
|
||||
<li>{#syntax#}[]T{#endsyntax#} - is a slice (a fat pointer, which contains a pointer of type {#syntax#}[*]T{#endsyntax#} and a length).
|
||||
<ul>
|
||||
<li>Supports index syntax: {#syntax#}slice[i]{#endsyntax#}</li>
|
||||
<li>Supports slice syntax: {#syntax#}slice[start..end]{#endsyntax#}</li>
|
||||
|
||||
@ -359,7 +359,17 @@
|
||||
|
||||
#listFns dt {
|
||||
font-family: var(--mono);
|
||||
display: flex;
|
||||
flex-direction: colunm;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#listFns dt .fnSignature {
|
||||
overflow-x: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.argBreaker {
|
||||
display: none;
|
||||
}
|
||||
@ -711,7 +721,11 @@
|
||||
<h2>Examples</h2>
|
||||
<ul id="listFnExamples" class="examples"></ul>
|
||||
</div>
|
||||
<div id="sectTests" class="hidden">
|
||||
<div id="sectDocTests" class="hidden">
|
||||
<h2>DocTests</h2>
|
||||
<pre id="docTestsCode"></pre>
|
||||
</div>
|
||||
<div id="sectTests" class="hidden">
|
||||
<h2>Tests</h2>
|
||||
<div class="table-container">
|
||||
<table>
|
||||
|
||||
@ -13,6 +13,8 @@ var zigAnalysis;
|
||||
const domListTypes = document.getElementById("listTypes");
|
||||
const domSectTests = document.getElementById("sectTests");
|
||||
const domListTests = document.getElementById("listTests");
|
||||
const domSectDocTests = document.getElementById("sectDocTests");
|
||||
const domDocTestsCode = document.getElementById("docTestsCode");
|
||||
const domSectNamespaces = document.getElementById("sectNamespaces");
|
||||
const domListNamespaces = document.getElementById("listNamespaces");
|
||||
const domSectErrSets = document.getElementById("sectErrSets");
|
||||
@ -241,7 +243,8 @@ var zigAnalysis;
|
||||
return (
|
||||
typeKind === typeKinds.Struct ||
|
||||
typeKind === typeKinds.Union ||
|
||||
typeKind === typeKinds.Enum
|
||||
typeKind === typeKinds.Enum ||
|
||||
typeKind === typeKinds.Opaque
|
||||
);
|
||||
}
|
||||
|
||||
@ -384,6 +387,7 @@ var zigAnalysis;
|
||||
domSectPkgs.classList.add("hidden");
|
||||
domSectTypes.classList.add("hidden");
|
||||
domSectTests.classList.add("hidden");
|
||||
domSectDocTests.classList.add("hidden");
|
||||
domSectNamespaces.classList.add("hidden");
|
||||
domSectErrSets.classList.add("hidden");
|
||||
domSectFns.classList.add("hidden");
|
||||
@ -452,6 +456,10 @@ var zigAnalysis;
|
||||
let lastIsDecl = isDecl(last);
|
||||
let lastIsType = isType(last);
|
||||
let lastIsContainerType = isContainerType(last);
|
||||
|
||||
if (lastIsDecl){
|
||||
renderDocTest(last);
|
||||
}
|
||||
|
||||
if (lastIsContainerType) {
|
||||
return renderContainer(last);
|
||||
@ -477,6 +485,14 @@ var zigAnalysis;
|
||||
|
||||
return renderValue(last);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function renderDocTest(decl) {
|
||||
if (!("decltest" in decl)) return;
|
||||
const astNode = zigAnalysis.astNodes[decl.decltest];
|
||||
domSectDocTests.classList.remove("hidden");
|
||||
domDocTestsCode.innerHTML = astNode.code;
|
||||
}
|
||||
|
||||
function renderUnknownDecl(decl) {
|
||||
@ -1405,6 +1421,30 @@ var zigAnalysis;
|
||||
operator += "**";
|
||||
break;
|
||||
}
|
||||
case "cmp_eq": {
|
||||
operator += "==";
|
||||
break;
|
||||
}
|
||||
case "cmp_neq": {
|
||||
operator += "!=";
|
||||
break;
|
||||
}
|
||||
case "cmp_gt": {
|
||||
operator += ">";
|
||||
break;
|
||||
}
|
||||
case "cmp_gte": {
|
||||
operator += ">=";
|
||||
break;
|
||||
}
|
||||
case "cmp_lt": {
|
||||
operator += "<";
|
||||
break;
|
||||
}
|
||||
case "cmp_lte": {
|
||||
operator += "<=";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
console.log("operator not handled yet or doesn't exist!");
|
||||
}
|
||||
@ -1555,6 +1595,10 @@ var zigAnalysis;
|
||||
return '"' + escapeHtml(expr.string) + '"';
|
||||
}
|
||||
|
||||
case "int_big": {
|
||||
return (expr.int_big.negated ? "-" : "") + expr.int_big.value;
|
||||
}
|
||||
|
||||
case "anytype": {
|
||||
return "anytype";
|
||||
}
|
||||
@ -1581,8 +1625,7 @@ var zigAnalysis;
|
||||
}
|
||||
case typeKinds.Opaque: {
|
||||
let opaqueObj = typeObj;
|
||||
|
||||
return opaqueObj.name;
|
||||
return opaqueObj;
|
||||
}
|
||||
case typeKinds.ComptimeExpr: {
|
||||
return "anyopaque";
|
||||
@ -2285,7 +2328,7 @@ var zigAnalysis;
|
||||
|
||||
return "<a style=\"float: right;\" href=\"" +
|
||||
sourceFileUrlTemplate.replace("{{file}}",
|
||||
zigAnalysis.files[srcNode.file]).replace("{{line}}", srcNode.line) + "\">[src]</a>";
|
||||
zigAnalysis.files[srcNode.file]).replace("{{line}}", srcNode.line + 1) + "\">[src]</a>";
|
||||
}
|
||||
|
||||
function renderContainer(container) {
|
||||
@ -2393,24 +2436,26 @@ var zigAnalysis;
|
||||
resizeDomList(
|
||||
domListFns,
|
||||
fnsList.length,
|
||||
"<div><dt></dt><dd></dd></div>"
|
||||
"<div><dt><div class=\"fnSignature\"></div><div></div></dt><dd></dd></div>"
|
||||
);
|
||||
|
||||
for (let i = 0; i < fnsList.length; i += 1) {
|
||||
let decl = fnsList[i];
|
||||
let trDom = domListFns.children[i];
|
||||
|
||||
let tdFnCode = trDom.children[0];
|
||||
let tdFnSignature = trDom.children[0].children[0];
|
||||
let tdFnSrc = trDom.children[0].children[1];
|
||||
let tdDesc = trDom.children[1];
|
||||
|
||||
let declType = resolveValue(decl.value);
|
||||
console.assert("type" in declType.expr);
|
||||
tdFnCode.innerHTML = exprName(declType.expr, {
|
||||
tdFnSignature.innerHTML = exprName(declType.expr, {
|
||||
wantHtml: true,
|
||||
wantLink: true,
|
||||
fnDecl: decl,
|
||||
linkFnNameDecl: navLinkDecl(decl.name),
|
||||
}) + renderSourceFileLink(decl);
|
||||
});
|
||||
tdFnSrc.innerHTML = renderSourceFileLink(decl);
|
||||
|
||||
let docs = zigAnalysis.astNodes[decl.src].docs;
|
||||
if (docs != null) {
|
||||
|
||||
@ -769,16 +769,13 @@ const LinuxThreadImpl = struct {
|
||||
),
|
||||
.x86_64 => asm volatile (
|
||||
\\ movq $11, %%rax
|
||||
\\ movq %[ptr], %%rbx
|
||||
\\ movq %[len], %%rcx
|
||||
\\ syscall
|
||||
\\ movq $60, %%rax
|
||||
\\ movq $1, %%rdi
|
||||
\\ syscall
|
||||
:
|
||||
: [ptr] "r" (@ptrToInt(self.mapped.ptr)),
|
||||
[len] "r" (self.mapped.len),
|
||||
: "memory"
|
||||
: [ptr] "{rdi}" (@ptrToInt(self.mapped.ptr)),
|
||||
[len] "{rsi}" (self.mapped.len),
|
||||
),
|
||||
.arm, .armeb, .thumb, .thumbeb => asm volatile (
|
||||
\\ mov r7, #91
|
||||
|
||||
@ -419,6 +419,91 @@ pub const DebugType = enum(u32) {
|
||||
EX_DLLCHARACTERISTICS = 20,
|
||||
};
|
||||
|
||||
pub const ImportDirectoryEntry = extern struct {
|
||||
/// The RVA of the import lookup table.
|
||||
/// This table contains a name or ordinal for each import.
|
||||
/// (The name "Characteristics" is used in Winnt.h, but no longer describes this field.)
|
||||
import_lookup_table_rva: u32,
|
||||
|
||||
/// The stamp that is set to zero until the image is bound.
|
||||
/// After the image is bound, this field is set to the time/data stamp of the DLL.
|
||||
time_date_stamp: u32,
|
||||
|
||||
/// The index of the first forwarder reference.
|
||||
forwarder_chain: u32,
|
||||
|
||||
/// The address of an ASCII string that contains the name of the DLL.
|
||||
/// This address is relative to the image base.
|
||||
name_rva: u32,
|
||||
|
||||
/// The RVA of the import address table.
|
||||
/// The contents of this table are identical to the contents of the import lookup table until the image is bound.
|
||||
import_address_table_rva: u32,
|
||||
};
|
||||
|
||||
pub const ImportLookupEntry32 = struct {
|
||||
pub const ByName = packed struct {
|
||||
name_table_rva: u31,
|
||||
flag: u1 = 0,
|
||||
};
|
||||
|
||||
pub const ByOrdinal = packed struct {
|
||||
ordinal_number: u16,
|
||||
unused: u15 = 0,
|
||||
flag: u1 = 1,
|
||||
};
|
||||
|
||||
const mask = 0x80000000;
|
||||
|
||||
pub fn getImportByName(raw: u32) ?ByName {
|
||||
if (mask & raw != 0) return null;
|
||||
return @bitCast(ByName, raw);
|
||||
}
|
||||
|
||||
pub fn getImportByOrdinal(raw: u32) ?ByOrdinal {
|
||||
if (mask & raw == 0) return null;
|
||||
return @bitCast(ByOrdinal, raw);
|
||||
}
|
||||
};
|
||||
|
||||
pub const ImportLookupEntry64 = struct {
|
||||
pub const ByName = packed struct {
|
||||
name_table_rva: u31,
|
||||
unused: u32 = 0,
|
||||
flag: u1 = 0,
|
||||
};
|
||||
|
||||
pub const ByOrdinal = packed struct {
|
||||
ordinal_number: u16,
|
||||
unused: u47 = 0,
|
||||
flag: u1 = 1,
|
||||
};
|
||||
|
||||
const mask = 0x8000000000000000;
|
||||
|
||||
pub fn getImportByName(raw: u64) ?ByName {
|
||||
if (mask & raw != 0) return null;
|
||||
return @bitCast(ByName, raw);
|
||||
}
|
||||
|
||||
pub fn getImportByOrdinal(raw: u64) ?ByOrdinal {
|
||||
if (mask & raw == 0) return null;
|
||||
return @bitCast(ByOrdinal, raw);
|
||||
}
|
||||
};
|
||||
|
||||
/// Every name ends with a NULL byte. IF the NULL byte does not fall on
|
||||
/// 2byte boundary, the entry structure is padded to ensure 2byte alignment.
|
||||
pub const ImportHintNameEntry = extern struct {
|
||||
/// An index into the export name pointer table.
|
||||
/// A match is attempted first with this value. If it fails, a binary search is performed on the DLL's export name pointer table.
|
||||
hint: u16,
|
||||
|
||||
/// Pointer to NULL terminated ASCII name.
|
||||
/// Variable length...
|
||||
name: [1]u8,
|
||||
};
|
||||
|
||||
pub const SectionHeader = extern struct {
|
||||
name: [8]u8,
|
||||
virtual_size: u32,
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
//! return,
|
||||
//! } ++ "): ";
|
||||
//!
|
||||
//! const prefix = "[" ++ level.asText() ++ "] " ++ scope_prefix;
|
||||
//! const prefix = "[" ++ comptime level.asText() ++ "] " ++ scope_prefix;
|
||||
//!
|
||||
//! // Print the message to stderr, silently ignoring any errors
|
||||
//! std.debug.getStderrMutex().lock();
|
||||
|
||||
@ -334,13 +334,13 @@ pub const Rational = struct {
|
||||
/// Returns math.Order.lt, math.Order.eq, math.Order.gt if a < b, a == b or a
|
||||
/// > b respectively.
|
||||
pub fn order(a: Rational, b: Rational) !math.Order {
|
||||
return cmpInternal(a, b, true);
|
||||
return cmpInternal(a, b, false);
|
||||
}
|
||||
|
||||
/// Returns math.Order.lt, math.Order.eq, math.Order.gt if |a| < |b|, |a| ==
|
||||
/// |b| or |a| > |b| respectively.
|
||||
pub fn orderAbs(a: Rational, b: Rational) !math.Order {
|
||||
return cmpInternal(a, b, false);
|
||||
return cmpInternal(a, b, true);
|
||||
}
|
||||
|
||||
// p/q > x/y iff p*y > x*q
|
||||
@ -704,6 +704,18 @@ test "big.rational order" {
|
||||
try testing.expect((try a.order(b)) == .eq);
|
||||
}
|
||||
|
||||
test "big.rational order/orderAbs with negative" {
|
||||
var a = try Rational.init(testing.allocator);
|
||||
defer a.deinit();
|
||||
var b = try Rational.init(testing.allocator);
|
||||
defer b.deinit();
|
||||
|
||||
try a.setRatio(1, 1);
|
||||
try b.setRatio(-2, 1);
|
||||
try testing.expect((try a.order(b)) == .gt);
|
||||
try testing.expect((try a.orderAbs(b)) == .lt);
|
||||
}
|
||||
|
||||
test "big.rational add single-limb" {
|
||||
var a = try Rational.init(testing.allocator);
|
||||
defer a.deinit();
|
||||
|
||||
@ -3447,6 +3447,9 @@ pub const BindError = error{
|
||||
/// A nonexistent interface was requested or the requested address was not local.
|
||||
AddressNotAvailable,
|
||||
|
||||
/// The address is not valid for the address family of socket.
|
||||
AddressFamilyNotSupported,
|
||||
|
||||
/// Too many symbolic links were encountered in resolving addr.
|
||||
SymLinkLoop,
|
||||
|
||||
@ -3502,6 +3505,7 @@ pub fn bind(sock: socket_t, addr: *const sockaddr, len: socklen_t) BindError!voi
|
||||
.BADF => unreachable, // always a race condition if this error is returned
|
||||
.INVAL => unreachable, // invalid parameters
|
||||
.NOTSOCK => unreachable, // invalid `sockfd`
|
||||
.AFNOSUPPORT => return error.AddressFamilyNotSupported,
|
||||
.ADDRNOTAVAIL => return error.AddressNotAvailable,
|
||||
.FAULT => unreachable, // invalid `addr` pointer
|
||||
.LOOP => return error.SymLinkLoop,
|
||||
|
||||
@ -268,7 +268,7 @@ test "sizeof" {
|
||||
pub const CIntLiteralRadix = enum { decimal, octal, hexadecimal };
|
||||
|
||||
fn PromoteIntLiteralReturnType(comptime SuffixType: type, comptime number: comptime_int, comptime radix: CIntLiteralRadix) type {
|
||||
const signed_decimal = [_]type{ c_int, c_long, c_longlong };
|
||||
const signed_decimal = [_]type{ c_int, c_long, c_longlong, c_ulonglong };
|
||||
const signed_oct_hex = [_]type{ c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong };
|
||||
const unsigned = [_]type{ c_uint, c_ulong, c_ulonglong };
|
||||
|
||||
|
||||
@ -16,6 +16,28 @@ test "zig fmt: preserves clobbers in inline asm with stray comma" {
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: remove trailing comma at the end of assembly clobber" {
|
||||
try testTransform(
|
||||
\\fn foo() void {
|
||||
\\ asm volatile (""
|
||||
\\ : [_] "" (-> type),
|
||||
\\ :
|
||||
\\ : "clobber1", "clobber2",
|
||||
\\ );
|
||||
\\}
|
||||
\\
|
||||
,
|
||||
\\fn foo() void {
|
||||
\\ asm volatile (""
|
||||
\\ : [_] "" (-> type),
|
||||
\\ :
|
||||
\\ : "clobber1", "clobber2"
|
||||
\\ );
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: respect line breaks in struct field value declaration" {
|
||||
try testCanonical(
|
||||
\\const Foo = struct {
|
||||
@ -5035,6 +5057,21 @@ test "zig fmt: make single-line if no trailing comma" {
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: preserve container doc comment in container without trailing comma" {
|
||||
try testTransform(
|
||||
\\const A = enum(u32) {
|
||||
\\//! comment
|
||||
\\_ };
|
||||
\\
|
||||
,
|
||||
\\const A = enum(u32) {
|
||||
\\ //! comment
|
||||
\\ _,
|
||||
\\};
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: make single-line if no trailing comma" {
|
||||
try testCanonical(
|
||||
\\// Test trailing comma syntax
|
||||
|
||||
@ -1933,12 +1933,15 @@ fn renderContainerDecl(
|
||||
break :one_line;
|
||||
}
|
||||
|
||||
// 2. A member of the container has a doc comment.
|
||||
// 2. The container has a container comment.
|
||||
if (token_tags[lbrace + 1] == .container_doc_comment) break :one_line;
|
||||
|
||||
// 3. A member of the container has a doc comment.
|
||||
for (token_tags[lbrace + 1 .. rbrace - 1]) |tag| {
|
||||
if (tag == .doc_comment) break :one_line;
|
||||
}
|
||||
|
||||
// 3. The container has non-field members.
|
||||
// 4. The container has non-field members.
|
||||
for (container_decl.ast.members) |member| {
|
||||
if (!node_tags[member].isContainerField()) break :one_line;
|
||||
}
|
||||
@ -2114,9 +2117,19 @@ fn renderAsm(
|
||||
return renderToken(ais, tree, tok_i + 1, space);
|
||||
},
|
||||
.comma => {
|
||||
try renderToken(ais, tree, tok_i, .none);
|
||||
try renderToken(ais, tree, tok_i + 1, .space);
|
||||
tok_i += 2;
|
||||
switch (token_tags[tok_i + 2]) {
|
||||
.r_paren => {
|
||||
ais.setIndentDelta(indent_delta);
|
||||
ais.popIndent();
|
||||
try renderToken(ais, tree, tok_i, .newline);
|
||||
return renderToken(ais, tree, tok_i + 2, space);
|
||||
},
|
||||
else => {
|
||||
try renderToken(ais, tree, tok_i, .none);
|
||||
try renderToken(ais, tree, tok_i + 1, .space);
|
||||
tok_i += 2;
|
||||
},
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
@ -2348,7 +2361,7 @@ fn renderSpace(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, lexeme_len: us
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if there exists a comment between any of the tokens from
|
||||
/// Returns true if there exists a line comment between any of the tokens from
|
||||
/// `start_token` to `end_token`. This is used to determine if e.g. a
|
||||
/// fn_proto should be wrapped and have a trailing comma inserted even if
|
||||
/// there is none in the source.
|
||||
|
||||
@ -5127,7 +5127,7 @@ fn tryExpr(
|
||||
else => .none,
|
||||
};
|
||||
// This could be a pointer or value depending on the `rl` parameter.
|
||||
const operand = try expr(parent_gz, scope, operand_rl, operand_node);
|
||||
const operand = try reachableExpr(parent_gz, scope, operand_rl, operand_node, node);
|
||||
const is_inline = parent_gz.force_comptime;
|
||||
const is_inline_bit = @as(u2, @boolToInt(is_inline));
|
||||
const is_ptr_bit = @as(u2, @boolToInt(operand_rl == .ref)) << 1;
|
||||
|
||||
606
src/Autodoc.zig
606
src/Autodoc.zig
File diff suppressed because it is too large
Load Diff
@ -4635,7 +4635,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
|
||||
decl.analysis = .complete;
|
||||
decl.generation = mod.generation;
|
||||
|
||||
const has_runtime_bits = try sema.fnHasRuntimeBits(&block_scope, ty_src, decl.ty);
|
||||
const has_runtime_bits = try sema.fnHasRuntimeBits(decl.ty);
|
||||
|
||||
if (has_runtime_bits) {
|
||||
// We don't fully codegen the decl until later, but we do need to reserve a global
|
||||
|
||||
191
src/Sema.zig
191
src/Sema.zig
@ -2565,7 +2565,7 @@ fn zirEnumDecl(
|
||||
}
|
||||
}
|
||||
|
||||
if (small.nonexhaustive) {
|
||||
if (small.nonexhaustive and enum_obj.tag_ty.zigTypeTag() != .ComptimeInt) {
|
||||
if (fields_len > 1 and std.math.log2_int(u64, fields_len) == enum_obj.tag_ty.bitSize(sema.mod.getTarget())) {
|
||||
return sema.fail(block, src, "non-exhaustive enum specifies every value", .{});
|
||||
}
|
||||
@ -2586,6 +2586,7 @@ fn zirEnumDecl(
|
||||
var cur_bit_bag: u32 = undefined;
|
||||
var field_i: u32 = 0;
|
||||
var last_tag_val: ?Value = null;
|
||||
var tag_val_buf: Value.Payload.U64 = undefined;
|
||||
while (field_i < fields_len) : (field_i += 1) {
|
||||
if (field_i % 32 == 0) {
|
||||
cur_bit_bag = sema.code.extra[bit_bag_index];
|
||||
@ -2641,6 +2642,21 @@ fn zirEnumDecl(
|
||||
.ty = enum_obj.tag_ty,
|
||||
.mod = mod,
|
||||
});
|
||||
} else {
|
||||
tag_val_buf = .{
|
||||
.base = .{ .tag = .int_u64 },
|
||||
.data = field_i,
|
||||
};
|
||||
last_tag_val = Value.initPayload(&tag_val_buf.base);
|
||||
}
|
||||
|
||||
if (!(try sema.intFitsInType(block, src, last_tag_val.?, enum_obj.tag_ty, null))) {
|
||||
const tree = try sema.getAstTree(block);
|
||||
const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i);
|
||||
const msg = try sema.errMsg(block, field_src, "enumeration value '{}' too large for type '{}'", .{
|
||||
last_tag_val.?.fmtValue(enum_obj.tag_ty, mod), enum_obj.tag_ty.fmt(mod),
|
||||
});
|
||||
return sema.failWithOwnedErrorMsg(msg);
|
||||
}
|
||||
}
|
||||
return decl_val;
|
||||
@ -2849,7 +2865,7 @@ fn zirRetPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].node;
|
||||
const src = LazySrcLoc.nodeOffset(inst_data);
|
||||
|
||||
if (block.is_comptime or try sema.typeRequiresComptime(block, src, sema.fn_ret_ty)) {
|
||||
if (block.is_comptime or try sema.typeRequiresComptime(sema.fn_ret_ty)) {
|
||||
const fn_ret_ty = try sema.resolveTypeFields(block, src, sema.fn_ret_ty);
|
||||
return sema.analyzeComptimeAlloc(block, fn_ret_ty, 0, src);
|
||||
}
|
||||
@ -5040,7 +5056,7 @@ pub fn analyzeExport(
|
||||
try mod.ensureDeclAnalyzed(exported_decl_index);
|
||||
const exported_decl = mod.declPtr(exported_decl_index);
|
||||
|
||||
if (!sema.validateExternType(exported_decl.ty, .other)) {
|
||||
if (!try sema.validateExternType(block, src, exported_decl.ty, .other)) {
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{exported_decl.ty.fmt(sema.mod)});
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
@ -5569,7 +5585,11 @@ fn zirCall(
|
||||
const param_ty_inst = try sema.addType(param_ty);
|
||||
try sema.inst_map.put(sema.gpa, inst, param_ty_inst);
|
||||
|
||||
resolved_args[arg_index] = try sema.resolveBody(block, args_body[arg_start..arg_end], inst);
|
||||
const resolved = try sema.resolveBody(block, args_body[arg_start..arg_end], inst);
|
||||
if (sema.typeOf(resolved).zigTypeTag() == .NoReturn) {
|
||||
return resolved;
|
||||
}
|
||||
resolved_args[arg_index] = resolved;
|
||||
}
|
||||
|
||||
return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src);
|
||||
@ -5768,7 +5788,7 @@ fn analyzeCall(
|
||||
var is_comptime_call = block.is_comptime or modifier == .compile_time;
|
||||
var comptime_only_ret_ty = false;
|
||||
if (!is_comptime_call) {
|
||||
if (sema.typeRequiresComptime(block, func_src, func_ty_info.return_type)) |ct| {
|
||||
if (sema.typeRequiresComptime(func_ty_info.return_type)) |ct| {
|
||||
is_comptime_call = ct;
|
||||
comptime_only_ret_ty = ct;
|
||||
} else |err| switch (err) {
|
||||
@ -6047,7 +6067,7 @@ fn analyzeCall(
|
||||
break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges);
|
||||
};
|
||||
|
||||
if (!is_comptime_call) {
|
||||
if (!is_comptime_call and sema.typeOf(result).zigTypeTag() != .NoReturn) {
|
||||
try sema.emitDbgInline(
|
||||
block,
|
||||
module_fn,
|
||||
@ -6206,7 +6226,7 @@ fn analyzeInlineCallArg(
|
||||
const param_ty = try sema.analyzeAsType(param_block, param_src, param_ty_inst);
|
||||
new_fn_info.param_types[arg_i.*] = param_ty;
|
||||
const uncasted_arg = uncasted_args[arg_i.*];
|
||||
if (try sema.typeRequiresComptime(arg_block, arg_src, param_ty)) {
|
||||
if (try sema.typeRequiresComptime(param_ty)) {
|
||||
_ = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime only type must be comptime known") catch |err| {
|
||||
if (err == error.AnalysisFail and sema.err != null) {
|
||||
try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty);
|
||||
@ -6308,7 +6328,7 @@ fn analyzeGenericCallArg(
|
||||
) !void {
|
||||
const is_runtime = comptime_arg.val.tag() == .generic_poison and
|
||||
comptime_arg.ty.hasRuntimeBits() and
|
||||
!(try sema.typeRequiresComptime(block, arg_src, comptime_arg.ty));
|
||||
!(try sema.typeRequiresComptime(comptime_arg.ty));
|
||||
if (is_runtime) {
|
||||
const param_ty = new_fn_info.param_types[runtime_i.*];
|
||||
const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
|
||||
@ -6573,7 +6593,7 @@ fn instantiateGenericCall(
|
||||
}
|
||||
} else if (is_anytype) {
|
||||
const arg_ty = sema.typeOf(arg);
|
||||
if (try sema.typeRequiresComptime(block, .unneeded, arg_ty)) {
|
||||
if (try sema.typeRequiresComptime(arg_ty)) {
|
||||
const arg_val = try sema.resolveConstValue(block, .unneeded, arg, undefined);
|
||||
const child_arg = try child_sema.addConstant(arg_ty, arg_val);
|
||||
child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg);
|
||||
@ -6626,7 +6646,7 @@ fn instantiateGenericCall(
|
||||
const arg = child_sema.inst_map.get(inst).?;
|
||||
const copied_arg_ty = try child_sema.typeOf(arg).copy(new_decl_arena_allocator);
|
||||
|
||||
if (try sema.typeRequiresComptime(block, .unneeded, copied_arg_ty)) {
|
||||
if (try sema.typeRequiresComptime(copied_arg_ty)) {
|
||||
is_comptime = true;
|
||||
}
|
||||
|
||||
@ -6657,7 +6677,7 @@ fn instantiateGenericCall(
|
||||
// If the call evaluated to a return type that requires comptime, never mind
|
||||
// our generic instantiation. Instead we need to perform a comptime call.
|
||||
const new_fn_info = new_decl.ty.fnInfo();
|
||||
if (try sema.typeRequiresComptime(block, call_src, new_fn_info.return_type)) {
|
||||
if (try sema.typeRequiresComptime(new_fn_info.return_type)) {
|
||||
return error.ComptimeReturn;
|
||||
}
|
||||
// Similarly, if the call evaluated to a generic type we need to instead
|
||||
@ -7838,7 +7858,7 @@ fn funcCommon(
|
||||
}
|
||||
|
||||
var ret_ty_requires_comptime = false;
|
||||
const ret_poison = if (sema.typeRequiresComptime(block, ret_ty_src, bare_return_type)) |ret_comptime| rp: {
|
||||
const ret_poison = if (sema.typeRequiresComptime(bare_return_type)) |ret_comptime| rp: {
|
||||
ret_ty_requires_comptime = ret_comptime;
|
||||
break :rp bare_return_type.tag() == .generic_poison;
|
||||
} else |err| switch (err) {
|
||||
@ -7876,7 +7896,7 @@ fn funcCommon(
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(msg);
|
||||
}
|
||||
if (!Type.fnCallingConventionAllowsZigTypes(cc_workaround) and !sema.validateExternType(return_type, .ret_ty)) {
|
||||
if (!Type.fnCallingConventionAllowsZigTypes(cc_workaround) and !try sema.validateExternType(block, ret_ty_src, return_type, .ret_ty)) {
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(block, ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{
|
||||
return_type.fmt(sema.mod), @tagName(cc_workaround),
|
||||
@ -8072,7 +8092,7 @@ fn analyzeParameter(
|
||||
cc: std.builtin.CallingConvention,
|
||||
has_body: bool,
|
||||
) !void {
|
||||
const requires_comptime = try sema.typeRequiresComptime(block, param_src, param.ty);
|
||||
const requires_comptime = try sema.typeRequiresComptime(param.ty);
|
||||
comptime_params[i] = param.is_comptime or requires_comptime;
|
||||
const this_generic = param.ty.tag() == .generic_poison;
|
||||
is_generic.* = is_generic.* or this_generic;
|
||||
@ -8095,7 +8115,7 @@ fn analyzeParameter(
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(msg);
|
||||
}
|
||||
if (!Type.fnCallingConventionAllowsZigTypes(cc) and !sema.validateExternType(param.ty, .param_ty)) {
|
||||
if (!Type.fnCallingConventionAllowsZigTypes(cc) and !try sema.validateExternType(block, param_src, param.ty, .param_ty)) {
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(block, param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{
|
||||
param.ty.fmt(sema.mod), @tagName(cc),
|
||||
@ -8177,7 +8197,7 @@ fn zirParam(
|
||||
}
|
||||
};
|
||||
const is_comptime = comptime_syntax or
|
||||
try sema.typeRequiresComptime(block, src, param_ty);
|
||||
try sema.typeRequiresComptime(param_ty);
|
||||
if (sema.inst_map.get(inst)) |arg| {
|
||||
if (is_comptime) {
|
||||
// We have a comptime value for this parameter so it should be elided from the
|
||||
@ -8237,7 +8257,7 @@ fn zirParamAnytype(
|
||||
|
||||
if (sema.inst_map.get(inst)) |air_ref| {
|
||||
const param_ty = sema.typeOf(air_ref);
|
||||
if (comptime_syntax or try sema.typeRequiresComptime(block, src, param_ty)) {
|
||||
if (comptime_syntax or try sema.typeRequiresComptime(param_ty)) {
|
||||
// We have a comptime value for this parameter so it should be elided from the
|
||||
// function type of the function instruction in this block.
|
||||
return;
|
||||
@ -10379,7 +10399,9 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
|
||||
}
|
||||
}
|
||||
unreachable;
|
||||
} else unreachable;
|
||||
} else {
|
||||
return sema.fail(block, operand_src, "no package named '{s}' available", .{operand});
|
||||
};
|
||||
return sema.fail(block, operand_src, "no package named '{s}' available within package '{s}'", .{ operand, parent });
|
||||
},
|
||||
else => {
|
||||
@ -15563,7 +15585,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
||||
} else if (inst_data.size == .Many and elem_ty.zigTypeTag() == .Opaque) {
|
||||
return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{});
|
||||
} else if (inst_data.size == .C) {
|
||||
if (!sema.validateExternType(elem_ty, .other)) {
|
||||
if (!try sema.validateExternType(block, elem_ty_src, elem_ty, .other)) {
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(block, elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)});
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
@ -16661,7 +16683,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
|
||||
} else if (ptr_size == .Many and elem_ty.zigTypeTag() == .Opaque) {
|
||||
return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{});
|
||||
} else if (ptr_size == .C) {
|
||||
if (!sema.validateExternType(elem_ty, .other)) {
|
||||
if (!try sema.validateExternType(block, src, elem_ty, .other)) {
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(block, src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)});
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
@ -17499,7 +17521,7 @@ fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
|
||||
|
||||
if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
|
||||
const target = sema.mod.getTarget();
|
||||
const result_val = try val.intToFloat(sema.arena, operand_ty, dest_ty, target);
|
||||
const result_val = try val.intToFloatAdvanced(sema.arena, operand_ty, dest_ty, target, sema.kit(block, operand_src));
|
||||
return sema.addConstant(dest_ty, result_val);
|
||||
} else if (dest_ty.zigTypeTag() == .ComptimeFloat) {
|
||||
return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_float' must be comptime known");
|
||||
@ -20343,12 +20365,13 @@ fn validateRunTimeType(
|
||||
.Int,
|
||||
.Float,
|
||||
.ErrorSet,
|
||||
.Enum,
|
||||
.Frame,
|
||||
.AnyFrame,
|
||||
.Void,
|
||||
=> return true,
|
||||
|
||||
.Enum => return !(try sema.typeRequiresComptime(ty)),
|
||||
|
||||
.BoundFn,
|
||||
.ComptimeFloat,
|
||||
.ComptimeInt,
|
||||
@ -20381,7 +20404,7 @@ fn validateRunTimeType(
|
||||
|
||||
.Struct, .Union => {
|
||||
const resolved_ty = try sema.resolveTypeFields(block, src, ty);
|
||||
const needs_comptime = try sema.typeRequiresComptime(block, src, resolved_ty);
|
||||
const needs_comptime = try sema.typeRequiresComptime(resolved_ty);
|
||||
return !needs_comptime;
|
||||
},
|
||||
};
|
||||
@ -20489,7 +20512,7 @@ fn explainWhyTypeIsComptimeInner(
|
||||
.range = .type,
|
||||
});
|
||||
|
||||
if (try sema.typeRequiresComptime(block, src, field.ty)) {
|
||||
if (try sema.typeRequiresComptime(field.ty)) {
|
||||
try mod.errNoteNonLazy(field_src_loc, msg, "struct requires comptime because of this field", .{});
|
||||
try sema.explainWhyTypeIsComptimeInner(block, src, msg, field_src_loc, field.ty, type_set);
|
||||
}
|
||||
@ -20509,7 +20532,7 @@ fn explainWhyTypeIsComptimeInner(
|
||||
.range = .type,
|
||||
});
|
||||
|
||||
if (try sema.typeRequiresComptime(block, src, field.ty)) {
|
||||
if (try sema.typeRequiresComptime(field.ty)) {
|
||||
try mod.errNoteNonLazy(field_src_loc, msg, "union requires comptime because of this field", .{});
|
||||
try sema.explainWhyTypeIsComptimeInner(block, src, msg, field_src_loc, field.ty, type_set);
|
||||
}
|
||||
@ -20528,7 +20551,14 @@ const ExternPosition = enum {
|
||||
|
||||
/// Returns true if `ty` is allowed in extern types.
|
||||
/// Does *NOT* require `ty` to be resolved in any way.
|
||||
fn validateExternType(sema: *Sema, ty: Type, position: ExternPosition) bool {
|
||||
/// Calls `resolveTypeLayout` for packed containers.
|
||||
fn validateExternType(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
src: LazySrcLoc,
|
||||
ty: Type,
|
||||
position: ExternPosition,
|
||||
) !bool {
|
||||
switch (ty.zigTypeTag()) {
|
||||
.Type,
|
||||
.ComptimeFloat,
|
||||
@ -20556,17 +20586,25 @@ fn validateExternType(sema: *Sema, ty: Type, position: ExternPosition) bool {
|
||||
.Fn => return !Type.fnCallingConventionAllowsZigTypes(ty.fnCallingConvention()),
|
||||
.Enum => {
|
||||
var buf: Type.Payload.Bits = undefined;
|
||||
return sema.validateExternType(ty.intTagType(&buf), position);
|
||||
return sema.validateExternType(block, src, ty.intTagType(&buf), position);
|
||||
},
|
||||
.Struct, .Union => switch (ty.containerLayout()) {
|
||||
.Extern, .Packed => return true,
|
||||
else => return false,
|
||||
.Extern => return true,
|
||||
.Packed => {
|
||||
const target = sema.mod.getTarget();
|
||||
const bit_size = try ty.bitSizeAdvanced(target, sema.kit(block, src));
|
||||
switch (bit_size) {
|
||||
8, 16, 32, 64, 128 => return true,
|
||||
else => return false,
|
||||
}
|
||||
},
|
||||
.Auto => return false,
|
||||
},
|
||||
.Array => {
|
||||
if (position == .ret_ty or position == .param_ty) return false;
|
||||
return sema.validateExternType(ty.elemType2(), .other);
|
||||
return sema.validateExternType(block, src, ty.elemType2(), .other);
|
||||
},
|
||||
.Vector => return sema.validateExternType(ty.elemType2(), .other),
|
||||
.Vector => return sema.validateExternType(block, src, ty.elemType2(), .other),
|
||||
.Optional => return ty.isPtrLikeOptional(),
|
||||
}
|
||||
}
|
||||
@ -20618,8 +20656,8 @@ fn explainWhyTypeIsNotExtern(
|
||||
try mod.errNoteNonLazy(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(sema.mod)});
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position);
|
||||
},
|
||||
.Struct => try mod.errNoteNonLazy(src_loc, msg, "only structs with packed or extern layout are extern compatible", .{}),
|
||||
.Union => try mod.errNoteNonLazy(src_loc, msg, "only unions with packed or extern layout are extern compatible", .{}),
|
||||
.Struct => try mod.errNoteNonLazy(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}),
|
||||
.Union => try mod.errNoteNonLazy(src_loc, msg, "only extern unions and ABI sized packed unions are extern compatible", .{}),
|
||||
.Array => {
|
||||
if (position == .ret_ty) {
|
||||
return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a return type", .{});
|
||||
@ -22998,7 +23036,7 @@ fn coerceExtra(
|
||||
}
|
||||
break :int;
|
||||
};
|
||||
const result_val = try val.intToFloat(sema.arena, inst_ty, dest_ty, target);
|
||||
const result_val = try val.intToFloatAdvanced(sema.arena, inst_ty, dest_ty, target, sema.kit(block, inst_src));
|
||||
// TODO implement this compile error
|
||||
//const int_again_val = try result_val.floatToInt(sema.arena, inst_ty);
|
||||
//if (!int_again_val.eql(val, inst_ty, mod)) {
|
||||
@ -23422,8 +23460,11 @@ const InMemoryCoercionResult = union(enum) {
|
||||
var index: u6 = 0;
|
||||
var actual_noalias = false;
|
||||
while (true) : (index += 1) {
|
||||
if (param.actual << index != param.wanted << index) {
|
||||
actual_noalias = (param.actual << index) == (1 << 31);
|
||||
const actual = @truncate(u1, param.actual >> index);
|
||||
const wanted = @truncate(u1, param.wanted >> index);
|
||||
if (actual != wanted) {
|
||||
actual_noalias = actual == 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!actual_noalias) {
|
||||
@ -23917,7 +23958,7 @@ fn coerceInMemoryAllowedFns(
|
||||
|
||||
if (dest_info.noalias_bits != src_info.noalias_bits) {
|
||||
return InMemoryCoercionResult{ .fn_param_noalias = .{
|
||||
.actual = dest_info.noalias_bits,
|
||||
.actual = src_info.noalias_bits,
|
||||
.wanted = dest_info.noalias_bits,
|
||||
} };
|
||||
}
|
||||
@ -24075,16 +24116,40 @@ fn coerceVarArgParam(
|
||||
inst: Air.Inst.Ref,
|
||||
inst_src: LazySrcLoc,
|
||||
) !Air.Inst.Ref {
|
||||
const inst_ty = sema.typeOf(inst);
|
||||
if (block.is_typeof) return inst;
|
||||
|
||||
switch (inst_ty.zigTypeTag()) {
|
||||
const coerced = switch (sema.typeOf(inst).zigTypeTag()) {
|
||||
// TODO consider casting to c_int/f64 if they fit
|
||||
.ComptimeInt, .ComptimeFloat => return sema.fail(block, inst_src, "integer and float literals in var args function must be casted", .{}),
|
||||
else => {},
|
||||
.ComptimeInt, .ComptimeFloat => return sema.fail(
|
||||
block,
|
||||
inst_src,
|
||||
"integer and float literals passed variadic function must be casted to a fixed-size number type",
|
||||
.{},
|
||||
),
|
||||
.Fn => blk: {
|
||||
const fn_val = try sema.resolveConstValue(block, .unneeded, inst, undefined);
|
||||
const fn_decl = fn_val.pointerDecl().?;
|
||||
break :blk try sema.analyzeDeclRef(fn_decl);
|
||||
},
|
||||
.Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}),
|
||||
else => inst,
|
||||
};
|
||||
|
||||
const coerced_ty = sema.typeOf(coerced);
|
||||
if (!try sema.validateExternType(block, inst_src, coerced_ty, .other)) {
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(block, inst_src, "cannot pass '{}' to variadic function", .{coerced_ty.fmt(sema.mod)});
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
|
||||
const src_decl = sema.mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, inst_src.toSrcLoc(src_decl), coerced_ty, .other);
|
||||
|
||||
try sema.addDeclaredHereNote(msg, coerced_ty);
|
||||
break :msg msg;
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(msg);
|
||||
}
|
||||
// TODO implement more of this function.
|
||||
return inst;
|
||||
return coerced;
|
||||
}
|
||||
|
||||
// TODO migrate callsites to use storePtr2 instead.
|
||||
@ -27579,7 +27644,7 @@ pub fn resolveTypeLayout(
|
||||
// In case of querying the ABI alignment of this optional, we will ask
|
||||
// for hasRuntimeBits() of the payload type, so we need "requires comptime"
|
||||
// to be known already before this function returns.
|
||||
_ = try sema.typeRequiresComptime(block, src, payload_ty);
|
||||
_ = try sema.typeRequiresComptime(payload_ty);
|
||||
return sema.resolveTypeLayout(block, src, payload_ty);
|
||||
},
|
||||
.ErrorUnion => {
|
||||
@ -27634,7 +27699,7 @@ fn resolveStructLayout(
|
||||
// for hasRuntimeBits() of each field, so we need "requires comptime"
|
||||
// to be known already before this function returns.
|
||||
for (struct_obj.fields.values()) |field, i| {
|
||||
_ = sema.typeRequiresComptime(block, src, field.ty) catch |err| switch (err) {
|
||||
_ = sema.typeRequiresComptime(field.ty) catch |err| switch (err) {
|
||||
error.AnalysisFail => {
|
||||
const msg = sema.err orelse return err;
|
||||
try sema.addFieldErrNote(block, ty, i, msg, "while checking this field", .{});
|
||||
@ -27866,7 +27931,7 @@ fn resolveStructFully(
|
||||
}
|
||||
|
||||
// And let's not forget comptime-only status.
|
||||
_ = try sema.typeRequiresComptime(block, src, ty);
|
||||
_ = try sema.typeRequiresComptime(ty);
|
||||
}
|
||||
|
||||
fn resolveUnionFully(
|
||||
@ -27899,7 +27964,7 @@ fn resolveUnionFully(
|
||||
}
|
||||
|
||||
// And let's not forget comptime-only status.
|
||||
_ = try sema.typeRequiresComptime(block, src, ty);
|
||||
_ = try sema.typeRequiresComptime(ty);
|
||||
}
|
||||
|
||||
pub fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type {
|
||||
@ -28273,7 +28338,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(msg);
|
||||
}
|
||||
if (struct_obj.layout == .Extern and !sema.validateExternType(field.ty, .other)) {
|
||||
if (struct_obj.layout == .Extern and !try sema.validateExternType(&block_scope, src, field.ty, .other)) {
|
||||
const msg = msg: {
|
||||
const tree = try sema.getAstTree(&block_scope);
|
||||
const fields_src = enumFieldSrcLoc(decl, tree.*, 0, i);
|
||||
@ -28610,7 +28675,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(msg);
|
||||
}
|
||||
if (union_obj.layout == .Extern and !sema.validateExternType(field_ty, .union_field)) {
|
||||
if (union_obj.layout == .Extern and !try sema.validateExternType(&block_scope, src, field_ty, .union_field)) {
|
||||
const msg = msg: {
|
||||
const tree = try sema.getAstTree(&block_scope);
|
||||
const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i);
|
||||
@ -29002,7 +29067,7 @@ pub fn typeHasOnePossibleValue(
|
||||
},
|
||||
.enum_nonexhaustive => {
|
||||
const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;
|
||||
if (!(try sema.typeHasRuntimeBits(block, src, tag_ty))) {
|
||||
if (tag_ty.zigTypeTag() != .ComptimeInt and !(try sema.typeHasRuntimeBits(block, src, tag_ty))) {
|
||||
return Value.zero;
|
||||
} else {
|
||||
return null;
|
||||
@ -29534,7 +29599,7 @@ fn typePtrOrOptionalPtrTy(
|
||||
/// TODO assert the return value matches `ty.comptimeOnly`
|
||||
/// TODO merge these implementations together with the "advanced"/sema_kit pattern seen
|
||||
/// elsewhere in value.zig
|
||||
pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
|
||||
pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
|
||||
return switch (ty.tag()) {
|
||||
.u1,
|
||||
.u8,
|
||||
@ -29625,7 +29690,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
|
||||
.array,
|
||||
.array_sentinel,
|
||||
.vector,
|
||||
=> return sema.typeRequiresComptime(block, src, ty.childType()),
|
||||
=> return sema.typeRequiresComptime(ty.childType()),
|
||||
|
||||
.pointer,
|
||||
.single_const_pointer,
|
||||
@ -29641,7 +29706,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
|
||||
if (child_ty.zigTypeTag() == .Fn) {
|
||||
return child_ty.fnInfo().is_generic;
|
||||
} else {
|
||||
return sema.typeRequiresComptime(block, src, child_ty);
|
||||
return sema.typeRequiresComptime(child_ty);
|
||||
}
|
||||
},
|
||||
|
||||
@ -29650,14 +29715,14 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
|
||||
.optional_single_const_pointer,
|
||||
=> {
|
||||
var buf: Type.Payload.ElemType = undefined;
|
||||
return sema.typeRequiresComptime(block, src, ty.optionalChild(&buf));
|
||||
return sema.typeRequiresComptime(ty.optionalChild(&buf));
|
||||
},
|
||||
|
||||
.tuple, .anon_struct => {
|
||||
const tuple = ty.tupleFields();
|
||||
for (tuple.types) |field_ty, i| {
|
||||
const have_comptime_val = tuple.values[i].tag() != .unreachable_value;
|
||||
if (!have_comptime_val and try sema.typeRequiresComptime(block, src, field_ty)) {
|
||||
if (!have_comptime_val and try sema.typeRequiresComptime(field_ty)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -29678,7 +29743,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
|
||||
struct_obj.requires_comptime = .wip;
|
||||
for (struct_obj.fields.values()) |field| {
|
||||
if (field.is_comptime) continue;
|
||||
if (try sema.typeRequiresComptime(block, src, field.ty)) {
|
||||
if (try sema.typeRequiresComptime(field.ty)) {
|
||||
struct_obj.requires_comptime = .yes;
|
||||
return true;
|
||||
}
|
||||
@ -29702,7 +29767,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
|
||||
|
||||
union_obj.requires_comptime = .wip;
|
||||
for (union_obj.fields.values()) |field| {
|
||||
if (try sema.typeRequiresComptime(block, src, field.ty)) {
|
||||
if (try sema.typeRequiresComptime(field.ty)) {
|
||||
union_obj.requires_comptime = .yes;
|
||||
return true;
|
||||
}
|
||||
@ -29713,18 +29778,18 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
|
||||
}
|
||||
},
|
||||
|
||||
.error_union => return sema.typeRequiresComptime(block, src, ty.errorUnionPayload()),
|
||||
.error_union => return sema.typeRequiresComptime(ty.errorUnionPayload()),
|
||||
.anyframe_T => {
|
||||
const child_ty = ty.castTag(.anyframe_T).?.data;
|
||||
return sema.typeRequiresComptime(block, src, child_ty);
|
||||
return sema.typeRequiresComptime(child_ty);
|
||||
},
|
||||
.enum_numbered => {
|
||||
const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty;
|
||||
return sema.typeRequiresComptime(block, src, tag_ty);
|
||||
return sema.typeRequiresComptime(tag_ty);
|
||||
},
|
||||
.enum_full, .enum_nonexhaustive => {
|
||||
const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty;
|
||||
return sema.typeRequiresComptime(block, src, tag_ty);
|
||||
return sema.typeRequiresComptime(tag_ty);
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -29762,7 +29827,7 @@ fn unionFieldAlignment(
|
||||
}
|
||||
|
||||
/// Synchronize logic with `Type.isFnOrHasRuntimeBits`.
|
||||
pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
|
||||
pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
|
||||
const fn_info = ty.fnInfo();
|
||||
if (fn_info.is_generic) return false;
|
||||
if (fn_info.is_var_args) return true;
|
||||
@ -29771,7 +29836,7 @@ pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) C
|
||||
.Inline => return false,
|
||||
else => {},
|
||||
}
|
||||
if (try sema.typeRequiresComptime(block, src, fn_info.return_type)) {
|
||||
if (try sema.typeRequiresComptime(fn_info.return_type)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@ -3,6 +3,69 @@ const builtin = @import("builtin");
|
||||
const bits = @import("bits.zig");
|
||||
const Register = bits.Register;
|
||||
const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
|
||||
const Type = @import("../../type.zig").Type;
|
||||
|
||||
pub const Class = enum { memory, integer, none, float_array };
|
||||
|
||||
pub fn classifyType(ty: Type, target: std.Target) [2]Class {
|
||||
if (!ty.hasRuntimeBitsIgnoreComptime()) return .{ .none, .none };
|
||||
switch (ty.zigTypeTag()) {
|
||||
.Struct => {
|
||||
if (ty.containerLayout() == .Packed) return .{ .integer, .none };
|
||||
|
||||
if (ty.structFieldCount() <= 4) {
|
||||
const fields = ty.structFields();
|
||||
var float_size: ?u64 = null;
|
||||
for (fields.values()) |field| {
|
||||
if (field.ty.zigTypeTag() != .Float) break;
|
||||
const field_size = field.ty.bitSize(target);
|
||||
const prev_size = float_size orelse {
|
||||
float_size = field_size;
|
||||
continue;
|
||||
};
|
||||
if (field_size != prev_size) break;
|
||||
} else {
|
||||
return .{ .float_array, .none };
|
||||
}
|
||||
}
|
||||
const bit_size = ty.bitSize(target);
|
||||
if (bit_size > 128) return .{ .memory, .none };
|
||||
if (bit_size > 64) return .{ .integer, .integer };
|
||||
return .{ .integer, .none };
|
||||
},
|
||||
.Union => {
|
||||
const bit_size = ty.bitSize(target);
|
||||
if (bit_size > 128) return .{ .memory, .none };
|
||||
if (bit_size > 64) return .{ .integer, .integer };
|
||||
return .{ .integer, .none };
|
||||
},
|
||||
.Int, .Enum, .ErrorSet, .Vector, .Float, .Bool => return .{ .integer, .none },
|
||||
.Array => return .{ .memory, .none },
|
||||
.Optional => {
|
||||
std.debug.assert(ty.isPtrLikeOptional());
|
||||
return .{ .integer, .none };
|
||||
},
|
||||
.Pointer => {
|
||||
std.debug.assert(!ty.isSlice());
|
||||
return .{ .integer, .none };
|
||||
},
|
||||
.ErrorUnion,
|
||||
.Frame,
|
||||
.AnyFrame,
|
||||
.NoReturn,
|
||||
.Void,
|
||||
.Type,
|
||||
.ComptimeFloat,
|
||||
.ComptimeInt,
|
||||
.Undefined,
|
||||
.Null,
|
||||
.BoundFn,
|
||||
.Fn,
|
||||
.Opaque,
|
||||
.EnumLiteral,
|
||||
=> unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
const callee_preserved_regs_impl = if (builtin.os.tag.isDarwin()) struct {
|
||||
pub const callee_preserved_regs = [_]Register{
|
||||
|
||||
@ -2394,9 +2394,7 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
|
||||
const decl_index = decl_ref_mut.data.decl_index;
|
||||
return self.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl_index);
|
||||
}
|
||||
|
||||
const target = self.target;
|
||||
|
||||
switch (ty.zigTypeTag()) {
|
||||
.Void => return WValue{ .none = {} },
|
||||
.Int => {
|
||||
|
||||
@ -23,6 +23,10 @@ pub fn classifyType(ty: Type, target: Target) [2]Class {
|
||||
if (!ty.hasRuntimeBitsIgnoreComptime()) return none;
|
||||
switch (ty.zigTypeTag()) {
|
||||
.Struct => {
|
||||
if (ty.containerLayout() == .Packed) {
|
||||
if (ty.bitSize(target) <= 64) return direct;
|
||||
return .{ .direct, .direct };
|
||||
}
|
||||
// When the struct type is non-scalar
|
||||
if (ty.structFieldCount() > 1) return memory;
|
||||
// When the struct's alignment is non-natural
|
||||
@ -57,6 +61,10 @@ pub fn classifyType(ty: Type, target: Target) [2]Class {
|
||||
return direct;
|
||||
},
|
||||
.Union => {
|
||||
if (ty.containerLayout() == .Packed) {
|
||||
if (ty.bitSize(target) <= 64) return direct;
|
||||
return .{ .direct, .direct };
|
||||
}
|
||||
const layout = ty.unionGetLayout(target);
|
||||
std.debug.assert(layout.tag_size == 0);
|
||||
if (ty.unionFields().count() > 1) return memory;
|
||||
|
||||
@ -5,7 +5,7 @@ const assert = std.debug.assert;
|
||||
const Register = @import("bits.zig").Register;
|
||||
const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
|
||||
|
||||
pub const Class = enum { integer, sse, sseup, x87, x87up, complex_x87, memory, none };
|
||||
pub const Class = enum { integer, sse, sseup, x87, x87up, complex_x87, memory, none, win_i128 };
|
||||
|
||||
pub fn classifyWindows(ty: Type, target: Target) Class {
|
||||
// https://docs.microsoft.com/en-gb/cpp/build/x64-calling-convention?view=vs-2017
|
||||
@ -34,7 +34,15 @@ pub fn classifyWindows(ty: Type, target: Target) Class {
|
||||
=> switch (ty.abiSize(target)) {
|
||||
0 => unreachable,
|
||||
1, 2, 4, 8 => return .integer,
|
||||
else => return .memory,
|
||||
else => switch (ty.zigTypeTag()) {
|
||||
.Int => return .win_i128,
|
||||
.Struct, .Union => if (ty.containerLayout() == .Packed) {
|
||||
return .win_i128;
|
||||
} else {
|
||||
return .memory;
|
||||
},
|
||||
else => return .memory,
|
||||
},
|
||||
},
|
||||
|
||||
.Float, .Vector => return .sse,
|
||||
@ -174,6 +182,12 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {
|
||||
// "If the size of the aggregate exceeds a single eightbyte, each is classified
|
||||
// separately.".
|
||||
const ty_size = ty.abiSize(target);
|
||||
if (ty.containerLayout() == .Packed) {
|
||||
assert(ty_size <= 128);
|
||||
result[0] = .integer;
|
||||
if (ty_size > 64) result[1] = .integer;
|
||||
return result;
|
||||
}
|
||||
if (ty_size > 64)
|
||||
return memory_class;
|
||||
|
||||
@ -284,6 +298,12 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {
|
||||
// "If the size of the aggregate exceeds a single eightbyte, each is classified
|
||||
// separately.".
|
||||
const ty_size = ty.abiSize(target);
|
||||
if (ty.containerLayout() == .Packed) {
|
||||
assert(ty_size <= 128);
|
||||
result[0] = .integer;
|
||||
if (ty_size > 64) result[1] = .integer;
|
||||
return result;
|
||||
}
|
||||
if (ty_size > 64)
|
||||
return memory_class;
|
||||
|
||||
|
||||
@ -79,6 +79,16 @@ pub fn genHtml(
|
||||
\\ text-align: right;
|
||||
\\ color: #999;
|
||||
\\ }
|
||||
\\
|
||||
\\ .line {
|
||||
\\ width: 100%;
|
||||
\\ display: inline-block;
|
||||
\\ }
|
||||
\\ .line:target {
|
||||
\\ border-top: 1px solid #ccc;
|
||||
\\ border-bottom: 1px solid #ccc;
|
||||
\\ background: #fafafa;
|
||||
\\ }
|
||||
\\
|
||||
\\ @media (prefers-color-scheme: dark) {
|
||||
\\ body{
|
||||
@ -90,6 +100,11 @@ pub fn genHtml(
|
||||
\\ background: #222;
|
||||
\\ border: unset;
|
||||
\\ }
|
||||
\\ .line:target {
|
||||
\\ border-top: 1px solid #444;
|
||||
\\ border-bottom: 1px solid #444;
|
||||
\\ background: #333;
|
||||
\\ }
|
||||
\\ .tok-kw {
|
||||
\\ color: #eee;
|
||||
\\ }
|
||||
|
||||
@ -23,6 +23,7 @@ const LazySrcLoc = Module.LazySrcLoc;
|
||||
const CType = @import("../type.zig").CType;
|
||||
const x86_64_abi = @import("../arch/x86_64/abi.zig");
|
||||
const wasm_c_abi = @import("../arch/wasm/abi.zig");
|
||||
const aarch64_c_abi = @import("../arch/aarch64/abi.zig");
|
||||
|
||||
const Error = error{ OutOfMemory, CodegenFail };
|
||||
|
||||
@ -314,6 +315,15 @@ pub fn supportsTailCall(target: std.Target) bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO can this be done with simpler logic / different API binding?
|
||||
fn deleteLlvmGlobal(llvm_global: *const llvm.Value) void {
|
||||
if (llvm_global.globalGetValueType().getTypeKind() == .Function) {
|
||||
llvm_global.deleteFunction();
|
||||
return;
|
||||
}
|
||||
return llvm_global.deleteGlobal();
|
||||
}
|
||||
|
||||
pub const Object = struct {
|
||||
gpa: Allocator,
|
||||
module: *Module,
|
||||
@ -667,7 +677,7 @@ pub const Object = struct {
|
||||
|
||||
const new_global_ptr = other_global.constBitCast(llvm_global.typeOf());
|
||||
llvm_global.replaceAllUsesWith(new_global_ptr);
|
||||
object.deleteLlvmGlobal(llvm_global);
|
||||
deleteLlvmGlobal(llvm_global);
|
||||
entry.value_ptr.* = new_global_ptr;
|
||||
}
|
||||
object.extern_collisions.clearRetainingCapacity();
|
||||
@ -693,7 +703,7 @@ pub const Object = struct {
|
||||
const new_global_ptr = llvm_global.constBitCast(other_global.typeOf());
|
||||
other_global.replaceAllUsesWith(new_global_ptr);
|
||||
llvm_global.takeName(other_global);
|
||||
other_global.deleteGlobal();
|
||||
deleteLlvmGlobal(other_global);
|
||||
// Problem: now we need to replace in the decl_map that
|
||||
// the extern decl index points to this new global. However we don't
|
||||
// know the decl index.
|
||||
@ -1084,6 +1094,26 @@ pub const Object = struct {
|
||||
try args.ensureUnusedCapacity(1);
|
||||
args.appendAssumeCapacity(casted);
|
||||
},
|
||||
.float_array => {
|
||||
const param_ty = fn_info.param_types[it.zig_index - 1];
|
||||
const param_llvm_ty = try dg.lowerType(param_ty);
|
||||
const param = llvm_func.getParam(llvm_arg_i);
|
||||
llvm_arg_i += 1;
|
||||
|
||||
const alignment = param_ty.abiAlignment(target);
|
||||
const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty);
|
||||
arg_ptr.setAlignment(alignment);
|
||||
const casted_ptr = builder.buildBitCast(arg_ptr, param.typeOf().pointerType(0), "");
|
||||
_ = builder.buildStore(param, casted_ptr);
|
||||
|
||||
if (isByRef(param_ty)) {
|
||||
try args.append(arg_ptr);
|
||||
} else {
|
||||
const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, "");
|
||||
load_inst.setAlignment(alignment);
|
||||
try args.append(load_inst);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -1191,15 +1221,6 @@ pub const Object = struct {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// TODO can this be done with simpler logic / different API binding?
|
||||
fn deleteLlvmGlobal(o: Object, llvm_global: *const llvm.Value) void {
|
||||
if (o.llvm_module.getNamedFunction(llvm_global.getValueName()) != null) {
|
||||
llvm_global.deleteFunction();
|
||||
return;
|
||||
}
|
||||
return llvm_global.deleteGlobal();
|
||||
}
|
||||
|
||||
pub fn updateDeclExports(
|
||||
self: *Object,
|
||||
module: *Module,
|
||||
@ -1294,7 +1315,7 @@ pub const Object = struct {
|
||||
alias.setAliasee(llvm_global);
|
||||
} else {
|
||||
_ = self.llvm_module.addAlias(
|
||||
llvm_global.typeOf(),
|
||||
llvm_global.globalGetValueType(),
|
||||
0,
|
||||
llvm_global,
|
||||
exp_name_z,
|
||||
@ -2527,6 +2548,7 @@ pub const DeclGen = struct {
|
||||
.multiple_llvm_ints,
|
||||
.multiple_llvm_float,
|
||||
.as_u16,
|
||||
.float_array,
|
||||
=> continue,
|
||||
|
||||
.slice => unreachable, // extern functions do not support slice types.
|
||||
@ -3093,6 +3115,13 @@ pub const DeclGen = struct {
|
||||
.as_u16 => {
|
||||
try llvm_params.append(dg.context.intType(16));
|
||||
},
|
||||
.float_array => {
|
||||
const param_ty = fn_info.param_types[it.zig_index - 1];
|
||||
const float_ty = try dg.lowerType(param_ty.structFieldType(0));
|
||||
const field_count = @intCast(c_uint, param_ty.structFieldCount());
|
||||
const arr_ty = float_ty.arrayType(field_count);
|
||||
try llvm_params.append(arr_ty);
|
||||
},
|
||||
};
|
||||
|
||||
return llvm.functionType(
|
||||
@ -4719,6 +4748,27 @@ pub const FuncGen = struct {
|
||||
const casted = self.builder.buildBitCast(llvm_arg, self.dg.context.intType(16), "");
|
||||
try llvm_args.append(casted);
|
||||
},
|
||||
.float_array => {
|
||||
const arg = args[it.zig_index - 1];
|
||||
const arg_ty = self.air.typeOf(arg);
|
||||
var llvm_arg = try self.resolveInst(arg);
|
||||
if (!isByRef(arg_ty)) {
|
||||
const p = self.buildAlloca(llvm_arg.typeOf());
|
||||
const store_inst = self.builder.buildStore(llvm_arg, p);
|
||||
store_inst.setAlignment(arg_ty.abiAlignment(target));
|
||||
llvm_arg = store_inst;
|
||||
}
|
||||
|
||||
const float_ty = try self.dg.lowerType(arg_ty.structFieldType(0));
|
||||
const field_count = @intCast(u32, arg_ty.structFieldCount());
|
||||
const array_llvm_ty = float_ty.arrayType(field_count);
|
||||
|
||||
const casted = self.builder.buildBitCast(llvm_arg, array_llvm_ty.pointerType(0), "");
|
||||
const alignment = arg_ty.abiAlignment(target);
|
||||
const load_inst = self.builder.buildLoad(array_llvm_ty, casted, "");
|
||||
load_inst.setAlignment(alignment);
|
||||
try llvm_args.append(load_inst);
|
||||
},
|
||||
};
|
||||
|
||||
const call = self.builder.buildCall(
|
||||
@ -9240,7 +9290,7 @@ pub const FuncGen = struct {
|
||||
}
|
||||
},
|
||||
},
|
||||
.Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty, field_index),
|
||||
.Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
@ -9250,19 +9300,16 @@ pub const FuncGen = struct {
|
||||
inst: Air.Inst.Index,
|
||||
union_ptr: *const llvm.Value,
|
||||
union_ty: Type,
|
||||
field_index: c_uint,
|
||||
) !?*const llvm.Value {
|
||||
const union_obj = union_ty.cast(Type.Payload.Union).?.data;
|
||||
const field = &union_obj.fields.values()[field_index];
|
||||
if (!field.ty.hasRuntimeBitsIgnoreComptime()) {
|
||||
return null;
|
||||
}
|
||||
const target = self.dg.module.getTarget();
|
||||
const layout = union_ty.unionGetLayout(target);
|
||||
const result_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
|
||||
if (layout.payload_size == 0) {
|
||||
return self.builder.buildBitCast(union_ptr, result_llvm_ty, "");
|
||||
}
|
||||
const payload_index = @boolToInt(layout.tag_align >= layout.payload_align);
|
||||
const union_llvm_ty = try self.dg.lowerType(union_ty);
|
||||
const union_field_ptr = self.builder.buildStructGEP(union_llvm_ty, union_ptr, payload_index, "");
|
||||
const result_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
|
||||
return self.builder.buildBitCast(union_field_ptr, result_llvm_ty, "");
|
||||
}
|
||||
|
||||
@ -9832,6 +9879,7 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool
|
||||
else => return x86_64_abi.classifySystemV(fn_info.return_type, target)[0] == .memory,
|
||||
},
|
||||
.wasm32 => return wasm_c_abi.classifyType(fn_info.return_type, target)[0] == .indirect,
|
||||
.aarch64, .aarch64_be => return aarch64_c_abi.classifyType(fn_info.return_type, target)[0] == .memory,
|
||||
else => return false, // TODO investigate C ABI for other architectures
|
||||
},
|
||||
else => return false,
|
||||
@ -9862,22 +9910,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.
|
||||
}
|
||||
},
|
||||
.C => {
|
||||
const is_scalar = switch (fn_info.return_type.zigTypeTag()) {
|
||||
.Void,
|
||||
.Bool,
|
||||
.NoReturn,
|
||||
.Int,
|
||||
.Float,
|
||||
.Pointer,
|
||||
.Optional,
|
||||
.ErrorSet,
|
||||
.Enum,
|
||||
.AnyFrame,
|
||||
.Vector,
|
||||
=> true,
|
||||
|
||||
else => false,
|
||||
};
|
||||
const is_scalar = isScalar(fn_info.return_type);
|
||||
switch (target.cpu.arch) {
|
||||
.mips, .mipsel => return dg.lowerType(fn_info.return_type),
|
||||
.x86_64 => switch (target.os.tag) {
|
||||
@ -9890,6 +9923,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.
|
||||
return dg.context.intType(@intCast(c_uint, abi_size * 8));
|
||||
}
|
||||
},
|
||||
.win_i128 => return dg.context.intType(64).vectorType(2),
|
||||
.memory => return dg.context.voidType(),
|
||||
.sse => return dg.lowerType(fn_info.return_type),
|
||||
else => unreachable,
|
||||
@ -9930,6 +9964,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.
|
||||
@panic("TODO");
|
||||
},
|
||||
.memory => unreachable, // handled above
|
||||
.win_i128 => unreachable, // windows only
|
||||
.none => break,
|
||||
}
|
||||
}
|
||||
@ -9954,6 +9989,24 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm.
|
||||
const abi_size = scalar_type.abiSize(target);
|
||||
return dg.context.intType(@intCast(c_uint, abi_size * 8));
|
||||
},
|
||||
.aarch64, .aarch64_be => {
|
||||
if (is_scalar) {
|
||||
return dg.lowerType(fn_info.return_type);
|
||||
}
|
||||
const classes = aarch64_c_abi.classifyType(fn_info.return_type, target);
|
||||
if (classes[0] == .memory or classes[0] == .none) {
|
||||
return dg.context.voidType();
|
||||
}
|
||||
if (classes[0] == .float_array) {
|
||||
return dg.lowerType(fn_info.return_type);
|
||||
}
|
||||
if (classes[1] == .none) {
|
||||
const bit_size = fn_info.return_type.bitSize(target);
|
||||
return dg.context.intType(@intCast(c_uint, bit_size));
|
||||
}
|
||||
|
||||
return dg.context.intType(64).arrayType(2);
|
||||
},
|
||||
// TODO investigate C ABI for other architectures
|
||||
else => return dg.lowerType(fn_info.return_type),
|
||||
}
|
||||
@ -9981,6 +10034,7 @@ const ParamTypeIterator = struct {
|
||||
multiple_llvm_float,
|
||||
slice,
|
||||
as_u16,
|
||||
float_array,
|
||||
};
|
||||
|
||||
pub fn next(it: *ParamTypeIterator) ?Lowering {
|
||||
@ -10025,22 +10079,7 @@ const ParamTypeIterator = struct {
|
||||
@panic("TODO implement async function lowering in the LLVM backend");
|
||||
},
|
||||
.C => {
|
||||
const is_scalar = switch (ty.zigTypeTag()) {
|
||||
.Void,
|
||||
.Bool,
|
||||
.NoReturn,
|
||||
.Int,
|
||||
.Float,
|
||||
.Pointer,
|
||||
.Optional,
|
||||
.ErrorSet,
|
||||
.Enum,
|
||||
.AnyFrame,
|
||||
.Vector,
|
||||
=> true,
|
||||
|
||||
else => false,
|
||||
};
|
||||
const is_scalar = isScalar(ty);
|
||||
switch (it.target.cpu.arch) {
|
||||
.riscv32, .riscv64 => {
|
||||
it.zig_index += 1;
|
||||
@ -10069,6 +10108,11 @@ const ParamTypeIterator = struct {
|
||||
return .abi_sized_int;
|
||||
}
|
||||
},
|
||||
.win_i128 => {
|
||||
it.zig_index += 1;
|
||||
it.llvm_index += 1;
|
||||
return .byref;
|
||||
},
|
||||
.memory => {
|
||||
it.zig_index += 1;
|
||||
it.llvm_index += 1;
|
||||
@ -10123,6 +10167,7 @@ const ParamTypeIterator = struct {
|
||||
@panic("TODO");
|
||||
},
|
||||
.memory => unreachable, // handled above
|
||||
.win_i128 => unreachable, // windows only
|
||||
.none => break,
|
||||
}
|
||||
}
|
||||
@ -10155,6 +10200,28 @@ const ParamTypeIterator = struct {
|
||||
}
|
||||
return .abi_sized_int;
|
||||
},
|
||||
.aarch64, .aarch64_be => {
|
||||
it.zig_index += 1;
|
||||
it.llvm_index += 1;
|
||||
if (is_scalar) {
|
||||
return .byval;
|
||||
}
|
||||
const classes = aarch64_c_abi.classifyType(ty, it.target);
|
||||
if (classes[0] == .memory) {
|
||||
return .byref;
|
||||
}
|
||||
if (classes[0] == .float_array) {
|
||||
return .float_array;
|
||||
}
|
||||
if (classes[1] == .none) {
|
||||
it.llvm_types_len = 1;
|
||||
} else {
|
||||
it.llvm_types_len = 2;
|
||||
}
|
||||
it.llvm_types_buffer[0] = 64;
|
||||
it.llvm_types_buffer[1] = 64;
|
||||
return .multiple_llvm_ints;
|
||||
},
|
||||
// TODO investigate C ABI for other architectures
|
||||
else => {
|
||||
it.zig_index += 1;
|
||||
@ -10294,6 +10361,27 @@ fn isByRef(ty: Type) bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn isScalar(ty: Type) bool {
|
||||
return switch (ty.zigTypeTag()) {
|
||||
.Void,
|
||||
.Bool,
|
||||
.NoReturn,
|
||||
.Int,
|
||||
.Float,
|
||||
.Pointer,
|
||||
.Optional,
|
||||
.ErrorSet,
|
||||
.Enum,
|
||||
.AnyFrame,
|
||||
.Vector,
|
||||
=> true,
|
||||
|
||||
.Struct => ty.containerLayout() == .Packed,
|
||||
.Union => ty.containerLayout() == .Packed,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
/// This function returns true if we expect LLVM to lower x86_fp80 correctly
|
||||
/// and false if we expect LLVM to crash if it counters an x86_fp80 type.
|
||||
fn backendSupportsF80(target: std.Target) bool {
|
||||
|
||||
@ -50,6 +50,7 @@ text_section_index: ?u16 = null,
|
||||
got_section_index: ?u16 = null,
|
||||
rdata_section_index: ?u16 = null,
|
||||
data_section_index: ?u16 = null,
|
||||
reloc_section_index: ?u16 = null,
|
||||
|
||||
locals: std.ArrayListUnmanaged(coff.Symbol) = .{},
|
||||
globals: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{},
|
||||
@ -98,11 +99,16 @@ atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{},
|
||||
/// with `Decl` `main`, and lives as long as that `Decl`.
|
||||
unnamed_const_atoms: UnnamedConstTable = .{},
|
||||
|
||||
/// A table of relocations indexed by the owning them `TextBlock`.
|
||||
/// Note that once we refactor `TextBlock`'s lifetime and ownership rules,
|
||||
/// A table of relocations indexed by the owning them `Atom`.
|
||||
/// Note that once we refactor `Atom`'s lifetime and ownership rules,
|
||||
/// this will be a table indexed by index into the list of Atoms.
|
||||
relocs: RelocTable = .{},
|
||||
|
||||
/// A table of base relocations indexed by the owning them `Atom`.
|
||||
/// Note that once we refactor `Atom`'s lifetime and ownership rules,
|
||||
/// this will be a table indexed by index into the list of Atoms.
|
||||
base_relocs: BaseRelocationTable = .{},
|
||||
|
||||
pub const Reloc = struct {
|
||||
@"type": enum {
|
||||
got,
|
||||
@ -117,6 +123,7 @@ pub const Reloc = struct {
|
||||
};
|
||||
|
||||
const RelocTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Reloc));
|
||||
const BaseRelocationTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(u32));
|
||||
const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom));
|
||||
|
||||
const default_file_alignment: u16 = 0x200;
|
||||
@ -150,7 +157,17 @@ const Section = struct {
|
||||
free_list: std.ArrayListUnmanaged(*Atom) = .{},
|
||||
};
|
||||
|
||||
pub const PtrWidth = enum { p32, p64 };
|
||||
pub const PtrWidth = enum {
|
||||
p32,
|
||||
p64,
|
||||
|
||||
fn abiSize(pw: PtrWidth) u4 {
|
||||
return switch (pw) {
|
||||
.p32 => 4,
|
||||
.p64 => 8,
|
||||
};
|
||||
}
|
||||
};
|
||||
pub const SrcFn = void;
|
||||
|
||||
pub const Export = struct {
|
||||
@ -274,6 +291,14 @@ pub fn deinit(self: *Coff) void {
|
||||
}
|
||||
self.relocs.deinit(gpa);
|
||||
}
|
||||
|
||||
{
|
||||
var it = self.base_relocs.valueIterator();
|
||||
while (it.next()) |relocs| {
|
||||
relocs.deinit(gpa);
|
||||
}
|
||||
self.base_relocs.deinit(gpa);
|
||||
}
|
||||
}
|
||||
|
||||
fn populateMissingMetadata(self: *Coff) !void {
|
||||
@ -307,7 +332,7 @@ fn populateMissingMetadata(self: *Coff) !void {
|
||||
|
||||
if (self.got_section_index == null) {
|
||||
self.got_section_index = @intCast(u16, self.sections.slice().len);
|
||||
const file_size = @intCast(u32, self.base.options.symbol_count_hint);
|
||||
const file_size = @intCast(u32, self.base.options.symbol_count_hint) * self.ptr_width.abiSize();
|
||||
const off = self.findFreeSpace(file_size, self.page_size);
|
||||
log.debug("found .got free space 0x{x} to 0x{x}", .{ off, off + file_size });
|
||||
var header = coff.SectionHeader{
|
||||
@ -378,6 +403,31 @@ fn populateMissingMetadata(self: *Coff) !void {
|
||||
try self.sections.append(gpa, .{ .header = header });
|
||||
}
|
||||
|
||||
if (self.reloc_section_index == null) {
|
||||
self.reloc_section_index = @intCast(u16, self.sections.slice().len);
|
||||
const file_size = @intCast(u32, self.base.options.symbol_count_hint) * @sizeOf(coff.BaseRelocation);
|
||||
const off = self.findFreeSpace(file_size, self.page_size);
|
||||
log.debug("found .reloc free space 0x{x} to 0x{x}", .{ off, off + file_size });
|
||||
var header = coff.SectionHeader{
|
||||
.name = undefined,
|
||||
.virtual_size = file_size,
|
||||
.virtual_address = off,
|
||||
.size_of_raw_data = file_size,
|
||||
.pointer_to_raw_data = off,
|
||||
.pointer_to_relocations = 0,
|
||||
.pointer_to_linenumbers = 0,
|
||||
.number_of_relocations = 0,
|
||||
.number_of_linenumbers = 0,
|
||||
.flags = .{
|
||||
.CNT_INITIALIZED_DATA = 1,
|
||||
.MEM_PURGEABLE = 1,
|
||||
.MEM_READ = 1,
|
||||
},
|
||||
};
|
||||
try self.setSectionName(&header, ".reloc");
|
||||
try self.sections.append(gpa, .{ .header = header });
|
||||
}
|
||||
|
||||
if (self.strtab_offset == null) {
|
||||
try self.strtab.buffer.append(gpa, 0);
|
||||
self.strtab_offset = self.findFreeSpace(@intCast(u32, self.strtab.len()), 1);
|
||||
@ -605,6 +655,14 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {
|
||||
.prev_vaddr = sym.value,
|
||||
});
|
||||
|
||||
const target_sym = self.getSymbol(target);
|
||||
switch (target_sym.section_number) {
|
||||
.UNDEFINED => @panic("TODO generate a binding for undefined GOT target"),
|
||||
.ABSOLUTE => {},
|
||||
.DEBUG => unreachable, // not possible
|
||||
else => try atom.addBaseRelocation(self, 0),
|
||||
}
|
||||
|
||||
return atom;
|
||||
}
|
||||
|
||||
@ -1179,6 +1237,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
|
||||
try self.resolveRelocs(atom.*);
|
||||
}
|
||||
}
|
||||
try self.writeBaseRelocations();
|
||||
|
||||
if (self.getEntryPoint()) |entry_sym_loc| {
|
||||
self.entry_addr = self.getSymbol(entry_sym_loc).value;
|
||||
@ -1216,6 +1275,83 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v
|
||||
log.debug("TODO implement updateDeclLineNumber", .{});
|
||||
}
|
||||
|
||||
/// TODO: note if we need to rewrite base relocations by dirtying any of the entries in the global table
|
||||
/// TODO: note that .ABSOLUTE is used as padding within each block; we could use this fact to do
|
||||
/// incremental updates and writes into the table instead of doing it all at once
|
||||
fn writeBaseRelocations(self: *Coff) !void {
|
||||
const gpa = self.base.allocator;
|
||||
|
||||
var pages = std.AutoHashMap(u32, std.ArrayList(coff.BaseRelocation)).init(gpa);
|
||||
defer {
|
||||
var it = pages.valueIterator();
|
||||
while (it.next()) |inner| {
|
||||
inner.deinit();
|
||||
}
|
||||
pages.deinit();
|
||||
}
|
||||
|
||||
var it = self.base_relocs.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const atom = entry.key_ptr.*;
|
||||
const offsets = entry.value_ptr.*;
|
||||
|
||||
for (offsets.items) |offset| {
|
||||
const sym = atom.getSymbol(self);
|
||||
const rva = sym.value + offset;
|
||||
const page = mem.alignBackwardGeneric(u32, rva, self.page_size);
|
||||
const gop = try pages.getOrPut(page);
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = std.ArrayList(coff.BaseRelocation).init(gpa);
|
||||
}
|
||||
try gop.value_ptr.append(.{
|
||||
.offset = @intCast(u12, rva - page),
|
||||
.@"type" = .DIR64,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var buffer = std.ArrayList(u8).init(gpa);
|
||||
defer buffer.deinit();
|
||||
|
||||
var pages_it = pages.iterator();
|
||||
while (pages_it.next()) |entry| {
|
||||
// Pad to required 4byte alignment
|
||||
if (!mem.isAlignedGeneric(
|
||||
usize,
|
||||
entry.value_ptr.items.len * @sizeOf(coff.BaseRelocation),
|
||||
@sizeOf(u32),
|
||||
)) {
|
||||
try entry.value_ptr.append(.{
|
||||
.offset = 0,
|
||||
.@"type" = .ABSOLUTE,
|
||||
});
|
||||
}
|
||||
|
||||
const block_size = @intCast(
|
||||
u32,
|
||||
entry.value_ptr.items.len * @sizeOf(coff.BaseRelocation) + @sizeOf(coff.BaseRelocationDirectoryEntry),
|
||||
);
|
||||
try buffer.ensureUnusedCapacity(block_size);
|
||||
buffer.appendSliceAssumeCapacity(mem.asBytes(&coff.BaseRelocationDirectoryEntry{
|
||||
.page_rva = entry.key_ptr.*,
|
||||
.block_size = block_size,
|
||||
}));
|
||||
buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(entry.value_ptr.items));
|
||||
}
|
||||
|
||||
const header = &self.sections.items(.header)[self.reloc_section_index.?];
|
||||
const sect_capacity = self.allocatedSize(header.pointer_to_raw_data);
|
||||
const needed_size = @intCast(u32, buffer.items.len);
|
||||
assert(needed_size < sect_capacity); // TODO expand .reloc section
|
||||
|
||||
try self.base.file.?.pwriteAll(buffer.items, header.pointer_to_raw_data);
|
||||
|
||||
self.data_directories[@enumToInt(coff.DirectoryEntry.BASERELOC)] = .{
|
||||
.virtual_address = header.virtual_address,
|
||||
.size = needed_size,
|
||||
};
|
||||
}
|
||||
|
||||
fn writeStrtab(self: *Coff) !void {
|
||||
const allocated_size = self.allocatedSize(self.strtab_offset.?);
|
||||
const needed_size = @intCast(u32, self.strtab.len());
|
||||
@ -1277,8 +1413,8 @@ fn writeHeader(self: *Coff) !void {
|
||||
writer.writeAll(mem.asBytes(&coff_header)) catch unreachable;
|
||||
|
||||
const dll_flags: coff.DllFlags = .{
|
||||
.HIGH_ENTROPY_VA = 0, //@boolToInt(self.base.options.pie),
|
||||
.DYNAMIC_BASE = 0,
|
||||
.HIGH_ENTROPY_VA = 1, // TODO do we want to permit non-PIE builds at all?
|
||||
.DYNAMIC_BASE = 1,
|
||||
.TERMINAL_SERVER_AWARE = 1, // We are not a legacy app
|
||||
.NX_COMPAT = 1, // We are compatible with Data Execution Prevention
|
||||
};
|
||||
|
||||
@ -2,6 +2,7 @@ const Atom = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const coff = std.coff;
|
||||
const log = std.log.scoped(.link);
|
||||
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
@ -100,11 +101,20 @@ pub fn freeListEligible(self: Atom, coff_file: *const Coff) bool {
|
||||
|
||||
pub fn addRelocation(self: *Atom, coff_file: *Coff, reloc: Reloc) !void {
|
||||
const gpa = coff_file.base.allocator;
|
||||
// TODO causes a segfault on Windows
|
||||
// log.debug("adding reloc of type {s} to target %{d}", .{ @tagName(reloc.@"type"), reloc.target.sym_index });
|
||||
log.debug(" (adding reloc of type {s} to target %{d})", .{ @tagName(reloc.@"type"), reloc.target.sym_index });
|
||||
const gop = try coff_file.relocs.getOrPut(gpa, self);
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = .{};
|
||||
}
|
||||
try gop.value_ptr.append(gpa, reloc);
|
||||
}
|
||||
|
||||
pub fn addBaseRelocation(self: *Atom, coff_file: *Coff, offset: u32) !void {
|
||||
const gpa = coff_file.base.allocator;
|
||||
log.debug(" (adding base relocation at offset 0x{x} in %{d})", .{ offset, self.sym_index });
|
||||
const gop = try coff_file.base_relocs.getOrPut(gpa, self);
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = .{};
|
||||
}
|
||||
try gop.value_ptr.append(gpa, offset);
|
||||
}
|
||||
|
||||
@ -607,6 +607,24 @@ fn resolveSymbolsInArchives(self: *Wasm) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn checkUndefinedSymbols(self: *const Wasm) !void {
|
||||
var found_undefined_symbols = false;
|
||||
for (self.undefs.values()) |undef| {
|
||||
const symbol = undef.getSymbol(self);
|
||||
if (symbol.tag == .data) {
|
||||
found_undefined_symbols = true;
|
||||
const file_name = if (undef.file) |file_index| name: {
|
||||
break :name self.objects.items[file_index].name;
|
||||
} else self.name;
|
||||
log.err("could not resolve undefined symbol '{s}'", .{undef.getName(self)});
|
||||
log.err(" defined in '{s}'", .{file_name});
|
||||
}
|
||||
}
|
||||
if (found_undefined_symbols) {
|
||||
return error.UndefinedSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Wasm) void {
|
||||
const gpa = self.base.allocator;
|
||||
if (build_options.have_llvm) {
|
||||
@ -783,15 +801,17 @@ pub fn updateDecl(self: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi
|
||||
|
||||
decl.link.wasm.clear();
|
||||
|
||||
if (decl.isExtern()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (decl.val.castTag(.function)) |_| {
|
||||
return;
|
||||
} else if (decl.val.castTag(.extern_fn)) |_| {
|
||||
return;
|
||||
}
|
||||
|
||||
if (decl.isExtern()) {
|
||||
const variable = decl.getVariable().?;
|
||||
const name = mem.sliceTo(decl.name, 0);
|
||||
return self.addOrUpdateImport(name, decl.link.wasm.sym_index, variable.lib_name, null);
|
||||
}
|
||||
const val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
|
||||
|
||||
var code_writer = std.ArrayList(u8).init(self.base.allocator);
|
||||
@ -834,19 +854,18 @@ pub fn updateDeclLineNumber(self: *Wasm, mod: *Module, decl: *const Module.Decl)
|
||||
}
|
||||
|
||||
fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void {
|
||||
if (code.len == 0) return;
|
||||
const mod = self.base.options.module.?;
|
||||
const atom: *Atom = &decl.link.wasm;
|
||||
atom.size = @intCast(u32, code.len);
|
||||
atom.alignment = decl.ty.abiAlignment(self.base.options.target);
|
||||
const symbol = &self.symbols.items[atom.sym_index];
|
||||
|
||||
const full_name = try decl.getFullyQualifiedName(mod);
|
||||
defer self.base.allocator.free(full_name);
|
||||
symbol.name = try self.string_table.put(self.base.allocator, full_name);
|
||||
try atom.code.appendSlice(self.base.allocator, code);
|
||||
|
||||
try self.resolved_symbols.put(self.base.allocator, atom.symbolLoc(), {});
|
||||
|
||||
if (code.len == 0) return;
|
||||
atom.size = @intCast(u32, code.len);
|
||||
atom.alignment = decl.ty.abiAlignment(self.base.options.target);
|
||||
}
|
||||
|
||||
/// From a given symbol location, returns its `wasm.GlobalType`.
|
||||
@ -1235,7 +1254,10 @@ pub fn addOrUpdateImport(
|
||||
.kind = .{ .function = ty_index },
|
||||
};
|
||||
}
|
||||
} else @panic("TODO: Implement undefined symbols for non-function declarations");
|
||||
} else {
|
||||
symbol.tag = .data;
|
||||
return; // non-functions will not be imported from the runtime, but only resolved during link-time
|
||||
}
|
||||
}
|
||||
|
||||
/// Kind represents the type of an Atom, which is only
|
||||
@ -1438,7 +1460,7 @@ fn setupImports(self: *Wasm) !void {
|
||||
if (std.mem.eql(u8, symbol_loc.getName(self), "__indirect_function_table")) {
|
||||
continue;
|
||||
}
|
||||
if (symbol.tag == .data or !symbol.requiresImport()) {
|
||||
if (!symbol.requiresImport()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -2007,6 +2029,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
|
||||
}
|
||||
|
||||
try self.resolveSymbolsInArchives();
|
||||
try self.checkUndefinedSymbols();
|
||||
|
||||
// When we finish/error we reset the state of the linker
|
||||
// So we can rebuild the binary file on each incremental update
|
||||
|
||||
@ -172,18 +172,16 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa
|
||||
.R_WASM_MEMORY_ADDR_SLEB,
|
||||
.R_WASM_MEMORY_ADDR_SLEB64,
|
||||
=> {
|
||||
if (symbol.isUndefined() and symbol.isWeak()) {
|
||||
return 0;
|
||||
}
|
||||
std.debug.assert(symbol.tag == .data);
|
||||
std.debug.assert(symbol.tag == .data and !symbol.isUndefined());
|
||||
const merge_segment = wasm_bin.base.options.output_mode != .Obj;
|
||||
const segment_info = if (self.file) |object_index| blk: {
|
||||
const target_atom_loc = wasm_bin.discarded.get(target_loc) orelse target_loc;
|
||||
const target_atom = wasm_bin.symbol_atom.get(target_atom_loc).?;
|
||||
const segment_info = if (target_atom.file) |object_index| blk: {
|
||||
break :blk wasm_bin.objects.items[object_index].segment_info;
|
||||
} else wasm_bin.segment_info.items;
|
||||
const segment_name = segment_info[symbol.index].outputName(merge_segment);
|
||||
const atom_index = wasm_bin.data_segments.get(segment_name).?;
|
||||
const target_atom = wasm_bin.symbol_atom.get(target_loc).?;
|
||||
const segment = wasm_bin.segments.items[atom_index];
|
||||
const segment_index = wasm_bin.data_segments.get(segment_name).?;
|
||||
const segment = wasm_bin.segments.items[segment_index];
|
||||
return target_atom.offset + segment.offset + (relocation.addend orelse 0);
|
||||
},
|
||||
.R_WASM_EVENT_INDEX_LEB => return symbol.index,
|
||||
|
||||
@ -79,9 +79,9 @@ pub const Flag = enum(u32) {
|
||||
/// Verifies if the given symbol should be imported from the
|
||||
/// host environment or not
|
||||
pub fn requiresImport(self: Symbol) bool {
|
||||
if (self.tag == .data) return false;
|
||||
if (!self.isUndefined()) return false;
|
||||
if (self.isWeak()) return false;
|
||||
if (self.tag == .data) return false;
|
||||
// if (self.isDefined() and self.isWeak()) return true; //TODO: Only when building shared lib
|
||||
|
||||
return true;
|
||||
|
||||
14
src/main.zig
14
src/main.zig
@ -2750,8 +2750,22 @@ fn buildOutputType(
|
||||
|
||||
// Transfer packages added with --pkg-begin/--pkg-end to the root package
|
||||
if (main_pkg) |pkg| {
|
||||
var it = pkg_tree_root.table.valueIterator();
|
||||
while (it.next()) |p| {
|
||||
if (p.*.parent == &pkg_tree_root) {
|
||||
p.*.parent = pkg;
|
||||
}
|
||||
}
|
||||
pkg.table = pkg_tree_root.table;
|
||||
pkg_tree_root.table = .{};
|
||||
} else {
|
||||
// Remove any dangling pointers just in case.
|
||||
var it = pkg_tree_root.table.valueIterator();
|
||||
while (it.next()) |p| {
|
||||
if (p.*.parent == &pkg_tree_root) {
|
||||
p.*.parent = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const self_exe_path = try introspect.findZigExePath(arena);
|
||||
|
||||
@ -1166,6 +1166,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
|
||||
});
|
||||
}
|
||||
|
||||
if (!c.zig_is_stage1 and is_packed) {
|
||||
return failDecl(c, record_loc, bare_name, "cannot translate packed record union", .{});
|
||||
}
|
||||
|
||||
const record_payload = try c.arena.create(ast.Payload.Record);
|
||||
record_payload.* = .{
|
||||
.base = .{ .tag = ([2]Tag{ .@"struct", .@"union" })[@boolToInt(is_union)] },
|
||||
|
||||
@ -2042,6 +2042,9 @@ pub const Type = extern union {
|
||||
try writer.writeAll("fn(");
|
||||
for (fn_info.param_types) |param_ty, i| {
|
||||
if (i != 0) try writer.writeAll(", ");
|
||||
if (std.math.cast(u5, i)) |index| if (@truncate(u1, fn_info.noalias_bits >> index) != 0) {
|
||||
try writer.writeAll("noalias ");
|
||||
};
|
||||
if (param_ty.tag() == .generic_poison) {
|
||||
try writer.writeAll("anytype");
|
||||
} else {
|
||||
@ -2398,7 +2401,7 @@ pub const Type = extern union {
|
||||
} else if (ty.childType().zigTypeTag() == .Fn) {
|
||||
return !ty.childType().fnInfo().is_generic;
|
||||
} else if (sema_kit) |sk| {
|
||||
return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty));
|
||||
return !(try sk.sema.typeRequiresComptime(ty));
|
||||
} else {
|
||||
return !comptimeOnly(ty);
|
||||
}
|
||||
@ -2437,7 +2440,7 @@ pub const Type = extern union {
|
||||
if (ignore_comptime_only) {
|
||||
return true;
|
||||
} else if (sema_kit) |sk| {
|
||||
return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, child_ty));
|
||||
return !(try sk.sema.typeRequiresComptime(child_ty));
|
||||
} else {
|
||||
return !comptimeOnly(child_ty);
|
||||
}
|
||||
|
||||
@ -2940,17 +2940,24 @@ pub const Value = extern union {
|
||||
}
|
||||
|
||||
pub fn intToFloat(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, target: Target) !Value {
|
||||
return intToFloatAdvanced(val, arena, int_ty, float_ty, target, null) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn intToFloatAdvanced(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, target: Target, sema_kit: ?Module.WipAnalysis) !Value {
|
||||
if (int_ty.zigTypeTag() == .Vector) {
|
||||
const result_data = try arena.alloc(Value, int_ty.vectorLen());
|
||||
for (result_data) |*scalar, i| {
|
||||
scalar.* = try intToFloatScalar(val.indexVectorlike(i), arena, float_ty.scalarType(), target);
|
||||
scalar.* = try intToFloatScalar(val.indexVectorlike(i), arena, float_ty.scalarType(), target, sema_kit);
|
||||
}
|
||||
return Value.Tag.aggregate.create(arena, result_data);
|
||||
}
|
||||
return intToFloatScalar(val, arena, float_ty, target);
|
||||
return intToFloatScalar(val, arena, float_ty, target, sema_kit);
|
||||
}
|
||||
|
||||
pub fn intToFloatScalar(val: Value, arena: Allocator, float_ty: Type, target: Target) !Value {
|
||||
pub fn intToFloatScalar(val: Value, arena: Allocator, float_ty: Type, target: Target, sema_kit: ?Module.WipAnalysis) !Value {
|
||||
switch (val.tag()) {
|
||||
.undef, .zero, .one => return val,
|
||||
.the_only_possible_value => return Value.initTag(.zero), // for i0, u0
|
||||
@ -2970,6 +2977,22 @@ pub const Value = extern union {
|
||||
const float = bigIntToFloat(limbs, false);
|
||||
return floatToValue(float, arena, float_ty, target);
|
||||
},
|
||||
.lazy_align => {
|
||||
const ty = val.castTag(.lazy_align).?.data;
|
||||
if (sema_kit) |sk| {
|
||||
return intToFloatInner((try ty.abiAlignmentAdvanced(target, .{ .sema_kit = sk })).scalar, arena, float_ty, target);
|
||||
} else {
|
||||
return intToFloatInner(ty.abiAlignment(target), arena, float_ty, target);
|
||||
}
|
||||
},
|
||||
.lazy_size => {
|
||||
const ty = val.castTag(.lazy_size).?.data;
|
||||
if (sema_kit) |sk| {
|
||||
return intToFloatInner((try ty.abiSizeAdvanced(target, .{ .sema_kit = sk })).scalar, arena, float_ty, target);
|
||||
} else {
|
||||
return intToFloatInner(ty.abiSize(target), arena, float_ty, target);
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,6 +85,7 @@ test {
|
||||
_ = @import("behavior/bugs/12033.zig");
|
||||
_ = @import("behavior/bugs/12430.zig");
|
||||
_ = @import("behavior/bugs/12486.zig");
|
||||
_ = @import("behavior/bugs/12680.zig");
|
||||
_ = @import("behavior/byteswap.zig");
|
||||
_ = @import("behavior/byval_arg_var.zig");
|
||||
_ = @import("behavior/call.zig");
|
||||
|
||||
17
test/behavior/bugs/12680.zig
Normal file
17
test/behavior/bugs/12680.zig
Normal file
@ -0,0 +1,17 @@
|
||||
const std = @import("std");
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
const other_file = @import("12680_other_file.zig");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
extern fn test_func() callconv(.C) usize;
|
||||
|
||||
test "export a function twice" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
// If it exports the function correctly, `test_func` and `testFunc` will points to the same address.
|
||||
try expectEqual(test_func(), other_file.testFunc());
|
||||
}
|
||||
8
test/behavior/bugs/12680_other_file.zig
Normal file
8
test/behavior/bugs/12680_other_file.zig
Normal file
@ -0,0 +1,8 @@
|
||||
// export this function twice
|
||||
pub export fn testFunc() callconv(.C) usize {
|
||||
return @ptrToInt(&testFunc);
|
||||
}
|
||||
|
||||
comptime {
|
||||
@export(testFunc, .{ .name = "test_func", .linkage = .Strong });
|
||||
}
|
||||
@ -1175,3 +1175,10 @@ test "Non-exhaustive enum with nonstandard int size behaves correctly" {
|
||||
const E = enum(u15) { _ };
|
||||
try expect(@sizeOf(E) == @sizeOf(u15));
|
||||
}
|
||||
|
||||
test "Non-exhaustive enum backed by comptime_int" {
|
||||
const E = enum(comptime_int) { a, b, c, _ };
|
||||
comptime var e: E = .a;
|
||||
e = @intToEnum(E, 378089457309184723749);
|
||||
try expect(@enumToInt(e) == 378089457309184723749);
|
||||
}
|
||||
|
||||
@ -579,3 +579,29 @@ test "runtime init of unnamed packed struct type" {
|
||||
}
|
||||
}{ .x = z }).m();
|
||||
}
|
||||
|
||||
test "packed struct passed to callconv(.C) function" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
|
||||
const S = struct {
|
||||
const Packed = packed struct {
|
||||
a: u16,
|
||||
b: bool = true,
|
||||
c: bool = true,
|
||||
d: u46 = 0,
|
||||
};
|
||||
|
||||
fn foo(p: Packed, a1: u64, a2: u64, a3: u64, a4: u64, a5: u64) callconv(.C) bool {
|
||||
return p.a == 12345 and p.b == true and p.c == true and p.d == 0 and a1 == 5 and a2 == 4 and a3 == 3 and a4 == 2 and a5 == 1;
|
||||
}
|
||||
};
|
||||
const result = S.foo(S.Packed{
|
||||
.a = 12345,
|
||||
.b = true,
|
||||
.c = true,
|
||||
}, 5, 4, 3, 2, 1);
|
||||
try expect(result);
|
||||
}
|
||||
|
||||
@ -301,3 +301,14 @@ test "array access of generic param in typeof expression" {
|
||||
try expect(S.first("a") == 'a');
|
||||
comptime try expect(S.first("a") == 'a');
|
||||
}
|
||||
|
||||
test "lazy size cast to float" {
|
||||
{
|
||||
const S = struct { a: u8 };
|
||||
try expect(@intToFloat(f32, @sizeOf(S)) == 1.0);
|
||||
}
|
||||
{
|
||||
const S = struct { a: u8 };
|
||||
try expect(@as(f32, @sizeOf(S)) == 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,3 +48,5 @@ typedef _Bool uintptr_t;
|
||||
|
||||
#define CAST_TO_BOOL(X) (_Bool)(X)
|
||||
#define CAST_TO_UINTPTR(X) (uintptr_t)(X)
|
||||
|
||||
#define LARGE_INT 18446744073709550592
|
||||
|
||||
@ -113,3 +113,13 @@ test "cast functions" {
|
||||
try expectEqual(true, h.CAST_TO_BOOL(S.foo));
|
||||
try expect(h.CAST_TO_UINTPTR(S.foo) != 0);
|
||||
}
|
||||
|
||||
test "large integer macro" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
|
||||
try expectEqual(@as(c_ulonglong, 18446744073709550592), h.LARGE_INT);
|
||||
}
|
||||
|
||||
@ -690,7 +690,7 @@ test "union with only 1 field casted to its enum type which has enum value speci
|
||||
|
||||
var e = Expr{ .Literal = Literal{ .Bool = true } };
|
||||
comptime try expect(Tag(ExprTag) == comptime_int);
|
||||
var t = @as(ExprTag, e);
|
||||
comptime var t = @as(ExprTag, e);
|
||||
try expect(t == Expr.Literal);
|
||||
try expect(@enumToInt(t) == 33);
|
||||
comptime try expect(@enumToInt(t) == 33);
|
||||
@ -1352,3 +1352,31 @@ test "@unionInit uses tag value instead of field index" {
|
||||
}
|
||||
try expect(@enumToInt(u) == 255);
|
||||
}
|
||||
|
||||
test "union field ptr - zero sized payload" {
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
const U = union {
|
||||
foo: void,
|
||||
bar: void,
|
||||
fn bar(_: *void) void {}
|
||||
};
|
||||
var u: U = .{ .foo = {} };
|
||||
U.bar(&u.foo);
|
||||
}
|
||||
|
||||
test "union field ptr - zero sized field" {
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
const U = union {
|
||||
foo: void,
|
||||
bar: u32,
|
||||
fn bar(_: *void) void {}
|
||||
};
|
||||
var u: U = .{ .foo = {} };
|
||||
U.bar(&u.foo);
|
||||
}
|
||||
|
||||
@ -86,24 +86,8 @@ struct MedStructMixed {
|
||||
void zig_med_struct_mixed(struct MedStructMixed);
|
||||
struct MedStructMixed zig_ret_med_struct_mixed();
|
||||
|
||||
struct SmallPackedStruct {
|
||||
uint8_t a: 2;
|
||||
uint8_t b: 2;
|
||||
uint8_t c: 2;
|
||||
uint8_t d: 2;
|
||||
uint8_t e: 1;
|
||||
};
|
||||
|
||||
struct BigPackedStruct {
|
||||
uint64_t a: 64;
|
||||
uint64_t b: 64;
|
||||
uint64_t c: 64;
|
||||
uint64_t d: 64;
|
||||
uint8_t e: 8;
|
||||
};
|
||||
|
||||
//void zig_small_packed_struct(struct SmallPackedStruct); // #1481
|
||||
void zig_big_packed_struct(struct BigPackedStruct);
|
||||
void zig_small_packed_struct(uint8_t);
|
||||
void zig_big_packed_struct(__int128);
|
||||
|
||||
struct SplitStructInts {
|
||||
uint64_t a;
|
||||
@ -176,13 +160,19 @@ void run_c_tests(void) {
|
||||
}
|
||||
|
||||
{
|
||||
struct BigPackedStruct s = {1, 2, 3, 4, 5};
|
||||
__int128 s = 0;
|
||||
s |= 1 << 0;
|
||||
s |= (__int128)2 << 64;
|
||||
zig_big_packed_struct(s);
|
||||
}
|
||||
|
||||
{
|
||||
struct SmallPackedStruct s = {0, 1, 2, 3, 1};
|
||||
//zig_small_packed_struct(s);
|
||||
uint8_t s = 0;
|
||||
s |= 0 << 0;
|
||||
s |= 1 << 2;
|
||||
s |= 2 << 4;
|
||||
s |= 3 << 6;
|
||||
zig_small_packed_struct(s);
|
||||
}
|
||||
|
||||
{
|
||||
@ -378,42 +368,32 @@ void c_split_struct_mixed(struct SplitStructMixed x) {
|
||||
assert_or_panic(y.c == 1337.0f);
|
||||
}
|
||||
|
||||
struct SmallPackedStruct c_ret_small_packed_struct() {
|
||||
struct SmallPackedStruct s = {
|
||||
.a = 0,
|
||||
.b = 1,
|
||||
.c = 2,
|
||||
.d = 3,
|
||||
.e = 1,
|
||||
};
|
||||
uint8_t c_ret_small_packed_struct() {
|
||||
uint8_t s = 0;
|
||||
s |= 0 << 0;
|
||||
s |= 1 << 2;
|
||||
s |= 2 << 4;
|
||||
s |= 3 << 6;
|
||||
return s;
|
||||
}
|
||||
|
||||
void c_small_packed_struct(struct SmallPackedStruct x) {
|
||||
assert_or_panic(x.a == 0);
|
||||
assert_or_panic(x.a == 1);
|
||||
assert_or_panic(x.a == 2);
|
||||
assert_or_panic(x.a == 3);
|
||||
assert_or_panic(x.e == 1);
|
||||
void c_small_packed_struct(uint8_t x) {
|
||||
assert_or_panic(((x >> 0) & 0x3) == 0);
|
||||
assert_or_panic(((x >> 2) & 0x3) == 1);
|
||||
assert_or_panic(((x >> 4) & 0x3) == 2);
|
||||
assert_or_panic(((x >> 6) & 0x3) == 3);
|
||||
}
|
||||
|
||||
struct BigPackedStruct c_ret_big_packed_struct() {
|
||||
struct BigPackedStruct s = {
|
||||
.a = 1,
|
||||
.b = 2,
|
||||
.c = 3,
|
||||
.d = 4,
|
||||
.e = 5,
|
||||
};
|
||||
__int128 c_ret_big_packed_struct() {
|
||||
__int128 s = 0;
|
||||
s |= 1 << 0;
|
||||
s |= (__int128)2 << 64;
|
||||
return s;
|
||||
}
|
||||
|
||||
void c_big_packed_struct(struct BigPackedStruct x) {
|
||||
assert_or_panic(x.a == 1);
|
||||
assert_or_panic(x.b == 2);
|
||||
assert_or_panic(x.c == 3);
|
||||
assert_or_panic(x.d == 4);
|
||||
assert_or_panic(x.e == 5);
|
||||
void c_big_packed_struct(__int128 x) {
|
||||
assert_or_panic(((x >> 0) & 0xFFFFFFFFFFFFFFFF) == 1);
|
||||
assert_or_panic(((x >> 64) & 0xFFFFFFFFFFFFFFFF) == 2);
|
||||
}
|
||||
|
||||
struct SplitStructMixed c_ret_split_struct_mixed() {
|
||||
|
||||
@ -110,7 +110,7 @@ test "C ABI floats" {
|
||||
}
|
||||
|
||||
test "C ABI long double" {
|
||||
if (!builtin.cpu.arch.isWasm()) return error.SkipZigTest;
|
||||
if (!builtin.cpu.arch.isWasm() and !builtin.cpu.arch.isAARCH64()) return error.SkipZigTest;
|
||||
c_long_double(12.34);
|
||||
}
|
||||
|
||||
@ -263,37 +263,30 @@ const SmallPackedStruct = packed struct {
|
||||
b: u2,
|
||||
c: u2,
|
||||
d: u2,
|
||||
e: bool,
|
||||
};
|
||||
const c_small_packed_struct: fn (SmallPackedStruct) callconv(.C) void = @compileError("TODO: #1481");
|
||||
extern fn c_small_packed_struct(SmallPackedStruct) void;
|
||||
extern fn c_ret_small_packed_struct() SmallPackedStruct;
|
||||
|
||||
// waiting on #1481
|
||||
//export fn zig_small_packed_struct(x: SmallPackedStruct) void {
|
||||
// expect(x.a == 0) catch @panic("test failure");
|
||||
// expect(x.b == 1) catch @panic("test failure");
|
||||
// expect(x.c == 2) catch @panic("test failure");
|
||||
// expect(x.d == 3) catch @panic("test failure");
|
||||
// expect(x.e) catch @panic("test failure");
|
||||
//}
|
||||
export fn zig_small_packed_struct(x: SmallPackedStruct) void {
|
||||
expect(x.a == 0) catch @panic("test failure");
|
||||
expect(x.b == 1) catch @panic("test failure");
|
||||
expect(x.c == 2) catch @panic("test failure");
|
||||
expect(x.d == 3) catch @panic("test failure");
|
||||
}
|
||||
|
||||
test "C ABI small packed struct" {
|
||||
var s = SmallPackedStruct{ .a = 0, .b = 1, .c = 2, .d = 3, .e = true };
|
||||
_ = s; //c_small_packed_struct(s); // waiting on #1481
|
||||
var s = SmallPackedStruct{ .a = 0, .b = 1, .c = 2, .d = 3 };
|
||||
c_small_packed_struct(s);
|
||||
var s2 = c_ret_small_packed_struct();
|
||||
try expect(s2.a == 0);
|
||||
try expect(s2.b == 1);
|
||||
try expect(s2.c == 2);
|
||||
try expect(s2.d == 3);
|
||||
try expect(s2.e);
|
||||
}
|
||||
|
||||
const BigPackedStruct = packed struct {
|
||||
a: u64,
|
||||
b: u64,
|
||||
c: u64,
|
||||
d: u64,
|
||||
e: u8,
|
||||
};
|
||||
extern fn c_big_packed_struct(BigPackedStruct) void;
|
||||
extern fn c_ret_big_packed_struct() BigPackedStruct;
|
||||
@ -301,20 +294,14 @@ extern fn c_ret_big_packed_struct() BigPackedStruct;
|
||||
export fn zig_big_packed_struct(x: BigPackedStruct) void {
|
||||
expect(x.a == 1) catch @panic("test failure");
|
||||
expect(x.b == 2) catch @panic("test failure");
|
||||
expect(x.c == 3) catch @panic("test failure");
|
||||
expect(x.d == 4) catch @panic("test failure");
|
||||
expect(x.e == 5) catch @panic("test failure");
|
||||
}
|
||||
|
||||
test "C ABI big packed struct" {
|
||||
var s = BigPackedStruct{ .a = 1, .b = 2, .c = 3, .d = 4, .e = 5 };
|
||||
var s = BigPackedStruct{ .a = 1, .b = 2 };
|
||||
c_big_packed_struct(s);
|
||||
var s2 = c_ret_big_packed_struct();
|
||||
try expect(s2.a == 1);
|
||||
try expect(s2.b == 2);
|
||||
try expect(s2.c == 3);
|
||||
try expect(s2.d == 4);
|
||||
try expect(s2.e == 5);
|
||||
}
|
||||
|
||||
const SplitStructInt = extern struct {
|
||||
|
||||
@ -10,5 +10,5 @@ export fn a() void {
|
||||
// target=native
|
||||
//
|
||||
// :3:19: error: C pointers cannot point to non-C-ABI-compatible type 'tmp.Foo'
|
||||
// :3:19: note: only structs with packed or extern layout are extern compatible
|
||||
// :3:19: note: only extern structs and ABI sized packed structs are extern compatible
|
||||
// :1:13: note: struct declared here
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
pub export fn entry() void {
|
||||
const E = enum(comptime_int) { a, b, c, _ };
|
||||
var e: E = .a;
|
||||
_ = e;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :3:12: error: variable of type 'tmp.entry.E' must be const or comptime
|
||||
@ -10,5 +10,5 @@ export fn entry(foo: Foo) void { _ = foo; }
|
||||
// target=native
|
||||
//
|
||||
// :6:17: error: parameter of type 'tmp.Foo' not allowed in function with calling convention 'C'
|
||||
// :6:17: note: only structs with packed or extern layout are extern compatible
|
||||
// :6:17: note: only extern structs and ABI sized packed structs are extern compatible
|
||||
// :1:13: note: struct declared here
|
||||
|
||||
@ -10,5 +10,5 @@ export fn entry(foo: Foo) void { _ = foo; }
|
||||
// target=native
|
||||
//
|
||||
// :6:17: error: parameter of type 'tmp.Foo' not allowed in function with calling convention 'C'
|
||||
// :6:17: note: only unions with packed or extern layout are extern compatible
|
||||
// :6:17: note: only extern unions and ABI sized packed unions are extern compatible
|
||||
// :1:13: note: union declared here
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
extern fn printf([*:0]const u8, ...) c_int;
|
||||
|
||||
pub export fn entry() void {
|
||||
_ = printf("%d %d %d %d\n", 1, 2, 3, 4);
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :4:33: error: integer and float literals in var args function must be casted
|
||||
20
test/cases/compile_errors/noalias_param_coersion.zig
Normal file
20
test/cases/compile_errors/noalias_param_coersion.zig
Normal file
@ -0,0 +1,20 @@
|
||||
pub export fn entry() void {
|
||||
comptime var x: fn (noalias *i32, noalias *i32) void = undefined;
|
||||
x = bar;
|
||||
}
|
||||
pub export fn entry1() void {
|
||||
comptime var x: fn (*i32, *i32) void = undefined;
|
||||
x = foo;
|
||||
}
|
||||
|
||||
fn foo(noalias _: *i32, noalias _: *i32) void {}
|
||||
fn bar(noalias _: *i32, _: *i32) void {}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :3:9: error: expected type 'fn(noalias *i32, noalias *i32) void', found 'fn(noalias *i32, *i32) void'
|
||||
// :3:9: note: regular parameter 1 cannot cast into a noalias parameter
|
||||
// :7:9: error: expected type 'fn(*i32, *i32) void', found 'fn(noalias *i32, noalias *i32) void'
|
||||
// :7:9: note: noalias parameter 0 cannot cast into a regular parameter
|
||||
@ -2,13 +2,13 @@ const Moo = enum(u8) {
|
||||
Last = 255,
|
||||
Over,
|
||||
};
|
||||
pub fn main() void {
|
||||
pub export fn entry() void {
|
||||
var y = Moo.Last;
|
||||
_ = y;
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:3:5: error: enumeration value 256 too large for type 'u8'
|
||||
// :3:5: error: enumeration value '256' too large for type 'u8'
|
||||
@ -12,7 +12,7 @@ export fn entry() void {
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage1
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// tmp.zig:6:5: error: enumeration value 4 too large for type 'u2'
|
||||
// :6:5: error: enumeration value '4' too large for type 'u2'
|
||||
11
test/cases/compile_errors/try_return.zig
Normal file
11
test/cases/compile_errors/try_return.zig
Normal file
@ -0,0 +1,11 @@
|
||||
pub fn foo() !void {
|
||||
try return bar();
|
||||
}
|
||||
pub fn bar() !void {}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :2:5: error: unreachable code
|
||||
// :2:9: note: control flow is diverted here
|
||||
29
test/cases/compile_errors/variadic_arg_validation.zig
Normal file
29
test/cases/compile_errors/variadic_arg_validation.zig
Normal file
@ -0,0 +1,29 @@
|
||||
extern fn printf([*:0]const u8, ...) c_int;
|
||||
|
||||
pub export fn entry() void {
|
||||
_ = printf("%d %d %d %d\n", 1, 2, 3, 4);
|
||||
}
|
||||
|
||||
pub export fn entry1() void {
|
||||
var arr: [2]u8 = undefined;
|
||||
_ = printf("%d\n", arr);
|
||||
}
|
||||
|
||||
pub export fn entry2() void {
|
||||
_ = printf("%d\n", @as(u48, 2));
|
||||
}
|
||||
|
||||
pub export fn entry3() void {
|
||||
_ = printf("%d\n", {});
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :4:33: error: integer and float literals passed variadic function must be casted to a fixed-size number type
|
||||
// :9:24: error: arrays must be passed by reference to variadic function
|
||||
// :13:24: error: cannot pass 'u48' to variadic function
|
||||
// :13:24: note: only integers with power of two bits are extern compatible
|
||||
// :17:24: error: cannot pass 'void' to variadic function
|
||||
// :17:24: note: 'void' is a zero bit type; for C 'void' use 'anyopaque'
|
||||
@ -52,6 +52,12 @@ fn addWasmCases(cases: *tests.StandaloneContext) void {
|
||||
.build_modes = true,
|
||||
.requires_stage2 = true,
|
||||
});
|
||||
|
||||
cases.addBuildFile("test/link/wasm/extern/build.zig", .{
|
||||
.build_modes = true,
|
||||
.requires_stage2 = true,
|
||||
.use_emulation = true,
|
||||
});
|
||||
}
|
||||
|
||||
fn addMachOCases(cases: *tests.StandaloneContext) void {
|
||||
|
||||
17
test/link/wasm/extern/build.zig
vendored
Normal file
17
test/link/wasm/extern/build.zig
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub fn build(b: *std.build.Builder) void {
|
||||
const mode = b.standardReleaseOptions();
|
||||
const exe = b.addExecutable("extern", "main.zig");
|
||||
exe.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .wasi });
|
||||
exe.setBuildMode(mode);
|
||||
exe.addCSourceFile("foo.c", &.{});
|
||||
exe.use_llvm = false;
|
||||
exe.use_lld = false;
|
||||
|
||||
const run = exe.runEmulatable();
|
||||
run.expectStdOutEqual("Result: 30");
|
||||
|
||||
const test_step = b.step("test", "Run linker test");
|
||||
test_step.dependOn(&run.step);
|
||||
}
|
||||
1
test/link/wasm/extern/foo.c
vendored
Normal file
1
test/link/wasm/extern/foo.c
vendored
Normal file
@ -0,0 +1 @@
|
||||
int foo = 30;
|
||||
8
test/link/wasm/extern/main.zig
vendored
Normal file
8
test/link/wasm/extern/main.zig
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
const std = @import("std");
|
||||
|
||||
extern const foo: u32;
|
||||
|
||||
pub fn main() void {
|
||||
const std_out = std.io.getStdOut();
|
||||
std_out.writer().print("Result: {d}", .{foo}) catch {};
|
||||
}
|
||||
@ -250,18 +250,20 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
|
||||
\\}
|
||||
, "");
|
||||
|
||||
cases.add("struct initializer - packed",
|
||||
\\#define _NO_CRT_STDIO_INLINE 1
|
||||
\\#include <stdint.h>
|
||||
\\#include <stdlib.h>
|
||||
\\struct s {uint8_t x,y;
|
||||
\\ uint32_t z;} __attribute__((packed)) s0 = {1, 2};
|
||||
\\int main() {
|
||||
\\ /* sizeof nor offsetof currently supported */
|
||||
\\ if (((intptr_t)&s0.z - (intptr_t)&s0.x) != 2) abort();
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
if (@import("builtin").zig_backend == .stage1) {
|
||||
cases.add("struct initializer - packed",
|
||||
\\#define _NO_CRT_STDIO_INLINE 1
|
||||
\\#include <stdint.h>
|
||||
\\#include <stdlib.h>
|
||||
\\struct s {uint8_t x,y;
|
||||
\\ uint32_t z;} __attribute__((packed)) s0 = {1, 2};
|
||||
\\int main() {
|
||||
\\ /* sizeof nor offsetof currently supported */
|
||||
\\ if (((intptr_t)&s0.z - (intptr_t)&s0.x) != 2) abort();
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
}
|
||||
|
||||
cases.add("cast signed array index to unsigned",
|
||||
\\#include <stdlib.h>
|
||||
|
||||
@ -13,6 +13,8 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
|
||||
cases.add("test/standalone/guess_number/main.zig");
|
||||
cases.add("test/standalone/main_return_error/error_u8.zig");
|
||||
cases.add("test/standalone/main_return_error/error_u8_non_zero.zig");
|
||||
cases.add("test/standalone/noreturn_call/inline.zig");
|
||||
cases.add("test/standalone/noreturn_call/as_arg.zig");
|
||||
cases.addBuildFile("test/standalone/main_pkg_path/build.zig", .{});
|
||||
cases.addBuildFile("test/standalone/shared_library/build.zig", .{});
|
||||
cases.addBuildFile("test/standalone/mix_o_files/build.zig", .{});
|
||||
@ -48,6 +50,9 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
|
||||
cases.addBuildFile("test/c_abi/build.zig", .{});
|
||||
}
|
||||
}
|
||||
if (builtin.cpu.arch.isAARCH64() and builtin.zig_backend == .stage2_llvm) {
|
||||
cases.addBuildFile("test/c_abi/build.zig", .{});
|
||||
}
|
||||
// C ABI tests only pass for the Wasm target when using stage2
|
||||
cases.addBuildFile("test/c_abi/build_wasm.zig", .{
|
||||
.requires_stage2 = true,
|
||||
@ -66,6 +71,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
|
||||
if (builtin.os.tag == .linux) {
|
||||
cases.addBuildFile("test/standalone/pie/build.zig", .{});
|
||||
}
|
||||
cases.addBuildFile("test/standalone/issue_12706/build.zig", .{});
|
||||
|
||||
// Ensure the development tools are buildable.
|
||||
|
||||
|
||||
39
test/standalone/issue_12706/build.zig
Normal file
39
test/standalone/issue_12706/build.zig
Normal file
@ -0,0 +1,39 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const Builder = std.build.Builder;
|
||||
const CrossTarget = std.zig.CrossTarget;
|
||||
|
||||
// TODO integrate this with the std.build executor API
|
||||
fn isRunnableTarget(t: CrossTarget) bool {
|
||||
if (t.isNative()) return true;
|
||||
|
||||
return (t.getOsTag() == builtin.os.tag and
|
||||
t.getCpuArch() == builtin.cpu.arch);
|
||||
}
|
||||
|
||||
pub fn build(b: *Builder) void {
|
||||
const mode = b.standardReleaseOptions();
|
||||
const target = b.standardTargetOptions(.{});
|
||||
|
||||
const exe = b.addExecutable("main", "main.zig");
|
||||
exe.setBuildMode(mode);
|
||||
exe.install();
|
||||
|
||||
const c_sources = [_][]const u8{
|
||||
"test.c",
|
||||
};
|
||||
|
||||
exe.addCSourceFiles(&c_sources, &.{});
|
||||
exe.linkLibC();
|
||||
|
||||
exe.setTarget(target);
|
||||
b.default_step.dependOn(&exe.step);
|
||||
|
||||
const test_step = b.step("test", "Test the program");
|
||||
if (isRunnableTarget(target)) {
|
||||
const run_cmd = exe.run();
|
||||
test_step.dependOn(&run_cmd.step);
|
||||
} else {
|
||||
test_step.dependOn(&exe.step);
|
||||
}
|
||||
}
|
||||
12
test/standalone/issue_12706/main.zig
Normal file
12
test/standalone/issue_12706/main.zig
Normal file
@ -0,0 +1,12 @@
|
||||
const std = @import("std");
|
||||
extern fn testFnPtr(n: c_int, ...) void;
|
||||
|
||||
const val: c_int = 123;
|
||||
|
||||
fn func(a: c_int) callconv(.C) void {
|
||||
std.debug.assert(a == val);
|
||||
}
|
||||
|
||||
pub fn main() void {
|
||||
testFnPtr(2, func, val);
|
||||
}
|
||||
11
test/standalone/issue_12706/test.c
Normal file
11
test/standalone/issue_12706/test.c
Normal file
@ -0,0 +1,11 @@
|
||||
#include <stdarg.h>
|
||||
|
||||
void testFnPtr(int n, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, n);
|
||||
|
||||
void (*fnPtr)(int) = va_arg(ap, void (*)(int));
|
||||
int arg = va_arg(ap, int);
|
||||
fnPtr(arg);
|
||||
va_end(ap);
|
||||
}
|
||||
8
test/standalone/noreturn_call/as_arg.zig
Normal file
8
test/standalone/noreturn_call/as_arg.zig
Normal file
@ -0,0 +1,8 @@
|
||||
const std = @import("std");
|
||||
fn foo() noreturn {
|
||||
std.process.exit(0);
|
||||
}
|
||||
fn bar(_: u8, _: u8) void {}
|
||||
pub fn main() void {
|
||||
bar(foo(), @compileError("bad"));
|
||||
}
|
||||
10
test/standalone/noreturn_call/inline.zig
Normal file
10
test/standalone/noreturn_call/inline.zig
Normal file
@ -0,0 +1,10 @@
|
||||
pub fn main() void {
|
||||
_ = bar();
|
||||
}
|
||||
inline fn bar() u8 {
|
||||
noret();
|
||||
}
|
||||
const std = @import("std");
|
||||
inline fn noret() noreturn {
|
||||
std.process.exit(0);
|
||||
}
|
||||
@ -728,20 +728,22 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\}
|
||||
});
|
||||
|
||||
cases.add("struct initializer - packed",
|
||||
\\struct {int x,y,z;} __attribute__((packed)) s0 = {1, 2};
|
||||
, &[_][]const u8{
|
||||
\\const struct_unnamed_1 = packed struct {
|
||||
\\ x: c_int,
|
||||
\\ y: c_int,
|
||||
\\ z: c_int,
|
||||
\\};
|
||||
\\pub export var s0: struct_unnamed_1 = struct_unnamed_1{
|
||||
\\ .x = @as(c_int, 1),
|
||||
\\ .y = @as(c_int, 2),
|
||||
\\ .z = 0,
|
||||
\\};
|
||||
});
|
||||
if (builtin.zig_backend == .stage1) {
|
||||
cases.add("struct initializer - packed",
|
||||
\\struct {int x,y,z;} __attribute__((packed)) s0 = {1, 2};
|
||||
, &[_][]const u8{
|
||||
\\const struct_unnamed_1 = packed struct {
|
||||
\\ x: c_int,
|
||||
\\ y: c_int,
|
||||
\\ z: c_int,
|
||||
\\};
|
||||
\\pub export var s0: struct_unnamed_1 = struct_unnamed_1{
|
||||
\\ .x = @as(c_int, 1),
|
||||
\\ .y = @as(c_int, 2),
|
||||
\\ .z = 0,
|
||||
\\};
|
||||
});
|
||||
}
|
||||
|
||||
// Test case temporarily disabled:
|
||||
// https://github.com/ziglang/zig/issues/12055
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user