| author | |
| committer | |
| log | b7900de1684021ff86c67105e14e34968821ea02 |
| tree | b881a288071705ffb8cd65ede5f8e7a1452b6dce |
| parent | 20145016ac0d098e8e63d5107a05eca376d1e7bb |
| parent | e2bb92b2e27dc54852a0227345e294ae383358fd |
72 files changed, 1691 insertions(+), 580 deletions(-)
.github/CODEOWNERS+2-1| ... | ... | @@ -1,3 +1,4 @@ |
| 1 | 1 | # Autodoc |
| 2 | 2 | /src/Autodoc.zig @kristoff-it |
| 3 | /lib/docs/* @kristoff-it | |
| \ No newline at end of file | ||
| 3 | /src/autodoc/* @kristoff-it | |
| 4 | /lib/docs/* @kristoff-it |
ci/azure/macos_script+1| ... | ... | @@ -52,6 +52,7 @@ stage3-release/bin/zig build test docs \ |
| 52 | 52 | --zig-lib-dir "$(pwd)/../lib" \ |
| 53 | 53 | -Denable-macos-sdk \ |
| 54 | 54 | -Dstatic-llvm \ |
| 55 | -Dskip-non-native \ | |
| 55 | 56 | --search-prefix "$PREFIX" |
| 56 | 57 | |
| 57 | 58 | if [ "${BUILD_REASON}" != "PullRequest" ]; then |
ci/drone/test_linux_misc+1-1| ... | ... | @@ -16,4 +16,4 @@ $ZIG build test-universal-libc -Dskip-non-native --zig-lib-dir lib |
| 16 | 16 | $ZIG build test-stack-traces -Dskip-non-native --zig-lib-dir lib |
| 17 | 17 | $ZIG build test-cli -Dskip-non-native --zig-lib-dir lib |
| 18 | 18 | $ZIG build test-asm-link -Dskip-non-native --zig-lib-dir lib |
| 19 | $ZIG build test-translate-c -Dskip-non-native --zig-lib-dir lib | |
| 19 | # $ZIG build test-translate-c -Dskip-non-native --zig-lib-dir lib |
ci/srht/update_download_page+37-21| ... | ... | @@ -101,32 +101,48 @@ CIDIR="$(pwd)" |
| 101 | 101 | |
| 102 | 102 | cd "$HOME" |
| 103 | 103 | |
| 104 | # Upload new stdlib autodocs | |
| 105 | mkdir -p docs_to_upload/documentation/master/std/ | |
| 106 | gzip -c -9 "$ZIGDIR/docs/std/index.html" > docs_to_upload/documentation/master/std/index.html | |
| 107 | gzip -c -9 "$ZIGDIR/docs/std/data.js" > docs_to_upload/documentation/master/std/data.js | |
| 108 | gzip -c -9 "$ZIGDIR/docs/std/main.js" > docs_to_upload/documentation/master/std/main.js | |
| 109 | gzip -c -9 "$LANGREF" > docs_to_upload/documentation/master/index.html | |
| 110 | $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/ | |
| 111 | ||
| 112 | mkdir -p docs_src_to_upload/documentation/master/std/ | |
| 113 | cp -r "$ZIGDIR/docs/std/src" docs_src_to_upload/documentation/master/std/ | |
| 114 | $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/ | |
| 115 | ||
| 116 | ## Copy without compression: | |
| 117 | # mkdir -p docs_to_upload/documentation/master/std/ | |
| 118 | # cp "$ZIGDIR/docs/std/index.html" docs_to_upload/documentation/master/std/index.html | |
| 119 | # cp "$ZIGDIR/docs/std/data.js" docs_to_upload/documentation/master/std/data.js | |
| 120 | # cp "$ZIGDIR/docs/std/main.js" docs_to_upload/documentation/master/std/main.js | |
| 121 | # cp "$LANGREF" docs_to_upload/documentation/master/index.html | |
| 122 | # $S3CMD put -P --no-mime-magic --recursive --add-header="Cache-Control: max-age=0, must-revalidate" "docs_to_upload/" s3://ziglang.org/ | |
| 104 | # Update autodocs and langref directly to S3 in order to prevent the | |
| 105 | # www.ziglang.org git repo from growing too big. | |
| 106 | ||
| 107 | # Please do not edit this script to pre-compress the artifacts before they hit | |
| 108 | # S3. This prevents the website from working on browsers that do not support gzip | |
| 109 | # encoding. Cloudfront will automatically compress files if they are less than | |
| 110 | # 9.5 MiB, and the client advertises itself as capable of decompressing. | |
| 111 | # The data.js file is currently 16 MiB. In order to fix this problem, we need to do | |
| 112 | # one of the following things: | |
| 113 | # * Reduce the size of data.js to less than 9.5 MiB. | |
| 114 | # * Figure out how to adjust the Cloudfront settings to increase the max size for | |
| 115 | # auto-compressed objects. | |
| 116 | # * Migrate to fastly. | |
| 117 | $S3CMD put -P --no-mime-magic \ | |
| 118 | --add-header="Cache-Control: max-age=0, must-revalidate" \ | |
| 119 | "$LANGREF" s3://ziglang.org/documentation/master/index.html | |
| 120 | ||
| 121 | $S3CMD put -P --no-mime-magic \ | |
| 122 | --add-header="Cache-Control: max-age=0, must-revalidate" \ | |
| 123 | "$ZIGDIR/docs/std/index.html" s3://ziglang.org/documentation/master/std/index.html | |
| 124 | ||
| 125 | $S3CMD put -P --no-mime-magic \ | |
| 126 | --add-header="Cache-Control: max-age=0, must-revalidate" \ | |
| 127 | "$ZIGDIR/docs/std/main.js" s3://ziglang.org/documentation/master/std/main.js | |
| 128 | ||
| 129 | $S3CMD put -P --no-mime-magic \ | |
| 130 | --add-header="Cache-Control: max-age=0, must-revalidate" \ | |
| 131 | "$ZIGDIR/docs/std/data.js" s3://ziglang.org/documentation/master/std/data.js | |
| 132 | ||
| 133 | $S3CMD put -P --no-mime-magic --recursive \ | |
| 134 | --add-header="Cache-Control: max-age=0, must-revalidate" \ | |
| 135 | -m "text/html" \ | |
| 136 | "$ZIGDIR/docs/std/src/" s3://ziglang.org/documentation/master/std/src/ | |
| 137 | ||
| 138 | $S3CMD put -P --no-mime-magic \ | |
| 139 | --add-header="cache-control: public, max-age=31536000, immutable" \ | |
| 140 | "$HOME/$SRC_TARBALL" s3://ziglang.org/builds/ | |
| 123 | 141 | |
| 124 | 142 | git clone --depth 1 git@github.com:ziglang/www.ziglang.org.git |
| 125 | 143 | cd www.ziglang.org |
| 126 | 144 | WWWDIR="$(pwd)" |
| 127 | 145 | |
| 128 | $S3CMD put -P --no-mime-magic --add-header="cache-control: public, max-age=31536000, immutable" "$HOME/$SRC_TARBALL" s3://ziglang.org/builds/ | |
| 129 | ||
| 130 | 146 | cd "$WWWDIR" |
| 131 | 147 | cp "$CIDIR/out/index.json" data/releases.json |
| 132 | 148 | git add data/releases.json |
ci/zinc/drone.yml+5| ... | ... | @@ -75,6 +75,11 @@ steps: |
| 75 | 75 | depends_on: |
| 76 | 76 | - macos_package |
| 77 | 77 | - linux_package |
| 78 | when: | |
| 79 | branch: | |
| 80 | - master | |
| 81 | event: | |
| 82 | - push | |
| 78 | 83 | image: ci/debian-amd64:11.1-9 |
| 79 | 84 | environment: |
| 80 | 85 | SRHT_OAUTH_TOKEN: |
ci/zinc/linux_package+1-1| ... | ... | @@ -29,7 +29,7 @@ tar cfJ "$TARBALL" "$BASENAME" |
| 29 | 29 | SHASUM=$(sha256sum $TARBALL | cut '-d ' -f1) |
| 30 | 30 | BYTESIZE=$(wc -c < $TARBALL) |
| 31 | 31 | |
| 32 | MANIFEST="manifest.json" | |
| 32 | MANIFEST="manifest-$TARGET.json" | |
| 33 | 33 | touch $MANIFEST |
| 34 | 34 | echo "{\"tarball\": \"$TARBALL\"," >>$MANIFEST |
| 35 | 35 | echo "\"shasum\": \"$SHASUM\"," >>$MANIFEST |
ci/zinc/macos_package+1-1| ... | ... | @@ -33,7 +33,7 @@ tar cfJ "$TARBALL" "$BASENAME" |
| 33 | 33 | SHASUM=$(sha256sum $TARBALL | cut '-d ' -f1) |
| 34 | 34 | BYTESIZE=$(wc -c < $TARBALL) |
| 35 | 35 | |
| 36 | MANIFEST="manifest.json" | |
| 36 | MANIFEST="manifest-$TARGET.json" | |
| 37 | 37 | touch $MANIFEST |
| 38 | 38 | echo "{\"tarball\": \"$TARBALL\"," >>$MANIFEST |
| 39 | 39 | echo "\"shasum\": \"$SHASUM\"," >>$MANIFEST |
doc/langref.html.in+1-1| ... | ... | @@ -2631,7 +2631,7 @@ test "Conversion between vectors, arrays, and slices" { |
| 2631 | 2631 | </li> |
| 2632 | 2632 | </ul> |
| 2633 | 2633 | <ul> |
| 2634 | <li>{#syntax#}[]T{#endsyntax#} - pointer to runtime-known number of items. | |
| 2634 | <li>{#syntax#}[]T{#endsyntax#} - is a slice (a fat pointer, which contains a pointer of type {#syntax#}[*]T{#endsyntax#} and a length). | |
| 2635 | 2635 | <ul> |
| 2636 | 2636 | <li>Supports index syntax: {#syntax#}slice[i]{#endsyntax#}</li> |
| 2637 | 2637 | <li>Supports slice syntax: {#syntax#}slice[start..end]{#endsyntax#}</li> |
lib/docs/index.html+15-1| ... | ... | @@ -359,7 +359,17 @@ |
| 359 | 359 | |
| 360 | 360 | #listFns dt { |
| 361 | 361 | font-family: var(--mono); |
| 362 | display: flex; | |
| 363 | flex-direction: colunm; | |
| 364 | justify-content: space-between; | |
| 365 | } | |
| 366 | ||
| 367 | #listFns dt .fnSignature { | |
| 368 | overflow-x: hidden; | |
| 369 | white-space: nowrap; | |
| 370 | text-overflow: ellipsis; | |
| 362 | 371 | } |
| 372 | ||
| 363 | 373 | .argBreaker { |
| 364 | 374 | display: none; |
| 365 | 375 | } |
| ... | ... | @@ -711,7 +721,11 @@ |
| 711 | 721 | <h2>Examples</h2> |
| 712 | 722 | <ul id="listFnExamples" class="examples"></ul> |
| 713 | 723 | </div> |
| 714 | <div id="sectTests" class="hidden"> | |
| 724 | <div id="sectDocTests" class="hidden"> | |
| 725 | <h2>DocTests</h2> | |
| 726 | <pre id="docTestsCode"></pre> | |
| 727 | </div> | |
| 728 | <div id="sectTests" class="hidden"> | |
| 715 | 729 | <h2>Tests</h2> |
| 716 | 730 | <div class="table-container"> |
| 717 | 731 | <table> |
lib/docs/main.js+53-8| ... | ... | @@ -13,6 +13,8 @@ var zigAnalysis; |
| 13 | 13 | const domListTypes = document.getElementById("listTypes"); |
| 14 | 14 | const domSectTests = document.getElementById("sectTests"); |
| 15 | 15 | const domListTests = document.getElementById("listTests"); |
| 16 | const domSectDocTests = document.getElementById("sectDocTests"); | |
| 17 | const domDocTestsCode = document.getElementById("docTestsCode"); | |
| 16 | 18 | const domSectNamespaces = document.getElementById("sectNamespaces"); |
| 17 | 19 | const domListNamespaces = document.getElementById("listNamespaces"); |
| 18 | 20 | const domSectErrSets = document.getElementById("sectErrSets"); |
| ... | ... | @@ -241,7 +243,8 @@ var zigAnalysis; |
| 241 | 243 | return ( |
| 242 | 244 | typeKind === typeKinds.Struct || |
| 243 | 245 | typeKind === typeKinds.Union || |
| 244 | typeKind === typeKinds.Enum | |
| 246 | typeKind === typeKinds.Enum || | |
| 247 | typeKind === typeKinds.Opaque | |
| 245 | 248 | ); |
| 246 | 249 | } |
| 247 | 250 | |
| ... | ... | @@ -384,6 +387,7 @@ var zigAnalysis; |
| 384 | 387 | domSectPkgs.classList.add("hidden"); |
| 385 | 388 | domSectTypes.classList.add("hidden"); |
| 386 | 389 | domSectTests.classList.add("hidden"); |
| 390 | domSectDocTests.classList.add("hidden"); | |
| 387 | 391 | domSectNamespaces.classList.add("hidden"); |
| 388 | 392 | domSectErrSets.classList.add("hidden"); |
| 389 | 393 | domSectFns.classList.add("hidden"); |
| ... | ... | @@ -452,6 +456,10 @@ var zigAnalysis; |
| 452 | 456 | let lastIsDecl = isDecl(last); |
| 453 | 457 | let lastIsType = isType(last); |
| 454 | 458 | let lastIsContainerType = isContainerType(last); |
| 459 | ||
| 460 | if (lastIsDecl){ | |
| 461 | renderDocTest(last); | |
| 462 | } | |
| 455 | 463 | |
| 456 | 464 | if (lastIsContainerType) { |
| 457 | 465 | return renderContainer(last); |
| ... | ... | @@ -477,6 +485,14 @@ var zigAnalysis; |
| 477 | 485 | |
| 478 | 486 | return renderValue(last); |
| 479 | 487 | } |
| 488 | ||
| 489 | } | |
| 490 | ||
| 491 | function renderDocTest(decl) { | |
| 492 | if (!("decltest" in decl)) return; | |
| 493 | const astNode = zigAnalysis.astNodes[decl.decltest]; | |
| 494 | domSectDocTests.classList.remove("hidden"); | |
| 495 | domDocTestsCode.innerHTML = astNode.code; | |
| 480 | 496 | } |
| 481 | 497 | |
| 482 | 498 | function renderUnknownDecl(decl) { |
| ... | ... | @@ -1405,6 +1421,30 @@ var zigAnalysis; |
| 1405 | 1421 | operator += "**"; |
| 1406 | 1422 | break; |
| 1407 | 1423 | } |
| 1424 | case "cmp_eq": { | |
| 1425 | operator += "=="; | |
| 1426 | break; | |
| 1427 | } | |
| 1428 | case "cmp_neq": { | |
| 1429 | operator += "!="; | |
| 1430 | break; | |
| 1431 | } | |
| 1432 | case "cmp_gt": { | |
| 1433 | operator += ">"; | |
| 1434 | break; | |
| 1435 | } | |
| 1436 | case "cmp_gte": { | |
| 1437 | operator += ">="; | |
| 1438 | break; | |
| 1439 | } | |
| 1440 | case "cmp_lt": { | |
| 1441 | operator += "<"; | |
| 1442 | break; | |
| 1443 | } | |
| 1444 | case "cmp_lte": { | |
| 1445 | operator += "<="; | |
| 1446 | break; | |
| 1447 | } | |
| 1408 | 1448 | default: |
| 1409 | 1449 | console.log("operator not handled yet or doesn't exist!"); |
| 1410 | 1450 | } |
| ... | ... | @@ -1555,6 +1595,10 @@ var zigAnalysis; |
| 1555 | 1595 | return '"' + escapeHtml(expr.string) + '"'; |
| 1556 | 1596 | } |
| 1557 | 1597 | |
| 1598 | case "int_big": { | |
| 1599 | return (expr.int_big.negated ? "-" : "") + expr.int_big.value; | |
| 1600 | } | |
| 1601 | ||
| 1558 | 1602 | case "anytype": { |
| 1559 | 1603 | return "anytype"; |
| 1560 | 1604 | } |
| ... | ... | @@ -1581,8 +1625,7 @@ var zigAnalysis; |
| 1581 | 1625 | } |
| 1582 | 1626 | case typeKinds.Opaque: { |
| 1583 | 1627 | let opaqueObj = typeObj; |
| 1584 | ||
| 1585 | return opaqueObj.name; | |
| 1628 | return opaqueObj; | |
| 1586 | 1629 | } |
| 1587 | 1630 | case typeKinds.ComptimeExpr: { |
| 1588 | 1631 | return "anyopaque"; |
| ... | ... | @@ -2285,7 +2328,7 @@ var zigAnalysis; |
| 2285 | 2328 | |
| 2286 | 2329 | return "<a style=\"float: right;\" href=\"" + |
| 2287 | 2330 | sourceFileUrlTemplate.replace("{{file}}", |
| 2288 | zigAnalysis.files[srcNode.file]).replace("{{line}}", srcNode.line) + "\">[src]</a>"; | |
| 2331 | zigAnalysis.files[srcNode.file]).replace("{{line}}", srcNode.line + 1) + "\">[src]</a>"; | |
| 2289 | 2332 | } |
| 2290 | 2333 | |
| 2291 | 2334 | function renderContainer(container) { |
| ... | ... | @@ -2393,24 +2436,26 @@ var zigAnalysis; |
| 2393 | 2436 | resizeDomList( |
| 2394 | 2437 | domListFns, |
| 2395 | 2438 | fnsList.length, |
| 2396 | "<div><dt></dt><dd></dd></div>" | |
| 2439 | "<div><dt><div class=\"fnSignature\"></div><div></div></dt><dd></dd></div>" | |
| 2397 | 2440 | ); |
| 2398 | 2441 | |
| 2399 | 2442 | for (let i = 0; i < fnsList.length; i += 1) { |
| 2400 | 2443 | let decl = fnsList[i]; |
| 2401 | 2444 | let trDom = domListFns.children[i]; |
| 2402 | 2445 | |
| 2403 | let tdFnCode = trDom.children[0]; | |
| 2446 | let tdFnSignature = trDom.children[0].children[0]; | |
| 2447 | let tdFnSrc = trDom.children[0].children[1]; | |
| 2404 | 2448 | let tdDesc = trDom.children[1]; |
| 2405 | 2449 | |
| 2406 | 2450 | let declType = resolveValue(decl.value); |
| 2407 | 2451 | console.assert("type" in declType.expr); |
| 2408 | tdFnCode.innerHTML = exprName(declType.expr, { | |
| 2452 | tdFnSignature.innerHTML = exprName(declType.expr, { | |
| 2409 | 2453 | wantHtml: true, |
| 2410 | 2454 | wantLink: true, |
| 2411 | 2455 | fnDecl: decl, |
| 2412 | 2456 | linkFnNameDecl: navLinkDecl(decl.name), |
| 2413 | }) + renderSourceFileLink(decl); | |
| 2457 | }); | |
| 2458 | tdFnSrc.innerHTML = renderSourceFileLink(decl); | |
| 2414 | 2459 | |
| 2415 | 2460 | let docs = zigAnalysis.astNodes[decl.src].docs; |
| 2416 | 2461 | if (docs != null) { |
lib/std/Thread.zig+2-5| ... | ... | @@ -769,16 +769,13 @@ const LinuxThreadImpl = struct { |
| 769 | 769 | ), |
| 770 | 770 | .x86_64 => asm volatile ( |
| 771 | 771 | \\ movq $11, %%rax |
| 772 | \\ movq %[ptr], %%rbx | |
| 773 | \\ movq %[len], %%rcx | |
| 774 | 772 | \\ syscall |
| 775 | 773 | \\ movq $60, %%rax |
| 776 | 774 | \\ movq $1, %%rdi |
| 777 | 775 | \\ syscall |
| 778 | 776 | : |
| 779 | : [ptr] "r" (@ptrToInt(self.mapped.ptr)), | |
| 780 | [len] "r" (self.mapped.len), | |
| 781 | : "memory" | |
| 777 | : [ptr] "{rdi}" (@ptrToInt(self.mapped.ptr)), | |
| 778 | [len] "{rsi}" (self.mapped.len), | |
| 782 | 779 | ), |
| 783 | 780 | .arm, .armeb, .thumb, .thumbeb => asm volatile ( |
| 784 | 781 | \\ mov r7, #91 |
lib/std/coff.zig+85| ... | ... | @@ -419,6 +419,91 @@ pub const DebugType = enum(u32) { |
| 419 | 419 | EX_DLLCHARACTERISTICS = 20, |
| 420 | 420 | }; |
| 421 | 421 | |
| 422 | pub const ImportDirectoryEntry = extern struct { | |
| 423 | /// The RVA of the import lookup table. | |
| 424 | /// This table contains a name or ordinal for each import. | |
| 425 | /// (The name "Characteristics" is used in Winnt.h, but no longer describes this field.) | |
| 426 | import_lookup_table_rva: u32, | |
| 427 | ||
| 428 | /// The stamp that is set to zero until the image is bound. | |
| 429 | /// After the image is bound, this field is set to the time/data stamp of the DLL. | |
| 430 | time_date_stamp: u32, | |
| 431 | ||
| 432 | /// The index of the first forwarder reference. | |
| 433 | forwarder_chain: u32, | |
| 434 | ||
| 435 | /// The address of an ASCII string that contains the name of the DLL. | |
| 436 | /// This address is relative to the image base. | |
| 437 | name_rva: u32, | |
| 438 | ||
| 439 | /// The RVA of the import address table. | |
| 440 | /// The contents of this table are identical to the contents of the import lookup table until the image is bound. | |
| 441 | import_address_table_rva: u32, | |
| 442 | }; | |
| 443 | ||
| 444 | pub const ImportLookupEntry32 = struct { | |
| 445 | pub const ByName = packed struct { | |
| 446 | name_table_rva: u31, | |
| 447 | flag: u1 = 0, | |
| 448 | }; | |
| 449 | ||
| 450 | pub const ByOrdinal = packed struct { | |
| 451 | ordinal_number: u16, | |
| 452 | unused: u15 = 0, | |
| 453 | flag: u1 = 1, | |
| 454 | }; | |
| 455 | ||
| 456 | const mask = 0x80000000; | |
| 457 | ||
| 458 | pub fn getImportByName(raw: u32) ?ByName { | |
| 459 | if (mask & raw != 0) return null; | |
| 460 | return @bitCast(ByName, raw); | |
| 461 | } | |
| 462 | ||
| 463 | pub fn getImportByOrdinal(raw: u32) ?ByOrdinal { | |
| 464 | if (mask & raw == 0) return null; | |
| 465 | return @bitCast(ByOrdinal, raw); | |
| 466 | } | |
| 467 | }; | |
| 468 | ||
| 469 | pub const ImportLookupEntry64 = struct { | |
| 470 | pub const ByName = packed struct { | |
| 471 | name_table_rva: u31, | |
| 472 | unused: u32 = 0, | |
| 473 | flag: u1 = 0, | |
| 474 | }; | |
| 475 | ||
| 476 | pub const ByOrdinal = packed struct { | |
| 477 | ordinal_number: u16, | |
| 478 | unused: u47 = 0, | |
| 479 | flag: u1 = 1, | |
| 480 | }; | |
| 481 | ||
| 482 | const mask = 0x8000000000000000; | |
| 483 | ||
| 484 | pub fn getImportByName(raw: u64) ?ByName { | |
| 485 | if (mask & raw != 0) return null; | |
| 486 | return @bitCast(ByName, raw); | |
| 487 | } | |
| 488 | ||
| 489 | pub fn getImportByOrdinal(raw: u64) ?ByOrdinal { | |
| 490 | if (mask & raw == 0) return null; | |
| 491 | return @bitCast(ByOrdinal, raw); | |
| 492 | } | |
| 493 | }; | |
| 494 | ||
| 495 | /// Every name ends with a NULL byte. IF the NULL byte does not fall on | |
| 496 | /// 2byte boundary, the entry structure is padded to ensure 2byte alignment. | |
| 497 | pub const ImportHintNameEntry = extern struct { | |
| 498 | /// An index into the export name pointer table. | |
| 499 | /// A match is attempted first with this value. If it fails, a binary search is performed on the DLL's export name pointer table. | |
| 500 | hint: u16, | |
| 501 | ||
| 502 | /// Pointer to NULL terminated ASCII name. | |
| 503 | /// Variable length... | |
| 504 | name: [1]u8, | |
| 505 | }; | |
| 506 | ||
| 422 | 507 | pub const SectionHeader = extern struct { |
| 423 | 508 | name: [8]u8, |
| 424 | 509 | virtual_size: u32, |
lib/std/log.zig+1-1| ... | ... | @@ -38,7 +38,7 @@ |
| 38 | 38 | //! return, |
| 39 | 39 | //! } ++ "): "; |
| 40 | 40 | //! |
| 41 | //! const prefix = "[" ++ level.asText() ++ "] " ++ scope_prefix; | |
| 41 | //! const prefix = "[" ++ comptime level.asText() ++ "] " ++ scope_prefix; | |
| 42 | 42 | //! |
| 43 | 43 | //! // Print the message to stderr, silently ignoring any errors |
| 44 | 44 | //! std.debug.getStderrMutex().lock(); |
lib/std/math/big/rational.zig+14-2| ... | ... | @@ -334,13 +334,13 @@ pub const Rational = struct { |
| 334 | 334 | /// Returns math.Order.lt, math.Order.eq, math.Order.gt if a < b, a == b or a |
| 335 | 335 | /// > b respectively. |
| 336 | 336 | pub fn order(a: Rational, b: Rational) !math.Order { |
| 337 | return cmpInternal(a, b, true); | |
| 337 | return cmpInternal(a, b, false); | |
| 338 | 338 | } |
| 339 | 339 | |
| 340 | 340 | /// Returns math.Order.lt, math.Order.eq, math.Order.gt if |a| < |b|, |a| == |
| 341 | 341 | /// |b| or |a| > |b| respectively. |
| 342 | 342 | pub fn orderAbs(a: Rational, b: Rational) !math.Order { |
| 343 | return cmpInternal(a, b, false); | |
| 343 | return cmpInternal(a, b, true); | |
| 344 | 344 | } |
| 345 | 345 | |
| 346 | 346 | // p/q > x/y iff p*y > x*q |
| ... | ... | @@ -704,6 +704,18 @@ test "big.rational order" { |
| 704 | 704 | try testing.expect((try a.order(b)) == .eq); |
| 705 | 705 | } |
| 706 | 706 | |
| 707 | test "big.rational order/orderAbs with negative" { | |
| 708 | var a = try Rational.init(testing.allocator); | |
| 709 | defer a.deinit(); | |
| 710 | var b = try Rational.init(testing.allocator); | |
| 711 | defer b.deinit(); | |
| 712 | ||
| 713 | try a.setRatio(1, 1); | |
| 714 | try b.setRatio(-2, 1); | |
| 715 | try testing.expect((try a.order(b)) == .gt); | |
| 716 | try testing.expect((try a.orderAbs(b)) == .lt); | |
| 717 | } | |
| 718 | ||
| 707 | 719 | test "big.rational add single-limb" { |
| 708 | 720 | var a = try Rational.init(testing.allocator); |
| 709 | 721 | defer a.deinit(); |
lib/std/os.zig+4| ... | ... | @@ -3447,6 +3447,9 @@ pub const BindError = error{ |
| 3447 | 3447 | /// A nonexistent interface was requested or the requested address was not local. |
| 3448 | 3448 | AddressNotAvailable, |
| 3449 | 3449 | |
| 3450 | /// The address is not valid for the address family of socket. | |
| 3451 | AddressFamilyNotSupported, | |
| 3452 | ||
| 3450 | 3453 | /// Too many symbolic links were encountered in resolving addr. |
| 3451 | 3454 | SymLinkLoop, |
| 3452 | 3455 | |
| ... | ... | @@ -3502,6 +3505,7 @@ pub fn bind(sock: socket_t, addr: *const sockaddr, len: socklen_t) BindError!voi |
| 3502 | 3505 | .BADF => unreachable, // always a race condition if this error is returned |
| 3503 | 3506 | .INVAL => unreachable, // invalid parameters |
| 3504 | 3507 | .NOTSOCK => unreachable, // invalid `sockfd` |
| 3508 | .AFNOSUPPORT => return error.AddressFamilyNotSupported, | |
| 3505 | 3509 | .ADDRNOTAVAIL => return error.AddressNotAvailable, |
| 3506 | 3510 | .FAULT => unreachable, // invalid `addr` pointer |
| 3507 | 3511 | .LOOP => return error.SymLinkLoop, |
lib/std/zig/c_translation.zig+1-1| ... | ... | @@ -268,7 +268,7 @@ test "sizeof" { |
| 268 | 268 | pub const CIntLiteralRadix = enum { decimal, octal, hexadecimal }; |
| 269 | 269 | |
| 270 | 270 | fn PromoteIntLiteralReturnType(comptime SuffixType: type, comptime number: comptime_int, comptime radix: CIntLiteralRadix) type { |
| 271 | const signed_decimal = [_]type{ c_int, c_long, c_longlong }; | |
| 271 | const signed_decimal = [_]type{ c_int, c_long, c_longlong, c_ulonglong }; | |
| 272 | 272 | const signed_oct_hex = [_]type{ c_int, c_uint, c_long, c_ulong, c_longlong, c_ulonglong }; |
| 273 | 273 | const unsigned = [_]type{ c_uint, c_ulong, c_ulonglong }; |
| 274 | 274 |
lib/std/zig/parser_test.zig+37| ... | ... | @@ -16,6 +16,28 @@ test "zig fmt: preserves clobbers in inline asm with stray comma" { |
| 16 | 16 | ); |
| 17 | 17 | } |
| 18 | 18 | |
| 19 | test "zig fmt: remove trailing comma at the end of assembly clobber" { | |
| 20 | try testTransform( | |
| 21 | \\fn foo() void { | |
| 22 | \\ asm volatile ("" | |
| 23 | \\ : [_] "" (-> type), | |
| 24 | \\ : | |
| 25 | \\ : "clobber1", "clobber2", | |
| 26 | \\ ); | |
| 27 | \\} | |
| 28 | \\ | |
| 29 | , | |
| 30 | \\fn foo() void { | |
| 31 | \\ asm volatile ("" | |
| 32 | \\ : [_] "" (-> type), | |
| 33 | \\ : | |
| 34 | \\ : "clobber1", "clobber2" | |
| 35 | \\ ); | |
| 36 | \\} | |
| 37 | \\ | |
| 38 | ); | |
| 39 | } | |
| 40 | ||
| 19 | 41 | test "zig fmt: respect line breaks in struct field value declaration" { |
| 20 | 42 | try testCanonical( |
| 21 | 43 | \\const Foo = struct { |
| ... | ... | @@ -5035,6 +5057,21 @@ test "zig fmt: make single-line if no trailing comma" { |
| 5035 | 5057 | ); |
| 5036 | 5058 | } |
| 5037 | 5059 | |
| 5060 | test "zig fmt: preserve container doc comment in container without trailing comma" { | |
| 5061 | try testTransform( | |
| 5062 | \\const A = enum(u32) { | |
| 5063 | \\//! comment | |
| 5064 | \\_ }; | |
| 5065 | \\ | |
| 5066 | , | |
| 5067 | \\const A = enum(u32) { | |
| 5068 | \\ //! comment | |
| 5069 | \\ _, | |
| 5070 | \\}; | |
| 5071 | \\ | |
| 5072 | ); | |
| 5073 | } | |
| 5074 | ||
| 5038 | 5075 | test "zig fmt: make single-line if no trailing comma" { |
| 5039 | 5076 | try testCanonical( |
| 5040 | 5077 | \\// Test trailing comma syntax |
lib/std/zig/render.zig+19-6| ... | ... | @@ -1933,12 +1933,15 @@ fn renderContainerDecl( |
| 1933 | 1933 | break :one_line; |
| 1934 | 1934 | } |
| 1935 | 1935 | |
| 1936 | // 2. A member of the container has a doc comment. | |
| 1936 | // 2. The container has a container comment. | |
| 1937 | if (token_tags[lbrace + 1] == .container_doc_comment) break :one_line; | |
| 1938 | ||
| 1939 | // 3. A member of the container has a doc comment. | |
| 1937 | 1940 | for (token_tags[lbrace + 1 .. rbrace - 1]) |tag| { |
| 1938 | 1941 | if (tag == .doc_comment) break :one_line; |
| 1939 | 1942 | } |
| 1940 | 1943 | |
| 1941 | // 3. The container has non-field members. | |
| 1944 | // 4. The container has non-field members. | |
| 1942 | 1945 | for (container_decl.ast.members) |member| { |
| 1943 | 1946 | if (!node_tags[member].isContainerField()) break :one_line; |
| 1944 | 1947 | } |
| ... | ... | @@ -2114,9 +2117,19 @@ fn renderAsm( |
| 2114 | 2117 | return renderToken(ais, tree, tok_i + 1, space); |
| 2115 | 2118 | }, |
| 2116 | 2119 | .comma => { |
| 2117 | try renderToken(ais, tree, tok_i, .none); | |
| 2118 | try renderToken(ais, tree, tok_i + 1, .space); | |
| 2119 | tok_i += 2; | |
| 2120 | switch (token_tags[tok_i + 2]) { | |
| 2121 | .r_paren => { | |
| 2122 | ais.setIndentDelta(indent_delta); | |
| 2123 | ais.popIndent(); | |
| 2124 | try renderToken(ais, tree, tok_i, .newline); | |
| 2125 | return renderToken(ais, tree, tok_i + 2, space); | |
| 2126 | }, | |
| 2127 | else => { | |
| 2128 | try renderToken(ais, tree, tok_i, .none); | |
| 2129 | try renderToken(ais, tree, tok_i + 1, .space); | |
| 2130 | tok_i += 2; | |
| 2131 | }, | |
| 2132 | } | |
| 2120 | 2133 | }, |
| 2121 | 2134 | else => unreachable, |
| 2122 | 2135 | } |
| ... | ... | @@ -2348,7 +2361,7 @@ fn renderSpace(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, lexeme_len: us |
| 2348 | 2361 | } |
| 2349 | 2362 | } |
| 2350 | 2363 | |
| 2351 | /// Returns true if there exists a comment between any of the tokens from | |
| 2364 | /// Returns true if there exists a line comment between any of the tokens from | |
| 2352 | 2365 | /// `start_token` to `end_token`. This is used to determine if e.g. a |
| 2353 | 2366 | /// fn_proto should be wrapped and have a trailing comma inserted even if |
| 2354 | 2367 | /// there is none in the source. |
src/AstGen.zig+1-1| ... | ... | @@ -5127,7 +5127,7 @@ fn tryExpr( |
| 5127 | 5127 | else => .none, |
| 5128 | 5128 | }; |
| 5129 | 5129 | // This could be a pointer or value depending on the `rl` parameter. |
| 5130 | const operand = try expr(parent_gz, scope, operand_rl, operand_node); | |
| 5130 | const operand = try reachableExpr(parent_gz, scope, operand_rl, operand_node, node); | |
| 5131 | 5131 | const is_inline = parent_gz.force_comptime; |
| 5132 | 5132 | const is_inline_bit = @as(u2, @boolToInt(is_inline)); |
| 5133 | 5133 | const is_ptr_bit = @as(u2, @boolToInt(operand_rl == .ref)) << 1; |
src/Autodoc.zig+384-230| ... | ... | @@ -1,6 +1,7 @@ |
| 1 | 1 | const builtin = @import("builtin"); |
| 2 | 2 | const std = @import("std"); |
| 3 | 3 | const build_options = @import("build_options"); |
| 4 | const Ast = std.zig.Ast; | |
| 4 | 5 | const Autodoc = @This(); |
| 5 | 6 | const Compilation = @import("Compilation.zig"); |
| 6 | 7 | const Module = @import("Module.zig"); |
| ... | ... | @@ -47,6 +48,19 @@ const RefPathResumeInfo = struct { |
| 47 | 48 | ref_path: []DocData.Expr, |
| 48 | 49 | }; |
| 49 | 50 | |
| 51 | /// Used to accumulate src_node offsets. | |
| 52 | /// In ZIR, all ast node indices are relative to the parent decl. | |
| 53 | /// More concretely, `union_decl`, `struct_decl`, `enum_decl` and `opaque_decl` | |
| 54 | /// and the value of each of their decls participate in the relative offset | |
| 55 | /// counting, and nothing else. | |
| 56 | /// We keep track of the line and byte values for these instructions in order | |
| 57 | /// to avoid tokenizing every file (on new lines) from the start every time. | |
| 58 | const SrcLocInfo = struct { | |
| 59 | bytes: u32 = 0, | |
| 60 | line: usize = 0, | |
| 61 | src_node: u32 = 0, | |
| 62 | }; | |
| 63 | ||
| 50 | 64 | var arena_allocator: std.heap.ArenaAllocator = undefined; |
| 51 | 65 | pub fn init(m: *Module, doc_location: Compilation.EmitLoc) Autodoc { |
| 52 | 66 | arena_allocator = std.heap.ArenaAllocator.init(m.gpa); |
| ... | ... | @@ -202,7 +216,7 @@ pub fn generateZirData(self: *Autodoc) !void { |
| 202 | 216 | |
| 203 | 217 | try self.ast_nodes.append(self.arena, .{ .name = "(root)" }); |
| 204 | 218 | try self.files.put(self.arena, file, main_type_index); |
| 205 | _ = try self.walkInstruction(file, &root_scope, 1, Zir.main_struct_inst, false); | |
| 219 | _ = try self.walkInstruction(file, &root_scope, .{}, Zir.main_struct_inst, false); | |
| 206 | 220 | |
| 207 | 221 | if (self.ref_paths_pending_on_decls.count() > 0) { |
| 208 | 222 | @panic("some decl paths were never fully analized (pending on decls)"); |
| ... | ... | @@ -467,6 +481,7 @@ const DocData = struct { |
| 467 | 481 | line: usize = 0, |
| 468 | 482 | col: usize = 0, |
| 469 | 483 | name: ?[]const u8 = null, |
| 484 | code: ?[]const u8 = null, | |
| 470 | 485 | docs: ?[]const u8 = null, |
| 471 | 486 | fields: ?[]usize = null, // index into astNodes |
| 472 | 487 | @"comptime": bool = false, |
| ... | ... | @@ -562,7 +577,13 @@ const DocData = struct { |
| 562 | 577 | is_extern: bool = false, |
| 563 | 578 | }, |
| 564 | 579 | BoundFn: struct { name: []const u8 }, |
| 565 | Opaque: struct { name: []const u8 }, | |
| 580 | Opaque: struct { | |
| 581 | name: []const u8, | |
| 582 | src: usize, // index into astNodes | |
| 583 | privDecls: []usize = &.{}, // index into decls | |
| 584 | pubDecls: []usize = &.{}, // index into decls | |
| 585 | ast: usize, | |
| 586 | }, | |
| 566 | 587 | Frame: struct { name: []const u8 }, |
| 567 | 588 | AnyFrame: struct { name: []const u8 }, |
| 568 | 589 | Vector: struct { name: []const u8 }, |
| ... | ... | @@ -625,7 +646,7 @@ const DocData = struct { |
| 625 | 646 | negated: bool = false, |
| 626 | 647 | }, |
| 627 | 648 | int_big: struct { |
| 628 | value: []const u8, // direct value | |
| 649 | value: []const u8, // string representation | |
| 629 | 650 | negated: bool = false, |
| 630 | 651 | }, |
| 631 | 652 | float: f64, // direct value |
| ... | ... | @@ -712,12 +733,6 @@ const DocData = struct { |
| 712 | 733 | if (self.int.negated) try w.writeAll("-"); |
| 713 | 734 | try jsw.emitNumber(self.int.value); |
| 714 | 735 | }, |
| 715 | .int_big => { | |
| 716 | ||
| 717 | //@panic("TODO: json serialization of big ints!"); | |
| 718 | //if (v.negated) try w.writeAll("-"); | |
| 719 | //try jsw.emitNumber(v.value); | |
| 720 | }, | |
| 721 | 736 | .builtinField => { |
| 722 | 737 | try jsw.emitString(@tagName(self.builtinField)); |
| 723 | 738 | }, |
| ... | ... | @@ -758,8 +773,8 @@ const DocData = struct { |
| 758 | 773 | const AutodocErrors = error{ |
| 759 | 774 | OutOfMemory, |
| 760 | 775 | CurrentWorkingDirectoryUnlinked, |
| 761 | Unexpected, | |
| 762 | }; | |
| 776 | UnexpectedEndOfFile, | |
| 777 | } || std.fs.File.OpenError || std.fs.File.ReadError; | |
| 763 | 778 | |
| 764 | 779 | /// Called when we need to analyze a Zir instruction. |
| 765 | 780 | /// For example it gets called by `generateZirData` on instruction 0, |
| ... | ... | @@ -773,7 +788,7 @@ fn walkInstruction( |
| 773 | 788 | self: *Autodoc, |
| 774 | 789 | file: *File, |
| 775 | 790 | parent_scope: *Scope, |
| 776 | parent_line: usize, | |
| 791 | parent_src: SrcLocInfo, | |
| 777 | 792 | inst_index: usize, |
| 778 | 793 | need_type: bool, // true if the caller needs us to provide also a typeRef |
| 779 | 794 | ) AutodocErrors!DocData.WalkResult { |
| ... | ... | @@ -865,7 +880,7 @@ fn walkInstruction( |
| 865 | 880 | return self.walkInstruction( |
| 866 | 881 | new_file, |
| 867 | 882 | &root_scope, |
| 868 | 1, | |
| 883 | .{}, | |
| 869 | 884 | Zir.main_struct_inst, |
| 870 | 885 | false, |
| 871 | 886 | ); |
| ... | ... | @@ -890,14 +905,14 @@ fn walkInstruction( |
| 890 | 905 | return self.walkInstruction( |
| 891 | 906 | new_file.file, |
| 892 | 907 | &new_scope, |
| 893 | 1, | |
| 908 | .{}, | |
| 894 | 909 | Zir.main_struct_inst, |
| 895 | 910 | need_type, |
| 896 | 911 | ); |
| 897 | 912 | }, |
| 898 | 913 | .ret_node => { |
| 899 | 914 | const un_node = data[inst_index].un_node; |
| 900 | return self.walkRef(file, parent_scope, parent_line, un_node.operand, false); | |
| 915 | return self.walkRef(file, parent_scope, parent_src, un_node.operand, false); | |
| 901 | 916 | }, |
| 902 | 917 | .ret_load => { |
| 903 | 918 | const un_node = data[inst_index].un_node; |
| ... | ... | @@ -928,7 +943,7 @@ fn walkInstruction( |
| 928 | 943 | } |
| 929 | 944 | |
| 930 | 945 | if (result_ref) |rr| { |
| 931 | return self.walkRef(file, parent_scope, parent_line, rr, need_type); | |
| 946 | return self.walkRef(file, parent_scope, parent_src, rr, need_type); | |
| 932 | 947 | } |
| 933 | 948 | |
| 934 | 949 | return DocData.WalkResult{ |
| ... | ... | @@ -937,11 +952,11 @@ fn walkInstruction( |
| 937 | 952 | }, |
| 938 | 953 | .closure_get => { |
| 939 | 954 | const inst_node = data[inst_index].inst_node; |
| 940 | return try self.walkInstruction(file, parent_scope, parent_line, inst_node.inst, need_type); | |
| 955 | return try self.walkInstruction(file, parent_scope, parent_src, inst_node.inst, need_type); | |
| 941 | 956 | }, |
| 942 | 957 | .closure_capture => { |
| 943 | 958 | const un_tok = data[inst_index].un_tok; |
| 944 | return try self.walkRef(file, parent_scope, parent_line, un_tok.operand, need_type); | |
| 959 | return try self.walkRef(file, parent_scope, parent_src, un_tok.operand, need_type); | |
| 945 | 960 | }, |
| 946 | 961 | .cmpxchg_strong, .cmpxchg_weak => { |
| 947 | 962 | const pl_node = data[inst_index].pl_node; |
| ... | ... | @@ -956,7 +971,7 @@ fn walkInstruction( |
| 956 | 971 | var ptr: DocData.WalkResult = try self.walkRef( |
| 957 | 972 | file, |
| 958 | 973 | parent_scope, |
| 959 | parent_line, | |
| 974 | parent_src, | |
| 960 | 975 | extra.data.ptr, |
| 961 | 976 | false, |
| 962 | 977 | ); |
| ... | ... | @@ -966,7 +981,7 @@ fn walkInstruction( |
| 966 | 981 | var expected_value: DocData.WalkResult = try self.walkRef( |
| 967 | 982 | file, |
| 968 | 983 | parent_scope, |
| 969 | parent_line, | |
| 984 | parent_src, | |
| 970 | 985 | extra.data.expected_value, |
| 971 | 986 | false, |
| 972 | 987 | ); |
| ... | ... | @@ -976,7 +991,7 @@ fn walkInstruction( |
| 976 | 991 | var new_value: DocData.WalkResult = try self.walkRef( |
| 977 | 992 | file, |
| 978 | 993 | parent_scope, |
| 979 | parent_line, | |
| 994 | parent_src, | |
| 980 | 995 | extra.data.new_value, |
| 981 | 996 | false, |
| 982 | 997 | ); |
| ... | ... | @@ -986,7 +1001,7 @@ fn walkInstruction( |
| 986 | 1001 | var success_order: DocData.WalkResult = try self.walkRef( |
| 987 | 1002 | file, |
| 988 | 1003 | parent_scope, |
| 989 | parent_line, | |
| 1004 | parent_src, | |
| 990 | 1005 | extra.data.success_order, |
| 991 | 1006 | false, |
| 992 | 1007 | ); |
| ... | ... | @@ -996,7 +1011,7 @@ fn walkInstruction( |
| 996 | 1011 | var failure_order: DocData.WalkResult = try self.walkRef( |
| 997 | 1012 | file, |
| 998 | 1013 | parent_scope, |
| 999 | parent_line, | |
| 1014 | parent_src, | |
| 1000 | 1015 | extra.data.failure_order, |
| 1001 | 1016 | false, |
| 1002 | 1017 | ); |
| ... | ... | @@ -1047,10 +1062,11 @@ fn walkInstruction( |
| 1047 | 1062 | }, |
| 1048 | 1063 | .compile_error => { |
| 1049 | 1064 | const un_node = data[inst_index].un_node; |
| 1065 | ||
| 1050 | 1066 | var operand: DocData.WalkResult = try self.walkRef( |
| 1051 | 1067 | file, |
| 1052 | 1068 | parent_scope, |
| 1053 | parent_line, | |
| 1069 | parent_src, | |
| 1054 | 1070 | un_node.operand, |
| 1055 | 1071 | false, |
| 1056 | 1072 | ); |
| ... | ... | @@ -1084,15 +1100,24 @@ fn walkInstruction( |
| 1084 | 1100 | }, |
| 1085 | 1101 | .int_big => { |
| 1086 | 1102 | // @check |
| 1087 | const str = data[inst_index].str.get(file.zir); | |
| 1088 | _ = str; | |
| 1089 | printWithContext( | |
| 1090 | file, | |
| 1091 | inst_index, | |
| 1092 | "TODO: implement `{s}` for walkInstruction\n\n", | |
| 1093 | .{@tagName(tags[inst_index])}, | |
| 1094 | ); | |
| 1095 | return self.cteTodo(@tagName(tags[inst_index])); | |
| 1103 | const str = data[inst_index].str; //.get(file.zir); | |
| 1104 | const byte_count = str.len * @sizeOf(std.math.big.Limb); | |
| 1105 | const limb_bytes = file.zir.string_bytes[str.start..][0..byte_count]; | |
| 1106 | ||
| 1107 | var limbs = try self.arena.alloc(std.math.big.Limb, str.len); | |
| 1108 | std.mem.copy(u8, std.mem.sliceAsBytes(limbs), limb_bytes); | |
| 1109 | ||
| 1110 | const big_int = std.math.big.int.Const{ | |
| 1111 | .limbs = limbs, | |
| 1112 | .positive = true, | |
| 1113 | }; | |
| 1114 | ||
| 1115 | const as_string = try big_int.toStringAlloc(self.arena, 10, .lower); | |
| 1116 | ||
| 1117 | return DocData.WalkResult{ | |
| 1118 | .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) }, | |
| 1119 | .expr = .{ .int_big = .{ .value = as_string } }, | |
| 1120 | }; | |
| 1096 | 1121 | }, |
| 1097 | 1122 | |
| 1098 | 1123 | .slice_start => { |
| ... | ... | @@ -1105,14 +1130,14 @@ fn walkInstruction( |
| 1105 | 1130 | var lhs: DocData.WalkResult = try self.walkRef( |
| 1106 | 1131 | file, |
| 1107 | 1132 | parent_scope, |
| 1108 | parent_line, | |
| 1133 | parent_src, | |
| 1109 | 1134 | extra.data.lhs, |
| 1110 | 1135 | false, |
| 1111 | 1136 | ); |
| 1112 | 1137 | var start: DocData.WalkResult = try self.walkRef( |
| 1113 | 1138 | file, |
| 1114 | 1139 | parent_scope, |
| 1115 | parent_line, | |
| 1140 | parent_src, | |
| 1116 | 1141 | extra.data.start, |
| 1117 | 1142 | false, |
| 1118 | 1143 | ); |
| ... | ... | @@ -1138,21 +1163,21 @@ fn walkInstruction( |
| 1138 | 1163 | var lhs: DocData.WalkResult = try self.walkRef( |
| 1139 | 1164 | file, |
| 1140 | 1165 | parent_scope, |
| 1141 | parent_line, | |
| 1166 | parent_src, | |
| 1142 | 1167 | extra.data.lhs, |
| 1143 | 1168 | false, |
| 1144 | 1169 | ); |
| 1145 | 1170 | var start: DocData.WalkResult = try self.walkRef( |
| 1146 | 1171 | file, |
| 1147 | 1172 | parent_scope, |
| 1148 | parent_line, | |
| 1173 | parent_src, | |
| 1149 | 1174 | extra.data.start, |
| 1150 | 1175 | false, |
| 1151 | 1176 | ); |
| 1152 | 1177 | var end: DocData.WalkResult = try self.walkRef( |
| 1153 | 1178 | file, |
| 1154 | 1179 | parent_scope, |
| 1155 | parent_line, | |
| 1180 | parent_src, | |
| 1156 | 1181 | extra.data.end, |
| 1157 | 1182 | false, |
| 1158 | 1183 | ); |
| ... | ... | @@ -1180,28 +1205,28 @@ fn walkInstruction( |
| 1180 | 1205 | var lhs: DocData.WalkResult = try self.walkRef( |
| 1181 | 1206 | file, |
| 1182 | 1207 | parent_scope, |
| 1183 | parent_line, | |
| 1208 | parent_src, | |
| 1184 | 1209 | extra.data.lhs, |
| 1185 | 1210 | false, |
| 1186 | 1211 | ); |
| 1187 | 1212 | var start: DocData.WalkResult = try self.walkRef( |
| 1188 | 1213 | file, |
| 1189 | 1214 | parent_scope, |
| 1190 | parent_line, | |
| 1215 | parent_src, | |
| 1191 | 1216 | extra.data.start, |
| 1192 | 1217 | false, |
| 1193 | 1218 | ); |
| 1194 | 1219 | var end: DocData.WalkResult = try self.walkRef( |
| 1195 | 1220 | file, |
| 1196 | 1221 | parent_scope, |
| 1197 | parent_line, | |
| 1222 | parent_src, | |
| 1198 | 1223 | extra.data.end, |
| 1199 | 1224 | false, |
| 1200 | 1225 | ); |
| 1201 | 1226 | var sentinel: DocData.WalkResult = try self.walkRef( |
| 1202 | 1227 | file, |
| 1203 | 1228 | parent_scope, |
| 1204 | parent_line, | |
| 1229 | parent_src, | |
| 1205 | 1230 | extra.data.sentinel, |
| 1206 | 1231 | false, |
| 1207 | 1232 | ); |
| ... | ... | @@ -1251,14 +1276,14 @@ fn walkInstruction( |
| 1251 | 1276 | var lhs: DocData.WalkResult = try self.walkRef( |
| 1252 | 1277 | file, |
| 1253 | 1278 | parent_scope, |
| 1254 | parent_line, | |
| 1279 | parent_src, | |
| 1255 | 1280 | extra.data.lhs, |
| 1256 | 1281 | false, |
| 1257 | 1282 | ); |
| 1258 | 1283 | var rhs: DocData.WalkResult = try self.walkRef( |
| 1259 | 1284 | file, |
| 1260 | 1285 | parent_scope, |
| 1261 | parent_line, | |
| 1286 | parent_src, | |
| 1262 | 1287 | extra.data.rhs, |
| 1263 | 1288 | false, |
| 1264 | 1289 | ); |
| ... | ... | @@ -1278,6 +1303,50 @@ fn walkInstruction( |
| 1278 | 1303 | .expr = .{ .binOpIndex = binop_index }, |
| 1279 | 1304 | }; |
| 1280 | 1305 | }, |
| 1306 | // compare operators | |
| 1307 | .cmp_eq, | |
| 1308 | .cmp_neq, | |
| 1309 | .cmp_gt, | |
| 1310 | .cmp_gte, | |
| 1311 | .cmp_lt, | |
| 1312 | .cmp_lte, | |
| 1313 | => { | |
| 1314 | const pl_node = data[inst_index].pl_node; | |
| 1315 | const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index); | |
| 1316 | ||
| 1317 | const binop_index = self.exprs.items.len; | |
| 1318 | try self.exprs.append(self.arena, .{ .binOp = .{ .lhs = 0, .rhs = 0 } }); | |
| 1319 | ||
| 1320 | var lhs: DocData.WalkResult = try self.walkRef( | |
| 1321 | file, | |
| 1322 | parent_scope, | |
| 1323 | parent_src, | |
| 1324 | extra.data.lhs, | |
| 1325 | false, | |
| 1326 | ); | |
| 1327 | var rhs: DocData.WalkResult = try self.walkRef( | |
| 1328 | file, | |
| 1329 | parent_scope, | |
| 1330 | parent_src, | |
| 1331 | extra.data.rhs, | |
| 1332 | false, | |
| 1333 | ); | |
| 1334 | ||
| 1335 | const lhs_index = self.exprs.items.len; | |
| 1336 | try self.exprs.append(self.arena, lhs.expr); | |
| 1337 | const rhs_index = self.exprs.items.len; | |
| 1338 | try self.exprs.append(self.arena, rhs.expr); | |
| 1339 | self.exprs.items[binop_index] = .{ .binOp = .{ | |
| 1340 | .name = @tagName(tags[inst_index]), | |
| 1341 | .lhs = lhs_index, | |
| 1342 | .rhs = rhs_index, | |
| 1343 | } }; | |
| 1344 | ||
| 1345 | return DocData.WalkResult{ | |
| 1346 | .typeRef = .{ .type = @enumToInt(Ref.bool_type) }, | |
| 1347 | .expr = .{ .binOpIndex = binop_index }, | |
| 1348 | }; | |
| 1349 | }, | |
| 1281 | 1350 | |
| 1282 | 1351 | // builtin functions |
| 1283 | 1352 | .align_of, |
| ... | ... | @@ -1319,7 +1388,7 @@ fn walkInstruction( |
| 1319 | 1388 | const un_node = data[inst_index].un_node; |
| 1320 | 1389 | const bin_index = self.exprs.items.len; |
| 1321 | 1390 | try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } }); |
| 1322 | const param = try self.walkRef(file, parent_scope, parent_line, un_node.operand, false); | |
| 1391 | const param = try self.walkRef(file, parent_scope, parent_src, un_node.operand, false); | |
| 1323 | 1392 | |
| 1324 | 1393 | const param_index = self.exprs.items.len; |
| 1325 | 1394 | try self.exprs.append(self.arena, param.expr); |
| ... | ... | @@ -1368,14 +1437,14 @@ fn walkInstruction( |
| 1368 | 1437 | var lhs: DocData.WalkResult = try self.walkRef( |
| 1369 | 1438 | file, |
| 1370 | 1439 | parent_scope, |
| 1371 | parent_line, | |
| 1440 | parent_src, | |
| 1372 | 1441 | extra.data.lhs, |
| 1373 | 1442 | false, |
| 1374 | 1443 | ); |
| 1375 | 1444 | var rhs: DocData.WalkResult = try self.walkRef( |
| 1376 | 1445 | file, |
| 1377 | 1446 | parent_scope, |
| 1378 | parent_line, | |
| 1447 | parent_src, | |
| 1379 | 1448 | extra.data.rhs, |
| 1380 | 1449 | false, |
| 1381 | 1450 | ); |
| ... | ... | @@ -1398,14 +1467,14 @@ fn walkInstruction( |
| 1398 | 1467 | var lhs: DocData.WalkResult = try self.walkRef( |
| 1399 | 1468 | file, |
| 1400 | 1469 | parent_scope, |
| 1401 | parent_line, | |
| 1470 | parent_src, | |
| 1402 | 1471 | extra.data.lhs, |
| 1403 | 1472 | false, |
| 1404 | 1473 | ); |
| 1405 | 1474 | var rhs: DocData.WalkResult = try self.walkRef( |
| 1406 | 1475 | file, |
| 1407 | 1476 | parent_scope, |
| 1408 | parent_line, | |
| 1477 | parent_src, | |
| 1409 | 1478 | extra.data.rhs, |
| 1410 | 1479 | false, |
| 1411 | 1480 | ); |
| ... | ... | @@ -1428,14 +1497,14 @@ fn walkInstruction( |
| 1428 | 1497 | var lhs: DocData.WalkResult = try self.walkRef( |
| 1429 | 1498 | file, |
| 1430 | 1499 | parent_scope, |
| 1431 | parent_line, | |
| 1500 | parent_src, | |
| 1432 | 1501 | extra.data.lhs, |
| 1433 | 1502 | false, |
| 1434 | 1503 | ); |
| 1435 | 1504 | var rhs: DocData.WalkResult = try self.walkRef( |
| 1436 | 1505 | file, |
| 1437 | 1506 | parent_scope, |
| 1438 | parent_line, | |
| 1507 | parent_src, | |
| 1439 | 1508 | extra.data.rhs, |
| 1440 | 1509 | false, |
| 1441 | 1510 | ); |
| ... | ... | @@ -1455,7 +1524,7 @@ fn walkInstruction( |
| 1455 | 1524 | |
| 1456 | 1525 | // var operand: DocData.WalkResult = try self.walkRef( |
| 1457 | 1526 | // file, |
| 1458 | // parent_scope, parent_line, | |
| 1527 | // parent_scope, parent_src, | |
| 1459 | 1528 | // un_node.operand, |
| 1460 | 1529 | // false, |
| 1461 | 1530 | // ); |
| ... | ... | @@ -1464,7 +1533,8 @@ fn walkInstruction( |
| 1464 | 1533 | // }, |
| 1465 | 1534 | .overflow_arithmetic_ptr => { |
| 1466 | 1535 | const un_node = data[inst_index].un_node; |
| 1467 | const elem_type_ref = try self.walkRef(file, parent_scope, parent_line, un_node.operand, false); | |
| 1536 | ||
| 1537 | const elem_type_ref = try self.walkRef(file, parent_scope, parent_src, un_node.operand, false); | |
| 1468 | 1538 | const type_slot_index = self.types.items.len; |
| 1469 | 1539 | try self.types.append(self.arena, .{ |
| 1470 | 1540 | .Pointer = .{ |
| ... | ... | @@ -1489,7 +1559,7 @@ fn walkInstruction( |
| 1489 | 1559 | const elem_type_ref = try self.walkRef( |
| 1490 | 1560 | file, |
| 1491 | 1561 | parent_scope, |
| 1492 | parent_line, | |
| 1562 | parent_src, | |
| 1493 | 1563 | extra.data.elem_type, |
| 1494 | 1564 | false, |
| 1495 | 1565 | ); |
| ... | ... | @@ -1499,7 +1569,7 @@ fn walkInstruction( |
| 1499 | 1569 | var sentinel: ?DocData.Expr = null; |
| 1500 | 1570 | if (ptr.flags.has_sentinel) { |
| 1501 | 1571 | const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]); |
| 1502 | const ref_result = try self.walkRef(file, parent_scope, parent_line, ref, false); | |
| 1572 | const ref_result = try self.walkRef(file, parent_scope, parent_src, ref, false); | |
| 1503 | 1573 | sentinel = ref_result.expr; |
| 1504 | 1574 | extra_index += 1; |
| 1505 | 1575 | } |
| ... | ... | @@ -1507,21 +1577,21 @@ fn walkInstruction( |
| 1507 | 1577 | var @"align": ?DocData.Expr = null; |
| 1508 | 1578 | if (ptr.flags.has_align) { |
| 1509 | 1579 | const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]); |
| 1510 | const ref_result = try self.walkRef(file, parent_scope, parent_line, ref, false); | |
| 1580 | const ref_result = try self.walkRef(file, parent_scope, parent_src, ref, false); | |
| 1511 | 1581 | @"align" = ref_result.expr; |
| 1512 | 1582 | extra_index += 1; |
| 1513 | 1583 | } |
| 1514 | 1584 | var address_space: ?DocData.Expr = null; |
| 1515 | 1585 | if (ptr.flags.has_addrspace) { |
| 1516 | 1586 | const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]); |
| 1517 | const ref_result = try self.walkRef(file, parent_scope, parent_line, ref, false); | |
| 1587 | const ref_result = try self.walkRef(file, parent_scope, parent_src, ref, false); | |
| 1518 | 1588 | address_space = ref_result.expr; |
| 1519 | 1589 | extra_index += 1; |
| 1520 | 1590 | } |
| 1521 | 1591 | var bit_start: ?DocData.Expr = null; |
| 1522 | 1592 | if (ptr.flags.has_bit_range) { |
| 1523 | 1593 | const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]); |
| 1524 | const ref_result = try self.walkRef(file, parent_scope, parent_line, ref, false); | |
| 1594 | const ref_result = try self.walkRef(file, parent_scope, parent_src, ref, false); | |
| 1525 | 1595 | address_space = ref_result.expr; |
| 1526 | 1596 | extra_index += 1; |
| 1527 | 1597 | } |
| ... | ... | @@ -1529,7 +1599,7 @@ fn walkInstruction( |
| 1529 | 1599 | var host_size: ?DocData.Expr = null; |
| 1530 | 1600 | if (ptr.flags.has_bit_range) { |
| 1531 | 1601 | const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]); |
| 1532 | const ref_result = try self.walkRef(file, parent_scope, parent_line, ref, false); | |
| 1602 | const ref_result = try self.walkRef(file, parent_scope, parent_src, ref, false); | |
| 1533 | 1603 | host_size = ref_result.expr; |
| 1534 | 1604 | } |
| 1535 | 1605 | |
| ... | ... | @@ -1558,9 +1628,10 @@ fn walkInstruction( |
| 1558 | 1628 | }, |
| 1559 | 1629 | .array_type => { |
| 1560 | 1630 | const pl_node = data[inst_index].pl_node; |
| 1631 | ||
| 1561 | 1632 | const bin = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index).data; |
| 1562 | const len = try self.walkRef(file, parent_scope, parent_line, bin.lhs, false); | |
| 1563 | const child = try self.walkRef(file, parent_scope, parent_line, bin.rhs, false); | |
| 1633 | const len = try self.walkRef(file, parent_scope, parent_src, bin.lhs, false); | |
| 1634 | const child = try self.walkRef(file, parent_scope, parent_src, bin.rhs, false); | |
| 1564 | 1635 | |
| 1565 | 1636 | const type_slot_index = self.types.items.len; |
| 1566 | 1637 | try self.types.append(self.arena, .{ |
| ... | ... | @@ -1578,9 +1649,9 @@ fn walkInstruction( |
| 1578 | 1649 | .array_type_sentinel => { |
| 1579 | 1650 | const pl_node = data[inst_index].pl_node; |
| 1580 | 1651 | const extra = file.zir.extraData(Zir.Inst.ArrayTypeSentinel, pl_node.payload_index); |
| 1581 | const len = try self.walkRef(file, parent_scope, parent_line, extra.data.len, false); | |
| 1582 | const sentinel = try self.walkRef(file, parent_scope, parent_line, extra.data.sentinel, false); | |
| 1583 | const elem_type = try self.walkRef(file, parent_scope, parent_line, extra.data.elem_type, false); | |
| 1652 | const len = try self.walkRef(file, parent_scope, parent_src, extra.data.len, false); | |
| 1653 | const sentinel = try self.walkRef(file, parent_scope, parent_src, extra.data.sentinel, false); | |
| 1654 | const elem_type = try self.walkRef(file, parent_scope, parent_src, extra.data.elem_type, false); | |
| 1584 | 1655 | |
| 1585 | 1656 | const type_slot_index = self.types.items.len; |
| 1586 | 1657 | try self.types.append(self.arena, .{ |
| ... | ... | @@ -1602,10 +1673,10 @@ fn walkInstruction( |
| 1602 | 1673 | const array_data = try self.arena.alloc(usize, operands.len - 1); |
| 1603 | 1674 | |
| 1604 | 1675 | std.debug.assert(operands.len > 0); |
| 1605 | var array_type = try self.walkRef(file, parent_scope, parent_line, operands[0], false); | |
| 1676 | var array_type = try self.walkRef(file, parent_scope, parent_src, operands[0], false); | |
| 1606 | 1677 | |
| 1607 | 1678 | for (operands[1..]) |op, idx| { |
| 1608 | const wr = try self.walkRef(file, parent_scope, parent_line, op, false); | |
| 1679 | const wr = try self.walkRef(file, parent_scope, parent_src, op, false); | |
| 1609 | 1680 | const expr_index = self.exprs.items.len; |
| 1610 | 1681 | try self.exprs.append(self.arena, wr.expr); |
| 1611 | 1682 | array_data[idx] = expr_index; |
| ... | ... | @@ -1623,7 +1694,7 @@ fn walkInstruction( |
| 1623 | 1694 | const array_data = try self.arena.alloc(usize, operands.len); |
| 1624 | 1695 | |
| 1625 | 1696 | for (operands) |op, idx| { |
| 1626 | const wr = try self.walkRef(file, parent_scope, parent_line, op, false); | |
| 1697 | const wr = try self.walkRef(file, parent_scope, parent_src, op, false); | |
| 1627 | 1698 | const expr_index = self.exprs.items.len; |
| 1628 | 1699 | try self.exprs.append(self.arena, wr.expr); |
| 1629 | 1700 | array_data[idx] = expr_index; |
| ... | ... | @@ -1641,10 +1712,10 @@ fn walkInstruction( |
| 1641 | 1712 | const array_data = try self.arena.alloc(usize, operands.len - 1); |
| 1642 | 1713 | |
| 1643 | 1714 | std.debug.assert(operands.len > 0); |
| 1644 | var array_type = try self.walkRef(file, parent_scope, parent_line, operands[0], false); | |
| 1715 | var array_type = try self.walkRef(file, parent_scope, parent_src, operands[0], false); | |
| 1645 | 1716 | |
| 1646 | 1717 | for (operands[1..]) |op, idx| { |
| 1647 | const wr = try self.walkRef(file, parent_scope, parent_line, op, false); | |
| 1718 | const wr = try self.walkRef(file, parent_scope, parent_src, op, false); | |
| 1648 | 1719 | const expr_index = self.exprs.items.len; |
| 1649 | 1720 | try self.exprs.append(self.arena, wr.expr); |
| 1650 | 1721 | array_data[idx] = expr_index; |
| ... | ... | @@ -1673,7 +1744,7 @@ fn walkInstruction( |
| 1673 | 1744 | const array_data = try self.arena.alloc(usize, operands.len); |
| 1674 | 1745 | |
| 1675 | 1746 | for (operands) |op, idx| { |
| 1676 | const wr = try self.walkRef(file, parent_scope, parent_line, op, false); | |
| 1747 | const wr = try self.walkRef(file, parent_scope, parent_src, op, false); | |
| 1677 | 1748 | const expr_index = self.exprs.items.len; |
| 1678 | 1749 | try self.exprs.append(self.arena, wr.expr); |
| 1679 | 1750 | array_data[idx] = expr_index; |
| ... | ... | @@ -1705,15 +1776,17 @@ fn walkInstruction( |
| 1705 | 1776 | }, |
| 1706 | 1777 | .negate => { |
| 1707 | 1778 | const un_node = data[inst_index].un_node; |
| 1779 | ||
| 1708 | 1780 | var operand: DocData.WalkResult = try self.walkRef( |
| 1709 | 1781 | file, |
| 1710 | 1782 | parent_scope, |
| 1711 | parent_line, | |
| 1783 | parent_src, | |
| 1712 | 1784 | un_node.operand, |
| 1713 | 1785 | need_type, |
| 1714 | 1786 | ); |
| 1715 | 1787 | switch (operand.expr) { |
| 1716 | 1788 | .int => |*int| int.negated = true, |
| 1789 | .int_big => |*int_big| int_big.negated = true, | |
| 1717 | 1790 | else => { |
| 1718 | 1791 | printWithContext( |
| 1719 | 1792 | file, |
| ... | ... | @@ -1727,10 +1800,11 @@ fn walkInstruction( |
| 1727 | 1800 | }, |
| 1728 | 1801 | .size_of => { |
| 1729 | 1802 | const un_node = data[inst_index].un_node; |
| 1803 | ||
| 1730 | 1804 | const operand = try self.walkRef( |
| 1731 | 1805 | file, |
| 1732 | 1806 | parent_scope, |
| 1733 | parent_line, | |
| 1807 | parent_src, | |
| 1734 | 1808 | un_node.operand, |
| 1735 | 1809 | false, |
| 1736 | 1810 | ); |
| ... | ... | @@ -1744,10 +1818,11 @@ fn walkInstruction( |
| 1744 | 1818 | .bit_size_of => { |
| 1745 | 1819 | // not working correctly with `align()` |
| 1746 | 1820 | const un_node = data[inst_index].un_node; |
| 1821 | ||
| 1747 | 1822 | const operand = try self.walkRef( |
| 1748 | 1823 | file, |
| 1749 | 1824 | parent_scope, |
| 1750 | parent_line, | |
| 1825 | parent_src, | |
| 1751 | 1826 | un_node.operand, |
| 1752 | 1827 | need_type, |
| 1753 | 1828 | ); |
| ... | ... | @@ -1765,7 +1840,7 @@ fn walkInstruction( |
| 1765 | 1840 | const operand = try self.walkRef( |
| 1766 | 1841 | file, |
| 1767 | 1842 | parent_scope, |
| 1768 | parent_line, | |
| 1843 | parent_src, | |
| 1769 | 1844 | un_node.operand, |
| 1770 | 1845 | false, |
| 1771 | 1846 | ); |
| ... | ... | @@ -1782,7 +1857,8 @@ fn walkInstruction( |
| 1782 | 1857 | const pl_node = data[inst_index].pl_node; |
| 1783 | 1858 | const extra = file.zir.extraData(Zir.Inst.SwitchBlock, pl_node.payload_index); |
| 1784 | 1859 | const cond_index = self.exprs.items.len; |
| 1785 | _ = try self.walkRef(file, parent_scope, parent_line, extra.data.operand, false); | |
| 1860 | ||
| 1861 | _ = try self.walkRef(file, parent_scope, parent_src, extra.data.operand, false); | |
| 1786 | 1862 | |
| 1787 | 1863 | const ast_index = self.ast_nodes.items.len; |
| 1788 | 1864 | const type_index = self.types.items.len - 1; |
| ... | ... | @@ -1810,7 +1886,7 @@ fn walkInstruction( |
| 1810 | 1886 | const operand = try self.walkRef( |
| 1811 | 1887 | file, |
| 1812 | 1888 | parent_scope, |
| 1813 | parent_line, | |
| 1889 | parent_src, | |
| 1814 | 1890 | un_node.operand, |
| 1815 | 1891 | need_type, |
| 1816 | 1892 | ); |
| ... | ... | @@ -1833,10 +1909,11 @@ fn walkInstruction( |
| 1833 | 1909 | |
| 1834 | 1910 | .typeof => { |
| 1835 | 1911 | const un_node = data[inst_index].un_node; |
| 1912 | ||
| 1836 | 1913 | const operand = try self.walkRef( |
| 1837 | 1914 | file, |
| 1838 | 1915 | parent_scope, |
| 1839 | parent_line, | |
| 1916 | parent_src, | |
| 1840 | 1917 | un_node.operand, |
| 1841 | 1918 | need_type, |
| 1842 | 1919 | ); |
| ... | ... | @@ -1852,11 +1929,10 @@ fn walkInstruction( |
| 1852 | 1929 | const pl_node = data[inst_index].pl_node; |
| 1853 | 1930 | const extra = file.zir.extraData(Zir.Inst.Block, pl_node.payload_index); |
| 1854 | 1931 | const body = file.zir.extra[extra.end..][extra.data.body_len - 1]; |
| 1855 | ||
| 1856 | 1932 | var operand: DocData.WalkResult = try self.walkRef( |
| 1857 | 1933 | file, |
| 1858 | 1934 | parent_scope, |
| 1859 | parent_line, | |
| 1935 | parent_src, | |
| 1860 | 1936 | data[body].@"break".operand, |
| 1861 | 1937 | false, |
| 1862 | 1938 | ); |
| ... | ... | @@ -1872,10 +1948,11 @@ fn walkInstruction( |
| 1872 | 1948 | .type_info => { |
| 1873 | 1949 | // @check |
| 1874 | 1950 | const un_node = data[inst_index].un_node; |
| 1951 | ||
| 1875 | 1952 | const operand = try self.walkRef( |
| 1876 | 1953 | file, |
| 1877 | 1954 | parent_scope, |
| 1878 | parent_line, | |
| 1955 | parent_src, | |
| 1879 | 1956 | un_node.operand, |
| 1880 | 1957 | need_type, |
| 1881 | 1958 | ); |
| ... | ... | @@ -1894,7 +1971,7 @@ fn walkInstruction( |
| 1894 | 1971 | const dest_type_walk = try self.walkRef( |
| 1895 | 1972 | file, |
| 1896 | 1973 | parent_scope, |
| 1897 | parent_line, | |
| 1974 | parent_src, | |
| 1898 | 1975 | extra.data.dest_type, |
| 1899 | 1976 | false, |
| 1900 | 1977 | ); |
| ... | ... | @@ -1902,7 +1979,7 @@ fn walkInstruction( |
| 1902 | 1979 | const operand = try self.walkRef( |
| 1903 | 1980 | file, |
| 1904 | 1981 | parent_scope, |
| 1905 | parent_line, | |
| 1982 | parent_src, | |
| 1906 | 1983 | extra.data.operand, |
| 1907 | 1984 | false, |
| 1908 | 1985 | ); |
| ... | ... | @@ -1927,10 +2004,11 @@ fn walkInstruction( |
| 1927 | 2004 | }, |
| 1928 | 2005 | .optional_type => { |
| 1929 | 2006 | const un_node = data[inst_index].un_node; |
| 2007 | ||
| 1930 | 2008 | const operand: DocData.WalkResult = try self.walkRef( |
| 1931 | 2009 | file, |
| 1932 | 2010 | parent_scope, |
| 1933 | parent_line, | |
| 2011 | parent_src, | |
| 1934 | 2012 | un_node.operand, |
| 1935 | 2013 | false, |
| 1936 | 2014 | ); |
| ... | ... | @@ -2014,7 +2092,7 @@ fn walkInstruction( |
| 2014 | 2092 | } |
| 2015 | 2093 | } |
| 2016 | 2094 | |
| 2017 | break :blk try self.walkRef(file, parent_scope, parent_line, lhs_ref, false); | |
| 2095 | break :blk try self.walkRef(file, parent_scope, parent_src, lhs_ref, false); | |
| 2018 | 2096 | }; |
| 2019 | 2097 | try path.append(self.arena, wr.expr); |
| 2020 | 2098 | |
| ... | ... | @@ -2065,7 +2143,7 @@ fn walkInstruction( |
| 2065 | 2143 | return self.walkRef( |
| 2066 | 2144 | file, |
| 2067 | 2145 | parent_scope, |
| 2068 | parent_line, | |
| 2146 | parent_src, | |
| 2069 | 2147 | getBlockInlineBreak(file.zir, inst_index), |
| 2070 | 2148 | need_type, |
| 2071 | 2149 | ); |
| ... | ... | @@ -2092,13 +2170,18 @@ fn walkInstruction( |
| 2092 | 2170 | Zir.Inst.FieldType, |
| 2093 | 2171 | field_pl_node.payload_index, |
| 2094 | 2172 | ); |
| 2173 | const field_src = try self.srcLocInfo( | |
| 2174 | file, | |
| 2175 | field_pl_node.src_node, | |
| 2176 | parent_src, | |
| 2177 | ); | |
| 2095 | 2178 | |
| 2096 | 2179 | // On first iteration use field info to find out the struct type |
| 2097 | 2180 | if (idx == extra.end) { |
| 2098 | 2181 | const wr = try self.walkRef( |
| 2099 | 2182 | file, |
| 2100 | 2183 | parent_scope, |
| 2101 | parent_line, | |
| 2184 | field_src, | |
| 2102 | 2185 | field_extra.data.container_type, |
| 2103 | 2186 | false, |
| 2104 | 2187 | ); |
| ... | ... | @@ -2109,7 +2192,7 @@ fn walkInstruction( |
| 2109 | 2192 | const value = try self.walkRef( |
| 2110 | 2193 | file, |
| 2111 | 2194 | parent_scope, |
| 2112 | parent_line, | |
| 2195 | parent_src, | |
| 2113 | 2196 | init_extra.data.init, |
| 2114 | 2197 | need_type, |
| 2115 | 2198 | ); |
| ... | ... | @@ -2123,10 +2206,11 @@ fn walkInstruction( |
| 2123 | 2206 | }, |
| 2124 | 2207 | .struct_init_empty => { |
| 2125 | 2208 | const un_node = data[inst_index].un_node; |
| 2209 | ||
| 2126 | 2210 | var operand: DocData.WalkResult = try self.walkRef( |
| 2127 | 2211 | file, |
| 2128 | 2212 | parent_scope, |
| 2129 | parent_line, | |
| 2213 | parent_src, | |
| 2130 | 2214 | un_node.operand, |
| 2131 | 2215 | false, |
| 2132 | 2216 | ); |
| ... | ... | @@ -2159,7 +2243,7 @@ fn walkInstruction( |
| 2159 | 2243 | const value = try self.walkRef( |
| 2160 | 2244 | file, |
| 2161 | 2245 | parent_scope, |
| 2162 | parent_line, | |
| 2246 | parent_src, | |
| 2163 | 2247 | init_extra.data.init, |
| 2164 | 2248 | need_type, |
| 2165 | 2249 | ); |
| ... | ... | @@ -2235,7 +2319,7 @@ fn walkInstruction( |
| 2235 | 2319 | const pl_node = data[inst_index].pl_node; |
| 2236 | 2320 | const extra = file.zir.extraData(Zir.Inst.Call, pl_node.payload_index); |
| 2237 | 2321 | |
| 2238 | const callee = try self.walkRef(file, parent_scope, parent_line, extra.data.callee, need_type); | |
| 2322 | const callee = try self.walkRef(file, parent_scope, parent_src, extra.data.callee, need_type); | |
| 2239 | 2323 | |
| 2240 | 2324 | const args_len = extra.data.flags.args_len; |
| 2241 | 2325 | var args = try self.arena.alloc(DocData.Expr, args_len); |
| ... | ... | @@ -2250,7 +2334,7 @@ fn walkInstruction( |
| 2250 | 2334 | // to show discrepancies between the types of provided |
| 2251 | 2335 | // arguments and the types declared in the function |
| 2252 | 2336 | // signature for its parameters. |
| 2253 | const wr = try self.walkRef(file, parent_scope, parent_line, ref, false); | |
| 2337 | const wr = try self.walkRef(file, parent_scope, parent_src, ref, false); | |
| 2254 | 2338 | args[i] = wr.expr; |
| 2255 | 2339 | } |
| 2256 | 2340 | |
| ... | ... | @@ -2281,7 +2365,7 @@ fn walkInstruction( |
| 2281 | 2365 | const result = self.analyzeFunction( |
| 2282 | 2366 | file, |
| 2283 | 2367 | parent_scope, |
| 2284 | parent_line, | |
| 2368 | parent_src, | |
| 2285 | 2369 | inst_index, |
| 2286 | 2370 | self_ast_node_index, |
| 2287 | 2371 | type_slot_index, |
| ... | ... | @@ -2297,7 +2381,7 @@ fn walkInstruction( |
| 2297 | 2381 | const result = self.analyzeFancyFunction( |
| 2298 | 2382 | file, |
| 2299 | 2383 | parent_scope, |
| 2300 | parent_line, | |
| 2384 | parent_src, | |
| 2301 | 2385 | inst_index, |
| 2302 | 2386 | self_ast_node_index, |
| 2303 | 2387 | type_slot_index, |
| ... | ... | @@ -2325,7 +2409,7 @@ fn walkInstruction( |
| 2325 | 2409 | |
| 2326 | 2410 | var array_type: ?DocData.Expr = null; |
| 2327 | 2411 | for (args) |arg, idx| { |
| 2328 | const wr = try self.walkRef(file, parent_scope, parent_line, arg, idx == 0); | |
| 2412 | const wr = try self.walkRef(file, parent_scope, parent_src, arg, idx == 0); | |
| 2329 | 2413 | if (idx == 0) { |
| 2330 | 2414 | array_type = wr.typeRef; |
| 2331 | 2415 | } |
| ... | ... | @@ -2355,36 +2439,91 @@ fn walkInstruction( |
| 2355 | 2439 | return result; |
| 2356 | 2440 | }, |
| 2357 | 2441 | .opaque_decl => { |
| 2442 | const type_slot_index = self.types.items.len; | |
| 2443 | try self.types.append(self.arena, .{ .Unanalyzed = .{} }); | |
| 2444 | ||
| 2445 | var scope: Scope = .{ | |
| 2446 | .parent = parent_scope, | |
| 2447 | .enclosing_type = type_slot_index, | |
| 2448 | }; | |
| 2449 | ||
| 2358 | 2450 | const small = @bitCast(Zir.Inst.OpaqueDecl.Small, extended.small); |
| 2359 | 2451 | var extra_index: usize = extended.operand; |
| 2452 | ||
| 2360 | 2453 | const src_node: ?i32 = if (small.has_src_node) blk: { |
| 2361 | 2454 | const src_node = @bitCast(i32, file.zir.extra[extra_index]); |
| 2362 | 2455 | extra_index += 1; |
| 2363 | 2456 | break :blk src_node; |
| 2364 | 2457 | } else null; |
| 2365 | _ = src_node; | |
| 2458 | ||
| 2459 | const src_info = if (src_node) |sn| | |
| 2460 | try self.srcLocInfo(file, sn, parent_src) | |
| 2461 | else | |
| 2462 | parent_src; | |
| 2463 | _ = src_info; | |
| 2366 | 2464 | |
| 2367 | 2465 | const decls_len = if (small.has_decls_len) blk: { |
| 2368 | 2466 | const decls_len = file.zir.extra[extra_index]; |
| 2369 | 2467 | extra_index += 1; |
| 2370 | 2468 | break :blk decls_len; |
| 2371 | 2469 | } else 0; |
| 2372 | _ = decls_len; | |
| 2373 | ||
| 2374 | const decls_bits = file.zir.extra[extra_index]; | |
| 2375 | _ = decls_bits; | |
| 2376 | ||
| 2377 | // const sep = "=" ** 200; | |
| 2378 | // log.debug("{s}", .{sep}); | |
| 2379 | // log.debug("small = {any}", .{small}); | |
| 2380 | // log.debug("src_node = {}", .{src_node}); | |
| 2381 | // log.debug("decls_len = {}", .{decls_len}); | |
| 2382 | // log.debug("decls_bit = {}", .{decls_bits}); | |
| 2383 | // log.debug("{s}", .{sep}); | |
| 2384 | const type_slot_index = self.types.items.len - 1; | |
| 2385 | try self.types.append(self.arena, .{ .Opaque = .{ .name = "TODO" } }); | |
| 2470 | ||
| 2471 | var decl_indexes: std.ArrayListUnmanaged(usize) = .{}; | |
| 2472 | var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{}; | |
| 2473 | ||
| 2474 | const decls_first_index = self.decls.items.len; | |
| 2475 | // Decl name lookahead for reserving slots in `scope` (and `decls`). | |
| 2476 | // Done to make sure that all decl refs can be resolved correctly, | |
| 2477 | // even if we haven't fully analyzed the decl yet. | |
| 2478 | { | |
| 2479 | var it = file.zir.declIterator(@intCast(u32, inst_index)); | |
| 2480 | try self.decls.resize(self.arena, decls_first_index + it.decls_len); | |
| 2481 | for (self.decls.items[decls_first_index..]) |*slot| { | |
| 2482 | slot._analyzed = false; | |
| 2483 | } | |
| 2484 | var decls_slot_index = decls_first_index; | |
| 2485 | while (it.next()) |d| : (decls_slot_index += 1) { | |
| 2486 | const decl_name_index = file.zir.extra[d.sub_index + 5]; | |
| 2487 | try scope.insertDeclRef(self.arena, decl_name_index, decls_slot_index); | |
| 2488 | } | |
| 2489 | } | |
| 2490 | ||
| 2491 | extra_index = try self.walkDecls( | |
| 2492 | file, | |
| 2493 | &scope, | |
| 2494 | src_info, | |
| 2495 | decls_first_index, | |
| 2496 | decls_len, | |
| 2497 | &decl_indexes, | |
| 2498 | &priv_decl_indexes, | |
| 2499 | extra_index, | |
| 2500 | ); | |
| 2501 | ||
| 2502 | self.types.items[type_slot_index] = .{ | |
| 2503 | .Opaque = .{ | |
| 2504 | .name = "todo_name", | |
| 2505 | .src = self_ast_node_index, | |
| 2506 | .privDecls = priv_decl_indexes.items, | |
| 2507 | .pubDecls = decl_indexes.items, | |
| 2508 | .ast = self_ast_node_index, | |
| 2509 | }, | |
| 2510 | }; | |
| 2511 | if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| { | |
| 2512 | for (paths.items) |resume_info| { | |
| 2513 | try self.tryResolveRefPath( | |
| 2514 | resume_info.file, | |
| 2515 | inst_index, | |
| 2516 | resume_info.ref_path, | |
| 2517 | ); | |
| 2518 | } | |
| 2519 | ||
| 2520 | _ = self.ref_paths_pending_on_types.remove(type_slot_index); | |
| 2521 | // TODO: we should deallocate the arraylist that holds all the | |
| 2522 | // decl paths. not doing it now since it's arena-allocated | |
| 2523 | // anyway, but maybe we should put it elsewhere. | |
| 2524 | } | |
| 2386 | 2525 | return DocData.WalkResult{ |
| 2387 | .typeRef = .{ .type = @enumToInt(Ref.anyopaque_type) }, | |
| 2526 | .typeRef = .{ .type = @enumToInt(Ref.type_type) }, | |
| 2388 | 2527 | .expr = .{ .type = type_slot_index }, |
| 2389 | 2528 | }; |
| 2390 | 2529 | }, |
| ... | ... | @@ -2419,7 +2558,11 @@ fn walkInstruction( |
| 2419 | 2558 | extra_index += 1; |
| 2420 | 2559 | break :blk src_node; |
| 2421 | 2560 | } else null; |
| 2422 | _ = src_node; | |
| 2561 | ||
| 2562 | const src_info = if (src_node) |sn| | |
| 2563 | try self.srcLocInfo(file, sn, parent_src) | |
| 2564 | else | |
| 2565 | parent_src; | |
| 2423 | 2566 | |
| 2424 | 2567 | const tag_type: ?Ref = if (small.has_tag_type) blk: { |
| 2425 | 2568 | const tag_type = file.zir.extra[extra_index]; |
| ... | ... | @@ -2470,7 +2613,7 @@ fn walkInstruction( |
| 2470 | 2613 | extra_index = try self.walkDecls( |
| 2471 | 2614 | file, |
| 2472 | 2615 | &scope, |
| 2473 | parent_line, | |
| 2616 | src_info, | |
| 2474 | 2617 | decls_first_index, |
| 2475 | 2618 | decls_len, |
| 2476 | 2619 | &decl_indexes, |
| ... | ... | @@ -2491,7 +2634,7 @@ fn walkInstruction( |
| 2491 | 2634 | try self.collectUnionFieldInfo( |
| 2492 | 2635 | file, |
| 2493 | 2636 | &scope, |
| 2494 | parent_line, | |
| 2637 | src_info, | |
| 2495 | 2638 | fields_len, |
| 2496 | 2639 | &field_type_refs, |
| 2497 | 2640 | &field_name_indexes, |
| ... | ... | @@ -2541,7 +2684,11 @@ fn walkInstruction( |
| 2541 | 2684 | extra_index += 1; |
| 2542 | 2685 | break :blk src_node; |
| 2543 | 2686 | } else null; |
| 2544 | _ = src_node; | |
| 2687 | ||
| 2688 | const src_info = if (src_node) |sn| | |
| 2689 | try self.srcLocInfo(file, sn, parent_src) | |
| 2690 | else | |
| 2691 | parent_src; | |
| 2545 | 2692 | |
| 2546 | 2693 | const tag_type: ?Ref = if (small.has_tag_type) blk: { |
| 2547 | 2694 | const tag_type = file.zir.extra[extra_index]; |
| ... | ... | @@ -2592,7 +2739,7 @@ fn walkInstruction( |
| 2592 | 2739 | extra_index = try self.walkDecls( |
| 2593 | 2740 | file, |
| 2594 | 2741 | &scope, |
| 2595 | parent_line, | |
| 2742 | src_info, | |
| 2596 | 2743 | decls_first_index, |
| 2597 | 2744 | decls_len, |
| 2598 | 2745 | &decl_indexes, |
| ... | ... | @@ -2687,7 +2834,11 @@ fn walkInstruction( |
| 2687 | 2834 | extra_index += 1; |
| 2688 | 2835 | break :blk src_node; |
| 2689 | 2836 | } else null; |
| 2690 | _ = src_node; | |
| 2837 | ||
| 2838 | const src_info = if (src_node) |sn| | |
| 2839 | try self.srcLocInfo(file, sn, parent_src) | |
| 2840 | else | |
| 2841 | parent_src; | |
| 2691 | 2842 | |
| 2692 | 2843 | const fields_len = if (small.has_fields_len) blk: { |
| 2693 | 2844 | const fields_len = file.zir.extra[extra_index]; |
| ... | ... | @@ -2736,7 +2887,7 @@ fn walkInstruction( |
| 2736 | 2887 | extra_index = try self.walkDecls( |
| 2737 | 2888 | file, |
| 2738 | 2889 | &scope, |
| 2739 | parent_line, | |
| 2890 | src_info, | |
| 2740 | 2891 | decls_first_index, |
| 2741 | 2892 | decls_len, |
| 2742 | 2893 | &decl_indexes, |
| ... | ... | @@ -2749,7 +2900,7 @@ fn walkInstruction( |
| 2749 | 2900 | try self.collectStructFieldInfo( |
| 2750 | 2901 | file, |
| 2751 | 2902 | &scope, |
| 2752 | parent_line, | |
| 2903 | src_info, | |
| 2753 | 2904 | fields_len, |
| 2754 | 2905 | &field_type_refs, |
| 2755 | 2906 | &field_name_indexes, |
| ... | ... | @@ -2793,7 +2944,7 @@ fn walkInstruction( |
| 2793 | 2944 | const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 2794 | 2945 | const bin_index = self.exprs.items.len; |
| 2795 | 2946 | try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } }); |
| 2796 | const param = try self.walkRef(file, parent_scope, parent_line, extra.operand, false); | |
| 2947 | const param = try self.walkRef(file, parent_scope, parent_src, extra.operand, false); | |
| 2797 | 2948 | |
| 2798 | 2949 | const param_index = self.exprs.items.len; |
| 2799 | 2950 | try self.exprs.append(self.arena, param.expr); |
| ... | ... | @@ -2821,13 +2972,14 @@ fn walkDecls( |
| 2821 | 2972 | self: *Autodoc, |
| 2822 | 2973 | file: *File, |
| 2823 | 2974 | scope: *Scope, |
| 2824 | parent_line: usize, | |
| 2975 | parent_src: SrcLocInfo, | |
| 2825 | 2976 | decls_first_index: usize, |
| 2826 | 2977 | decls_len: u32, |
| 2827 | 2978 | decl_indexes: *std.ArrayListUnmanaged(usize), |
| 2828 | 2979 | priv_decl_indexes: *std.ArrayListUnmanaged(usize), |
| 2829 | 2980 | extra_start: usize, |
| 2830 | 2981 | ) AutodocErrors!usize { |
| 2982 | const data = file.zir.instructions.items(.data); | |
| 2831 | 2983 | const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable; |
| 2832 | 2984 | var extra_index = extra_start + bit_bags_count; |
| 2833 | 2985 | var bit_bag_index: usize = extra_start; |
| ... | ... | @@ -2854,7 +3006,8 @@ fn walkDecls( |
| 2854 | 3006 | |
| 2855 | 3007 | // const hash_u32s = file.zir.extra[extra_index..][0..4]; |
| 2856 | 3008 | extra_index += 4; |
| 2857 | const line = parent_line + file.zir.extra[extra_index]; | |
| 3009 | ||
| 3010 | // const line = file.zir.extra[extra_index]; | |
| 2858 | 3011 | extra_index += 1; |
| 2859 | 3012 | const decl_name_index = file.zir.extra[extra_index]; |
| 2860 | 3013 | extra_index += 1; |
| ... | ... | @@ -2884,10 +3037,11 @@ fn walkDecls( |
| 2884 | 3037 | }; |
| 2885 | 3038 | _ = addrspace_inst; |
| 2886 | 3039 | |
| 2887 | // const pub_str = if (is_pub) "pub " else ""; | |
| 2888 | // const hash_bytes = @bitCast([16]u8, hash_u32s.*); | |
| 3040 | // This is known to work because decl values are always block_inlines | |
| 3041 | const value_pl_node = data[value_index].pl_node; | |
| 3042 | const decl_src = try self.srcLocInfo(file, value_pl_node.src_node, parent_src); | |
| 2889 | 3043 | |
| 2890 | var is_test = false; // we discover if it's a test by lookin at its name | |
| 3044 | var is_test = false; // we discover if it's a test by looking at its name | |
| 2891 | 3045 | const name: []const u8 = blk: { |
| 2892 | 3046 | if (decl_name_index == 0) { |
| 2893 | 3047 | break :blk if (is_exported) "usingnamespace" else "comptime"; |
| ... | ... | @@ -2895,84 +3049,32 @@ fn walkDecls( |
| 2895 | 3049 | is_test = true; |
| 2896 | 3050 | break :blk "test"; |
| 2897 | 3051 | } else if (decl_name_index == 2) { |
| 2898 | is_test = true; | |
| 2899 | // TODO: remove temporary hack | |
| 2900 | break :blk "test"; | |
| 2901 | // // it is a decltest | |
| 2902 | // const decl_being_tested = scope.resolveDeclName(doc_comment_index); | |
| 2903 | // const ast_node_index = idx: { | |
| 2904 | // const idx = self.ast_nodes.items.len; | |
| 2905 | // const file_source = file.getSource(self.module.gpa) catch unreachable; // TODO fix this | |
| 2906 | // const source_of_decltest_function = srcloc: { | |
| 2907 | // const func_index = getBlockInlineBreak(file.zir, value_index); | |
| 2908 | // // a decltest is always a function | |
| 2909 | // const tag = file.zir.instructions.items(.tag)[Zir.refToIndex(func_index).?]; | |
| 2910 | // std.debug.assert(tag == .func_extended); | |
| 2911 | ||
| 2912 | // const pl_node = file.zir.instructions.items(.data)[Zir.refToIndex(func_index).?].pl_node; | |
| 2913 | // const extra = file.zir.extraData(Zir.Inst.ExtendedFunc, pl_node.payload_index); | |
| 2914 | // const bits = @bitCast(Zir.Inst.ExtendedFunc.Bits, extra.data.bits); | |
| 2915 | ||
| 2916 | // var extra_index_for_this_func: usize = extra.end; | |
| 2917 | // if (bits.has_lib_name) extra_index_for_this_func += 1; | |
| 2918 | // if (bits.has_cc) extra_index_for_this_func += 1; | |
| 2919 | // if (bits.has_align) extra_index_for_this_func += 1; | |
| 2920 | ||
| 2921 | // const ret_ty_body = file.zir.extra[extra_index_for_this_func..][0..extra.data.ret_body_len]; | |
| 2922 | // extra_index_for_this_func += ret_ty_body.len; | |
| 2923 | ||
| 2924 | // const body = file.zir.extra[extra_index_for_this_func..][0..extra.data.body_len]; | |
| 2925 | // extra_index_for_this_func += body.len; | |
| 2926 | ||
| 2927 | // var src_locs: Zir.Inst.Func.SrcLocs = undefined; | |
| 2928 | // if (body.len != 0) { | |
| 2929 | // src_locs = file.zir.extraData(Zir.Inst.Func.SrcLocs, extra_index_for_this_func).data; | |
| 2930 | // } else { | |
| 2931 | // src_locs = .{ | |
| 2932 | // .lbrace_line = line, | |
| 2933 | // .rbrace_line = line, | |
| 2934 | // .columns = 0, // TODO get columns when body.len == 0 | |
| 2935 | // }; | |
| 2936 | // } | |
| 2937 | // break :srcloc src_locs; | |
| 2938 | // }; | |
| 2939 | // const source_slice = slice: { | |
| 2940 | // var start_byte_offset: u32 = 0; | |
| 2941 | // var end_byte_offset: u32 = 0; | |
| 2942 | // const rbrace_col = @truncate(u16, source_of_decltest_function.columns >> 16); | |
| 2943 | // var lines: u32 = 0; | |
| 2944 | // for (file_source.bytes) |b, i| { | |
| 2945 | // if (b == '\n') { | |
| 2946 | // lines += 1; | |
| 2947 | // } | |
| 2948 | // if (lines == source_of_decltest_function.lbrace_line) { | |
| 2949 | // start_byte_offset = @intCast(u32, i); | |
| 2950 | // } | |
| 2951 | // if (lines == source_of_decltest_function.rbrace_line) { | |
| 2952 | // end_byte_offset = @intCast(u32, i) + rbrace_col; | |
| 2953 | // break; | |
| 2954 | // } | |
| 2955 | // } | |
| 2956 | // break :slice file_source.bytes[start_byte_offset..end_byte_offset]; | |
| 2957 | // }; | |
| 2958 | // try self.ast_nodes.append(self.arena, .{ | |
| 2959 | // .file = 0, | |
| 2960 | // .line = line, | |
| 2961 | // .col = 0, | |
| 2962 | // .name = try self.arena.dupe(u8, source_slice), | |
| 2963 | // }); | |
| 2964 | // break :idx idx; | |
| 2965 | // }; | |
| 2966 | // self.decls.items[decl_being_tested].decltest = ast_node_index; | |
| 2967 | // self.decls.items[decls_slot_index] = .{ | |
| 2968 | // ._analyzed = true, | |
| 2969 | // .name = "test", | |
| 2970 | // .isTest = true, | |
| 2971 | // .src = ast_node_index, | |
| 2972 | // .value = .{ .expr = .{ .type = 0 } }, | |
| 2973 | // .kind = "const", | |
| 2974 | // }; | |
| 2975 | // continue; | |
| 3052 | // it is a decltest | |
| 3053 | const decl_being_tested = scope.resolveDeclName(doc_comment_index); | |
| 3054 | const func_index = getBlockInlineBreak(file.zir, value_index); | |
| 3055 | ||
| 3056 | const pl_node = data[Zir.refToIndex(func_index).?].pl_node; | |
| 3057 | const fn_src = try self.srcLocInfo(file, pl_node.src_node, decl_src); | |
| 3058 | const tree = try file.getTree(self.module.gpa); | |
| 3059 | const test_source_code = tree.getNodeSource(fn_src.src_node); | |
| 3060 | ||
| 3061 | const ast_node_index = self.ast_nodes.items.len; | |
| 3062 | try self.ast_nodes.append(self.arena, .{ | |
| 3063 | .file = 0, | |
| 3064 | .line = 0, | |
| 3065 | .col = 0, | |
| 3066 | .code = test_source_code, | |
| 3067 | }); | |
| 3068 | self.decls.items[decl_being_tested].decltest = ast_node_index; | |
| 3069 | self.decls.items[decls_slot_index] = .{ | |
| 3070 | ._analyzed = true, | |
| 3071 | .name = "test", | |
| 3072 | .isTest = true, | |
| 3073 | .src = ast_node_index, | |
| 3074 | .value = .{ .expr = .{ .type = 0 } }, | |
| 3075 | .kind = "const", | |
| 3076 | }; | |
| 3077 | continue; | |
| 2976 | 3078 | } else { |
| 2977 | 3079 | const raw_decl_name = file.zir.nullTerminatedString(decl_name_index); |
| 2978 | 3080 | if (raw_decl_name.len == 0) { |
| ... | ... | @@ -2993,8 +3095,8 @@ fn walkDecls( |
| 2993 | 3095 | const ast_node_index = idx: { |
| 2994 | 3096 | const idx = self.ast_nodes.items.len; |
| 2995 | 3097 | try self.ast_nodes.append(self.arena, .{ |
| 2996 | .file = self.files.getIndex(file) orelse unreachable, | |
| 2997 | .line = line, | |
| 3098 | .file = self.files.getIndex(file).?, | |
| 3099 | .line = decl_src.line, | |
| 2998 | 3100 | .col = 0, |
| 2999 | 3101 | .docs = doc_comment, |
| 3000 | 3102 | .fields = null, // walkInstruction will fill `fields` if necessary |
| ... | ... | @@ -3005,7 +3107,7 @@ fn walkDecls( |
| 3005 | 3107 | const walk_result = if (is_test) // TODO: decide if tests should show up at all |
| 3006 | 3108 | DocData.WalkResult{ .expr = .{ .void = .{} } } |
| 3007 | 3109 | else |
| 3008 | try self.walkInstruction(file, scope, line, value_index, true); | |
| 3110 | try self.walkInstruction(file, scope, decl_src, value_index, true); | |
| 3009 | 3111 | |
| 3010 | 3112 | if (is_pub) { |
| 3011 | 3113 | try decl_indexes.append(self.arena, decls_slot_index); |
| ... | ... | @@ -3381,6 +3483,37 @@ fn tryResolveRefPath( |
| 3381 | 3483 | path[i + 1] = (try self.cteTodo(child_string)).expr; |
| 3382 | 3484 | continue :outer; |
| 3383 | 3485 | }, |
| 3486 | .Opaque => |t_opaque| { | |
| 3487 | for (t_opaque.pubDecls) |d| { | |
| 3488 | // TODO: this could be improved a lot | |
| 3489 | // by having our own string table! | |
| 3490 | const decl = self.decls.items[d]; | |
| 3491 | if (std.mem.eql(u8, decl.name, child_string)) { | |
| 3492 | path[i + 1] = .{ .declRef = d }; | |
| 3493 | continue :outer; | |
| 3494 | } | |
| 3495 | } | |
| 3496 | for (t_opaque.privDecls) |d| { | |
| 3497 | // TODO: this could be improved a lot | |
| 3498 | // by having our own string table! | |
| 3499 | const decl = self.decls.items[d]; | |
| 3500 | if (std.mem.eql(u8, decl.name, child_string)) { | |
| 3501 | path[i + 1] = .{ .declRef = d }; | |
| 3502 | continue :outer; | |
| 3503 | } | |
| 3504 | } | |
| 3505 | ||
| 3506 | // if we got here, our search failed | |
| 3507 | printWithContext( | |
| 3508 | file, | |
| 3509 | inst_index, | |
| 3510 | "failed to match `{s}` in opaque", | |
| 3511 | .{child_string}, | |
| 3512 | ); | |
| 3513 | ||
| 3514 | path[i + 1] = (try self.cteTodo("match failure")).expr; | |
| 3515 | continue :outer; | |
| 3516 | }, | |
| 3384 | 3517 | }, |
| 3385 | 3518 | } |
| 3386 | 3519 | } |
| ... | ... | @@ -3401,7 +3534,7 @@ fn analyzeFancyFunction( |
| 3401 | 3534 | self: *Autodoc, |
| 3402 | 3535 | file: *File, |
| 3403 | 3536 | scope: *Scope, |
| 3404 | parent_line: usize, | |
| 3537 | parent_src: SrcLocInfo, | |
| 3405 | 3538 | inst_index: usize, |
| 3406 | 3539 | self_ast_node_index: usize, |
| 3407 | 3540 | type_slot_index: usize, |
| ... | ... | @@ -3466,7 +3599,7 @@ fn analyzeFancyFunction( |
| 3466 | 3599 | |
| 3467 | 3600 | const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1]; |
| 3468 | 3601 | const break_operand = data[break_index].@"break".operand; |
| 3469 | const param_type_ref = try self.walkRef(file, scope, parent_line, break_operand, false); | |
| 3602 | const param_type_ref = try self.walkRef(file, scope, parent_src, break_operand, false); | |
| 3470 | 3603 | |
| 3471 | 3604 | param_type_refs.appendAssumeCapacity(param_type_ref.expr); |
| 3472 | 3605 | }, |
| ... | ... | @@ -3475,8 +3608,8 @@ fn analyzeFancyFunction( |
| 3475 | 3608 | |
| 3476 | 3609 | self.ast_nodes.items[self_ast_node_index].fields = param_ast_indexes.items; |
| 3477 | 3610 | |
| 3478 | const inst_data = data[inst_index].pl_node; | |
| 3479 | const extra = file.zir.extraData(Zir.Inst.FuncFancy, inst_data.payload_index); | |
| 3611 | const pl_node = data[inst_index].pl_node; | |
| 3612 | const extra = file.zir.extraData(Zir.Inst.FuncFancy, pl_node.payload_index); | |
| 3480 | 3613 | |
| 3481 | 3614 | var extra_index: usize = extra.end; |
| 3482 | 3615 | |
| ... | ... | @@ -3490,7 +3623,7 @@ fn analyzeFancyFunction( |
| 3490 | 3623 | if (extra.data.bits.has_align_ref) { |
| 3491 | 3624 | const align_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]); |
| 3492 | 3625 | align_index = self.exprs.items.len; |
| 3493 | _ = try self.walkRef(file, scope, parent_line, align_ref, false); | |
| 3626 | _ = try self.walkRef(file, scope, parent_src, align_ref, false); | |
| 3494 | 3627 | extra_index += 1; |
| 3495 | 3628 | } else if (extra.data.bits.has_align_body) { |
| 3496 | 3629 | const align_body_len = file.zir.extra[extra_index]; |
| ... | ... | @@ -3507,7 +3640,7 @@ fn analyzeFancyFunction( |
| 3507 | 3640 | if (extra.data.bits.has_addrspace_ref) { |
| 3508 | 3641 | const addrspace_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]); |
| 3509 | 3642 | addrspace_index = self.exprs.items.len; |
| 3510 | _ = try self.walkRef(file, scope, parent_line, addrspace_ref, false); | |
| 3643 | _ = try self.walkRef(file, scope, parent_src, addrspace_ref, false); | |
| 3511 | 3644 | extra_index += 1; |
| 3512 | 3645 | } else if (extra.data.bits.has_addrspace_body) { |
| 3513 | 3646 | const addrspace_body_len = file.zir.extra[extra_index]; |
| ... | ... | @@ -3524,7 +3657,7 @@ fn analyzeFancyFunction( |
| 3524 | 3657 | if (extra.data.bits.has_section_ref) { |
| 3525 | 3658 | const section_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]); |
| 3526 | 3659 | section_index = self.exprs.items.len; |
| 3527 | _ = try self.walkRef(file, scope, parent_line, section_ref, false); | |
| 3660 | _ = try self.walkRef(file, scope, parent_src, section_ref, false); | |
| 3528 | 3661 | extra_index += 1; |
| 3529 | 3662 | } else if (extra.data.bits.has_section_body) { |
| 3530 | 3663 | const section_body_len = file.zir.extra[extra_index]; |
| ... | ... | @@ -3541,7 +3674,7 @@ fn analyzeFancyFunction( |
| 3541 | 3674 | if (extra.data.bits.has_cc_ref) { |
| 3542 | 3675 | const cc_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]); |
| 3543 | 3676 | cc_index = self.exprs.items.len; |
| 3544 | _ = try self.walkRef(file, scope, parent_line, cc_ref, false); | |
| 3677 | _ = try self.walkRef(file, scope, parent_src, cc_ref, false); | |
| 3545 | 3678 | extra_index += 1; |
| 3546 | 3679 | } else if (extra.data.bits.has_cc_body) { |
| 3547 | 3680 | const cc_body_len = file.zir.extra[extra_index]; |
| ... | ... | @@ -3560,14 +3693,14 @@ fn analyzeFancyFunction( |
| 3560 | 3693 | .none => DocData.Expr{ .void = .{} }, |
| 3561 | 3694 | else => blk: { |
| 3562 | 3695 | const ref = fn_info.ret_ty_ref; |
| 3563 | const wr = try self.walkRef(file, scope, parent_line, ref, false); | |
| 3696 | const wr = try self.walkRef(file, scope, parent_src, ref, false); | |
| 3564 | 3697 | break :blk wr.expr; |
| 3565 | 3698 | }, |
| 3566 | 3699 | }, |
| 3567 | 3700 | else => blk: { |
| 3568 | 3701 | const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1]; |
| 3569 | 3702 | const break_operand = data[last_instr_index].@"break".operand; |
| 3570 | const wr = try self.walkRef(file, scope, parent_line, break_operand, false); | |
| 3703 | const wr = try self.walkRef(file, scope, parent_src, break_operand, false); | |
| 3571 | 3704 | break :blk wr.expr; |
| 3572 | 3705 | }, |
| 3573 | 3706 | }; |
| ... | ... | @@ -3582,7 +3715,7 @@ fn analyzeFancyFunction( |
| 3582 | 3715 | break :blk try self.getGenericReturnType( |
| 3583 | 3716 | file, |
| 3584 | 3717 | scope, |
| 3585 | parent_line, | |
| 3718 | parent_src, | |
| 3586 | 3719 | fn_info.body[fn_info.body.len - 1], |
| 3587 | 3720 | ); |
| 3588 | 3721 | } else { |
| ... | ... | @@ -3619,7 +3752,7 @@ fn analyzeFunction( |
| 3619 | 3752 | self: *Autodoc, |
| 3620 | 3753 | file: *File, |
| 3621 | 3754 | scope: *Scope, |
| 3622 | parent_line: usize, | |
| 3755 | parent_src: SrcLocInfo, | |
| 3623 | 3756 | inst_index: usize, |
| 3624 | 3757 | self_ast_node_index: usize, |
| 3625 | 3758 | type_slot_index: usize, |
| ... | ... | @@ -3685,7 +3818,7 @@ fn analyzeFunction( |
| 3685 | 3818 | |
| 3686 | 3819 | const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1]; |
| 3687 | 3820 | const break_operand = data[break_index].@"break".operand; |
| 3688 | const param_type_ref = try self.walkRef(file, scope, parent_line, break_operand, false); | |
| 3821 | const param_type_ref = try self.walkRef(file, scope, parent_src, break_operand, false); | |
| 3689 | 3822 | |
| 3690 | 3823 | param_type_refs.appendAssumeCapacity(param_type_ref.expr); |
| 3691 | 3824 | }, |
| ... | ... | @@ -3698,14 +3831,14 @@ fn analyzeFunction( |
| 3698 | 3831 | .none => DocData.Expr{ .void = .{} }, |
| 3699 | 3832 | else => blk: { |
| 3700 | 3833 | const ref = fn_info.ret_ty_ref; |
| 3701 | const wr = try self.walkRef(file, scope, parent_line, ref, false); | |
| 3834 | const wr = try self.walkRef(file, scope, parent_src, ref, false); | |
| 3702 | 3835 | break :blk wr.expr; |
| 3703 | 3836 | }, |
| 3704 | 3837 | }, |
| 3705 | 3838 | else => blk: { |
| 3706 | 3839 | const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1]; |
| 3707 | 3840 | const break_operand = data[last_instr_index].@"break".operand; |
| 3708 | const wr = try self.walkRef(file, scope, parent_line, break_operand, false); | |
| 3841 | const wr = try self.walkRef(file, scope, parent_src, break_operand, false); | |
| 3709 | 3842 | break :blk wr.expr; |
| 3710 | 3843 | }, |
| 3711 | 3844 | }; |
| ... | ... | @@ -3720,7 +3853,7 @@ fn analyzeFunction( |
| 3720 | 3853 | break :blk try self.getGenericReturnType( |
| 3721 | 3854 | file, |
| 3722 | 3855 | scope, |
| 3723 | parent_line, | |
| 3856 | parent_src, | |
| 3724 | 3857 | fn_info.body[fn_info.body.len - 1], |
| 3725 | 3858 | ); |
| 3726 | 3859 | } else { |
| ... | ... | @@ -3761,11 +3894,11 @@ fn getGenericReturnType( |
| 3761 | 3894 | self: *Autodoc, |
| 3762 | 3895 | file: *File, |
| 3763 | 3896 | scope: *Scope, |
| 3764 | parent_line: usize, // function decl line | |
| 3897 | parent_src: SrcLocInfo, // function decl line | |
| 3765 | 3898 | body_end: usize, |
| 3766 | 3899 | ) !DocData.Expr { |
| 3767 | 3900 | // TODO: compute the correct line offset |
| 3768 | const wr = try self.walkInstruction(file, scope, parent_line, body_end, false); | |
| 3901 | const wr = try self.walkInstruction(file, scope, parent_src, body_end, false); | |
| 3769 | 3902 | return wr.expr; |
| 3770 | 3903 | } |
| 3771 | 3904 | |
| ... | ... | @@ -3773,7 +3906,7 @@ fn collectUnionFieldInfo( |
| 3773 | 3906 | self: *Autodoc, |
| 3774 | 3907 | file: *File, |
| 3775 | 3908 | scope: *Scope, |
| 3776 | parent_line: usize, | |
| 3909 | parent_src: SrcLocInfo, | |
| 3777 | 3910 | fields_len: usize, |
| 3778 | 3911 | field_type_refs: *std.ArrayListUnmanaged(DocData.Expr), |
| 3779 | 3912 | field_name_indexes: *std.ArrayListUnmanaged(usize), |
| ... | ... | @@ -3820,7 +3953,7 @@ fn collectUnionFieldInfo( |
| 3820 | 3953 | |
| 3821 | 3954 | // type |
| 3822 | 3955 | { |
| 3823 | const walk_result = try self.walkRef(file, scope, parent_line, field_type, false); | |
| 3956 | const walk_result = try self.walkRef(file, scope, parent_src, field_type, false); | |
| 3824 | 3957 | try field_type_refs.append(self.arena, walk_result.expr); |
| 3825 | 3958 | } |
| 3826 | 3959 | |
| ... | ... | @@ -3843,7 +3976,7 @@ fn collectStructFieldInfo( |
| 3843 | 3976 | self: *Autodoc, |
| 3844 | 3977 | file: *File, |
| 3845 | 3978 | scope: *Scope, |
| 3846 | parent_line: usize, | |
| 3979 | parent_src: SrcLocInfo, | |
| 3847 | 3980 | fields_len: usize, |
| 3848 | 3981 | field_type_refs: *std.ArrayListUnmanaged(DocData.Expr), |
| 3849 | 3982 | field_name_indexes: *std.ArrayListUnmanaged(usize), |
| ... | ... | @@ -3917,7 +4050,7 @@ fn collectStructFieldInfo( |
| 3917 | 4050 | for (fields) |field| { |
| 3918 | 4051 | const type_expr = expr: { |
| 3919 | 4052 | if (field.type_ref != .none) { |
| 3920 | const walk_result = try self.walkRef(file, scope, parent_line, field.type_ref, false); | |
| 4053 | const walk_result = try self.walkRef(file, scope, parent_src, field.type_ref, false); | |
| 3921 | 4054 | break :expr walk_result.expr; |
| 3922 | 4055 | } |
| 3923 | 4056 | |
| ... | ... | @@ -3927,7 +4060,7 @@ fn collectStructFieldInfo( |
| 3927 | 4060 | |
| 3928 | 4061 | const break_inst = body[body.len - 1]; |
| 3929 | 4062 | const operand = data[break_inst].@"break".operand; |
| 3930 | const walk_result = try self.walkRef(file, scope, parent_line, operand, false); | |
| 4063 | const walk_result = try self.walkRef(file, scope, parent_src, operand, false); | |
| 3931 | 4064 | break :expr walk_result.expr; |
| 3932 | 4065 | }; |
| 3933 | 4066 | |
| ... | ... | @@ -3957,7 +4090,7 @@ fn walkRef( |
| 3957 | 4090 | self: *Autodoc, |
| 3958 | 4091 | file: *File, |
| 3959 | 4092 | parent_scope: *Scope, |
| 3960 | parent_line: usize, | |
| 4093 | parent_src: SrcLocInfo, | |
| 3961 | 4094 | ref: Ref, |
| 3962 | 4095 | need_type: bool, // true when the caller needs also a typeRef for the return value |
| 3963 | 4096 | ) AutodocErrors!DocData.WalkResult { |
| ... | ... | @@ -4069,7 +4202,7 @@ fn walkRef( |
| 4069 | 4202 | } |
| 4070 | 4203 | } else { |
| 4071 | 4204 | const zir_index = enum_value - Ref.typed_value_map.len; |
| 4072 | return self.walkInstruction(file, parent_scope, parent_line, zir_index, need_type); | |
| 4205 | return self.walkInstruction(file, parent_scope, parent_src, zir_index, need_type); | |
| 4073 | 4206 | } |
| 4074 | 4207 | } |
| 4075 | 4208 | |
| ... | ... | @@ -4122,3 +4255,24 @@ fn writePackageTableToJson( |
| 4122 | 4255 | } |
| 4123 | 4256 | try jsw.endObject(); |
| 4124 | 4257 | } |
| 4258 | ||
| 4259 | fn srcLocInfo( | |
| 4260 | self: Autodoc, | |
| 4261 | file: *File, | |
| 4262 | src_node: i32, | |
| 4263 | parent_src: SrcLocInfo, | |
| 4264 | ) !SrcLocInfo { | |
| 4265 | const sn = @intCast(u32, @intCast(i32, parent_src.src_node) + src_node); | |
| 4266 | const tree = try file.getTree(self.module.gpa); | |
| 4267 | const node_idx = @bitCast(Ast.Node.Index, sn); | |
| 4268 | const tokens = tree.nodes.items(.main_token); | |
| 4269 | ||
| 4270 | const tok_idx = tokens[node_idx]; | |
| 4271 | const start = tree.tokens.items(.start)[tok_idx]; | |
| 4272 | const loc = tree.tokenLocation(parent_src.bytes, tok_idx); | |
| 4273 | return SrcLocInfo{ | |
| 4274 | .line = parent_src.line + loc.line, | |
| 4275 | .bytes = start, | |
| 4276 | .src_node = sn, | |
| 4277 | }; | |
| 4278 | } |
src/Module.zig+1-1| ... | ... | @@ -4635,7 +4635,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4635 | 4635 | decl.analysis = .complete; |
| 4636 | 4636 | decl.generation = mod.generation; |
| 4637 | 4637 | |
| 4638 | const has_runtime_bits = try sema.fnHasRuntimeBits(&block_scope, ty_src, decl.ty); | |
| 4638 | const has_runtime_bits = try sema.fnHasRuntimeBits(decl.ty); | |
| 4639 | 4639 | |
| 4640 | 4640 | if (has_runtime_bits) { |
| 4641 | 4641 | // We don't fully codegen the decl until later, but we do need to reserve a global |
src/Sema.zig+128-63| ... | ... | @@ -2565,7 +2565,7 @@ fn zirEnumDecl( |
| 2565 | 2565 | } |
| 2566 | 2566 | } |
| 2567 | 2567 | |
| 2568 | if (small.nonexhaustive) { | |
| 2568 | if (small.nonexhaustive and enum_obj.tag_ty.zigTypeTag() != .ComptimeInt) { | |
| 2569 | 2569 | if (fields_len > 1 and std.math.log2_int(u64, fields_len) == enum_obj.tag_ty.bitSize(sema.mod.getTarget())) { |
| 2570 | 2570 | return sema.fail(block, src, "non-exhaustive enum specifies every value", .{}); |
| 2571 | 2571 | } |
| ... | ... | @@ -2586,6 +2586,7 @@ fn zirEnumDecl( |
| 2586 | 2586 | var cur_bit_bag: u32 = undefined; |
| 2587 | 2587 | var field_i: u32 = 0; |
| 2588 | 2588 | var last_tag_val: ?Value = null; |
| 2589 | var tag_val_buf: Value.Payload.U64 = undefined; | |
| 2589 | 2590 | while (field_i < fields_len) : (field_i += 1) { |
| 2590 | 2591 | if (field_i % 32 == 0) { |
| 2591 | 2592 | cur_bit_bag = sema.code.extra[bit_bag_index]; |
| ... | ... | @@ -2641,6 +2642,21 @@ fn zirEnumDecl( |
| 2641 | 2642 | .ty = enum_obj.tag_ty, |
| 2642 | 2643 | .mod = mod, |
| 2643 | 2644 | }); |
| 2645 | } else { | |
| 2646 | tag_val_buf = .{ | |
| 2647 | .base = .{ .tag = .int_u64 }, | |
| 2648 | .data = field_i, | |
| 2649 | }; | |
| 2650 | last_tag_val = Value.initPayload(&tag_val_buf.base); | |
| 2651 | } | |
| 2652 | ||
| 2653 | if (!(try sema.intFitsInType(block, src, last_tag_val.?, enum_obj.tag_ty, null))) { | |
| 2654 | const tree = try sema.getAstTree(block); | |
| 2655 | const field_src = enumFieldSrcLoc(sema.mod.declPtr(block.src_decl), tree.*, src.node_offset.x, field_i); | |
| 2656 | const msg = try sema.errMsg(block, field_src, "enumeration value '{}' too large for type '{}'", .{ | |
| 2657 | last_tag_val.?.fmtValue(enum_obj.tag_ty, mod), enum_obj.tag_ty.fmt(mod), | |
| 2658 | }); | |
| 2659 | return sema.failWithOwnedErrorMsg(msg); | |
| 2644 | 2660 | } |
| 2645 | 2661 | } |
| 2646 | 2662 | return decl_val; |
| ... | ... | @@ -2849,7 +2865,7 @@ fn zirRetPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 2849 | 2865 | const inst_data = sema.code.instructions.items(.data)[inst].node; |
| 2850 | 2866 | const src = LazySrcLoc.nodeOffset(inst_data); |
| 2851 | 2867 | |
| 2852 | if (block.is_comptime or try sema.typeRequiresComptime(block, src, sema.fn_ret_ty)) { | |
| 2868 | if (block.is_comptime or try sema.typeRequiresComptime(sema.fn_ret_ty)) { | |
| 2853 | 2869 | const fn_ret_ty = try sema.resolveTypeFields(block, src, sema.fn_ret_ty); |
| 2854 | 2870 | return sema.analyzeComptimeAlloc(block, fn_ret_ty, 0, src); |
| 2855 | 2871 | } |
| ... | ... | @@ -5040,7 +5056,7 @@ pub fn analyzeExport( |
| 5040 | 5056 | try mod.ensureDeclAnalyzed(exported_decl_index); |
| 5041 | 5057 | const exported_decl = mod.declPtr(exported_decl_index); |
| 5042 | 5058 | |
| 5043 | if (!sema.validateExternType(exported_decl.ty, .other)) { | |
| 5059 | if (!try sema.validateExternType(block, src, exported_decl.ty, .other)) { | |
| 5044 | 5060 | const msg = msg: { |
| 5045 | 5061 | const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{exported_decl.ty.fmt(sema.mod)}); |
| 5046 | 5062 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -5569,7 +5585,11 @@ fn zirCall( |
| 5569 | 5585 | const param_ty_inst = try sema.addType(param_ty); |
| 5570 | 5586 | try sema.inst_map.put(sema.gpa, inst, param_ty_inst); |
| 5571 | 5587 | |
| 5572 | resolved_args[arg_index] = try sema.resolveBody(block, args_body[arg_start..arg_end], inst); | |
| 5588 | const resolved = try sema.resolveBody(block, args_body[arg_start..arg_end], inst); | |
| 5589 | if (sema.typeOf(resolved).zigTypeTag() == .NoReturn) { | |
| 5590 | return resolved; | |
| 5591 | } | |
| 5592 | resolved_args[arg_index] = resolved; | |
| 5573 | 5593 | } |
| 5574 | 5594 | |
| 5575 | 5595 | return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src); |
| ... | ... | @@ -5768,7 +5788,7 @@ fn analyzeCall( |
| 5768 | 5788 | var is_comptime_call = block.is_comptime or modifier == .compile_time; |
| 5769 | 5789 | var comptime_only_ret_ty = false; |
| 5770 | 5790 | if (!is_comptime_call) { |
| 5771 | if (sema.typeRequiresComptime(block, func_src, func_ty_info.return_type)) |ct| { | |
| 5791 | if (sema.typeRequiresComptime(func_ty_info.return_type)) |ct| { | |
| 5772 | 5792 | is_comptime_call = ct; |
| 5773 | 5793 | comptime_only_ret_ty = ct; |
| 5774 | 5794 | } else |err| switch (err) { |
| ... | ... | @@ -6047,7 +6067,7 @@ fn analyzeCall( |
| 6047 | 6067 | break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges); |
| 6048 | 6068 | }; |
| 6049 | 6069 | |
| 6050 | if (!is_comptime_call) { | |
| 6070 | if (!is_comptime_call and sema.typeOf(result).zigTypeTag() != .NoReturn) { | |
| 6051 | 6071 | try sema.emitDbgInline( |
| 6052 | 6072 | block, |
| 6053 | 6073 | module_fn, |
| ... | ... | @@ -6206,7 +6226,7 @@ fn analyzeInlineCallArg( |
| 6206 | 6226 | const param_ty = try sema.analyzeAsType(param_block, param_src, param_ty_inst); |
| 6207 | 6227 | new_fn_info.param_types[arg_i.*] = param_ty; |
| 6208 | 6228 | const uncasted_arg = uncasted_args[arg_i.*]; |
| 6209 | if (try sema.typeRequiresComptime(arg_block, arg_src, param_ty)) { | |
| 6229 | if (try sema.typeRequiresComptime(param_ty)) { | |
| 6210 | 6230 | _ = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime only type must be comptime known") catch |err| { |
| 6211 | 6231 | if (err == error.AnalysisFail and sema.err != null) { |
| 6212 | 6232 | try sema.addComptimeReturnTypeNote(arg_block, func, func_src, ret_ty, sema.err.?, comptime_only_ret_ty); |
| ... | ... | @@ -6308,7 +6328,7 @@ fn analyzeGenericCallArg( |
| 6308 | 6328 | ) !void { |
| 6309 | 6329 | const is_runtime = comptime_arg.val.tag() == .generic_poison and |
| 6310 | 6330 | comptime_arg.ty.hasRuntimeBits() and |
| 6311 | !(try sema.typeRequiresComptime(block, arg_src, comptime_arg.ty)); | |
| 6331 | !(try sema.typeRequiresComptime(comptime_arg.ty)); | |
| 6312 | 6332 | if (is_runtime) { |
| 6313 | 6333 | const param_ty = new_fn_info.param_types[runtime_i.*]; |
| 6314 | 6334 | const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src); |
| ... | ... | @@ -6573,7 +6593,7 @@ fn instantiateGenericCall( |
| 6573 | 6593 | } |
| 6574 | 6594 | } else if (is_anytype) { |
| 6575 | 6595 | const arg_ty = sema.typeOf(arg); |
| 6576 | if (try sema.typeRequiresComptime(block, .unneeded, arg_ty)) { | |
| 6596 | if (try sema.typeRequiresComptime(arg_ty)) { | |
| 6577 | 6597 | const arg_val = try sema.resolveConstValue(block, .unneeded, arg, undefined); |
| 6578 | 6598 | const child_arg = try child_sema.addConstant(arg_ty, arg_val); |
| 6579 | 6599 | child_sema.inst_map.putAssumeCapacityNoClobber(inst, child_arg); |
| ... | ... | @@ -6626,7 +6646,7 @@ fn instantiateGenericCall( |
| 6626 | 6646 | const arg = child_sema.inst_map.get(inst).?; |
| 6627 | 6647 | const copied_arg_ty = try child_sema.typeOf(arg).copy(new_decl_arena_allocator); |
| 6628 | 6648 | |
| 6629 | if (try sema.typeRequiresComptime(block, .unneeded, copied_arg_ty)) { | |
| 6649 | if (try sema.typeRequiresComptime(copied_arg_ty)) { | |
| 6630 | 6650 | is_comptime = true; |
| 6631 | 6651 | } |
| 6632 | 6652 | |
| ... | ... | @@ -6657,7 +6677,7 @@ fn instantiateGenericCall( |
| 6657 | 6677 | // If the call evaluated to a return type that requires comptime, never mind |
| 6658 | 6678 | // our generic instantiation. Instead we need to perform a comptime call. |
| 6659 | 6679 | const new_fn_info = new_decl.ty.fnInfo(); |
| 6660 | if (try sema.typeRequiresComptime(block, call_src, new_fn_info.return_type)) { | |
| 6680 | if (try sema.typeRequiresComptime(new_fn_info.return_type)) { | |
| 6661 | 6681 | return error.ComptimeReturn; |
| 6662 | 6682 | } |
| 6663 | 6683 | // Similarly, if the call evaluated to a generic type we need to instead |
| ... | ... | @@ -7838,7 +7858,7 @@ fn funcCommon( |
| 7838 | 7858 | } |
| 7839 | 7859 | |
| 7840 | 7860 | var ret_ty_requires_comptime = false; |
| 7841 | const ret_poison = if (sema.typeRequiresComptime(block, ret_ty_src, bare_return_type)) |ret_comptime| rp: { | |
| 7861 | const ret_poison = if (sema.typeRequiresComptime(bare_return_type)) |ret_comptime| rp: { | |
| 7842 | 7862 | ret_ty_requires_comptime = ret_comptime; |
| 7843 | 7863 | break :rp bare_return_type.tag() == .generic_poison; |
| 7844 | 7864 | } else |err| switch (err) { |
| ... | ... | @@ -7876,7 +7896,7 @@ fn funcCommon( |
| 7876 | 7896 | }; |
| 7877 | 7897 | return sema.failWithOwnedErrorMsg(msg); |
| 7878 | 7898 | } |
| 7879 | if (!Type.fnCallingConventionAllowsZigTypes(cc_workaround) and !sema.validateExternType(return_type, .ret_ty)) { | |
| 7899 | if (!Type.fnCallingConventionAllowsZigTypes(cc_workaround) and !try sema.validateExternType(block, ret_ty_src, return_type, .ret_ty)) { | |
| 7880 | 7900 | const msg = msg: { |
| 7881 | 7901 | const msg = try sema.errMsg(block, ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{ |
| 7882 | 7902 | return_type.fmt(sema.mod), @tagName(cc_workaround), |
| ... | ... | @@ -8072,7 +8092,7 @@ fn analyzeParameter( |
| 8072 | 8092 | cc: std.builtin.CallingConvention, |
| 8073 | 8093 | has_body: bool, |
| 8074 | 8094 | ) !void { |
| 8075 | const requires_comptime = try sema.typeRequiresComptime(block, param_src, param.ty); | |
| 8095 | const requires_comptime = try sema.typeRequiresComptime(param.ty); | |
| 8076 | 8096 | comptime_params[i] = param.is_comptime or requires_comptime; |
| 8077 | 8097 | const this_generic = param.ty.tag() == .generic_poison; |
| 8078 | 8098 | is_generic.* = is_generic.* or this_generic; |
| ... | ... | @@ -8095,7 +8115,7 @@ fn analyzeParameter( |
| 8095 | 8115 | }; |
| 8096 | 8116 | return sema.failWithOwnedErrorMsg(msg); |
| 8097 | 8117 | } |
| 8098 | if (!Type.fnCallingConventionAllowsZigTypes(cc) and !sema.validateExternType(param.ty, .param_ty)) { | |
| 8118 | if (!Type.fnCallingConventionAllowsZigTypes(cc) and !try sema.validateExternType(block, param_src, param.ty, .param_ty)) { | |
| 8099 | 8119 | const msg = msg: { |
| 8100 | 8120 | const msg = try sema.errMsg(block, param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{ |
| 8101 | 8121 | param.ty.fmt(sema.mod), @tagName(cc), |
| ... | ... | @@ -8177,7 +8197,7 @@ fn zirParam( |
| 8177 | 8197 | } |
| 8178 | 8198 | }; |
| 8179 | 8199 | const is_comptime = comptime_syntax or |
| 8180 | try sema.typeRequiresComptime(block, src, param_ty); | |
| 8200 | try sema.typeRequiresComptime(param_ty); | |
| 8181 | 8201 | if (sema.inst_map.get(inst)) |arg| { |
| 8182 | 8202 | if (is_comptime) { |
| 8183 | 8203 | // We have a comptime value for this parameter so it should be elided from the |
| ... | ... | @@ -8237,7 +8257,7 @@ fn zirParamAnytype( |
| 8237 | 8257 | |
| 8238 | 8258 | if (sema.inst_map.get(inst)) |air_ref| { |
| 8239 | 8259 | const param_ty = sema.typeOf(air_ref); |
| 8240 | if (comptime_syntax or try sema.typeRequiresComptime(block, src, param_ty)) { | |
| 8260 | if (comptime_syntax or try sema.typeRequiresComptime(param_ty)) { | |
| 8241 | 8261 | // We have a comptime value for this parameter so it should be elided from the |
| 8242 | 8262 | // function type of the function instruction in this block. |
| 8243 | 8263 | return; |
| ... | ... | @@ -10379,7 +10399,9 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 10379 | 10399 | } |
| 10380 | 10400 | } |
| 10381 | 10401 | unreachable; |
| 10382 | } else unreachable; | |
| 10402 | } else { | |
| 10403 | return sema.fail(block, operand_src, "no package named '{s}' available", .{operand}); | |
| 10404 | }; | |
| 10383 | 10405 | return sema.fail(block, operand_src, "no package named '{s}' available within package '{s}'", .{ operand, parent }); |
| 10384 | 10406 | }, |
| 10385 | 10407 | else => { |
| ... | ... | @@ -15563,7 +15585,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 15563 | 15585 | } else if (inst_data.size == .Many and elem_ty.zigTypeTag() == .Opaque) { |
| 15564 | 15586 | return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{}); |
| 15565 | 15587 | } else if (inst_data.size == .C) { |
| 15566 | if (!sema.validateExternType(elem_ty, .other)) { | |
| 15588 | if (!try sema.validateExternType(block, elem_ty_src, elem_ty, .other)) { | |
| 15567 | 15589 | const msg = msg: { |
| 15568 | 15590 | const msg = try sema.errMsg(block, elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)}); |
| 15569 | 15591 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -16661,7 +16683,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in |
| 16661 | 16683 | } else if (ptr_size == .Many and elem_ty.zigTypeTag() == .Opaque) { |
| 16662 | 16684 | return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{}); |
| 16663 | 16685 | } else if (ptr_size == .C) { |
| 16664 | if (!sema.validateExternType(elem_ty, .other)) { | |
| 16686 | if (!try sema.validateExternType(block, src, elem_ty, .other)) { | |
| 16665 | 16687 | const msg = msg: { |
| 16666 | 16688 | const msg = try sema.errMsg(block, src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)}); |
| 16667 | 16689 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -17499,7 +17521,7 @@ fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 17499 | 17521 | |
| 17500 | 17522 | if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| { |
| 17501 | 17523 | const target = sema.mod.getTarget(); |
| 17502 | const result_val = try val.intToFloat(sema.arena, operand_ty, dest_ty, target); | |
| 17524 | const result_val = try val.intToFloatAdvanced(sema.arena, operand_ty, dest_ty, target, sema.kit(block, operand_src)); | |
| 17503 | 17525 | return sema.addConstant(dest_ty, result_val); |
| 17504 | 17526 | } else if (dest_ty.zigTypeTag() == .ComptimeFloat) { |
| 17505 | 17527 | return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_float' must be comptime known"); |
| ... | ... | @@ -20343,12 +20365,13 @@ fn validateRunTimeType( |
| 20343 | 20365 | .Int, |
| 20344 | 20366 | .Float, |
| 20345 | 20367 | .ErrorSet, |
| 20346 | .Enum, | |
| 20347 | 20368 | .Frame, |
| 20348 | 20369 | .AnyFrame, |
| 20349 | 20370 | .Void, |
| 20350 | 20371 | => return true, |
| 20351 | 20372 | |
| 20373 | .Enum => return !(try sema.typeRequiresComptime(ty)), | |
| 20374 | ||
| 20352 | 20375 | .BoundFn, |
| 20353 | 20376 | .ComptimeFloat, |
| 20354 | 20377 | .ComptimeInt, |
| ... | ... | @@ -20381,7 +20404,7 @@ fn validateRunTimeType( |
| 20381 | 20404 | |
| 20382 | 20405 | .Struct, .Union => { |
| 20383 | 20406 | const resolved_ty = try sema.resolveTypeFields(block, src, ty); |
| 20384 | const needs_comptime = try sema.typeRequiresComptime(block, src, resolved_ty); | |
| 20407 | const needs_comptime = try sema.typeRequiresComptime(resolved_ty); | |
| 20385 | 20408 | return !needs_comptime; |
| 20386 | 20409 | }, |
| 20387 | 20410 | }; |
| ... | ... | @@ -20489,7 +20512,7 @@ fn explainWhyTypeIsComptimeInner( |
| 20489 | 20512 | .range = .type, |
| 20490 | 20513 | }); |
| 20491 | 20514 | |
| 20492 | if (try sema.typeRequiresComptime(block, src, field.ty)) { | |
| 20515 | if (try sema.typeRequiresComptime(field.ty)) { | |
| 20493 | 20516 | try mod.errNoteNonLazy(field_src_loc, msg, "struct requires comptime because of this field", .{}); |
| 20494 | 20517 | try sema.explainWhyTypeIsComptimeInner(block, src, msg, field_src_loc, field.ty, type_set); |
| 20495 | 20518 | } |
| ... | ... | @@ -20509,7 +20532,7 @@ fn explainWhyTypeIsComptimeInner( |
| 20509 | 20532 | .range = .type, |
| 20510 | 20533 | }); |
| 20511 | 20534 | |
| 20512 | if (try sema.typeRequiresComptime(block, src, field.ty)) { | |
| 20535 | if (try sema.typeRequiresComptime(field.ty)) { | |
| 20513 | 20536 | try mod.errNoteNonLazy(field_src_loc, msg, "union requires comptime because of this field", .{}); |
| 20514 | 20537 | try sema.explainWhyTypeIsComptimeInner(block, src, msg, field_src_loc, field.ty, type_set); |
| 20515 | 20538 | } |
| ... | ... | @@ -20528,7 +20551,14 @@ const ExternPosition = enum { |
| 20528 | 20551 | |
| 20529 | 20552 | /// Returns true if `ty` is allowed in extern types. |
| 20530 | 20553 | /// Does *NOT* require `ty` to be resolved in any way. |
| 20531 | fn validateExternType(sema: *Sema, ty: Type, position: ExternPosition) bool { | |
| 20554 | /// Calls `resolveTypeLayout` for packed containers. | |
| 20555 | fn validateExternType( | |
| 20556 | sema: *Sema, | |
| 20557 | block: *Block, | |
| 20558 | src: LazySrcLoc, | |
| 20559 | ty: Type, | |
| 20560 | position: ExternPosition, | |
| 20561 | ) !bool { | |
| 20532 | 20562 | switch (ty.zigTypeTag()) { |
| 20533 | 20563 | .Type, |
| 20534 | 20564 | .ComptimeFloat, |
| ... | ... | @@ -20556,17 +20586,25 @@ fn validateExternType(sema: *Sema, ty: Type, position: ExternPosition) bool { |
| 20556 | 20586 | .Fn => return !Type.fnCallingConventionAllowsZigTypes(ty.fnCallingConvention()), |
| 20557 | 20587 | .Enum => { |
| 20558 | 20588 | var buf: Type.Payload.Bits = undefined; |
| 20559 | return sema.validateExternType(ty.intTagType(&buf), position); | |
| 20589 | return sema.validateExternType(block, src, ty.intTagType(&buf), position); | |
| 20560 | 20590 | }, |
| 20561 | 20591 | .Struct, .Union => switch (ty.containerLayout()) { |
| 20562 | .Extern, .Packed => return true, | |
| 20563 | else => return false, | |
| 20592 | .Extern => return true, | |
| 20593 | .Packed => { | |
| 20594 | const target = sema.mod.getTarget(); | |
| 20595 | const bit_size = try ty.bitSizeAdvanced(target, sema.kit(block, src)); | |
| 20596 | switch (bit_size) { | |
| 20597 | 8, 16, 32, 64, 128 => return true, | |
| 20598 | else => return false, | |
| 20599 | } | |
| 20600 | }, | |
| 20601 | .Auto => return false, | |
| 20564 | 20602 | }, |
| 20565 | 20603 | .Array => { |
| 20566 | 20604 | if (position == .ret_ty or position == .param_ty) return false; |
| 20567 | return sema.validateExternType(ty.elemType2(), .other); | |
| 20605 | return sema.validateExternType(block, src, ty.elemType2(), .other); | |
| 20568 | 20606 | }, |
| 20569 | .Vector => return sema.validateExternType(ty.elemType2(), .other), | |
| 20607 | .Vector => return sema.validateExternType(block, src, ty.elemType2(), .other), | |
| 20570 | 20608 | .Optional => return ty.isPtrLikeOptional(), |
| 20571 | 20609 | } |
| 20572 | 20610 | } |
| ... | ... | @@ -20618,8 +20656,8 @@ fn explainWhyTypeIsNotExtern( |
| 20618 | 20656 | try mod.errNoteNonLazy(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(sema.mod)}); |
| 20619 | 20657 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position); |
| 20620 | 20658 | }, |
| 20621 | .Struct => try mod.errNoteNonLazy(src_loc, msg, "only structs with packed or extern layout are extern compatible", .{}), | |
| 20622 | .Union => try mod.errNoteNonLazy(src_loc, msg, "only unions with packed or extern layout are extern compatible", .{}), | |
| 20659 | .Struct => try mod.errNoteNonLazy(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}), | |
| 20660 | .Union => try mod.errNoteNonLazy(src_loc, msg, "only extern unions and ABI sized packed unions are extern compatible", .{}), | |
| 20623 | 20661 | .Array => { |
| 20624 | 20662 | if (position == .ret_ty) { |
| 20625 | 20663 | return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a return type", .{}); |
| ... | ... | @@ -22998,7 +23036,7 @@ fn coerceExtra( |
| 22998 | 23036 | } |
| 22999 | 23037 | break :int; |
| 23000 | 23038 | }; |
| 23001 | const result_val = try val.intToFloat(sema.arena, inst_ty, dest_ty, target); | |
| 23039 | const result_val = try val.intToFloatAdvanced(sema.arena, inst_ty, dest_ty, target, sema.kit(block, inst_src)); | |
| 23002 | 23040 | // TODO implement this compile error |
| 23003 | 23041 | //const int_again_val = try result_val.floatToInt(sema.arena, inst_ty); |
| 23004 | 23042 | //if (!int_again_val.eql(val, inst_ty, mod)) { |
| ... | ... | @@ -23422,8 +23460,11 @@ const InMemoryCoercionResult = union(enum) { |
| 23422 | 23460 | var index: u6 = 0; |
| 23423 | 23461 | var actual_noalias = false; |
| 23424 | 23462 | while (true) : (index += 1) { |
| 23425 | if (param.actual << index != param.wanted << index) { | |
| 23426 | actual_noalias = (param.actual << index) == (1 << 31); | |
| 23463 | const actual = @truncate(u1, param.actual >> index); | |
| 23464 | const wanted = @truncate(u1, param.wanted >> index); | |
| 23465 | if (actual != wanted) { | |
| 23466 | actual_noalias = actual == 1; | |
| 23467 | break; | |
| 23427 | 23468 | } |
| 23428 | 23469 | } |
| 23429 | 23470 | if (!actual_noalias) { |
| ... | ... | @@ -23917,7 +23958,7 @@ fn coerceInMemoryAllowedFns( |
| 23917 | 23958 | |
| 23918 | 23959 | if (dest_info.noalias_bits != src_info.noalias_bits) { |
| 23919 | 23960 | return InMemoryCoercionResult{ .fn_param_noalias = .{ |
| 23920 | .actual = dest_info.noalias_bits, | |
| 23961 | .actual = src_info.noalias_bits, | |
| 23921 | 23962 | .wanted = dest_info.noalias_bits, |
| 23922 | 23963 | } }; |
| 23923 | 23964 | } |
| ... | ... | @@ -24075,16 +24116,40 @@ fn coerceVarArgParam( |
| 24075 | 24116 | inst: Air.Inst.Ref, |
| 24076 | 24117 | inst_src: LazySrcLoc, |
| 24077 | 24118 | ) !Air.Inst.Ref { |
| 24078 | const inst_ty = sema.typeOf(inst); | |
| 24079 | 24119 | if (block.is_typeof) return inst; |
| 24080 | 24120 | |
| 24081 | switch (inst_ty.zigTypeTag()) { | |
| 24121 | const coerced = switch (sema.typeOf(inst).zigTypeTag()) { | |
| 24082 | 24122 | // TODO consider casting to c_int/f64 if they fit |
| 24083 | .ComptimeInt, .ComptimeFloat => return sema.fail(block, inst_src, "integer and float literals in var args function must be casted", .{}), | |
| 24084 | else => {}, | |
| 24123 | .ComptimeInt, .ComptimeFloat => return sema.fail( | |
| 24124 | block, | |
| 24125 | inst_src, | |
| 24126 | "integer and float literals passed variadic function must be casted to a fixed-size number type", | |
| 24127 | .{}, | |
| 24128 | ), | |
| 24129 | .Fn => blk: { | |
| 24130 | const fn_val = try sema.resolveConstValue(block, .unneeded, inst, undefined); | |
| 24131 | const fn_decl = fn_val.pointerDecl().?; | |
| 24132 | break :blk try sema.analyzeDeclRef(fn_decl); | |
| 24133 | }, | |
| 24134 | .Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}), | |
| 24135 | else => inst, | |
| 24136 | }; | |
| 24137 | ||
| 24138 | const coerced_ty = sema.typeOf(coerced); | |
| 24139 | if (!try sema.validateExternType(block, inst_src, coerced_ty, .other)) { | |
| 24140 | const msg = msg: { | |
| 24141 | const msg = try sema.errMsg(block, inst_src, "cannot pass '{}' to variadic function", .{coerced_ty.fmt(sema.mod)}); | |
| 24142 | errdefer msg.destroy(sema.gpa); | |
| 24143 | ||
| 24144 | const src_decl = sema.mod.declPtr(block.src_decl); | |
| 24145 | try sema.explainWhyTypeIsNotExtern(msg, inst_src.toSrcLoc(src_decl), coerced_ty, .other); | |
| 24146 | ||
| 24147 | try sema.addDeclaredHereNote(msg, coerced_ty); | |
| 24148 | break :msg msg; | |
| 24149 | }; | |
| 24150 | return sema.failWithOwnedErrorMsg(msg); | |
| 24085 | 24151 | } |
| 24086 | // TODO implement more of this function. | |
| 24087 | return inst; | |
| 24152 | return coerced; | |
| 24088 | 24153 | } |
| 24089 | 24154 | |
| 24090 | 24155 | // TODO migrate callsites to use storePtr2 instead. |
| ... | ... | @@ -27579,7 +27644,7 @@ pub fn resolveTypeLayout( |
| 27579 | 27644 | // In case of querying the ABI alignment of this optional, we will ask |
| 27580 | 27645 | // for hasRuntimeBits() of the payload type, so we need "requires comptime" |
| 27581 | 27646 | // to be known already before this function returns. |
| 27582 | _ = try sema.typeRequiresComptime(block, src, payload_ty); | |
| 27647 | _ = try sema.typeRequiresComptime(payload_ty); | |
| 27583 | 27648 | return sema.resolveTypeLayout(block, src, payload_ty); |
| 27584 | 27649 | }, |
| 27585 | 27650 | .ErrorUnion => { |
| ... | ... | @@ -27634,7 +27699,7 @@ fn resolveStructLayout( |
| 27634 | 27699 | // for hasRuntimeBits() of each field, so we need "requires comptime" |
| 27635 | 27700 | // to be known already before this function returns. |
| 27636 | 27701 | for (struct_obj.fields.values()) |field, i| { |
| 27637 | _ = sema.typeRequiresComptime(block, src, field.ty) catch |err| switch (err) { | |
| 27702 | _ = sema.typeRequiresComptime(field.ty) catch |err| switch (err) { | |
| 27638 | 27703 | error.AnalysisFail => { |
| 27639 | 27704 | const msg = sema.err orelse return err; |
| 27640 | 27705 | try sema.addFieldErrNote(block, ty, i, msg, "while checking this field", .{}); |
| ... | ... | @@ -27866,7 +27931,7 @@ fn resolveStructFully( |
| 27866 | 27931 | } |
| 27867 | 27932 | |
| 27868 | 27933 | // And let's not forget comptime-only status. |
| 27869 | _ = try sema.typeRequiresComptime(block, src, ty); | |
| 27934 | _ = try sema.typeRequiresComptime(ty); | |
| 27870 | 27935 | } |
| 27871 | 27936 | |
| 27872 | 27937 | fn resolveUnionFully( |
| ... | ... | @@ -27899,7 +27964,7 @@ fn resolveUnionFully( |
| 27899 | 27964 | } |
| 27900 | 27965 | |
| 27901 | 27966 | // And let's not forget comptime-only status. |
| 27902 | _ = try sema.typeRequiresComptime(block, src, ty); | |
| 27967 | _ = try sema.typeRequiresComptime(ty); | |
| 27903 | 27968 | } |
| 27904 | 27969 | |
| 27905 | 27970 | 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 |
| 28273 | 28338 | }; |
| 28274 | 28339 | return sema.failWithOwnedErrorMsg(msg); |
| 28275 | 28340 | } |
| 28276 | if (struct_obj.layout == .Extern and !sema.validateExternType(field.ty, .other)) { | |
| 28341 | if (struct_obj.layout == .Extern and !try sema.validateExternType(&block_scope, src, field.ty, .other)) { | |
| 28277 | 28342 | const msg = msg: { |
| 28278 | 28343 | const tree = try sema.getAstTree(&block_scope); |
| 28279 | 28344 | const fields_src = enumFieldSrcLoc(decl, tree.*, 0, i); |
| ... | ... | @@ -28610,7 +28675,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 28610 | 28675 | }; |
| 28611 | 28676 | return sema.failWithOwnedErrorMsg(msg); |
| 28612 | 28677 | } |
| 28613 | if (union_obj.layout == .Extern and !sema.validateExternType(field_ty, .union_field)) { | |
| 28678 | if (union_obj.layout == .Extern and !try sema.validateExternType(&block_scope, src, field_ty, .union_field)) { | |
| 28614 | 28679 | const msg = msg: { |
| 28615 | 28680 | const tree = try sema.getAstTree(&block_scope); |
| 28616 | 28681 | const field_src = enumFieldSrcLoc(decl, tree.*, 0, field_i); |
| ... | ... | @@ -29002,7 +29067,7 @@ pub fn typeHasOnePossibleValue( |
| 29002 | 29067 | }, |
| 29003 | 29068 | .enum_nonexhaustive => { |
| 29004 | 29069 | const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty; |
| 29005 | if (!(try sema.typeHasRuntimeBits(block, src, tag_ty))) { | |
| 29070 | if (tag_ty.zigTypeTag() != .ComptimeInt and !(try sema.typeHasRuntimeBits(block, src, tag_ty))) { | |
| 29006 | 29071 | return Value.zero; |
| 29007 | 29072 | } else { |
| 29008 | 29073 | return null; |
| ... | ... | @@ -29534,7 +29599,7 @@ fn typePtrOrOptionalPtrTy( |
| 29534 | 29599 | /// TODO assert the return value matches `ty.comptimeOnly` |
| 29535 | 29600 | /// TODO merge these implementations together with the "advanced"/sema_kit pattern seen |
| 29536 | 29601 | /// elsewhere in value.zig |
| 29537 | pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool { | |
| 29602 | pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { | |
| 29538 | 29603 | return switch (ty.tag()) { |
| 29539 | 29604 | .u1, |
| 29540 | 29605 | .u8, |
| ... | ... | @@ -29625,7 +29690,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ |
| 29625 | 29690 | .array, |
| 29626 | 29691 | .array_sentinel, |
| 29627 | 29692 | .vector, |
| 29628 | => return sema.typeRequiresComptime(block, src, ty.childType()), | |
| 29693 | => return sema.typeRequiresComptime(ty.childType()), | |
| 29629 | 29694 | |
| 29630 | 29695 | .pointer, |
| 29631 | 29696 | .single_const_pointer, |
| ... | ... | @@ -29641,7 +29706,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ |
| 29641 | 29706 | if (child_ty.zigTypeTag() == .Fn) { |
| 29642 | 29707 | return child_ty.fnInfo().is_generic; |
| 29643 | 29708 | } else { |
| 29644 | return sema.typeRequiresComptime(block, src, child_ty); | |
| 29709 | return sema.typeRequiresComptime(child_ty); | |
| 29645 | 29710 | } |
| 29646 | 29711 | }, |
| 29647 | 29712 | |
| ... | ... | @@ -29650,14 +29715,14 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ |
| 29650 | 29715 | .optional_single_const_pointer, |
| 29651 | 29716 | => { |
| 29652 | 29717 | var buf: Type.Payload.ElemType = undefined; |
| 29653 | return sema.typeRequiresComptime(block, src, ty.optionalChild(&buf)); | |
| 29718 | return sema.typeRequiresComptime(ty.optionalChild(&buf)); | |
| 29654 | 29719 | }, |
| 29655 | 29720 | |
| 29656 | 29721 | .tuple, .anon_struct => { |
| 29657 | 29722 | const tuple = ty.tupleFields(); |
| 29658 | 29723 | for (tuple.types) |field_ty, i| { |
| 29659 | 29724 | const have_comptime_val = tuple.values[i].tag() != .unreachable_value; |
| 29660 | if (!have_comptime_val and try sema.typeRequiresComptime(block, src, field_ty)) { | |
| 29725 | if (!have_comptime_val and try sema.typeRequiresComptime(field_ty)) { | |
| 29661 | 29726 | return true; |
| 29662 | 29727 | } |
| 29663 | 29728 | } |
| ... | ... | @@ -29678,7 +29743,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ |
| 29678 | 29743 | struct_obj.requires_comptime = .wip; |
| 29679 | 29744 | for (struct_obj.fields.values()) |field| { |
| 29680 | 29745 | if (field.is_comptime) continue; |
| 29681 | if (try sema.typeRequiresComptime(block, src, field.ty)) { | |
| 29746 | if (try sema.typeRequiresComptime(field.ty)) { | |
| 29682 | 29747 | struct_obj.requires_comptime = .yes; |
| 29683 | 29748 | return true; |
| 29684 | 29749 | } |
| ... | ... | @@ -29702,7 +29767,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ |
| 29702 | 29767 | |
| 29703 | 29768 | union_obj.requires_comptime = .wip; |
| 29704 | 29769 | for (union_obj.fields.values()) |field| { |
| 29705 | if (try sema.typeRequiresComptime(block, src, field.ty)) { | |
| 29770 | if (try sema.typeRequiresComptime(field.ty)) { | |
| 29706 | 29771 | union_obj.requires_comptime = .yes; |
| 29707 | 29772 | return true; |
| 29708 | 29773 | } |
| ... | ... | @@ -29713,18 +29778,18 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ |
| 29713 | 29778 | } |
| 29714 | 29779 | }, |
| 29715 | 29780 | |
| 29716 | .error_union => return sema.typeRequiresComptime(block, src, ty.errorUnionPayload()), | |
| 29781 | .error_union => return sema.typeRequiresComptime(ty.errorUnionPayload()), | |
| 29717 | 29782 | .anyframe_T => { |
| 29718 | 29783 | const child_ty = ty.castTag(.anyframe_T).?.data; |
| 29719 | return sema.typeRequiresComptime(block, src, child_ty); | |
| 29784 | return sema.typeRequiresComptime(child_ty); | |
| 29720 | 29785 | }, |
| 29721 | 29786 | .enum_numbered => { |
| 29722 | 29787 | const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty; |
| 29723 | return sema.typeRequiresComptime(block, src, tag_ty); | |
| 29788 | return sema.typeRequiresComptime(tag_ty); | |
| 29724 | 29789 | }, |
| 29725 | 29790 | .enum_full, .enum_nonexhaustive => { |
| 29726 | 29791 | const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty; |
| 29727 | return sema.typeRequiresComptime(block, src, tag_ty); | |
| 29792 | return sema.typeRequiresComptime(tag_ty); | |
| 29728 | 29793 | }, |
| 29729 | 29794 | }; |
| 29730 | 29795 | } |
| ... | ... | @@ -29762,7 +29827,7 @@ fn unionFieldAlignment( |
| 29762 | 29827 | } |
| 29763 | 29828 | |
| 29764 | 29829 | /// Synchronize logic with `Type.isFnOrHasRuntimeBits`. |
| 29765 | pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool { | |
| 29830 | pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool { | |
| 29766 | 29831 | const fn_info = ty.fnInfo(); |
| 29767 | 29832 | if (fn_info.is_generic) return false; |
| 29768 | 29833 | if (fn_info.is_var_args) return true; |
| ... | ... | @@ -29771,7 +29836,7 @@ pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) C |
| 29771 | 29836 | .Inline => return false, |
| 29772 | 29837 | else => {}, |
| 29773 | 29838 | } |
| 29774 | if (try sema.typeRequiresComptime(block, src, fn_info.return_type)) { | |
| 29839 | if (try sema.typeRequiresComptime(fn_info.return_type)) { | |
| 29775 | 29840 | return false; |
| 29776 | 29841 | } |
| 29777 | 29842 | return true; |
src/arch/aarch64/abi.zig+63| ... | ... | @@ -3,6 +3,69 @@ const builtin = @import("builtin"); |
| 3 | 3 | const bits = @import("bits.zig"); |
| 4 | 4 | const Register = bits.Register; |
| 5 | 5 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 6 | const Type = @import("../../type.zig").Type; | |
| 7 | ||
| 8 | pub const Class = enum { memory, integer, none, float_array }; | |
| 9 | ||
| 10 | pub fn classifyType(ty: Type, target: std.Target) [2]Class { | |
| 11 | if (!ty.hasRuntimeBitsIgnoreComptime()) return .{ .none, .none }; | |
| 12 | switch (ty.zigTypeTag()) { | |
| 13 | .Struct => { | |
| 14 | if (ty.containerLayout() == .Packed) return .{ .integer, .none }; | |
| 15 | ||
| 16 | if (ty.structFieldCount() <= 4) { | |
| 17 | const fields = ty.structFields(); | |
| 18 | var float_size: ?u64 = null; | |
| 19 | for (fields.values()) |field| { | |
| 20 | if (field.ty.zigTypeTag() != .Float) break; | |
| 21 | const field_size = field.ty.bitSize(target); | |
| 22 | const prev_size = float_size orelse { | |
| 23 | float_size = field_size; | |
| 24 | continue; | |
| 25 | }; | |
| 26 | if (field_size != prev_size) break; | |
| 27 | } else { | |
| 28 | return .{ .float_array, .none }; | |
| 29 | } | |
| 30 | } | |
| 31 | const bit_size = ty.bitSize(target); | |
| 32 | if (bit_size > 128) return .{ .memory, .none }; | |
| 33 | if (bit_size > 64) return .{ .integer, .integer }; | |
| 34 | return .{ .integer, .none }; | |
| 35 | }, | |
| 36 | .Union => { | |
| 37 | const bit_size = ty.bitSize(target); | |
| 38 | if (bit_size > 128) return .{ .memory, .none }; | |
| 39 | if (bit_size > 64) return .{ .integer, .integer }; | |
| 40 | return .{ .integer, .none }; | |
| 41 | }, | |
| 42 | .Int, .Enum, .ErrorSet, .Vector, .Float, .Bool => return .{ .integer, .none }, | |
| 43 | .Array => return .{ .memory, .none }, | |
| 44 | .Optional => { | |
| 45 | std.debug.assert(ty.isPtrLikeOptional()); | |
| 46 | return .{ .integer, .none }; | |
| 47 | }, | |
| 48 | .Pointer => { | |
| 49 | std.debug.assert(!ty.isSlice()); | |
| 50 | return .{ .integer, .none }; | |
| 51 | }, | |
| 52 | .ErrorUnion, | |
| 53 | .Frame, | |
| 54 | .AnyFrame, | |
| 55 | .NoReturn, | |
| 56 | .Void, | |
| 57 | .Type, | |
| 58 | .ComptimeFloat, | |
| 59 | .ComptimeInt, | |
| 60 | .Undefined, | |
| 61 | .Null, | |
| 62 | .BoundFn, | |
| 63 | .Fn, | |
| 64 | .Opaque, | |
| 65 | .EnumLiteral, | |
| 66 | => unreachable, | |
| 67 | } | |
| 68 | } | |
| 6 | 69 | |
| 7 | 70 | const callee_preserved_regs_impl = if (builtin.os.tag.isDarwin()) struct { |
| 8 | 71 | pub const callee_preserved_regs = [_]Register{ |
src/arch/wasm/CodeGen.zig-2| ... | ... | @@ -2394,9 +2394,7 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue { |
| 2394 | 2394 | const decl_index = decl_ref_mut.data.decl_index; |
| 2395 | 2395 | return self.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl_index); |
| 2396 | 2396 | } |
| 2397 | ||
| 2398 | 2397 | const target = self.target; |
| 2399 | ||
| 2400 | 2398 | switch (ty.zigTypeTag()) { |
| 2401 | 2399 | .Void => return WValue{ .none = {} }, |
| 2402 | 2400 | .Int => { |
src/arch/wasm/abi.zig+8| ... | ... | @@ -23,6 +23,10 @@ pub fn classifyType(ty: Type, target: Target) [2]Class { |
| 23 | 23 | if (!ty.hasRuntimeBitsIgnoreComptime()) return none; |
| 24 | 24 | switch (ty.zigTypeTag()) { |
| 25 | 25 | .Struct => { |
| 26 | if (ty.containerLayout() == .Packed) { | |
| 27 | if (ty.bitSize(target) <= 64) return direct; | |
| 28 | return .{ .direct, .direct }; | |
| 29 | } | |
| 26 | 30 | // When the struct type is non-scalar |
| 27 | 31 | if (ty.structFieldCount() > 1) return memory; |
| 28 | 32 | // When the struct's alignment is non-natural |
| ... | ... | @@ -57,6 +61,10 @@ pub fn classifyType(ty: Type, target: Target) [2]Class { |
| 57 | 61 | return direct; |
| 58 | 62 | }, |
| 59 | 63 | .Union => { |
| 64 | if (ty.containerLayout() == .Packed) { | |
| 65 | if (ty.bitSize(target) <= 64) return direct; | |
| 66 | return .{ .direct, .direct }; | |
| 67 | } | |
| 60 | 68 | const layout = ty.unionGetLayout(target); |
| 61 | 69 | std.debug.assert(layout.tag_size == 0); |
| 62 | 70 | if (ty.unionFields().count() > 1) return memory; |
src/arch/x86_64/abi.zig+22-2| ... | ... | @@ -5,7 +5,7 @@ const assert = std.debug.assert; |
| 5 | 5 | const Register = @import("bits.zig").Register; |
| 6 | 6 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 7 | 7 | |
| 8 | pub const Class = enum { integer, sse, sseup, x87, x87up, complex_x87, memory, none }; | |
| 8 | pub const Class = enum { integer, sse, sseup, x87, x87up, complex_x87, memory, none, win_i128 }; | |
| 9 | 9 | |
| 10 | 10 | pub fn classifyWindows(ty: Type, target: Target) Class { |
| 11 | 11 | // 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 { |
| 34 | 34 | => switch (ty.abiSize(target)) { |
| 35 | 35 | 0 => unreachable, |
| 36 | 36 | 1, 2, 4, 8 => return .integer, |
| 37 | else => return .memory, | |
| 37 | else => switch (ty.zigTypeTag()) { | |
| 38 | .Int => return .win_i128, | |
| 39 | .Struct, .Union => if (ty.containerLayout() == .Packed) { | |
| 40 | return .win_i128; | |
| 41 | } else { | |
| 42 | return .memory; | |
| 43 | }, | |
| 44 | else => return .memory, | |
| 45 | }, | |
| 38 | 46 | }, |
| 39 | 47 | |
| 40 | 48 | .Float, .Vector => return .sse, |
| ... | ... | @@ -174,6 +182,12 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class { |
| 174 | 182 | // "If the size of the aggregate exceeds a single eightbyte, each is classified |
| 175 | 183 | // separately.". |
| 176 | 184 | const ty_size = ty.abiSize(target); |
| 185 | if (ty.containerLayout() == .Packed) { | |
| 186 | assert(ty_size <= 128); | |
| 187 | result[0] = .integer; | |
| 188 | if (ty_size > 64) result[1] = .integer; | |
| 189 | return result; | |
| 190 | } | |
| 177 | 191 | if (ty_size > 64) |
| 178 | 192 | return memory_class; |
| 179 | 193 | |
| ... | ... | @@ -284,6 +298,12 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class { |
| 284 | 298 | // "If the size of the aggregate exceeds a single eightbyte, each is classified |
| 285 | 299 | // separately.". |
| 286 | 300 | const ty_size = ty.abiSize(target); |
| 301 | if (ty.containerLayout() == .Packed) { | |
| 302 | assert(ty_size <= 128); | |
| 303 | result[0] = .integer; | |
| 304 | if (ty_size > 64) result[1] = .integer; | |
| 305 | return result; | |
| 306 | } | |
| 287 | 307 | if (ty_size > 64) |
| 288 | 308 | return memory_class; |
| 289 | 309 |
src/autodoc/render_source.zig+15| ... | ... | @@ -79,6 +79,16 @@ pub fn genHtml( |
| 79 | 79 | \\ text-align: right; |
| 80 | 80 | \\ color: #999; |
| 81 | 81 | \\ } |
| 82 | \\ | |
| 83 | \\ .line { | |
| 84 | \\ width: 100%; | |
| 85 | \\ display: inline-block; | |
| 86 | \\ } | |
| 87 | \\ .line:target { | |
| 88 | \\ border-top: 1px solid #ccc; | |
| 89 | \\ border-bottom: 1px solid #ccc; | |
| 90 | \\ background: #fafafa; | |
| 91 | \\ } | |
| 82 | 92 | \\ |
| 83 | 93 | \\ @media (prefers-color-scheme: dark) { |
| 84 | 94 | \\ body{ |
| ... | ... | @@ -90,6 +100,11 @@ pub fn genHtml( |
| 90 | 100 | \\ background: #222; |
| 91 | 101 | \\ border: unset; |
| 92 | 102 | \\ } |
| 103 | \\ .line:target { | |
| 104 | \\ border-top: 1px solid #444; | |
| 105 | \\ border-bottom: 1px solid #444; | |
| 106 | \\ background: #333; | |
| 107 | \\ } | |
| 93 | 108 | \\ .tok-kw { |
| 94 | 109 | \\ color: #eee; |
| 95 | 110 | \\ } |
src/codegen/llvm.zig+140-52| ... | ... | @@ -23,6 +23,7 @@ const LazySrcLoc = Module.LazySrcLoc; |
| 23 | 23 | const CType = @import("../type.zig").CType; |
| 24 | 24 | const x86_64_abi = @import("../arch/x86_64/abi.zig"); |
| 25 | 25 | const wasm_c_abi = @import("../arch/wasm/abi.zig"); |
| 26 | const aarch64_c_abi = @import("../arch/aarch64/abi.zig"); | |
| 26 | 27 | |
| 27 | 28 | const Error = error{ OutOfMemory, CodegenFail }; |
| 28 | 29 | |
| ... | ... | @@ -314,6 +315,15 @@ pub fn supportsTailCall(target: std.Target) bool { |
| 314 | 315 | } |
| 315 | 316 | } |
| 316 | 317 | |
| 318 | /// TODO can this be done with simpler logic / different API binding? | |
| 319 | fn deleteLlvmGlobal(llvm_global: *const llvm.Value) void { | |
| 320 | if (llvm_global.globalGetValueType().getTypeKind() == .Function) { | |
| 321 | llvm_global.deleteFunction(); | |
| 322 | return; | |
| 323 | } | |
| 324 | return llvm_global.deleteGlobal(); | |
| 325 | } | |
| 326 | ||
| 317 | 327 | pub const Object = struct { |
| 318 | 328 | gpa: Allocator, |
| 319 | 329 | module: *Module, |
| ... | ... | @@ -667,7 +677,7 @@ pub const Object = struct { |
| 667 | 677 | |
| 668 | 678 | const new_global_ptr = other_global.constBitCast(llvm_global.typeOf()); |
| 669 | 679 | llvm_global.replaceAllUsesWith(new_global_ptr); |
| 670 | object.deleteLlvmGlobal(llvm_global); | |
| 680 | deleteLlvmGlobal(llvm_global); | |
| 671 | 681 | entry.value_ptr.* = new_global_ptr; |
| 672 | 682 | } |
| 673 | 683 | object.extern_collisions.clearRetainingCapacity(); |
| ... | ... | @@ -693,7 +703,7 @@ pub const Object = struct { |
| 693 | 703 | const new_global_ptr = llvm_global.constBitCast(other_global.typeOf()); |
| 694 | 704 | other_global.replaceAllUsesWith(new_global_ptr); |
| 695 | 705 | llvm_global.takeName(other_global); |
| 696 | other_global.deleteGlobal(); | |
| 706 | deleteLlvmGlobal(other_global); | |
| 697 | 707 | // Problem: now we need to replace in the decl_map that |
| 698 | 708 | // the extern decl index points to this new global. However we don't |
| 699 | 709 | // know the decl index. |
| ... | ... | @@ -1084,6 +1094,26 @@ pub const Object = struct { |
| 1084 | 1094 | try args.ensureUnusedCapacity(1); |
| 1085 | 1095 | args.appendAssumeCapacity(casted); |
| 1086 | 1096 | }, |
| 1097 | .float_array => { | |
| 1098 | const param_ty = fn_info.param_types[it.zig_index - 1]; | |
| 1099 | const param_llvm_ty = try dg.lowerType(param_ty); | |
| 1100 | const param = llvm_func.getParam(llvm_arg_i); | |
| 1101 | llvm_arg_i += 1; | |
| 1102 | ||
| 1103 | const alignment = param_ty.abiAlignment(target); | |
| 1104 | const arg_ptr = buildAllocaInner(builder, llvm_func, false, param_llvm_ty); | |
| 1105 | arg_ptr.setAlignment(alignment); | |
| 1106 | const casted_ptr = builder.buildBitCast(arg_ptr, param.typeOf().pointerType(0), ""); | |
| 1107 | _ = builder.buildStore(param, casted_ptr); | |
| 1108 | ||
| 1109 | if (isByRef(param_ty)) { | |
| 1110 | try args.append(arg_ptr); | |
| 1111 | } else { | |
| 1112 | const load_inst = builder.buildLoad(param_llvm_ty, arg_ptr, ""); | |
| 1113 | load_inst.setAlignment(alignment); | |
| 1114 | try args.append(load_inst); | |
| 1115 | } | |
| 1116 | }, | |
| 1087 | 1117 | }; |
| 1088 | 1118 | } |
| 1089 | 1119 | |
| ... | ... | @@ -1191,15 +1221,6 @@ pub const Object = struct { |
| 1191 | 1221 | return null; |
| 1192 | 1222 | } |
| 1193 | 1223 | |
| 1194 | /// TODO can this be done with simpler logic / different API binding? | |
| 1195 | fn deleteLlvmGlobal(o: Object, llvm_global: *const llvm.Value) void { | |
| 1196 | if (o.llvm_module.getNamedFunction(llvm_global.getValueName()) != null) { | |
| 1197 | llvm_global.deleteFunction(); | |
| 1198 | return; | |
| 1199 | } | |
| 1200 | return llvm_global.deleteGlobal(); | |
| 1201 | } | |
| 1202 | ||
| 1203 | 1224 | pub fn updateDeclExports( |
| 1204 | 1225 | self: *Object, |
| 1205 | 1226 | module: *Module, |
| ... | ... | @@ -1294,7 +1315,7 @@ pub const Object = struct { |
| 1294 | 1315 | alias.setAliasee(llvm_global); |
| 1295 | 1316 | } else { |
| 1296 | 1317 | _ = self.llvm_module.addAlias( |
| 1297 | llvm_global.typeOf(), | |
| 1318 | llvm_global.globalGetValueType(), | |
| 1298 | 1319 | 0, |
| 1299 | 1320 | llvm_global, |
| 1300 | 1321 | exp_name_z, |
| ... | ... | @@ -2527,6 +2548,7 @@ pub const DeclGen = struct { |
| 2527 | 2548 | .multiple_llvm_ints, |
| 2528 | 2549 | .multiple_llvm_float, |
| 2529 | 2550 | .as_u16, |
| 2551 | .float_array, | |
| 2530 | 2552 | => continue, |
| 2531 | 2553 | |
| 2532 | 2554 | .slice => unreachable, // extern functions do not support slice types. |
| ... | ... | @@ -3093,6 +3115,13 @@ pub const DeclGen = struct { |
| 3093 | 3115 | .as_u16 => { |
| 3094 | 3116 | try llvm_params.append(dg.context.intType(16)); |
| 3095 | 3117 | }, |
| 3118 | .float_array => { | |
| 3119 | const param_ty = fn_info.param_types[it.zig_index - 1]; | |
| 3120 | const float_ty = try dg.lowerType(param_ty.structFieldType(0)); | |
| 3121 | const field_count = @intCast(c_uint, param_ty.structFieldCount()); | |
| 3122 | const arr_ty = float_ty.arrayType(field_count); | |
| 3123 | try llvm_params.append(arr_ty); | |
| 3124 | }, | |
| 3096 | 3125 | }; |
| 3097 | 3126 | |
| 3098 | 3127 | return llvm.functionType( |
| ... | ... | @@ -4719,6 +4748,27 @@ pub const FuncGen = struct { |
| 4719 | 4748 | const casted = self.builder.buildBitCast(llvm_arg, self.dg.context.intType(16), ""); |
| 4720 | 4749 | try llvm_args.append(casted); |
| 4721 | 4750 | }, |
| 4751 | .float_array => { | |
| 4752 | const arg = args[it.zig_index - 1]; | |
| 4753 | const arg_ty = self.air.typeOf(arg); | |
| 4754 | var llvm_arg = try self.resolveInst(arg); | |
| 4755 | if (!isByRef(arg_ty)) { | |
| 4756 | const p = self.buildAlloca(llvm_arg.typeOf()); | |
| 4757 | const store_inst = self.builder.buildStore(llvm_arg, p); | |
| 4758 | store_inst.setAlignment(arg_ty.abiAlignment(target)); | |
| 4759 | llvm_arg = store_inst; | |
| 4760 | } | |
| 4761 | ||
| 4762 | const float_ty = try self.dg.lowerType(arg_ty.structFieldType(0)); | |
| 4763 | const field_count = @intCast(u32, arg_ty.structFieldCount()); | |
| 4764 | const array_llvm_ty = float_ty.arrayType(field_count); | |
| 4765 | ||
| 4766 | const casted = self.builder.buildBitCast(llvm_arg, array_llvm_ty.pointerType(0), ""); | |
| 4767 | const alignment = arg_ty.abiAlignment(target); | |
| 4768 | const load_inst = self.builder.buildLoad(array_llvm_ty, casted, ""); | |
| 4769 | load_inst.setAlignment(alignment); | |
| 4770 | try llvm_args.append(load_inst); | |
| 4771 | }, | |
| 4722 | 4772 | }; |
| 4723 | 4773 | |
| 4724 | 4774 | const call = self.builder.buildCall( |
| ... | ... | @@ -9240,7 +9290,7 @@ pub const FuncGen = struct { |
| 9240 | 9290 | } |
| 9241 | 9291 | }, |
| 9242 | 9292 | }, |
| 9243 | .Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty, field_index), | |
| 9293 | .Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty), | |
| 9244 | 9294 | else => unreachable, |
| 9245 | 9295 | } |
| 9246 | 9296 | } |
| ... | ... | @@ -9250,19 +9300,16 @@ pub const FuncGen = struct { |
| 9250 | 9300 | inst: Air.Inst.Index, |
| 9251 | 9301 | union_ptr: *const llvm.Value, |
| 9252 | 9302 | union_ty: Type, |
| 9253 | field_index: c_uint, | |
| 9254 | 9303 | ) !?*const llvm.Value { |
| 9255 | const union_obj = union_ty.cast(Type.Payload.Union).?.data; | |
| 9256 | const field = &union_obj.fields.values()[field_index]; | |
| 9257 | if (!field.ty.hasRuntimeBitsIgnoreComptime()) { | |
| 9258 | return null; | |
| 9259 | } | |
| 9260 | 9304 | const target = self.dg.module.getTarget(); |
| 9261 | 9305 | const layout = union_ty.unionGetLayout(target); |
| 9306 | const result_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst)); | |
| 9307 | if (layout.payload_size == 0) { | |
| 9308 | return self.builder.buildBitCast(union_ptr, result_llvm_ty, ""); | |
| 9309 | } | |
| 9262 | 9310 | const payload_index = @boolToInt(layout.tag_align >= layout.payload_align); |
| 9263 | 9311 | const union_llvm_ty = try self.dg.lowerType(union_ty); |
| 9264 | 9312 | const union_field_ptr = self.builder.buildStructGEP(union_llvm_ty, union_ptr, payload_index, ""); |
| 9265 | const result_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst)); | |
| 9266 | 9313 | return self.builder.buildBitCast(union_field_ptr, result_llvm_ty, ""); |
| 9267 | 9314 | } |
| 9268 | 9315 | |
| ... | ... | @@ -9832,6 +9879,7 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool |
| 9832 | 9879 | else => return x86_64_abi.classifySystemV(fn_info.return_type, target)[0] == .memory, |
| 9833 | 9880 | }, |
| 9834 | 9881 | .wasm32 => return wasm_c_abi.classifyType(fn_info.return_type, target)[0] == .indirect, |
| 9882 | .aarch64, .aarch64_be => return aarch64_c_abi.classifyType(fn_info.return_type, target)[0] == .memory, | |
| 9835 | 9883 | else => return false, // TODO investigate C ABI for other architectures |
| 9836 | 9884 | }, |
| 9837 | 9885 | else => return false, |
| ... | ... | @@ -9862,22 +9910,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm. |
| 9862 | 9910 | } |
| 9863 | 9911 | }, |
| 9864 | 9912 | .C => { |
| 9865 | const is_scalar = switch (fn_info.return_type.zigTypeTag()) { | |
| 9866 | .Void, | |
| 9867 | .Bool, | |
| 9868 | .NoReturn, | |
| 9869 | .Int, | |
| 9870 | .Float, | |
| 9871 | .Pointer, | |
| 9872 | .Optional, | |
| 9873 | .ErrorSet, | |
| 9874 | .Enum, | |
| 9875 | .AnyFrame, | |
| 9876 | .Vector, | |
| 9877 | => true, | |
| 9878 | ||
| 9879 | else => false, | |
| 9880 | }; | |
| 9913 | const is_scalar = isScalar(fn_info.return_type); | |
| 9881 | 9914 | switch (target.cpu.arch) { |
| 9882 | 9915 | .mips, .mipsel => return dg.lowerType(fn_info.return_type), |
| 9883 | 9916 | .x86_64 => switch (target.os.tag) { |
| ... | ... | @@ -9890,6 +9923,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm. |
| 9890 | 9923 | return dg.context.intType(@intCast(c_uint, abi_size * 8)); |
| 9891 | 9924 | } |
| 9892 | 9925 | }, |
| 9926 | .win_i128 => return dg.context.intType(64).vectorType(2), | |
| 9893 | 9927 | .memory => return dg.context.voidType(), |
| 9894 | 9928 | .sse => return dg.lowerType(fn_info.return_type), |
| 9895 | 9929 | else => unreachable, |
| ... | ... | @@ -9930,6 +9964,7 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm. |
| 9930 | 9964 | @panic("TODO"); |
| 9931 | 9965 | }, |
| 9932 | 9966 | .memory => unreachable, // handled above |
| 9967 | .win_i128 => unreachable, // windows only | |
| 9933 | 9968 | .none => break, |
| 9934 | 9969 | } |
| 9935 | 9970 | } |
| ... | ... | @@ -9954,6 +9989,24 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*const llvm. |
| 9954 | 9989 | const abi_size = scalar_type.abiSize(target); |
| 9955 | 9990 | return dg.context.intType(@intCast(c_uint, abi_size * 8)); |
| 9956 | 9991 | }, |
| 9992 | .aarch64, .aarch64_be => { | |
| 9993 | if (is_scalar) { | |
| 9994 | return dg.lowerType(fn_info.return_type); | |
| 9995 | } | |
| 9996 | const classes = aarch64_c_abi.classifyType(fn_info.return_type, target); | |
| 9997 | if (classes[0] == .memory or classes[0] == .none) { | |
| 9998 | return dg.context.voidType(); | |
| 9999 | } | |
| 10000 | if (classes[0] == .float_array) { | |
| 10001 | return dg.lowerType(fn_info.return_type); | |
| 10002 | } | |
| 10003 | if (classes[1] == .none) { | |
| 10004 | const bit_size = fn_info.return_type.bitSize(target); | |
| 10005 | return dg.context.intType(@intCast(c_uint, bit_size)); | |
| 10006 | } | |
| 10007 | ||
| 10008 | return dg.context.intType(64).arrayType(2); | |
| 10009 | }, | |
| 9957 | 10010 | // TODO investigate C ABI for other architectures |
| 9958 | 10011 | else => return dg.lowerType(fn_info.return_type), |
| 9959 | 10012 | } |
| ... | ... | @@ -9981,6 +10034,7 @@ const ParamTypeIterator = struct { |
| 9981 | 10034 | multiple_llvm_float, |
| 9982 | 10035 | slice, |
| 9983 | 10036 | as_u16, |
| 10037 | float_array, | |
| 9984 | 10038 | }; |
| 9985 | 10039 | |
| 9986 | 10040 | pub fn next(it: *ParamTypeIterator) ?Lowering { |
| ... | ... | @@ -10025,22 +10079,7 @@ const ParamTypeIterator = struct { |
| 10025 | 10079 | @panic("TODO implement async function lowering in the LLVM backend"); |
| 10026 | 10080 | }, |
| 10027 | 10081 | .C => { |
| 10028 | const is_scalar = switch (ty.zigTypeTag()) { | |
| 10029 | .Void, | |
| 10030 | .Bool, | |
| 10031 | .NoReturn, | |
| 10032 | .Int, | |
| 10033 | .Float, | |
| 10034 | .Pointer, | |
| 10035 | .Optional, | |
| 10036 | .ErrorSet, | |
| 10037 | .Enum, | |
| 10038 | .AnyFrame, | |
| 10039 | .Vector, | |
| 10040 | => true, | |
| 10041 | ||
| 10042 | else => false, | |
| 10043 | }; | |
| 10082 | const is_scalar = isScalar(ty); | |
| 10044 | 10083 | switch (it.target.cpu.arch) { |
| 10045 | 10084 | .riscv32, .riscv64 => { |
| 10046 | 10085 | it.zig_index += 1; |
| ... | ... | @@ -10069,6 +10108,11 @@ const ParamTypeIterator = struct { |
| 10069 | 10108 | return .abi_sized_int; |
| 10070 | 10109 | } |
| 10071 | 10110 | }, |
| 10111 | .win_i128 => { | |
| 10112 | it.zig_index += 1; | |
| 10113 | it.llvm_index += 1; | |
| 10114 | return .byref; | |
| 10115 | }, | |
| 10072 | 10116 | .memory => { |
| 10073 | 10117 | it.zig_index += 1; |
| 10074 | 10118 | it.llvm_index += 1; |
| ... | ... | @@ -10123,6 +10167,7 @@ const ParamTypeIterator = struct { |
| 10123 | 10167 | @panic("TODO"); |
| 10124 | 10168 | }, |
| 10125 | 10169 | .memory => unreachable, // handled above |
| 10170 | .win_i128 => unreachable, // windows only | |
| 10126 | 10171 | .none => break, |
| 10127 | 10172 | } |
| 10128 | 10173 | } |
| ... | ... | @@ -10155,6 +10200,28 @@ const ParamTypeIterator = struct { |
| 10155 | 10200 | } |
| 10156 | 10201 | return .abi_sized_int; |
| 10157 | 10202 | }, |
| 10203 | .aarch64, .aarch64_be => { | |
| 10204 | it.zig_index += 1; | |
| 10205 | it.llvm_index += 1; | |
| 10206 | if (is_scalar) { | |
| 10207 | return .byval; | |
| 10208 | } | |
| 10209 | const classes = aarch64_c_abi.classifyType(ty, it.target); | |
| 10210 | if (classes[0] == .memory) { | |
| 10211 | return .byref; | |
| 10212 | } | |
| 10213 | if (classes[0] == .float_array) { | |
| 10214 | return .float_array; | |
| 10215 | } | |
| 10216 | if (classes[1] == .none) { | |
| 10217 | it.llvm_types_len = 1; | |
| 10218 | } else { | |
| 10219 | it.llvm_types_len = 2; | |
| 10220 | } | |
| 10221 | it.llvm_types_buffer[0] = 64; | |
| 10222 | it.llvm_types_buffer[1] = 64; | |
| 10223 | return .multiple_llvm_ints; | |
| 10224 | }, | |
| 10158 | 10225 | // TODO investigate C ABI for other architectures |
| 10159 | 10226 | else => { |
| 10160 | 10227 | it.zig_index += 1; |
| ... | ... | @@ -10294,6 +10361,27 @@ fn isByRef(ty: Type) bool { |
| 10294 | 10361 | } |
| 10295 | 10362 | } |
| 10296 | 10363 | |
| 10364 | fn isScalar(ty: Type) bool { | |
| 10365 | return switch (ty.zigTypeTag()) { | |
| 10366 | .Void, | |
| 10367 | .Bool, | |
| 10368 | .NoReturn, | |
| 10369 | .Int, | |
| 10370 | .Float, | |
| 10371 | .Pointer, | |
| 10372 | .Optional, | |
| 10373 | .ErrorSet, | |
| 10374 | .Enum, | |
| 10375 | .AnyFrame, | |
| 10376 | .Vector, | |
| 10377 | => true, | |
| 10378 | ||
| 10379 | .Struct => ty.containerLayout() == .Packed, | |
| 10380 | .Union => ty.containerLayout() == .Packed, | |
| 10381 | else => false, | |
| 10382 | }; | |
| 10383 | } | |
| 10384 | ||
| 10297 | 10385 | /// This function returns true if we expect LLVM to lower x86_fp80 correctly |
| 10298 | 10386 | /// and false if we expect LLVM to crash if it counters an x86_fp80 type. |
| 10299 | 10387 | fn backendSupportsF80(target: std.Target) bool { |
src/link/Coff.zig+142-6| ... | ... | @@ -50,6 +50,7 @@ text_section_index: ?u16 = null, |
| 50 | 50 | got_section_index: ?u16 = null, |
| 51 | 51 | rdata_section_index: ?u16 = null, |
| 52 | 52 | data_section_index: ?u16 = null, |
| 53 | reloc_section_index: ?u16 = null, | |
| 53 | 54 | |
| 54 | 55 | locals: std.ArrayListUnmanaged(coff.Symbol) = .{}, |
| 55 | 56 | globals: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{}, |
| ... | ... | @@ -98,11 +99,16 @@ atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{}, |
| 98 | 99 | /// with `Decl` `main`, and lives as long as that `Decl`. |
| 99 | 100 | unnamed_const_atoms: UnnamedConstTable = .{}, |
| 100 | 101 | |
| 101 | /// A table of relocations indexed by the owning them `TextBlock`. | |
| 102 | /// Note that once we refactor `TextBlock`'s lifetime and ownership rules, | |
| 102 | /// A table of relocations indexed by the owning them `Atom`. | |
| 103 | /// Note that once we refactor `Atom`'s lifetime and ownership rules, | |
| 103 | 104 | /// this will be a table indexed by index into the list of Atoms. |
| 104 | 105 | relocs: RelocTable = .{}, |
| 105 | 106 | |
| 107 | /// A table of base relocations indexed by the owning them `Atom`. | |
| 108 | /// Note that once we refactor `Atom`'s lifetime and ownership rules, | |
| 109 | /// this will be a table indexed by index into the list of Atoms. | |
| 110 | base_relocs: BaseRelocationTable = .{}, | |
| 111 | ||
| 106 | 112 | pub const Reloc = struct { |
| 107 | 113 | @"type": enum { |
| 108 | 114 | got, |
| ... | ... | @@ -117,6 +123,7 @@ pub const Reloc = struct { |
| 117 | 123 | }; |
| 118 | 124 | |
| 119 | 125 | const RelocTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Reloc)); |
| 126 | const BaseRelocationTable = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(u32)); | |
| 120 | 127 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*Atom)); |
| 121 | 128 | |
| 122 | 129 | const default_file_alignment: u16 = 0x200; |
| ... | ... | @@ -150,7 +157,17 @@ const Section = struct { |
| 150 | 157 | free_list: std.ArrayListUnmanaged(*Atom) = .{}, |
| 151 | 158 | }; |
| 152 | 159 | |
| 153 | pub const PtrWidth = enum { p32, p64 }; | |
| 160 | pub const PtrWidth = enum { | |
| 161 | p32, | |
| 162 | p64, | |
| 163 | ||
| 164 | fn abiSize(pw: PtrWidth) u4 { | |
| 165 | return switch (pw) { | |
| 166 | .p32 => 4, | |
| 167 | .p64 => 8, | |
| 168 | }; | |
| 169 | } | |
| 170 | }; | |
| 154 | 171 | pub const SrcFn = void; |
| 155 | 172 | |
| 156 | 173 | pub const Export = struct { |
| ... | ... | @@ -274,6 +291,14 @@ pub fn deinit(self: *Coff) void { |
| 274 | 291 | } |
| 275 | 292 | self.relocs.deinit(gpa); |
| 276 | 293 | } |
| 294 | ||
| 295 | { | |
| 296 | var it = self.base_relocs.valueIterator(); | |
| 297 | while (it.next()) |relocs| { | |
| 298 | relocs.deinit(gpa); | |
| 299 | } | |
| 300 | self.base_relocs.deinit(gpa); | |
| 301 | } | |
| 277 | 302 | } |
| 278 | 303 | |
| 279 | 304 | fn populateMissingMetadata(self: *Coff) !void { |
| ... | ... | @@ -307,7 +332,7 @@ fn populateMissingMetadata(self: *Coff) !void { |
| 307 | 332 | |
| 308 | 333 | if (self.got_section_index == null) { |
| 309 | 334 | self.got_section_index = @intCast(u16, self.sections.slice().len); |
| 310 | const file_size = @intCast(u32, self.base.options.symbol_count_hint); | |
| 335 | const file_size = @intCast(u32, self.base.options.symbol_count_hint) * self.ptr_width.abiSize(); | |
| 311 | 336 | const off = self.findFreeSpace(file_size, self.page_size); |
| 312 | 337 | log.debug("found .got free space 0x{x} to 0x{x}", .{ off, off + file_size }); |
| 313 | 338 | var header = coff.SectionHeader{ |
| ... | ... | @@ -378,6 +403,31 @@ fn populateMissingMetadata(self: *Coff) !void { |
| 378 | 403 | try self.sections.append(gpa, .{ .header = header }); |
| 379 | 404 | } |
| 380 | 405 | |
| 406 | if (self.reloc_section_index == null) { | |
| 407 | self.reloc_section_index = @intCast(u16, self.sections.slice().len); | |
| 408 | const file_size = @intCast(u32, self.base.options.symbol_count_hint) * @sizeOf(coff.BaseRelocation); | |
| 409 | const off = self.findFreeSpace(file_size, self.page_size); | |
| 410 | log.debug("found .reloc free space 0x{x} to 0x{x}", .{ off, off + file_size }); | |
| 411 | var header = coff.SectionHeader{ | |
| 412 | .name = undefined, | |
| 413 | .virtual_size = file_size, | |
| 414 | .virtual_address = off, | |
| 415 | .size_of_raw_data = file_size, | |
| 416 | .pointer_to_raw_data = off, | |
| 417 | .pointer_to_relocations = 0, | |
| 418 | .pointer_to_linenumbers = 0, | |
| 419 | .number_of_relocations = 0, | |
| 420 | .number_of_linenumbers = 0, | |
| 421 | .flags = .{ | |
| 422 | .CNT_INITIALIZED_DATA = 1, | |
| 423 | .MEM_PURGEABLE = 1, | |
| 424 | .MEM_READ = 1, | |
| 425 | }, | |
| 426 | }; | |
| 427 | try self.setSectionName(&header, ".reloc"); | |
| 428 | try self.sections.append(gpa, .{ .header = header }); | |
| 429 | } | |
| 430 | ||
| 381 | 431 | if (self.strtab_offset == null) { |
| 382 | 432 | try self.strtab.buffer.append(gpa, 0); |
| 383 | 433 | self.strtab_offset = self.findFreeSpace(@intCast(u32, self.strtab.len()), 1); |
| ... | ... | @@ -605,6 +655,14 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom { |
| 605 | 655 | .prev_vaddr = sym.value, |
| 606 | 656 | }); |
| 607 | 657 | |
| 658 | const target_sym = self.getSymbol(target); | |
| 659 | switch (target_sym.section_number) { | |
| 660 | .UNDEFINED => @panic("TODO generate a binding for undefined GOT target"), | |
| 661 | .ABSOLUTE => {}, | |
| 662 | .DEBUG => unreachable, // not possible | |
| 663 | else => try atom.addBaseRelocation(self, 0), | |
| 664 | } | |
| 665 | ||
| 608 | 666 | return atom; |
| 609 | 667 | } |
| 610 | 668 | |
| ... | ... | @@ -1179,6 +1237,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1179 | 1237 | try self.resolveRelocs(atom.*); |
| 1180 | 1238 | } |
| 1181 | 1239 | } |
| 1240 | try self.writeBaseRelocations(); | |
| 1182 | 1241 | |
| 1183 | 1242 | if (self.getEntryPoint()) |entry_sym_loc| { |
| 1184 | 1243 | self.entry_addr = self.getSymbol(entry_sym_loc).value; |
| ... | ... | @@ -1216,6 +1275,83 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v |
| 1216 | 1275 | log.debug("TODO implement updateDeclLineNumber", .{}); |
| 1217 | 1276 | } |
| 1218 | 1277 | |
| 1278 | /// TODO: note if we need to rewrite base relocations by dirtying any of the entries in the global table | |
| 1279 | /// TODO: note that .ABSOLUTE is used as padding within each block; we could use this fact to do | |
| 1280 | /// incremental updates and writes into the table instead of doing it all at once | |
| 1281 | fn writeBaseRelocations(self: *Coff) !void { | |
| 1282 | const gpa = self.base.allocator; | |
| 1283 | ||
| 1284 | var pages = std.AutoHashMap(u32, std.ArrayList(coff.BaseRelocation)).init(gpa); | |
| 1285 | defer { | |
| 1286 | var it = pages.valueIterator(); | |
| 1287 | while (it.next()) |inner| { | |
| 1288 | inner.deinit(); | |
| 1289 | } | |
| 1290 | pages.deinit(); | |
| 1291 | } | |
| 1292 | ||
| 1293 | var it = self.base_relocs.iterator(); | |
| 1294 | while (it.next()) |entry| { | |
| 1295 | const atom = entry.key_ptr.*; | |
| 1296 | const offsets = entry.value_ptr.*; | |
| 1297 | ||
| 1298 | for (offsets.items) |offset| { | |
| 1299 | const sym = atom.getSymbol(self); | |
| 1300 | const rva = sym.value + offset; | |
| 1301 | const page = mem.alignBackwardGeneric(u32, rva, self.page_size); | |
| 1302 | const gop = try pages.getOrPut(page); | |
| 1303 | if (!gop.found_existing) { | |
| 1304 | gop.value_ptr.* = std.ArrayList(coff.BaseRelocation).init(gpa); | |
| 1305 | } | |
| 1306 | try gop.value_ptr.append(.{ | |
| 1307 | .offset = @intCast(u12, rva - page), | |
| 1308 | .@"type" = .DIR64, | |
| 1309 | }); | |
| 1310 | } | |
| 1311 | } | |
| 1312 | ||
| 1313 | var buffer = std.ArrayList(u8).init(gpa); | |
| 1314 | defer buffer.deinit(); | |
| 1315 | ||
| 1316 | var pages_it = pages.iterator(); | |
| 1317 | while (pages_it.next()) |entry| { | |
| 1318 | // Pad to required 4byte alignment | |
| 1319 | if (!mem.isAlignedGeneric( | |
| 1320 | usize, | |
| 1321 | entry.value_ptr.items.len * @sizeOf(coff.BaseRelocation), | |
| 1322 | @sizeOf(u32), | |
| 1323 | )) { | |
| 1324 | try entry.value_ptr.append(.{ | |
| 1325 | .offset = 0, | |
| 1326 | .@"type" = .ABSOLUTE, | |
| 1327 | }); | |
| 1328 | } | |
| 1329 | ||
| 1330 | const block_size = @intCast( | |
| 1331 | u32, | |
| 1332 | entry.value_ptr.items.len * @sizeOf(coff.BaseRelocation) + @sizeOf(coff.BaseRelocationDirectoryEntry), | |
| 1333 | ); | |
| 1334 | try buffer.ensureUnusedCapacity(block_size); | |
| 1335 | buffer.appendSliceAssumeCapacity(mem.asBytes(&coff.BaseRelocationDirectoryEntry{ | |
| 1336 | .page_rva = entry.key_ptr.*, | |
| 1337 | .block_size = block_size, | |
| 1338 | })); | |
| 1339 | buffer.appendSliceAssumeCapacity(mem.sliceAsBytes(entry.value_ptr.items)); | |
| 1340 | } | |
| 1341 | ||
| 1342 | const header = &self.sections.items(.header)[self.reloc_section_index.?]; | |
| 1343 | const sect_capacity = self.allocatedSize(header.pointer_to_raw_data); | |
| 1344 | const needed_size = @intCast(u32, buffer.items.len); | |
| 1345 | assert(needed_size < sect_capacity); // TODO expand .reloc section | |
| 1346 | ||
| 1347 | try self.base.file.?.pwriteAll(buffer.items, header.pointer_to_raw_data); | |
| 1348 | ||
| 1349 | self.data_directories[@enumToInt(coff.DirectoryEntry.BASERELOC)] = .{ | |
| 1350 | .virtual_address = header.virtual_address, | |
| 1351 | .size = needed_size, | |
| 1352 | }; | |
| 1353 | } | |
| 1354 | ||
| 1219 | 1355 | fn writeStrtab(self: *Coff) !void { |
| 1220 | 1356 | const allocated_size = self.allocatedSize(self.strtab_offset.?); |
| 1221 | 1357 | const needed_size = @intCast(u32, self.strtab.len()); |
| ... | ... | @@ -1277,8 +1413,8 @@ fn writeHeader(self: *Coff) !void { |
| 1277 | 1413 | writer.writeAll(mem.asBytes(&coff_header)) catch unreachable; |
| 1278 | 1414 | |
| 1279 | 1415 | const dll_flags: coff.DllFlags = .{ |
| 1280 | .HIGH_ENTROPY_VA = 0, //@boolToInt(self.base.options.pie), | |
| 1281 | .DYNAMIC_BASE = 0, | |
| 1416 | .HIGH_ENTROPY_VA = 1, // TODO do we want to permit non-PIE builds at all? | |
| 1417 | .DYNAMIC_BASE = 1, | |
| 1282 | 1418 | .TERMINAL_SERVER_AWARE = 1, // We are not a legacy app |
| 1283 | 1419 | .NX_COMPAT = 1, // We are compatible with Data Execution Prevention |
| 1284 | 1420 | }; |
src/link/Coff/Atom.zig+12-2| ... | ... | @@ -2,6 +2,7 @@ const Atom = @This(); |
| 2 | 2 | |
| 3 | 3 | const std = @import("std"); |
| 4 | 4 | const coff = std.coff; |
| 5 | const log = std.log.scoped(.link); | |
| 5 | 6 | |
| 6 | 7 | const Allocator = std.mem.Allocator; |
| 7 | 8 | |
| ... | ... | @@ -100,11 +101,20 @@ pub fn freeListEligible(self: Atom, coff_file: *const Coff) bool { |
| 100 | 101 | |
| 101 | 102 | pub fn addRelocation(self: *Atom, coff_file: *Coff, reloc: Reloc) !void { |
| 102 | 103 | const gpa = coff_file.base.allocator; |
| 103 | // TODO causes a segfault on Windows | |
| 104 | // log.debug("adding reloc of type {s} to target %{d}", .{ @tagName(reloc.@"type"), reloc.target.sym_index }); | |
| 104 | log.debug(" (adding reloc of type {s} to target %{d})", .{ @tagName(reloc.@"type"), reloc.target.sym_index }); | |
| 105 | 105 | const gop = try coff_file.relocs.getOrPut(gpa, self); |
| 106 | 106 | if (!gop.found_existing) { |
| 107 | 107 | gop.value_ptr.* = .{}; |
| 108 | 108 | } |
| 109 | 109 | try gop.value_ptr.append(gpa, reloc); |
| 110 | 110 | } |
| 111 | ||
| 112 | pub fn addBaseRelocation(self: *Atom, coff_file: *Coff, offset: u32) !void { | |
| 113 | const gpa = coff_file.base.allocator; | |
| 114 | log.debug(" (adding base relocation at offset 0x{x} in %{d})", .{ offset, self.sym_index }); | |
| 115 | const gop = try coff_file.base_relocs.getOrPut(gpa, self); | |
| 116 | if (!gop.found_existing) { | |
| 117 | gop.value_ptr.* = .{}; | |
| 118 | } | |
| 119 | try gop.value_ptr.append(gpa, offset); | |
| 120 | } |
src/link/Wasm.zig+34-11| ... | ... | @@ -607,6 +607,24 @@ fn resolveSymbolsInArchives(self: *Wasm) !void { |
| 607 | 607 | } |
| 608 | 608 | } |
| 609 | 609 | |
| 610 | fn checkUndefinedSymbols(self: *const Wasm) !void { | |
| 611 | var found_undefined_symbols = false; | |
| 612 | for (self.undefs.values()) |undef| { | |
| 613 | const symbol = undef.getSymbol(self); | |
| 614 | if (symbol.tag == .data) { | |
| 615 | found_undefined_symbols = true; | |
| 616 | const file_name = if (undef.file) |file_index| name: { | |
| 617 | break :name self.objects.items[file_index].name; | |
| 618 | } else self.name; | |
| 619 | log.err("could not resolve undefined symbol '{s}'", .{undef.getName(self)}); | |
| 620 | log.err(" defined in '{s}'", .{file_name}); | |
| 621 | } | |
| 622 | } | |
| 623 | if (found_undefined_symbols) { | |
| 624 | return error.UndefinedSymbol; | |
| 625 | } | |
| 626 | } | |
| 627 | ||
| 610 | 628 | pub fn deinit(self: *Wasm) void { |
| 611 | 629 | const gpa = self.base.allocator; |
| 612 | 630 | if (build_options.have_llvm) { |
| ... | ... | @@ -783,15 +801,17 @@ pub fn updateDecl(self: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi |
| 783 | 801 | |
| 784 | 802 | decl.link.wasm.clear(); |
| 785 | 803 | |
| 786 | if (decl.isExtern()) { | |
| 787 | return; | |
| 788 | } | |
| 789 | ||
| 790 | 804 | if (decl.val.castTag(.function)) |_| { |
| 791 | 805 | return; |
| 792 | 806 | } else if (decl.val.castTag(.extern_fn)) |_| { |
| 793 | 807 | return; |
| 794 | 808 | } |
| 809 | ||
| 810 | if (decl.isExtern()) { | |
| 811 | const variable = decl.getVariable().?; | |
| 812 | const name = mem.sliceTo(decl.name, 0); | |
| 813 | return self.addOrUpdateImport(name, decl.link.wasm.sym_index, variable.lib_name, null); | |
| 814 | } | |
| 795 | 815 | const val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; |
| 796 | 816 | |
| 797 | 817 | 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) |
| 834 | 854 | } |
| 835 | 855 | |
| 836 | 856 | fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void { |
| 837 | if (code.len == 0) return; | |
| 838 | 857 | const mod = self.base.options.module.?; |
| 839 | 858 | const atom: *Atom = &decl.link.wasm; |
| 840 | atom.size = @intCast(u32, code.len); | |
| 841 | atom.alignment = decl.ty.abiAlignment(self.base.options.target); | |
| 842 | 859 | const symbol = &self.symbols.items[atom.sym_index]; |
| 843 | ||
| 844 | 860 | const full_name = try decl.getFullyQualifiedName(mod); |
| 845 | 861 | defer self.base.allocator.free(full_name); |
| 846 | 862 | symbol.name = try self.string_table.put(self.base.allocator, full_name); |
| 847 | 863 | try atom.code.appendSlice(self.base.allocator, code); |
| 848 | ||
| 849 | 864 | try self.resolved_symbols.put(self.base.allocator, atom.symbolLoc(), {}); |
| 865 | ||
| 866 | if (code.len == 0) return; | |
| 867 | atom.size = @intCast(u32, code.len); | |
| 868 | atom.alignment = decl.ty.abiAlignment(self.base.options.target); | |
| 850 | 869 | } |
| 851 | 870 | |
| 852 | 871 | /// From a given symbol location, returns its `wasm.GlobalType`. |
| ... | ... | @@ -1235,7 +1254,10 @@ pub fn addOrUpdateImport( |
| 1235 | 1254 | .kind = .{ .function = ty_index }, |
| 1236 | 1255 | }; |
| 1237 | 1256 | } |
| 1238 | } else @panic("TODO: Implement undefined symbols for non-function declarations"); | |
| 1257 | } else { | |
| 1258 | symbol.tag = .data; | |
| 1259 | return; // non-functions will not be imported from the runtime, but only resolved during link-time | |
| 1260 | } | |
| 1239 | 1261 | } |
| 1240 | 1262 | |
| 1241 | 1263 | /// Kind represents the type of an Atom, which is only |
| ... | ... | @@ -1438,7 +1460,7 @@ fn setupImports(self: *Wasm) !void { |
| 1438 | 1460 | if (std.mem.eql(u8, symbol_loc.getName(self), "__indirect_function_table")) { |
| 1439 | 1461 | continue; |
| 1440 | 1462 | } |
| 1441 | if (symbol.tag == .data or !symbol.requiresImport()) { | |
| 1463 | if (!symbol.requiresImport()) { | |
| 1442 | 1464 | continue; |
| 1443 | 1465 | } |
| 1444 | 1466 | |
| ... | ... | @@ -2007,6 +2029,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2007 | 2029 | } |
| 2008 | 2030 | |
| 2009 | 2031 | try self.resolveSymbolsInArchives(); |
| 2032 | try self.checkUndefinedSymbols(); | |
| 2010 | 2033 | |
| 2011 | 2034 | // When we finish/error we reset the state of the linker |
| 2012 | 2035 | // So we can rebuild the binary file on each incremental update |
src/link/Wasm/Atom.zig+6-8| ... | ... | @@ -172,18 +172,16 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa |
| 172 | 172 | .R_WASM_MEMORY_ADDR_SLEB, |
| 173 | 173 | .R_WASM_MEMORY_ADDR_SLEB64, |
| 174 | 174 | => { |
| 175 | if (symbol.isUndefined() and symbol.isWeak()) { | |
| 176 | return 0; | |
| 177 | } | |
| 178 | std.debug.assert(symbol.tag == .data); | |
| 175 | std.debug.assert(symbol.tag == .data and !symbol.isUndefined()); | |
| 179 | 176 | const merge_segment = wasm_bin.base.options.output_mode != .Obj; |
| 180 | const segment_info = if (self.file) |object_index| blk: { | |
| 177 | const target_atom_loc = wasm_bin.discarded.get(target_loc) orelse target_loc; | |
| 178 | const target_atom = wasm_bin.symbol_atom.get(target_atom_loc).?; | |
| 179 | const segment_info = if (target_atom.file) |object_index| blk: { | |
| 181 | 180 | break :blk wasm_bin.objects.items[object_index].segment_info; |
| 182 | 181 | } else wasm_bin.segment_info.items; |
| 183 | 182 | const segment_name = segment_info[symbol.index].outputName(merge_segment); |
| 184 | const atom_index = wasm_bin.data_segments.get(segment_name).?; | |
| 185 | const target_atom = wasm_bin.symbol_atom.get(target_loc).?; | |
| 186 | const segment = wasm_bin.segments.items[atom_index]; | |
| 183 | const segment_index = wasm_bin.data_segments.get(segment_name).?; | |
| 184 | const segment = wasm_bin.segments.items[segment_index]; | |
| 187 | 185 | return target_atom.offset + segment.offset + (relocation.addend orelse 0); |
| 188 | 186 | }, |
| 189 | 187 | .R_WASM_EVENT_INDEX_LEB => return symbol.index, |
src/link/Wasm/Symbol.zig+1-1| ... | ... | @@ -79,9 +79,9 @@ pub const Flag = enum(u32) { |
| 79 | 79 | /// Verifies if the given symbol should be imported from the |
| 80 | 80 | /// host environment or not |
| 81 | 81 | pub fn requiresImport(self: Symbol) bool { |
| 82 | if (self.tag == .data) return false; | |
| 82 | 83 | if (!self.isUndefined()) return false; |
| 83 | 84 | if (self.isWeak()) return false; |
| 84 | if (self.tag == .data) return false; | |
| 85 | 85 | // if (self.isDefined() and self.isWeak()) return true; //TODO: Only when building shared lib |
| 86 | 86 | |
| 87 | 87 | return true; |
src/main.zig+14| ... | ... | @@ -2750,8 +2750,22 @@ fn buildOutputType( |
| 2750 | 2750 | |
| 2751 | 2751 | // Transfer packages added with --pkg-begin/--pkg-end to the root package |
| 2752 | 2752 | if (main_pkg) |pkg| { |
| 2753 | var it = pkg_tree_root.table.valueIterator(); | |
| 2754 | while (it.next()) |p| { | |
| 2755 | if (p.*.parent == &pkg_tree_root) { | |
| 2756 | p.*.parent = pkg; | |
| 2757 | } | |
| 2758 | } | |
| 2753 | 2759 | pkg.table = pkg_tree_root.table; |
| 2754 | 2760 | pkg_tree_root.table = .{}; |
| 2761 | } else { | |
| 2762 | // Remove any dangling pointers just in case. | |
| 2763 | var it = pkg_tree_root.table.valueIterator(); | |
| 2764 | while (it.next()) |p| { | |
| 2765 | if (p.*.parent == &pkg_tree_root) { | |
| 2766 | p.*.parent = null; | |
| 2767 | } | |
| 2768 | } | |
| 2755 | 2769 | } |
| 2756 | 2770 | |
| 2757 | 2771 | const self_exe_path = try introspect.findZigExePath(arena); |
src/translate_c.zig+4| ... | ... | @@ -1166,6 +1166,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD |
| 1166 | 1166 | }); |
| 1167 | 1167 | } |
| 1168 | 1168 | |
| 1169 | if (!c.zig_is_stage1 and is_packed) { | |
| 1170 | return failDecl(c, record_loc, bare_name, "cannot translate packed record union", .{}); | |
| 1171 | } | |
| 1172 | ||
| 1169 | 1173 | const record_payload = try c.arena.create(ast.Payload.Record); |
| 1170 | 1174 | record_payload.* = .{ |
| 1171 | 1175 | .base = .{ .tag = ([2]Tag{ .@"struct", .@"union" })[@boolToInt(is_union)] }, |
src/type.zig+5-2| ... | ... | @@ -2042,6 +2042,9 @@ pub const Type = extern union { |
| 2042 | 2042 | try writer.writeAll("fn("); |
| 2043 | 2043 | for (fn_info.param_types) |param_ty, i| { |
| 2044 | 2044 | if (i != 0) try writer.writeAll(", "); |
| 2045 | if (std.math.cast(u5, i)) |index| if (@truncate(u1, fn_info.noalias_bits >> index) != 0) { | |
| 2046 | try writer.writeAll("noalias "); | |
| 2047 | }; | |
| 2045 | 2048 | if (param_ty.tag() == .generic_poison) { |
| 2046 | 2049 | try writer.writeAll("anytype"); |
| 2047 | 2050 | } else { |
| ... | ... | @@ -2398,7 +2401,7 @@ pub const Type = extern union { |
| 2398 | 2401 | } else if (ty.childType().zigTypeTag() == .Fn) { |
| 2399 | 2402 | return !ty.childType().fnInfo().is_generic; |
| 2400 | 2403 | } else if (sema_kit) |sk| { |
| 2401 | return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, ty)); | |
| 2404 | return !(try sk.sema.typeRequiresComptime(ty)); | |
| 2402 | 2405 | } else { |
| 2403 | 2406 | return !comptimeOnly(ty); |
| 2404 | 2407 | } |
| ... | ... | @@ -2437,7 +2440,7 @@ pub const Type = extern union { |
| 2437 | 2440 | if (ignore_comptime_only) { |
| 2438 | 2441 | return true; |
| 2439 | 2442 | } else if (sema_kit) |sk| { |
| 2440 | return !(try sk.sema.typeRequiresComptime(sk.block, sk.src, child_ty)); | |
| 2443 | return !(try sk.sema.typeRequiresComptime(child_ty)); | |
| 2441 | 2444 | } else { |
| 2442 | 2445 | return !comptimeOnly(child_ty); |
| 2443 | 2446 | } |
src/value.zig+26-3| ... | ... | @@ -2940,17 +2940,24 @@ pub const Value = extern union { |
| 2940 | 2940 | } |
| 2941 | 2941 | |
| 2942 | 2942 | pub fn intToFloat(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, target: Target) !Value { |
| 2943 | return intToFloatAdvanced(val, arena, int_ty, float_ty, target, null) catch |err| switch (err) { | |
| 2944 | error.OutOfMemory => return error.OutOfMemory, | |
| 2945 | else => unreachable, | |
| 2946 | }; | |
| 2947 | } | |
| 2948 | ||
| 2949 | pub fn intToFloatAdvanced(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, target: Target, sema_kit: ?Module.WipAnalysis) !Value { | |
| 2943 | 2950 | if (int_ty.zigTypeTag() == .Vector) { |
| 2944 | 2951 | const result_data = try arena.alloc(Value, int_ty.vectorLen()); |
| 2945 | 2952 | for (result_data) |*scalar, i| { |
| 2946 | scalar.* = try intToFloatScalar(val.indexVectorlike(i), arena, float_ty.scalarType(), target); | |
| 2953 | scalar.* = try intToFloatScalar(val.indexVectorlike(i), arena, float_ty.scalarType(), target, sema_kit); | |
| 2947 | 2954 | } |
| 2948 | 2955 | return Value.Tag.aggregate.create(arena, result_data); |
| 2949 | 2956 | } |
| 2950 | return intToFloatScalar(val, arena, float_ty, target); | |
| 2957 | return intToFloatScalar(val, arena, float_ty, target, sema_kit); | |
| 2951 | 2958 | } |
| 2952 | 2959 | |
| 2953 | pub fn intToFloatScalar(val: Value, arena: Allocator, float_ty: Type, target: Target) !Value { | |
| 2960 | pub fn intToFloatScalar(val: Value, arena: Allocator, float_ty: Type, target: Target, sema_kit: ?Module.WipAnalysis) !Value { | |
| 2954 | 2961 | switch (val.tag()) { |
| 2955 | 2962 | .undef, .zero, .one => return val, |
| 2956 | 2963 | .the_only_possible_value => return Value.initTag(.zero), // for i0, u0 |
| ... | ... | @@ -2970,6 +2977,22 @@ pub const Value = extern union { |
| 2970 | 2977 | const float = bigIntToFloat(limbs, false); |
| 2971 | 2978 | return floatToValue(float, arena, float_ty, target); |
| 2972 | 2979 | }, |
| 2980 | .lazy_align => { | |
| 2981 | const ty = val.castTag(.lazy_align).?.data; | |
| 2982 | if (sema_kit) |sk| { | |
| 2983 | return intToFloatInner((try ty.abiAlignmentAdvanced(target, .{ .sema_kit = sk })).scalar, arena, float_ty, target); | |
| 2984 | } else { | |
| 2985 | return intToFloatInner(ty.abiAlignment(target), arena, float_ty, target); | |
| 2986 | } | |
| 2987 | }, | |
| 2988 | .lazy_size => { | |
| 2989 | const ty = val.castTag(.lazy_size).?.data; | |
| 2990 | if (sema_kit) |sk| { | |
| 2991 | return intToFloatInner((try ty.abiSizeAdvanced(target, .{ .sema_kit = sk })).scalar, arena, float_ty, target); | |
| 2992 | } else { | |
| 2993 | return intToFloatInner(ty.abiSize(target), arena, float_ty, target); | |
| 2994 | } | |
| 2995 | }, | |
| 2973 | 2996 | else => unreachable, |
| 2974 | 2997 | } |
| 2975 | 2998 | } |
test/behavior.zig+1| ... | ... | @@ -85,6 +85,7 @@ test { |
| 85 | 85 | _ = @import("behavior/bugs/12033.zig"); |
| 86 | 86 | _ = @import("behavior/bugs/12430.zig"); |
| 87 | 87 | _ = @import("behavior/bugs/12486.zig"); |
| 88 | _ = @import("behavior/bugs/12680.zig"); | |
| 88 | 89 | _ = @import("behavior/byteswap.zig"); |
| 89 | 90 | _ = @import("behavior/byval_arg_var.zig"); |
| 90 | 91 | _ = @import("behavior/call.zig"); |
test/behavior/bugs/12680.zig created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | const std = @import("std"); | |
| 2 | const expectEqual = std.testing.expectEqual; | |
| 3 | const other_file = @import("12680_other_file.zig"); | |
| 4 | const builtin = @import("builtin"); | |
| 5 | ||
| 6 | extern fn test_func() callconv(.C) usize; | |
| 7 | ||
| 8 | test "export a function twice" { | |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 10 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 11 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | |
| 12 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 13 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | |
| 14 | ||
| 15 | // If it exports the function correctly, `test_func` and `testFunc` will points to the same address. | |
| 16 | try expectEqual(test_func(), other_file.testFunc()); | |
| 17 | } |
test/behavior/bugs/12680_other_file.zig created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | // export this function twice | |
| 2 | pub export fn testFunc() callconv(.C) usize { | |
| 3 | return @ptrToInt(&testFunc); | |
| 4 | } | |
| 5 | ||
| 6 | comptime { | |
| 7 | @export(testFunc, .{ .name = "test_func", .linkage = .Strong }); | |
| 8 | } |
test/behavior/enum.zig+7| ... | ... | @@ -1175,3 +1175,10 @@ test "Non-exhaustive enum with nonstandard int size behaves correctly" { |
| 1175 | 1175 | const E = enum(u15) { _ }; |
| 1176 | 1176 | try expect(@sizeOf(E) == @sizeOf(u15)); |
| 1177 | 1177 | } |
| 1178 | ||
| 1179 | test "Non-exhaustive enum backed by comptime_int" { | |
| 1180 | const E = enum(comptime_int) { a, b, c, _ }; | |
| 1181 | comptime var e: E = .a; | |
| 1182 | e = @intToEnum(E, 378089457309184723749); | |
| 1183 | try expect(@enumToInt(e) == 378089457309184723749); | |
| 1184 | } |
test/behavior/packed-struct.zig+26| ... | ... | @@ -579,3 +579,29 @@ test "runtime init of unnamed packed struct type" { |
| 579 | 579 | } |
| 580 | 580 | }{ .x = z }).m(); |
| 581 | 581 | } |
| 582 | ||
| 583 | test "packed struct passed to callconv(.C) function" { | |
| 584 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 585 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 586 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 587 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | |
| 588 | ||
| 589 | const S = struct { | |
| 590 | const Packed = packed struct { | |
| 591 | a: u16, | |
| 592 | b: bool = true, | |
| 593 | c: bool = true, | |
| 594 | d: u46 = 0, | |
| 595 | }; | |
| 596 | ||
| 597 | fn foo(p: Packed, a1: u64, a2: u64, a3: u64, a4: u64, a5: u64) callconv(.C) bool { | |
| 598 | 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; | |
| 599 | } | |
| 600 | }; | |
| 601 | const result = S.foo(S.Packed{ | |
| 602 | .a = 12345, | |
| 603 | .b = true, | |
| 604 | .c = true, | |
| 605 | }, 5, 4, 3, 2, 1); | |
| 606 | try expect(result); | |
| 607 | } |
test/behavior/sizeof_and_typeof.zig+11| ... | ... | @@ -301,3 +301,14 @@ test "array access of generic param in typeof expression" { |
| 301 | 301 | try expect(S.first("a") == 'a'); |
| 302 | 302 | comptime try expect(S.first("a") == 'a'); |
| 303 | 303 | } |
| 304 | ||
| 305 | test "lazy size cast to float" { | |
| 306 | { | |
| 307 | const S = struct { a: u8 }; | |
| 308 | try expect(@intToFloat(f32, @sizeOf(S)) == 1.0); | |
| 309 | } | |
| 310 | { | |
| 311 | const S = struct { a: u8 }; | |
| 312 | try expect(@as(f32, @sizeOf(S)) == 1.0); | |
| 313 | } | |
| 314 | } |
test/behavior/translate_c_macros.h+2| ... | ... | @@ -48,3 +48,5 @@ typedef _Bool uintptr_t; |
| 48 | 48 | |
| 49 | 49 | #define CAST_TO_BOOL(X) (_Bool)(X) |
| 50 | 50 | #define CAST_TO_UINTPTR(X) (uintptr_t)(X) |
| 51 | ||
| 52 | #define LARGE_INT 18446744073709550592 |
test/behavior/translate_c_macros.zig+10| ... | ... | @@ -113,3 +113,13 @@ test "cast functions" { |
| 113 | 113 | try expectEqual(true, h.CAST_TO_BOOL(S.foo)); |
| 114 | 114 | try expect(h.CAST_TO_UINTPTR(S.foo) != 0); |
| 115 | 115 | } |
| 116 | ||
| 117 | test "large integer macro" { | |
| 118 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 119 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 120 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 121 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 122 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 123 | ||
| 124 | try expectEqual(@as(c_ulonglong, 18446744073709550592), h.LARGE_INT); | |
| 125 | } |
test/behavior/union.zig+29-1| ... | ... | @@ -690,7 +690,7 @@ test "union with only 1 field casted to its enum type which has enum value speci |
| 690 | 690 | |
| 691 | 691 | var e = Expr{ .Literal = Literal{ .Bool = true } }; |
| 692 | 692 | comptime try expect(Tag(ExprTag) == comptime_int); |
| 693 | var t = @as(ExprTag, e); | |
| 693 | comptime var t = @as(ExprTag, e); | |
| 694 | 694 | try expect(t == Expr.Literal); |
| 695 | 695 | try expect(@enumToInt(t) == 33); |
| 696 | 696 | comptime try expect(@enumToInt(t) == 33); |
| ... | ... | @@ -1352,3 +1352,31 @@ test "@unionInit uses tag value instead of field index" { |
| 1352 | 1352 | } |
| 1353 | 1353 | try expect(@enumToInt(u) == 255); |
| 1354 | 1354 | } |
| 1355 | ||
| 1356 | test "union field ptr - zero sized payload" { | |
| 1357 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 1358 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1359 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 1360 | ||
| 1361 | const U = union { | |
| 1362 | foo: void, | |
| 1363 | bar: void, | |
| 1364 | fn bar(_: *void) void {} | |
| 1365 | }; | |
| 1366 | var u: U = .{ .foo = {} }; | |
| 1367 | U.bar(&u.foo); | |
| 1368 | } | |
| 1369 | ||
| 1370 | test "union field ptr - zero sized field" { | |
| 1371 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 1372 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1373 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 1374 | ||
| 1375 | const U = union { | |
| 1376 | foo: void, | |
| 1377 | bar: u32, | |
| 1378 | fn bar(_: *void) void {} | |
| 1379 | }; | |
| 1380 | var u: U = .{ .foo = {} }; | |
| 1381 | U.bar(&u.foo); | |
| 1382 | } |
test/c_abi/cfuncs.c+29-49| ... | ... | @@ -86,24 +86,8 @@ struct MedStructMixed { |
| 86 | 86 | void zig_med_struct_mixed(struct MedStructMixed); |
| 87 | 87 | struct MedStructMixed zig_ret_med_struct_mixed(); |
| 88 | 88 | |
| 89 | struct SmallPackedStruct { | |
| 90 | uint8_t a: 2; | |
| 91 | uint8_t b: 2; | |
| 92 | uint8_t c: 2; | |
| 93 | uint8_t d: 2; | |
| 94 | uint8_t e: 1; | |
| 95 | }; | |
| 96 | ||
| 97 | struct BigPackedStruct { | |
| 98 | uint64_t a: 64; | |
| 99 | uint64_t b: 64; | |
| 100 | uint64_t c: 64; | |
| 101 | uint64_t d: 64; | |
| 102 | uint8_t e: 8; | |
| 103 | }; | |
| 104 | ||
| 105 | //void zig_small_packed_struct(struct SmallPackedStruct); // #1481 | |
| 106 | void zig_big_packed_struct(struct BigPackedStruct); | |
| 89 | void zig_small_packed_struct(uint8_t); | |
| 90 | void zig_big_packed_struct(__int128); | |
| 107 | 91 | |
| 108 | 92 | struct SplitStructInts { |
| 109 | 93 | uint64_t a; |
| ... | ... | @@ -176,13 +160,19 @@ void run_c_tests(void) { |
| 176 | 160 | } |
| 177 | 161 | |
| 178 | 162 | { |
| 179 | struct BigPackedStruct s = {1, 2, 3, 4, 5}; | |
| 163 | __int128 s = 0; | |
| 164 | s |= 1 << 0; | |
| 165 | s |= (__int128)2 << 64; | |
| 180 | 166 | zig_big_packed_struct(s); |
| 181 | 167 | } |
| 182 | 168 | |
| 183 | 169 | { |
| 184 | struct SmallPackedStruct s = {0, 1, 2, 3, 1}; | |
| 185 | //zig_small_packed_struct(s); | |
| 170 | uint8_t s = 0; | |
| 171 | s |= 0 << 0; | |
| 172 | s |= 1 << 2; | |
| 173 | s |= 2 << 4; | |
| 174 | s |= 3 << 6; | |
| 175 | zig_small_packed_struct(s); | |
| 186 | 176 | } |
| 187 | 177 | |
| 188 | 178 | { |
| ... | ... | @@ -378,42 +368,32 @@ void c_split_struct_mixed(struct SplitStructMixed x) { |
| 378 | 368 | assert_or_panic(y.c == 1337.0f); |
| 379 | 369 | } |
| 380 | 370 | |
| 381 | struct SmallPackedStruct c_ret_small_packed_struct() { | |
| 382 | struct SmallPackedStruct s = { | |
| 383 | .a = 0, | |
| 384 | .b = 1, | |
| 385 | .c = 2, | |
| 386 | .d = 3, | |
| 387 | .e = 1, | |
| 388 | }; | |
| 371 | uint8_t c_ret_small_packed_struct() { | |
| 372 | uint8_t s = 0; | |
| 373 | s |= 0 << 0; | |
| 374 | s |= 1 << 2; | |
| 375 | s |= 2 << 4; | |
| 376 | s |= 3 << 6; | |
| 389 | 377 | return s; |
| 390 | 378 | } |
| 391 | 379 | |
| 392 | void c_small_packed_struct(struct SmallPackedStruct x) { | |
| 393 | assert_or_panic(x.a == 0); | |
| 394 | assert_or_panic(x.a == 1); | |
| 395 | assert_or_panic(x.a == 2); | |
| 396 | assert_or_panic(x.a == 3); | |
| 397 | assert_or_panic(x.e == 1); | |
| 380 | void c_small_packed_struct(uint8_t x) { | |
| 381 | assert_or_panic(((x >> 0) & 0x3) == 0); | |
| 382 | assert_or_panic(((x >> 2) & 0x3) == 1); | |
| 383 | assert_or_panic(((x >> 4) & 0x3) == 2); | |
| 384 | assert_or_panic(((x >> 6) & 0x3) == 3); | |
| 398 | 385 | } |
| 399 | 386 | |
| 400 | struct BigPackedStruct c_ret_big_packed_struct() { | |
| 401 | struct BigPackedStruct s = { | |
| 402 | .a = 1, | |
| 403 | .b = 2, | |
| 404 | .c = 3, | |
| 405 | .d = 4, | |
| 406 | .e = 5, | |
| 407 | }; | |
| 387 | __int128 c_ret_big_packed_struct() { | |
| 388 | __int128 s = 0; | |
| 389 | s |= 1 << 0; | |
| 390 | s |= (__int128)2 << 64; | |
| 408 | 391 | return s; |
| 409 | 392 | } |
| 410 | 393 | |
| 411 | void c_big_packed_struct(struct BigPackedStruct x) { | |
| 412 | assert_or_panic(x.a == 1); | |
| 413 | assert_or_panic(x.b == 2); | |
| 414 | assert_or_panic(x.c == 3); | |
| 415 | assert_or_panic(x.d == 4); | |
| 416 | assert_or_panic(x.e == 5); | |
| 394 | void c_big_packed_struct(__int128 x) { | |
| 395 | assert_or_panic(((x >> 0) & 0xFFFFFFFFFFFFFFFF) == 1); | |
| 396 | assert_or_panic(((x >> 64) & 0xFFFFFFFFFFFFFFFF) == 2); | |
| 417 | 397 | } |
| 418 | 398 | |
| 419 | 399 | struct SplitStructMixed c_ret_split_struct_mixed() { |
test/c_abi/main.zig+11-24| ... | ... | @@ -110,7 +110,7 @@ test "C ABI floats" { |
| 110 | 110 | } |
| 111 | 111 | |
| 112 | 112 | test "C ABI long double" { |
| 113 | if (!builtin.cpu.arch.isWasm()) return error.SkipZigTest; | |
| 113 | if (!builtin.cpu.arch.isWasm() and !builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; | |
| 114 | 114 | c_long_double(12.34); |
| 115 | 115 | } |
| 116 | 116 | |
| ... | ... | @@ -263,37 +263,30 @@ const SmallPackedStruct = packed struct { |
| 263 | 263 | b: u2, |
| 264 | 264 | c: u2, |
| 265 | 265 | d: u2, |
| 266 | e: bool, | |
| 267 | 266 | }; |
| 268 | const c_small_packed_struct: fn (SmallPackedStruct) callconv(.C) void = @compileError("TODO: #1481"); | |
| 267 | extern fn c_small_packed_struct(SmallPackedStruct) void; | |
| 269 | 268 | extern fn c_ret_small_packed_struct() SmallPackedStruct; |
| 270 | 269 | |
| 271 | // waiting on #1481 | |
| 272 | //export fn zig_small_packed_struct(x: SmallPackedStruct) void { | |
| 273 | // expect(x.a == 0) catch @panic("test failure"); | |
| 274 | // expect(x.b == 1) catch @panic("test failure"); | |
| 275 | // expect(x.c == 2) catch @panic("test failure"); | |
| 276 | // expect(x.d == 3) catch @panic("test failure"); | |
| 277 | // expect(x.e) catch @panic("test failure"); | |
| 278 | //} | |
| 270 | export fn zig_small_packed_struct(x: SmallPackedStruct) void { | |
| 271 | expect(x.a == 0) catch @panic("test failure"); | |
| 272 | expect(x.b == 1) catch @panic("test failure"); | |
| 273 | expect(x.c == 2) catch @panic("test failure"); | |
| 274 | expect(x.d == 3) catch @panic("test failure"); | |
| 275 | } | |
| 279 | 276 | |
| 280 | 277 | test "C ABI small packed struct" { |
| 281 | var s = SmallPackedStruct{ .a = 0, .b = 1, .c = 2, .d = 3, .e = true }; | |
| 282 | _ = s; //c_small_packed_struct(s); // waiting on #1481 | |
| 278 | var s = SmallPackedStruct{ .a = 0, .b = 1, .c = 2, .d = 3 }; | |
| 279 | c_small_packed_struct(s); | |
| 283 | 280 | var s2 = c_ret_small_packed_struct(); |
| 284 | 281 | try expect(s2.a == 0); |
| 285 | 282 | try expect(s2.b == 1); |
| 286 | 283 | try expect(s2.c == 2); |
| 287 | 284 | try expect(s2.d == 3); |
| 288 | try expect(s2.e); | |
| 289 | 285 | } |
| 290 | 286 | |
| 291 | 287 | const BigPackedStruct = packed struct { |
| 292 | 288 | a: u64, |
| 293 | 289 | b: u64, |
| 294 | c: u64, | |
| 295 | d: u64, | |
| 296 | e: u8, | |
| 297 | 290 | }; |
| 298 | 291 | extern fn c_big_packed_struct(BigPackedStruct) void; |
| 299 | 292 | extern fn c_ret_big_packed_struct() BigPackedStruct; |
| ... | ... | @@ -301,20 +294,14 @@ extern fn c_ret_big_packed_struct() BigPackedStruct; |
| 301 | 294 | export fn zig_big_packed_struct(x: BigPackedStruct) void { |
| 302 | 295 | expect(x.a == 1) catch @panic("test failure"); |
| 303 | 296 | expect(x.b == 2) catch @panic("test failure"); |
| 304 | expect(x.c == 3) catch @panic("test failure"); | |
| 305 | expect(x.d == 4) catch @panic("test failure"); | |
| 306 | expect(x.e == 5) catch @panic("test failure"); | |
| 307 | 297 | } |
| 308 | 298 | |
| 309 | 299 | test "C ABI big packed struct" { |
| 310 | var s = BigPackedStruct{ .a = 1, .b = 2, .c = 3, .d = 4, .e = 5 }; | |
| 300 | var s = BigPackedStruct{ .a = 1, .b = 2 }; | |
| 311 | 301 | c_big_packed_struct(s); |
| 312 | 302 | var s2 = c_ret_big_packed_struct(); |
| 313 | 303 | try expect(s2.a == 1); |
| 314 | 304 | try expect(s2.b == 2); |
| 315 | try expect(s2.c == 3); | |
| 316 | try expect(s2.d == 4); | |
| 317 | try expect(s2.e == 5); | |
| 318 | 305 | } |
| 319 | 306 | |
| 320 | 307 | const SplitStructInt = extern struct { |
test/cases/compile_errors/C_pointer_pointing_to_non_C_ABI_compatible_type_or_has_align_attr.zig+1-1| ... | ... | @@ -10,5 +10,5 @@ export fn a() void { |
| 10 | 10 | // target=native |
| 11 | 11 | // |
| 12 | 12 | // :3:19: error: C pointers cannot point to non-C-ABI-compatible type 'tmp.Foo' |
| 13 | // :3:19: note: only structs with packed or extern layout are extern compatible | |
| 13 | // :3:19: note: only extern structs and ABI sized packed structs are extern compatible | |
| 14 | 14 | // :1:13: note: struct declared here |
test/cases/compile_errors/enum_backed_by_comptime_int_must_be_comptime.zig created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | pub export fn entry() void { | |
| 2 | const E = enum(comptime_int) { a, b, c, _ }; | |
| 3 | var e: E = .a; | |
| 4 | _ = e; | |
| 5 | } | |
| 6 | ||
| 7 | // error | |
| 8 | // backend=stage2 | |
| 9 | // target=native | |
| 10 | // | |
| 11 | // :3:12: error: variable of type 'tmp.entry.E' must be const or comptime |
test/cases/compile_errors/function_with_non-extern_non-packed_struct_parameter.zig+1-1| ... | ... | @@ -10,5 +10,5 @@ export fn entry(foo: Foo) void { _ = foo; } |
| 10 | 10 | // target=native |
| 11 | 11 | // |
| 12 | 12 | // :6:17: error: parameter of type 'tmp.Foo' not allowed in function with calling convention 'C' |
| 13 | // :6:17: note: only structs with packed or extern layout are extern compatible | |
| 13 | // :6:17: note: only extern structs and ABI sized packed structs are extern compatible | |
| 14 | 14 | // :1:13: note: struct declared here |
test/cases/compile_errors/function_with_non-extern_non-packed_union_parameter.zig+1-1| ... | ... | @@ -10,5 +10,5 @@ export fn entry(foo: Foo) void { _ = foo; } |
| 10 | 10 | // target=native |
| 11 | 11 | // |
| 12 | 12 | // :6:17: error: parameter of type 'tmp.Foo' not allowed in function with calling convention 'C' |
| 13 | // :6:17: note: only unions with packed or extern layout are extern compatible | |
| 13 | // :6:17: note: only extern unions and ABI sized packed unions are extern compatible | |
| 14 | 14 | // :1:13: note: union declared here |
test/cases/compile_errors/int_literal_passed_as_variadic_arg.zig deleted-11| ... | ... | @@ -1,11 +0,0 @@ |
| 1 | extern fn printf([*:0]const u8, ...) c_int; | |
| 2 | ||
| 3 | pub export fn entry() void { | |
| 4 | _ = printf("%d %d %d %d\n", 1, 2, 3, 4); | |
| 5 | } | |
| 6 | ||
| 7 | // error | |
| 8 | // backend=stage2 | |
| 9 | // target=native | |
| 10 | // | |
| 11 | // :4:33: error: integer and float literals in var args function must be casted |
test/cases/compile_errors/noalias_param_coersion.zig created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | pub export fn entry() void { | |
| 2 | comptime var x: fn (noalias *i32, noalias *i32) void = undefined; | |
| 3 | x = bar; | |
| 4 | } | |
| 5 | pub export fn entry1() void { | |
| 6 | comptime var x: fn (*i32, *i32) void = undefined; | |
| 7 | x = foo; | |
| 8 | } | |
| 9 | ||
| 10 | fn foo(noalias _: *i32, noalias _: *i32) void {} | |
| 11 | fn bar(noalias _: *i32, _: *i32) void {} | |
| 12 | ||
| 13 | // error | |
| 14 | // backend=stage2 | |
| 15 | // target=native | |
| 16 | // | |
| 17 | // :3:9: error: expected type 'fn(noalias *i32, noalias *i32) void', found 'fn(noalias *i32, *i32) void' | |
| 18 | // :3:9: note: regular parameter 1 cannot cast into a noalias parameter | |
| 19 | // :7:9: error: expected type 'fn(*i32, *i32) void', found 'fn(noalias *i32, noalias *i32) void' | |
| 20 | // :7:9: note: noalias parameter 0 cannot cast into a regular parameter |
test/cases/compile_errors/overflow_in_enum_value_allocation.zig created+14| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | const Moo = enum(u8) { | |
| 2 | Last = 255, | |
| 3 | Over, | |
| 4 | }; | |
| 5 | pub export fn entry() void { | |
| 6 | var y = Moo.Last; | |
| 7 | _ = y; | |
| 8 | } | |
| 9 | ||
| 10 | // error | |
| 11 | // backend=stage2 | |
| 12 | // target=native | |
| 13 | // | |
| 14 | // :3:5: error: enumeration value '256' too large for type 'u8' |
test/cases/compile_errors/specify_enum_tag_type_that_is_too_small.zig created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | const Small = enum (u2) { | |
| 2 | One, | |
| 3 | Two, | |
| 4 | Three, | |
| 5 | Four, | |
| 6 | Five, | |
| 7 | }; | |
| 8 | ||
| 9 | export fn entry() void { | |
| 10 | var x = Small.One; | |
| 11 | _ = x; | |
| 12 | } | |
| 13 | ||
| 14 | // error | |
| 15 | // backend=stage2 | |
| 16 | // target=native | |
| 17 | // | |
| 18 | // :6:5: error: enumeration value '4' too large for type 'u2' |
test/cases/compile_errors/stage1/obj/overflow_in_enum_value_allocation.zig deleted-14| ... | ... | @@ -1,14 +0,0 @@ |
| 1 | const Moo = enum(u8) { | |
| 2 | Last = 255, | |
| 3 | Over, | |
| 4 | }; | |
| 5 | pub fn main() void { | |
| 6 | var y = Moo.Last; | |
| 7 | _ = y; | |
| 8 | } | |
| 9 | ||
| 10 | // error | |
| 11 | // backend=stage1 | |
| 12 | // target=native | |
| 13 | // | |
| 14 | // tmp.zig:3:5: error: enumeration value 256 too large for type 'u8' |
test/cases/compile_errors/stage1/obj/specify_enum_tag_type_that_is_too_small.zig deleted-18| ... | ... | @@ -1,18 +0,0 @@ |
| 1 | const Small = enum (u2) { | |
| 2 | One, | |
| 3 | Two, | |
| 4 | Three, | |
| 5 | Four, | |
| 6 | Five, | |
| 7 | }; | |
| 8 | ||
| 9 | export fn entry() void { | |
| 10 | var x = Small.One; | |
| 11 | _ = x; | |
| 12 | } | |
| 13 | ||
| 14 | // error | |
| 15 | // backend=stage1 | |
| 16 | // target=native | |
| 17 | // | |
| 18 | // tmp.zig:6:5: error: enumeration value 4 too large for type 'u2' |
test/cases/compile_errors/try_return.zig created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | pub fn foo() !void { | |
| 2 | try return bar(); | |
| 3 | } | |
| 4 | pub fn bar() !void {} | |
| 5 | ||
| 6 | // error | |
| 7 | // backend=stage2 | |
| 8 | // target=native | |
| 9 | // | |
| 10 | // :2:5: error: unreachable code | |
| 11 | // :2:9: note: control flow is diverted here |
test/cases/compile_errors/variadic_arg_validation.zig created+29| ... | ... | @@ -0,0 +1,29 @@ |
| 1 | extern fn printf([*:0]const u8, ...) c_int; | |
| 2 | ||
| 3 | pub export fn entry() void { | |
| 4 | _ = printf("%d %d %d %d\n", 1, 2, 3, 4); | |
| 5 | } | |
| 6 | ||
| 7 | pub export fn entry1() void { | |
| 8 | var arr: [2]u8 = undefined; | |
| 9 | _ = printf("%d\n", arr); | |
| 10 | } | |
| 11 | ||
| 12 | pub export fn entry2() void { | |
| 13 | _ = printf("%d\n", @as(u48, 2)); | |
| 14 | } | |
| 15 | ||
| 16 | pub export fn entry3() void { | |
| 17 | _ = printf("%d\n", {}); | |
| 18 | } | |
| 19 | ||
| 20 | // error | |
| 21 | // backend=stage2 | |
| 22 | // target=native | |
| 23 | // | |
| 24 | // :4:33: error: integer and float literals passed variadic function must be casted to a fixed-size number type | |
| 25 | // :9:24: error: arrays must be passed by reference to variadic function | |
| 26 | // :13:24: error: cannot pass 'u48' to variadic function | |
| 27 | // :13:24: note: only integers with power of two bits are extern compatible | |
| 28 | // :17:24: error: cannot pass 'void' to variadic function | |
| 29 | // :17:24: note: 'void' is a zero bit type; for C 'void' use 'anyopaque' |
test/link.zig+6| ... | ... | @@ -52,6 +52,12 @@ fn addWasmCases(cases: *tests.StandaloneContext) void { |
| 52 | 52 | .build_modes = true, |
| 53 | 53 | .requires_stage2 = true, |
| 54 | 54 | }); |
| 55 | ||
| 56 | cases.addBuildFile("test/link/wasm/extern/build.zig", .{ | |
| 57 | .build_modes = true, | |
| 58 | .requires_stage2 = true, | |
| 59 | .use_emulation = true, | |
| 60 | }); | |
| 55 | 61 | } |
| 56 | 62 | |
| 57 | 63 | fn addMachOCases(cases: *tests.StandaloneContext) void { |
test/link/wasm/extern/build.zig created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub fn build(b: *std.build.Builder) void { | |
| 4 | const mode = b.standardReleaseOptions(); | |
| 5 | const exe = b.addExecutable("extern", "main.zig"); | |
| 6 | exe.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .wasi }); | |
| 7 | exe.setBuildMode(mode); | |
| 8 | exe.addCSourceFile("foo.c", &.{}); | |
| 9 | exe.use_llvm = false; | |
| 10 | exe.use_lld = false; | |
| 11 | ||
| 12 | const run = exe.runEmulatable(); | |
| 13 | run.expectStdOutEqual("Result: 30"); | |
| 14 | ||
| 15 | const test_step = b.step("test", "Run linker test"); | |
| 16 | test_step.dependOn(&run.step); | |
| 17 | } |
test/link/wasm/extern/foo.c created+1| ... | ... | @@ -0,0 +1 @@ |
| 1 | int foo = 30; |
test/link/wasm/extern/main.zig created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | extern const foo: u32; | |
| 4 | ||
| 5 | pub fn main() void { | |
| 6 | const std_out = std.io.getStdOut(); | |
| 7 | std_out.writer().print("Result: {d}", .{foo}) catch {}; | |
| 8 | } |
test/run_translated_c.zig+14-12| ... | ... | @@ -250,18 +250,20 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { |
| 250 | 250 | \\} |
| 251 | 251 | , ""); |
| 252 | 252 | |
| 253 | cases.add("struct initializer - packed", | |
| 254 | \\#define _NO_CRT_STDIO_INLINE 1 | |
| 255 | \\#include <stdint.h> | |
| 256 | \\#include <stdlib.h> | |
| 257 | \\struct s {uint8_t x,y; | |
| 258 | \\ uint32_t z;} __attribute__((packed)) s0 = {1, 2}; | |
| 259 | \\int main() { | |
| 260 | \\ /* sizeof nor offsetof currently supported */ | |
| 261 | \\ if (((intptr_t)&s0.z - (intptr_t)&s0.x) != 2) abort(); | |
| 262 | \\ return 0; | |
| 263 | \\} | |
| 264 | , ""); | |
| 253 | if (@import("builtin").zig_backend == .stage1) { | |
| 254 | cases.add("struct initializer - packed", | |
| 255 | \\#define _NO_CRT_STDIO_INLINE 1 | |
| 256 | \\#include <stdint.h> | |
| 257 | \\#include <stdlib.h> | |
| 258 | \\struct s {uint8_t x,y; | |
| 259 | \\ uint32_t z;} __attribute__((packed)) s0 = {1, 2}; | |
| 260 | \\int main() { | |
| 261 | \\ /* sizeof nor offsetof currently supported */ | |
| 262 | \\ if (((intptr_t)&s0.z - (intptr_t)&s0.x) != 2) abort(); | |
| 263 | \\ return 0; | |
| 264 | \\} | |
| 265 | , ""); | |
| 266 | } | |
| 265 | 267 | |
| 266 | 268 | cases.add("cast signed array index to unsigned", |
| 267 | 269 | \\#include <stdlib.h> |
test/standalone.zig+6| ... | ... | @@ -13,6 +13,8 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 13 | 13 | cases.add("test/standalone/guess_number/main.zig"); |
| 14 | 14 | cases.add("test/standalone/main_return_error/error_u8.zig"); |
| 15 | 15 | cases.add("test/standalone/main_return_error/error_u8_non_zero.zig"); |
| 16 | cases.add("test/standalone/noreturn_call/inline.zig"); | |
| 17 | cases.add("test/standalone/noreturn_call/as_arg.zig"); | |
| 16 | 18 | cases.addBuildFile("test/standalone/main_pkg_path/build.zig", .{}); |
| 17 | 19 | cases.addBuildFile("test/standalone/shared_library/build.zig", .{}); |
| 18 | 20 | cases.addBuildFile("test/standalone/mix_o_files/build.zig", .{}); |
| ... | ... | @@ -48,6 +50,9 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 48 | 50 | cases.addBuildFile("test/c_abi/build.zig", .{}); |
| 49 | 51 | } |
| 50 | 52 | } |
| 53 | if (builtin.cpu.arch.isAARCH64() and builtin.zig_backend == .stage2_llvm) { | |
| 54 | cases.addBuildFile("test/c_abi/build.zig", .{}); | |
| 55 | } | |
| 51 | 56 | // C ABI tests only pass for the Wasm target when using stage2 |
| 52 | 57 | cases.addBuildFile("test/c_abi/build_wasm.zig", .{ |
| 53 | 58 | .requires_stage2 = true, |
| ... | ... | @@ -66,6 +71,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 66 | 71 | if (builtin.os.tag == .linux) { |
| 67 | 72 | cases.addBuildFile("test/standalone/pie/build.zig", .{}); |
| 68 | 73 | } |
| 74 | cases.addBuildFile("test/standalone/issue_12706/build.zig", .{}); | |
| 69 | 75 | |
| 70 | 76 | // Ensure the development tools are buildable. |
| 71 | 77 |
test/standalone/issue_12706/build.zig created+39| ... | ... | @@ -0,0 +1,39 @@ |
| 1 | const std = @import("std"); | |
| 2 | const builtin = @import("builtin"); | |
| 3 | const Builder = std.build.Builder; | |
| 4 | const CrossTarget = std.zig.CrossTarget; | |
| 5 | ||
| 6 | // TODO integrate this with the std.build executor API | |
| 7 | fn isRunnableTarget(t: CrossTarget) bool { | |
| 8 | if (t.isNative()) return true; | |
| 9 | ||
| 10 | return (t.getOsTag() == builtin.os.tag and | |
| 11 | t.getCpuArch() == builtin.cpu.arch); | |
| 12 | } | |
| 13 | ||
| 14 | pub fn build(b: *Builder) void { | |
| 15 | const mode = b.standardReleaseOptions(); | |
| 16 | const target = b.standardTargetOptions(.{}); | |
| 17 | ||
| 18 | const exe = b.addExecutable("main", "main.zig"); | |
| 19 | exe.setBuildMode(mode); | |
| 20 | exe.install(); | |
| 21 | ||
| 22 | const c_sources = [_][]const u8{ | |
| 23 | "test.c", | |
| 24 | }; | |
| 25 | ||
| 26 | exe.addCSourceFiles(&c_sources, &.{}); | |
| 27 | exe.linkLibC(); | |
| 28 | ||
| 29 | exe.setTarget(target); | |
| 30 | b.default_step.dependOn(&exe.step); | |
| 31 | ||
| 32 | const test_step = b.step("test", "Test the program"); | |
| 33 | if (isRunnableTarget(target)) { | |
| 34 | const run_cmd = exe.run(); | |
| 35 | test_step.dependOn(&run_cmd.step); | |
| 36 | } else { | |
| 37 | test_step.dependOn(&exe.step); | |
| 38 | } | |
| 39 | } |
test/standalone/issue_12706/main.zig created+12| ... | ... | @@ -0,0 +1,12 @@ |
| 1 | const std = @import("std"); | |
| 2 | extern fn testFnPtr(n: c_int, ...) void; | |
| 3 | ||
| 4 | const val: c_int = 123; | |
| 5 | ||
| 6 | fn func(a: c_int) callconv(.C) void { | |
| 7 | std.debug.assert(a == val); | |
| 8 | } | |
| 9 | ||
| 10 | pub fn main() void { | |
| 11 | testFnPtr(2, func, val); | |
| 12 | } |
test/standalone/issue_12706/test.c created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | #include <stdarg.h> | |
| 2 | ||
| 3 | void testFnPtr(int n, ...) { | |
| 4 | va_list ap; | |
| 5 | va_start(ap, n); | |
| 6 | ||
| 7 | void (*fnPtr)(int) = va_arg(ap, void (*)(int)); | |
| 8 | int arg = va_arg(ap, int); | |
| 9 | fnPtr(arg); | |
| 10 | va_end(ap); | |
| 11 | } | |
| \ No newline at end of file |
test/standalone/noreturn_call/as_arg.zig created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | const std = @import("std"); | |
| 2 | fn foo() noreturn { | |
| 3 | std.process.exit(0); | |
| 4 | } | |
| 5 | fn bar(_: u8, _: u8) void {} | |
| 6 | pub fn main() void { | |
| 7 | bar(foo(), @compileError("bad")); | |
| 8 | } |
test/standalone/noreturn_call/inline.zig created+10| ... | ... | @@ -0,0 +1,10 @@ |
| 1 | pub fn main() void { | |
| 2 | _ = bar(); | |
| 3 | } | |
| 4 | inline fn bar() u8 { | |
| 5 | noret(); | |
| 6 | } | |
| 7 | const std = @import("std"); | |
| 8 | inline fn noret() noreturn { | |
| 9 | std.process.exit(0); | |
| 10 | } |
test/translate_c.zig+16-14| ... | ... | @@ -728,20 +728,22 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 728 | 728 | \\} |
| 729 | 729 | }); |
| 730 | 730 | |
| 731 | cases.add("struct initializer - packed", | |
| 732 | \\struct {int x,y,z;} __attribute__((packed)) s0 = {1, 2}; | |
| 733 | , &[_][]const u8{ | |
| 734 | \\const struct_unnamed_1 = packed struct { | |
| 735 | \\ x: c_int, | |
| 736 | \\ y: c_int, | |
| 737 | \\ z: c_int, | |
| 738 | \\}; | |
| 739 | \\pub export var s0: struct_unnamed_1 = struct_unnamed_1{ | |
| 740 | \\ .x = @as(c_int, 1), | |
| 741 | \\ .y = @as(c_int, 2), | |
| 742 | \\ .z = 0, | |
| 743 | \\}; | |
| 744 | }); | |
| 731 | if (builtin.zig_backend == .stage1) { | |
| 732 | cases.add("struct initializer - packed", | |
| 733 | \\struct {int x,y,z;} __attribute__((packed)) s0 = {1, 2}; | |
| 734 | , &[_][]const u8{ | |
| 735 | \\const struct_unnamed_1 = packed struct { | |
| 736 | \\ x: c_int, | |
| 737 | \\ y: c_int, | |
| 738 | \\ z: c_int, | |
| 739 | \\}; | |
| 740 | \\pub export var s0: struct_unnamed_1 = struct_unnamed_1{ | |
| 741 | \\ .x = @as(c_int, 1), | |
| 742 | \\ .y = @as(c_int, 2), | |
| 743 | \\ .z = 0, | |
| 744 | \\}; | |
| 745 | }); | |
| 746 | } | |
| 745 | 747 | |
| 746 | 748 | // Test case temporarily disabled: |
| 747 | 749 | // https://github.com/ziglang/zig/issues/12055 |