mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
Merge branch 'master' into translate-c-userland
This commit is contained in:
commit
2060c7c39b
@ -389,6 +389,8 @@ set(EMBEDDED_SOFTFLOAT_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF32.c"
|
||||
"${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_subMagsF64.c"
|
||||
"${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/s_tryPropagateNaNF128M.c"
|
||||
"${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f16_mulAdd.c"
|
||||
"${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/f128M_mulAdd.c"
|
||||
"${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/softfloat_state.c"
|
||||
"${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui32_to_f128M.c"
|
||||
"${CMAKE_SOURCE_DIR}/deps/SoftFloat-3e/source/ui64_to_f128M.c"
|
||||
@ -522,6 +524,9 @@ set(ZIG_STD_FILES
|
||||
"hash/siphash.zig"
|
||||
"hash_map.zig"
|
||||
"heap.zig"
|
||||
"heap/logging_allocator.zig"
|
||||
"http.zig"
|
||||
"http/headers.zig"
|
||||
"io.zig"
|
||||
"io/c_out_stream.zig"
|
||||
"io/seekable_stream.zig"
|
||||
@ -6653,15 +6658,18 @@ set(OPTIMIZED_C_FLAGS "-std=c99 -O3")
|
||||
set(EXE_LDFLAGS " ")
|
||||
if(MSVC)
|
||||
set(EXE_LDFLAGS "/STACK:16777216")
|
||||
elseif(ZIG_STATIC)
|
||||
elseif(MINGW)
|
||||
set(EXE_LDFLAGS "${EXE_LDFLAGS} -Wl,--stack,16777216")
|
||||
endif()
|
||||
|
||||
if(ZIG_STATIC)
|
||||
if(APPLE)
|
||||
set(EXE_LDFLAGS "-static-libgcc -static-libstdc++")
|
||||
else()
|
||||
set(EXE_LDFLAGS "-static")
|
||||
endif()
|
||||
else()
|
||||
set(EXE_LDFLAGS " ")
|
||||
endif()
|
||||
|
||||
if(ZIG_TEST_COVERAGE)
|
||||
set(EXE_CFLAGS "${EXE_CFLAGS} -fprofile-arcs -ftest-coverage")
|
||||
set(EXE_LDFLAGS "${EXE_LDFLAGS} -fprofile-arcs -ftest-coverage")
|
||||
@ -6729,6 +6737,7 @@ add_custom_command(
|
||||
"-Doutput-dir=${CMAKE_BINARY_DIR}"
|
||||
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
|
||||
DEPENDS
|
||||
zig0
|
||||
"${CMAKE_SOURCE_DIR}/src-self-hosted/dep_tokenizer.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src-self-hosted/stage1.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src-self-hosted/translate_c.zig"
|
||||
|
||||
@ -74,7 +74,8 @@ pub fn build(b: *Builder) !void {
|
||||
const skip_non_native = b.option(bool, "skip-non-native", "Main test suite skips non-native builds") orelse false;
|
||||
const skip_self_hosted = b.option(bool, "skip-self-hosted", "Main test suite skips building self hosted compiler") orelse false;
|
||||
if (!skip_self_hosted) {
|
||||
test_step.dependOn(&exe.step);
|
||||
// TODO re-enable this after https://github.com/ziglang/zig/issues/2377
|
||||
//test_step.dependOn(&exe.step);
|
||||
}
|
||||
const verbose_link_exe = b.option(bool, "verbose-link", "Print link command for self hosted compiler") orelse false;
|
||||
exe.setVerboseLink(verbose_link_exe);
|
||||
|
||||
@ -5096,7 +5096,7 @@ fn gimmeTheBiggerInteger(a: u64, b: u64) u64 {
|
||||
<p>
|
||||
For example, if we were to introduce another function to the above snippet:
|
||||
</p>
|
||||
{#code_begin|test_err|values of type 'type' must be comptime known#}
|
||||
{#code_begin|test_err|cannot store runtime value in type 'type'#}
|
||||
fn max(comptime T: type, a: T, b: T) T {
|
||||
return if (a > b) a else b;
|
||||
}
|
||||
@ -6259,6 +6259,13 @@ comptime {
|
||||
This function is only valid within function scope.
|
||||
</p>
|
||||
|
||||
{#header_close#}
|
||||
{#header_open|@mulAdd#}
|
||||
<pre>{#syntax#}@mulAdd(comptime T: type, a: T, b: T, c: T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
Fused multiply add (for floats), similar to {#syntax#}(a * b) + c{#endsyntax#}, except
|
||||
only rounds once, and is thus more accurate.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@byteSwap#}
|
||||
@ -7347,10 +7354,91 @@ test "@setRuntimeSafety" {
|
||||
<pre>{#syntax#}@sqrt(comptime T: type, value: T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
Performs the square root of a floating point number. Uses a dedicated hardware instruction
|
||||
when available. Currently only supports f32 and f64 at runtime. f128 at runtime is TODO.
|
||||
when available. Supports f16, f32, f64, and f128, as well as vectors.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@sin#}
|
||||
<pre>{#syntax#}@sin(comptime T: type, value: T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
This is a low-level intrinsic. Most code can use {#syntax#}std.math.sqrt{#endsyntax#} instead.
|
||||
Sine trigometric function on a floating point number. Uses a dedicated hardware instruction
|
||||
when available. Currently supports f32 and f64.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@cos#}
|
||||
<pre>{#syntax#}@cos(comptime T: type, value: T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
Cosine trigometric function on a floating point number. Uses a dedicated hardware instruction
|
||||
when available. Currently supports f32 and f64.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@exp#}
|
||||
<pre>{#syntax#}@exp(comptime T: type, value: T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
Base-e exponential function on a floating point number. Uses a dedicated hardware instruction
|
||||
when available. Currently supports f32 and f64.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@exp2#}
|
||||
<pre>{#syntax#}@exp2(comptime T: type, value: T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
Base-2 exponential function on a floating point number. Uses a dedicated hardware instruction
|
||||
when available. Currently supports f32 and f64.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@ln#}
|
||||
<pre>{#syntax#}@ln(comptime T: type, value: T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
Returns the natural logarithm of a floating point number. Uses a dedicated hardware instruction
|
||||
when available. Currently supports f32 and f64.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@log2#}
|
||||
<pre>{#syntax#}@log2(comptime T: type, value: T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
Returns the logarithm to the base 2 of a floating point number. Uses a dedicated hardware instruction
|
||||
when available. Currently supports f32 and f64.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@log10#}
|
||||
<pre>{#syntax#}@log10(comptime T: type, value: T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
Returns the logarithm to the base 10 of a floating point number. Uses a dedicated hardware instruction
|
||||
when available. Currently supports f32 and f64.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@fabs#}
|
||||
<pre>{#syntax#}@fabs(comptime T: type, value: T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
Returns the absolute value of a floating point number. Uses a dedicated hardware instruction
|
||||
when available. Currently supports f32 and f64.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@floor#}
|
||||
<pre>{#syntax#}@floor(comptime T: type, value: T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
Returns the largest integral value not greater than the given floating point number. Uses a dedicated hardware instruction
|
||||
when available. Currently supports f32 and f64.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@ceil#}
|
||||
<pre>{#syntax#}@ceil(comptime T: type, value: T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
Returns the largest integral value not less than the given floating point number. Uses a dedicated hardware instruction
|
||||
when available. Currently supports f32 and f64.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@trunc#}
|
||||
<pre>{#syntax#}@trunc(comptime T: type, value: T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
Rounds the given floating point number to an integer, towards zero. Uses a dedicated hardware instruction
|
||||
when available. Currently supports f32 and f64.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@round#}
|
||||
<pre>{#syntax#}@round(comptime T: type, value: T) T{#endsyntax#}</pre>
|
||||
<p>
|
||||
Rounds the given floating point number to an integer, away from zero. Uses a dedicated hardware instruction
|
||||
when available. Currently supports f32 and f64.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
|
||||
@ -998,7 +998,7 @@ fn printCharValues(out: var, bytes: []const u8) !void {
|
||||
|
||||
fn printUnderstandableChar(out: var, char: u8) !void {
|
||||
if (!std.ascii.isPrint(char) or char == ' ') {
|
||||
std.fmt.format(out.context, anyerror, out.output, "\\x{X2}", char) catch {};
|
||||
std.fmt.format(out.context, anyerror, out.output, "\\x{X:2}", char) catch {};
|
||||
} else {
|
||||
try out.write("'");
|
||||
try out.write([_]u8{printable_char_tab[char]});
|
||||
|
||||
@ -34,12 +34,17 @@ struct CodeGen;
|
||||
struct ConstExprValue;
|
||||
struct IrInstruction;
|
||||
struct IrInstructionCast;
|
||||
struct IrInstructionAllocaGen;
|
||||
struct IrBasicBlock;
|
||||
struct ScopeDecls;
|
||||
struct ZigWindowsSDK;
|
||||
struct Tld;
|
||||
struct TldExport;
|
||||
struct IrAnalyze;
|
||||
struct ResultLoc;
|
||||
struct ResultLocPeer;
|
||||
struct ResultLocPeerParent;
|
||||
struct ResultLocBitCast;
|
||||
|
||||
enum X64CABIClass {
|
||||
X64CABIClass_Unknown,
|
||||
@ -198,6 +203,9 @@ enum ConstPtrMut {
|
||||
// The pointer points to memory that is known only at runtime.
|
||||
// For example it may point to the initializer value of a variable.
|
||||
ConstPtrMutRuntimeVar,
|
||||
// The pointer points to memory for which it must be inferred whether the
|
||||
// value is comptime known or not.
|
||||
ConstPtrMutInfer,
|
||||
};
|
||||
|
||||
struct ConstPtrValue {
|
||||
@ -289,6 +297,7 @@ struct RuntimeHintSlice {
|
||||
struct ConstGlobalRefs {
|
||||
LLVMValueRef llvm_value;
|
||||
LLVMValueRef llvm_global;
|
||||
uint32_t align;
|
||||
};
|
||||
|
||||
struct ConstExprValue {
|
||||
@ -325,6 +334,10 @@ struct ConstExprValue {
|
||||
RuntimeHintPtr rh_ptr;
|
||||
RuntimeHintSlice rh_slice;
|
||||
} data;
|
||||
|
||||
// uncomment these to find bugs. can't leave them uncommented because of a gcc-9 warning
|
||||
//ConstExprValue(const ConstExprValue &other) = delete; // plz zero initialize with {}
|
||||
//ConstExprValue& operator= (const ConstExprValue &other) = delete; // use copy_const_val
|
||||
};
|
||||
|
||||
enum ReturnKnowledge {
|
||||
@ -426,7 +439,7 @@ enum NodeType {
|
||||
NodeTypeVariableDeclaration,
|
||||
NodeTypeTestDecl,
|
||||
NodeTypeBinOpExpr,
|
||||
NodeTypeUnwrapErrorExpr,
|
||||
NodeTypeCatchExpr,
|
||||
NodeTypeFloatLiteral,
|
||||
NodeTypeIntLiteral,
|
||||
NodeTypeStringLiteral,
|
||||
@ -1097,6 +1110,8 @@ struct ZigPackage {
|
||||
|
||||
// reminder: hash tables must be initialized before use
|
||||
HashMap<Buf *, ZigPackage *, buf_hash, buf_eql_buf> package_table;
|
||||
|
||||
bool added_to_cache;
|
||||
};
|
||||
|
||||
// Stuff that only applies to a struct which is the implicit root struct of a file
|
||||
@ -1364,7 +1379,7 @@ struct ZigFn {
|
||||
AstNode *fn_no_inline_set_node;
|
||||
AstNode *fn_static_eval_set_node;
|
||||
|
||||
ZigList<IrInstruction *> alloca_list;
|
||||
ZigList<IrInstructionAllocaGen *> alloca_gen_list;
|
||||
ZigList<ZigVar *> variable_list;
|
||||
|
||||
Buf *section_name;
|
||||
@ -1406,6 +1421,7 @@ enum BuiltinFnId {
|
||||
BuiltinFnIdSubWithOverflow,
|
||||
BuiltinFnIdMulWithOverflow,
|
||||
BuiltinFnIdShlWithOverflow,
|
||||
BuiltinFnIdMulAdd,
|
||||
BuiltinFnIdCInclude,
|
||||
BuiltinFnIdCDefine,
|
||||
BuiltinFnIdCUndef,
|
||||
@ -1433,6 +1449,19 @@ enum BuiltinFnId {
|
||||
BuiltinFnIdRem,
|
||||
BuiltinFnIdMod,
|
||||
BuiltinFnIdSqrt,
|
||||
BuiltinFnIdSin,
|
||||
BuiltinFnIdCos,
|
||||
BuiltinFnIdExp,
|
||||
BuiltinFnIdExp2,
|
||||
BuiltinFnIdLn,
|
||||
BuiltinFnIdLog2,
|
||||
BuiltinFnIdLog10,
|
||||
BuiltinFnIdFabs,
|
||||
BuiltinFnIdFloor,
|
||||
BuiltinFnIdCeil,
|
||||
BuiltinFnIdTrunc,
|
||||
BuiltinFnIdNearbyInt,
|
||||
BuiltinFnIdRound,
|
||||
BuiltinFnIdTruncate,
|
||||
BuiltinFnIdIntCast,
|
||||
BuiltinFnIdFloatCast,
|
||||
@ -1554,9 +1583,8 @@ enum ZigLLVMFnId {
|
||||
ZigLLVMFnIdClz,
|
||||
ZigLLVMFnIdPopCount,
|
||||
ZigLLVMFnIdOverflowArithmetic,
|
||||
ZigLLVMFnIdFloor,
|
||||
ZigLLVMFnIdCeil,
|
||||
ZigLLVMFnIdSqrt,
|
||||
ZigLLVMFnIdFMA,
|
||||
ZigLLVMFnIdFloatOp,
|
||||
ZigLLVMFnIdBswap,
|
||||
ZigLLVMFnIdBitReverse,
|
||||
};
|
||||
@ -1583,7 +1611,9 @@ struct ZigLLVMFnKey {
|
||||
uint32_t bit_count;
|
||||
} pop_count;
|
||||
struct {
|
||||
BuiltinFnId op;
|
||||
uint32_t bit_count;
|
||||
uint32_t vector_len; // 0 means not a vector
|
||||
} floating;
|
||||
struct {
|
||||
AddSubMul add_sub_mul;
|
||||
@ -1984,6 +2014,11 @@ struct ScopeDecls {
|
||||
bool any_imports_failed;
|
||||
};
|
||||
|
||||
enum LVal {
|
||||
LValNone,
|
||||
LValPtr,
|
||||
};
|
||||
|
||||
// This scope comes from a block expression in user code.
|
||||
// NodeTypeBlock
|
||||
struct ScopeBlock {
|
||||
@ -1992,12 +2027,14 @@ struct ScopeBlock {
|
||||
Buf *name;
|
||||
IrBasicBlock *end_block;
|
||||
IrInstruction *is_comptime;
|
||||
ResultLocPeerParent *peer_parent;
|
||||
ZigList<IrInstruction *> *incoming_values;
|
||||
ZigList<IrBasicBlock *> *incoming_blocks;
|
||||
|
||||
AstNode *safety_set_node;
|
||||
AstNode *fast_math_set_node;
|
||||
|
||||
LVal lval;
|
||||
bool safety_off;
|
||||
bool fast_math_on;
|
||||
};
|
||||
@ -2041,12 +2078,14 @@ struct ScopeCImport {
|
||||
struct ScopeLoop {
|
||||
Scope base;
|
||||
|
||||
LVal lval;
|
||||
Buf *name;
|
||||
IrBasicBlock *break_block;
|
||||
IrBasicBlock *continue_block;
|
||||
IrInstruction *is_comptime;
|
||||
ZigList<IrInstruction *> *incoming_values;
|
||||
ZigList<IrBasicBlock *> *incoming_blocks;
|
||||
ResultLocPeerParent *peer_parent;
|
||||
};
|
||||
|
||||
// This scope blocks certain things from working such as comptime continue
|
||||
@ -2123,6 +2162,8 @@ struct IrBasicBlock {
|
||||
const char *name_hint;
|
||||
size_t debug_id;
|
||||
size_t ref_count;
|
||||
// index into the basic block list
|
||||
size_t index;
|
||||
LLVMBasicBlockRef llvm_block;
|
||||
LLVMBasicBlockRef llvm_exit_block;
|
||||
// The instruction that referenced this basic block and caused us to
|
||||
@ -2133,11 +2174,10 @@ struct IrBasicBlock {
|
||||
// if the branch is comptime. The instruction points to the reason
|
||||
// the basic block must be comptime.
|
||||
IrInstruction *must_be_comptime_source_instr;
|
||||
};
|
||||
|
||||
enum LVal {
|
||||
LValNone,
|
||||
LValPtr,
|
||||
IrInstruction *suspend_instruction_ref;
|
||||
bool already_appended;
|
||||
bool suspended;
|
||||
bool in_resume_stack;
|
||||
};
|
||||
|
||||
// These instructions are in transition to having "pass 1" instructions
|
||||
@ -2170,19 +2210,17 @@ enum IrInstructionId {
|
||||
IrInstructionIdUnionFieldPtr,
|
||||
IrInstructionIdElemPtr,
|
||||
IrInstructionIdVarPtr,
|
||||
IrInstructionIdCall,
|
||||
IrInstructionIdReturnPtr,
|
||||
IrInstructionIdCallSrc,
|
||||
IrInstructionIdCallGen,
|
||||
IrInstructionIdConst,
|
||||
IrInstructionIdReturn,
|
||||
IrInstructionIdCast,
|
||||
IrInstructionIdResizeSlice,
|
||||
IrInstructionIdContainerInitList,
|
||||
IrInstructionIdContainerInitFields,
|
||||
IrInstructionIdStructInit,
|
||||
IrInstructionIdUnionInit,
|
||||
IrInstructionIdUnreachable,
|
||||
IrInstructionIdTypeOf,
|
||||
IrInstructionIdToPtrType,
|
||||
IrInstructionIdPtrTypeChild,
|
||||
IrInstructionIdSetCold,
|
||||
IrInstructionIdSetRuntimeSafety,
|
||||
IrInstructionIdSetFloatMode,
|
||||
@ -2207,6 +2245,7 @@ enum IrInstructionId {
|
||||
IrInstructionIdCDefine,
|
||||
IrInstructionIdCUndef,
|
||||
IrInstructionIdRef,
|
||||
IrInstructionIdRefGen,
|
||||
IrInstructionIdCompileErr,
|
||||
IrInstructionIdCompileLog,
|
||||
IrInstructionIdErrName,
|
||||
@ -2225,7 +2264,8 @@ enum IrInstructionId {
|
||||
IrInstructionIdBoolNot,
|
||||
IrInstructionIdMemset,
|
||||
IrInstructionIdMemcpy,
|
||||
IrInstructionIdSlice,
|
||||
IrInstructionIdSliceSrc,
|
||||
IrInstructionIdSliceGen,
|
||||
IrInstructionIdMemberCount,
|
||||
IrInstructionIdMemberType,
|
||||
IrInstructionIdMemberName,
|
||||
@ -2235,7 +2275,10 @@ enum IrInstructionId {
|
||||
IrInstructionIdHandle,
|
||||
IrInstructionIdAlignOf,
|
||||
IrInstructionIdOverflowOp,
|
||||
IrInstructionIdTestErr,
|
||||
IrInstructionIdTestErrSrc,
|
||||
IrInstructionIdTestErrGen,
|
||||
IrInstructionIdMulAdd,
|
||||
IrInstructionIdFloatOp,
|
||||
IrInstructionIdUnwrapErrCode,
|
||||
IrInstructionIdUnwrapErrPayload,
|
||||
IrInstructionIdErrWrapCode,
|
||||
@ -2244,7 +2287,7 @@ enum IrInstructionId {
|
||||
IrInstructionIdTestComptime,
|
||||
IrInstructionIdPtrCastSrc,
|
||||
IrInstructionIdPtrCastGen,
|
||||
IrInstructionIdBitCast,
|
||||
IrInstructionIdBitCastSrc,
|
||||
IrInstructionIdBitCastGen,
|
||||
IrInstructionIdWidenOrShorten,
|
||||
IrInstructionIdIntToPtr,
|
||||
@ -2268,6 +2311,10 @@ enum IrInstructionId {
|
||||
IrInstructionIdSetEvalBranchQuota,
|
||||
IrInstructionIdPtrType,
|
||||
IrInstructionIdAlignCast,
|
||||
IrInstructionIdImplicitCast,
|
||||
IrInstructionIdResolveResult,
|
||||
IrInstructionIdResetResult,
|
||||
IrInstructionIdResultPtr,
|
||||
IrInstructionIdOpaqueType,
|
||||
IrInstructionIdSetAlignStack,
|
||||
IrInstructionIdArgType,
|
||||
@ -2296,7 +2343,6 @@ enum IrInstructionId {
|
||||
IrInstructionIdAddImplicitReturnType,
|
||||
IrInstructionIdMergeErrRetTraces,
|
||||
IrInstructionIdMarkErrRetTracePtr,
|
||||
IrInstructionIdSqrt,
|
||||
IrInstructionIdErrSetCast,
|
||||
IrInstructionIdToBytes,
|
||||
IrInstructionIdFromBytes,
|
||||
@ -2307,10 +2353,13 @@ enum IrInstructionId {
|
||||
IrInstructionIdAssertNonNull,
|
||||
IrInstructionIdHasDecl,
|
||||
IrInstructionIdUndeclaredIdent,
|
||||
IrInstructionIdAllocaSrc,
|
||||
IrInstructionIdAllocaGen,
|
||||
IrInstructionIdEndExpr,
|
||||
IrInstructionIdPtrOfArrayToSlice,
|
||||
};
|
||||
|
||||
struct IrInstruction {
|
||||
IrInstructionId id;
|
||||
Scope *scope;
|
||||
AstNode *source_node;
|
||||
ConstExprValue value;
|
||||
@ -2324,6 +2373,7 @@ struct IrInstruction {
|
||||
// with this child field.
|
||||
IrInstruction *child;
|
||||
IrBasicBlock *owner_bb;
|
||||
IrInstructionId id;
|
||||
// true if this instruction was generated by zig and not from user code
|
||||
bool is_gen;
|
||||
};
|
||||
@ -2334,14 +2384,14 @@ struct IrInstructionDeclVarSrc {
|
||||
ZigVar *var;
|
||||
IrInstruction *var_type;
|
||||
IrInstruction *align_value;
|
||||
IrInstruction *init_value;
|
||||
IrInstruction *ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionDeclVarGen {
|
||||
IrInstruction base;
|
||||
|
||||
ZigVar *var;
|
||||
IrInstruction *init_value;
|
||||
IrInstruction *var_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionCondBr {
|
||||
@ -2351,6 +2401,7 @@ struct IrInstructionCondBr {
|
||||
IrBasicBlock *then_block;
|
||||
IrBasicBlock *else_block;
|
||||
IrInstruction *is_comptime;
|
||||
ResultLoc *result_loc;
|
||||
};
|
||||
|
||||
struct IrInstructionBr {
|
||||
@ -2403,6 +2454,7 @@ struct IrInstructionPhi {
|
||||
size_t incoming_count;
|
||||
IrBasicBlock **incoming_blocks;
|
||||
IrInstruction **incoming_values;
|
||||
ResultLocPeerParent *peer_parent;
|
||||
};
|
||||
|
||||
enum IrUnOp {
|
||||
@ -2418,8 +2470,9 @@ struct IrInstructionUnOp {
|
||||
IrInstruction base;
|
||||
|
||||
IrUnOp op_id;
|
||||
IrInstruction *value;
|
||||
LVal lval;
|
||||
IrInstruction *value;
|
||||
ResultLoc *result_loc;
|
||||
};
|
||||
|
||||
enum IrBinOp {
|
||||
@ -2476,7 +2529,7 @@ struct IrInstructionLoadPtrGen {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *ptr;
|
||||
LLVMValueRef tmp_ptr;
|
||||
IrInstruction *result_loc;
|
||||
};
|
||||
|
||||
struct IrInstructionStorePtr {
|
||||
@ -2489,6 +2542,7 @@ struct IrInstructionStorePtr {
|
||||
struct IrInstructionFieldPtr {
|
||||
IrInstruction base;
|
||||
|
||||
bool initializing;
|
||||
IrInstruction *container_ptr;
|
||||
Buf *field_name_buffer;
|
||||
IrInstruction *field_name_expr;
|
||||
@ -2505,9 +2559,10 @@ struct IrInstructionStructFieldPtr {
|
||||
struct IrInstructionUnionFieldPtr {
|
||||
IrInstruction base;
|
||||
|
||||
bool safety_check_on;
|
||||
bool initializing;
|
||||
IrInstruction *union_ptr;
|
||||
TypeUnionField *field;
|
||||
bool is_const;
|
||||
};
|
||||
|
||||
struct IrInstructionElemPtr {
|
||||
@ -2515,8 +2570,8 @@ struct IrInstructionElemPtr {
|
||||
|
||||
IrInstruction *array_ptr;
|
||||
IrInstruction *elem_index;
|
||||
IrInstruction *init_array_type;
|
||||
PtrLen ptr_len;
|
||||
bool is_const;
|
||||
bool safety_check_on;
|
||||
};
|
||||
|
||||
@ -2527,14 +2582,21 @@ struct IrInstructionVarPtr {
|
||||
ScopeFnDef *crossed_fndef_scope;
|
||||
};
|
||||
|
||||
struct IrInstructionCall {
|
||||
// For functions that have a return type for which handle_is_ptr is true, a
|
||||
// result location pointer is the secret first parameter ("sret"). This
|
||||
// instruction returns that pointer.
|
||||
struct IrInstructionReturnPtr {
|
||||
IrInstruction base;
|
||||
};
|
||||
|
||||
struct IrInstructionCallSrc {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *fn_ref;
|
||||
ZigFn *fn_entry;
|
||||
size_t arg_count;
|
||||
IrInstruction **args;
|
||||
LLVMValueRef tmp_ptr;
|
||||
ResultLoc *result_loc;
|
||||
|
||||
IrInstruction *async_allocator;
|
||||
IrInstruction *new_stack;
|
||||
@ -2543,6 +2605,21 @@ struct IrInstructionCall {
|
||||
bool is_comptime;
|
||||
};
|
||||
|
||||
struct IrInstructionCallGen {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *fn_ref;
|
||||
ZigFn *fn_entry;
|
||||
size_t arg_count;
|
||||
IrInstruction **args;
|
||||
IrInstruction *result_loc;
|
||||
|
||||
IrInstruction *async_allocator;
|
||||
IrInstruction *new_stack;
|
||||
FnInline fn_inline;
|
||||
bool is_async;
|
||||
};
|
||||
|
||||
struct IrInstructionConst {
|
||||
IrInstruction base;
|
||||
};
|
||||
@ -2565,7 +2642,6 @@ enum CastOp {
|
||||
CastOpNumLitToConcrete,
|
||||
CastOpErrSet,
|
||||
CastOpBitCast,
|
||||
CastOpPtrOfArrayToSlice,
|
||||
};
|
||||
|
||||
// TODO get rid of this instruction, replace with instructions for each op code
|
||||
@ -2575,14 +2651,13 @@ struct IrInstructionCast {
|
||||
IrInstruction *value;
|
||||
ZigType *dest_type;
|
||||
CastOp cast_op;
|
||||
LLVMValueRef tmp_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionResizeSlice {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *operand;
|
||||
LLVMValueRef tmp_ptr;
|
||||
IrInstruction *result_loc;
|
||||
};
|
||||
|
||||
struct IrInstructionContainerInitList {
|
||||
@ -2591,15 +2666,15 @@ struct IrInstructionContainerInitList {
|
||||
IrInstruction *container_type;
|
||||
IrInstruction *elem_type;
|
||||
size_t item_count;
|
||||
IrInstruction **items;
|
||||
LLVMValueRef tmp_ptr;
|
||||
IrInstruction **elem_result_loc_list;
|
||||
IrInstruction *result_loc;
|
||||
};
|
||||
|
||||
struct IrInstructionContainerInitFieldsField {
|
||||
Buf *name;
|
||||
IrInstruction *value;
|
||||
AstNode *source_node;
|
||||
TypeStructField *type_struct_field;
|
||||
IrInstruction *result_loc;
|
||||
};
|
||||
|
||||
struct IrInstructionContainerInitFields {
|
||||
@ -2608,29 +2683,7 @@ struct IrInstructionContainerInitFields {
|
||||
IrInstruction *container_type;
|
||||
size_t field_count;
|
||||
IrInstructionContainerInitFieldsField *fields;
|
||||
};
|
||||
|
||||
struct IrInstructionStructInitField {
|
||||
IrInstruction *value;
|
||||
TypeStructField *type_struct_field;
|
||||
};
|
||||
|
||||
struct IrInstructionStructInit {
|
||||
IrInstruction base;
|
||||
|
||||
ZigType *struct_type;
|
||||
size_t field_count;
|
||||
IrInstructionStructInitField *fields;
|
||||
LLVMValueRef tmp_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionUnionInit {
|
||||
IrInstruction base;
|
||||
|
||||
ZigType *union_type;
|
||||
TypeUnionField *field;
|
||||
IrInstruction *init_value;
|
||||
LLVMValueRef tmp_ptr;
|
||||
IrInstruction *result_loc;
|
||||
};
|
||||
|
||||
struct IrInstructionUnreachable {
|
||||
@ -2643,18 +2696,6 @@ struct IrInstructionTypeOf {
|
||||
IrInstruction *value;
|
||||
};
|
||||
|
||||
struct IrInstructionToPtrType {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionPtrTypeChild {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *value;
|
||||
};
|
||||
|
||||
struct IrInstructionSetCold {
|
||||
IrInstruction base;
|
||||
|
||||
@ -2748,8 +2789,9 @@ struct IrInstructionTestNonNull {
|
||||
struct IrInstructionOptionalUnwrapPtr {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *base_ptr;
|
||||
bool safety_check_on;
|
||||
bool initializing;
|
||||
IrInstruction *base_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionCtz {
|
||||
@ -2789,11 +2831,17 @@ struct IrInstructionRef {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *value;
|
||||
LLVMValueRef tmp_ptr;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
};
|
||||
|
||||
struct IrInstructionRefGen {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *operand;
|
||||
IrInstruction *result_loc;
|
||||
};
|
||||
|
||||
struct IrInstructionCompileErr {
|
||||
IrInstruction base;
|
||||
|
||||
@ -2845,26 +2893,26 @@ struct IrInstructionEmbedFile {
|
||||
struct IrInstructionCmpxchgSrc {
|
||||
IrInstruction base;
|
||||
|
||||
bool is_weak;
|
||||
IrInstruction *type_value;
|
||||
IrInstruction *ptr;
|
||||
IrInstruction *cmp_value;
|
||||
IrInstruction *new_value;
|
||||
IrInstruction *success_order_value;
|
||||
IrInstruction *failure_order_value;
|
||||
|
||||
bool is_weak;
|
||||
ResultLoc *result_loc;
|
||||
};
|
||||
|
||||
struct IrInstructionCmpxchgGen {
|
||||
IrInstruction base;
|
||||
|
||||
bool is_weak;
|
||||
AtomicOrder success_order;
|
||||
AtomicOrder failure_order;
|
||||
IrInstruction *ptr;
|
||||
IrInstruction *cmp_value;
|
||||
IrInstruction *new_value;
|
||||
LLVMValueRef tmp_ptr;
|
||||
AtomicOrder success_order;
|
||||
AtomicOrder failure_order;
|
||||
bool is_weak;
|
||||
IrInstruction *result_loc;
|
||||
};
|
||||
|
||||
struct IrInstructionFence {
|
||||
@ -2908,6 +2956,7 @@ struct IrInstructionToBytes {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *target;
|
||||
ResultLoc *result_loc;
|
||||
};
|
||||
|
||||
struct IrInstructionFromBytes {
|
||||
@ -2915,6 +2964,7 @@ struct IrInstructionFromBytes {
|
||||
|
||||
IrInstruction *dest_child_type;
|
||||
IrInstruction *target;
|
||||
ResultLoc *result_loc;
|
||||
};
|
||||
|
||||
struct IrInstructionIntToFloat {
|
||||
@ -2973,14 +3023,24 @@ struct IrInstructionMemcpy {
|
||||
IrInstruction *count;
|
||||
};
|
||||
|
||||
struct IrInstructionSlice {
|
||||
struct IrInstructionSliceSrc {
|
||||
IrInstruction base;
|
||||
|
||||
bool safety_check_on;
|
||||
IrInstruction *ptr;
|
||||
IrInstruction *start;
|
||||
IrInstruction *end;
|
||||
ResultLoc *result_loc;
|
||||
};
|
||||
|
||||
struct IrInstructionSliceGen {
|
||||
IrInstruction base;
|
||||
|
||||
bool safety_check_on;
|
||||
LLVMValueRef tmp_ptr;
|
||||
IrInstruction *ptr;
|
||||
IrInstruction *start;
|
||||
IrInstruction *end;
|
||||
IrInstruction *result_loc;
|
||||
};
|
||||
|
||||
struct IrInstructionMemberCount {
|
||||
@ -3038,6 +3098,15 @@ struct IrInstructionOverflowOp {
|
||||
ZigType *result_ptr_type;
|
||||
};
|
||||
|
||||
struct IrInstructionMulAdd {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *type_value;
|
||||
IrInstruction *op1;
|
||||
IrInstruction *op2;
|
||||
IrInstruction *op3;
|
||||
};
|
||||
|
||||
struct IrInstructionAlignOf {
|
||||
IrInstruction base;
|
||||
|
||||
@ -3045,44 +3114,54 @@ struct IrInstructionAlignOf {
|
||||
};
|
||||
|
||||
// returns true if error, returns false if not error
|
||||
struct IrInstructionTestErr {
|
||||
struct IrInstructionTestErrSrc {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *value;
|
||||
bool resolve_err_set;
|
||||
IrInstruction *base_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionUnwrapErrCode {
|
||||
struct IrInstructionTestErrGen {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *err_union;
|
||||
};
|
||||
|
||||
// Takes an error union pointer, returns a pointer to the error code.
|
||||
struct IrInstructionUnwrapErrCode {
|
||||
IrInstruction base;
|
||||
|
||||
bool initializing;
|
||||
IrInstruction *err_union_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionUnwrapErrPayload {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *value;
|
||||
bool safety_check_on;
|
||||
bool initializing;
|
||||
IrInstruction *value;
|
||||
};
|
||||
|
||||
struct IrInstructionOptionalWrap {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *value;
|
||||
LLVMValueRef tmp_ptr;
|
||||
IrInstruction *operand;
|
||||
IrInstruction *result_loc;
|
||||
};
|
||||
|
||||
struct IrInstructionErrWrapPayload {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *value;
|
||||
LLVMValueRef tmp_ptr;
|
||||
IrInstruction *operand;
|
||||
IrInstruction *result_loc;
|
||||
};
|
||||
|
||||
struct IrInstructionErrWrapCode {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *value;
|
||||
LLVMValueRef tmp_ptr;
|
||||
IrInstruction *operand;
|
||||
IrInstruction *result_loc;
|
||||
};
|
||||
|
||||
struct IrInstructionFnProto {
|
||||
@ -3117,18 +3196,17 @@ struct IrInstructionPtrCastGen {
|
||||
bool safety_check_on;
|
||||
};
|
||||
|
||||
struct IrInstructionBitCast {
|
||||
struct IrInstructionBitCastSrc {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *dest_type;
|
||||
IrInstruction *value;
|
||||
IrInstruction *operand;
|
||||
ResultLocBitCast *result_loc_bit_cast;
|
||||
};
|
||||
|
||||
struct IrInstructionBitCastGen {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *operand;
|
||||
LLVMValueRef tmp_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionWidenOrShorten {
|
||||
@ -3204,8 +3282,8 @@ struct IrInstructionTypeName {
|
||||
struct IrInstructionDeclRef {
|
||||
IrInstruction base;
|
||||
|
||||
Tld *tld;
|
||||
LVal lval;
|
||||
Tld *tld;
|
||||
};
|
||||
|
||||
struct IrInstructionPanic {
|
||||
@ -3461,11 +3539,13 @@ struct IrInstructionMarkErrRetTracePtr {
|
||||
IrInstruction *err_ret_trace_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionSqrt {
|
||||
// For float ops which take a single argument
|
||||
struct IrInstructionFloatOp {
|
||||
IrInstruction base;
|
||||
|
||||
BuiltinFnId op;
|
||||
IrInstruction *type;
|
||||
IrInstruction *op;
|
||||
IrInstruction *op1;
|
||||
};
|
||||
|
||||
struct IrInstructionCheckRuntimeScope {
|
||||
@ -3499,7 +3579,7 @@ struct IrInstructionVectorToArray {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *vector;
|
||||
LLVMValueRef tmp_ptr;
|
||||
IrInstruction *result_loc;
|
||||
};
|
||||
|
||||
struct IrInstructionAssertZero {
|
||||
@ -3527,6 +3607,139 @@ struct IrInstructionUndeclaredIdent {
|
||||
Buf *name;
|
||||
};
|
||||
|
||||
struct IrInstructionAllocaSrc {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *align;
|
||||
IrInstruction *is_comptime;
|
||||
const char *name_hint;
|
||||
};
|
||||
|
||||
struct IrInstructionAllocaGen {
|
||||
IrInstruction base;
|
||||
|
||||
uint32_t align;
|
||||
const char *name_hint;
|
||||
};
|
||||
|
||||
struct IrInstructionEndExpr {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *value;
|
||||
ResultLoc *result_loc;
|
||||
};
|
||||
|
||||
struct IrInstructionImplicitCast {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *dest_type;
|
||||
IrInstruction *target;
|
||||
ResultLoc *result_loc;
|
||||
};
|
||||
|
||||
// This one is for writing through the result pointer.
|
||||
struct IrInstructionResolveResult {
|
||||
IrInstruction base;
|
||||
|
||||
ResultLoc *result_loc;
|
||||
IrInstruction *ty;
|
||||
};
|
||||
|
||||
// This one is when you want to read the value of the result.
|
||||
// You have to give the value in case it is comptime.
|
||||
struct IrInstructionResultPtr {
|
||||
IrInstruction base;
|
||||
|
||||
ResultLoc *result_loc;
|
||||
IrInstruction *result;
|
||||
};
|
||||
|
||||
struct IrInstructionResetResult {
|
||||
IrInstruction base;
|
||||
|
||||
ResultLoc *result_loc;
|
||||
};
|
||||
|
||||
struct IrInstructionPtrOfArrayToSlice {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *operand;
|
||||
IrInstruction *result_loc;
|
||||
};
|
||||
|
||||
enum ResultLocId {
|
||||
ResultLocIdInvalid,
|
||||
ResultLocIdNone,
|
||||
ResultLocIdVar,
|
||||
ResultLocIdReturn,
|
||||
ResultLocIdPeer,
|
||||
ResultLocIdPeerParent,
|
||||
ResultLocIdInstruction,
|
||||
ResultLocIdBitCast,
|
||||
};
|
||||
|
||||
// Additions to this struct may need to be handled in
|
||||
// ir_reset_result
|
||||
struct ResultLoc {
|
||||
ResultLocId id;
|
||||
bool written;
|
||||
IrInstruction *resolved_loc; // result ptr
|
||||
IrInstruction *source_instruction;
|
||||
IrInstruction *gen_instruction; // value to store to the result loc
|
||||
ZigType *implicit_elem_type;
|
||||
};
|
||||
|
||||
struct ResultLocNone {
|
||||
ResultLoc base;
|
||||
};
|
||||
|
||||
struct ResultLocVar {
|
||||
ResultLoc base;
|
||||
|
||||
ZigVar *var;
|
||||
};
|
||||
|
||||
struct ResultLocReturn {
|
||||
ResultLoc base;
|
||||
};
|
||||
|
||||
struct IrSuspendPosition {
|
||||
size_t basic_block_index;
|
||||
size_t instruction_index;
|
||||
};
|
||||
|
||||
struct ResultLocPeerParent {
|
||||
ResultLoc base;
|
||||
|
||||
bool skipped;
|
||||
bool done_resuming;
|
||||
IrBasicBlock *end_bb;
|
||||
ResultLoc *parent;
|
||||
ZigList<ResultLocPeer *> peers;
|
||||
ZigType *resolved_type;
|
||||
IrInstruction *is_comptime;
|
||||
};
|
||||
|
||||
struct ResultLocPeer {
|
||||
ResultLoc base;
|
||||
|
||||
ResultLocPeerParent *parent;
|
||||
IrBasicBlock *next_bb;
|
||||
IrSuspendPosition suspend_pos;
|
||||
};
|
||||
|
||||
// The result location is the source instruction
|
||||
struct ResultLocInstruction {
|
||||
ResultLoc base;
|
||||
};
|
||||
|
||||
// The source_instruction is the destination type
|
||||
struct ResultLocBitCast {
|
||||
ResultLoc base;
|
||||
|
||||
ResultLoc *parent;
|
||||
};
|
||||
|
||||
static const size_t slice_ptr_index = 0;
|
||||
static const size_t slice_len_index = 1;
|
||||
|
||||
@ -3574,7 +3787,7 @@ struct FnWalkAttrs {
|
||||
|
||||
struct FnWalkCall {
|
||||
ZigList<LLVMValueRef> *gen_param_values;
|
||||
IrInstructionCall *inst;
|
||||
IrInstructionCallGen *inst;
|
||||
bool is_var_args;
|
||||
};
|
||||
|
||||
|
||||
@ -2995,7 +2995,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
|
||||
case NodeTypeBlock:
|
||||
case NodeTypeGroupedExpr:
|
||||
case NodeTypeBinOpExpr:
|
||||
case NodeTypeUnwrapErrorExpr:
|
||||
case NodeTypeCatchExpr:
|
||||
case NodeTypeFnCallExpr:
|
||||
case NodeTypeArrayAccessExpr:
|
||||
case NodeTypeSliceExpr:
|
||||
@ -4181,6 +4181,7 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) {
|
||||
case ConstPtrMutComptimeConst:
|
||||
hash_val += (uint32_t)4214318515;
|
||||
break;
|
||||
case ConstPtrMutInfer:
|
||||
case ConstPtrMutComptimeVar:
|
||||
hash_val += (uint32_t)1103195694;
|
||||
break;
|
||||
@ -4511,6 +4512,8 @@ bool fn_eval_cacheable(Scope *scope, ZigType *return_type) {
|
||||
ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
|
||||
if (type_is_invalid(var_scope->var->var_type))
|
||||
return false;
|
||||
if (var_scope->var->const_value->special == ConstValSpecialUndef)
|
||||
return false;
|
||||
if (can_mutate_comptime_var_state(var_scope->var->const_value))
|
||||
return false;
|
||||
} else if (scope->id == ScopeIdFnDef) {
|
||||
@ -4710,7 +4713,7 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) {
|
||||
void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
|
||||
auto entry = g->string_literals_table.maybe_get(str);
|
||||
if (entry != nullptr) {
|
||||
*const_val = *entry->value;
|
||||
memcpy(const_val, entry->value, sizeof(ConstExprValue));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -4998,12 +5001,9 @@ void init_const_undefined(CodeGen *g, ConstExprValue *const_val) {
|
||||
field_val->type = wanted_type->data.structure.fields[i].type_entry;
|
||||
assert(field_val->type);
|
||||
init_const_undefined(g, field_val);
|
||||
ConstParent *parent = get_const_val_parent(g, field_val);
|
||||
if (parent != nullptr) {
|
||||
parent->id = ConstParentIdStruct;
|
||||
parent->data.p_struct.struct_val = const_val;
|
||||
parent->data.p_struct.field_index = i;
|
||||
}
|
||||
field_val->parent.id = ConstParentIdStruct;
|
||||
field_val->parent.data.p_struct.struct_val = const_val;
|
||||
field_val->parent.data.p_struct.field_index = i;
|
||||
}
|
||||
} else {
|
||||
const_val->special = ConstValSpecialUndef;
|
||||
@ -5736,12 +5736,13 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) {
|
||||
return (uint32_t)(x.data.clz.bit_count) * (uint32_t)2428952817;
|
||||
case ZigLLVMFnIdPopCount:
|
||||
return (uint32_t)(x.data.clz.bit_count) * (uint32_t)101195049;
|
||||
case ZigLLVMFnIdFloor:
|
||||
return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1899859168;
|
||||
case ZigLLVMFnIdCeil:
|
||||
return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1953839089;
|
||||
case ZigLLVMFnIdSqrt:
|
||||
return (uint32_t)(x.data.floating.bit_count) * (uint32_t)2225366385;
|
||||
case ZigLLVMFnIdFloatOp:
|
||||
return (uint32_t)(x.data.floating.bit_count) * ((uint32_t)x.id + 1025) +
|
||||
(uint32_t)(x.data.floating.vector_len) * (((uint32_t)x.id << 5) + 1025) +
|
||||
(uint32_t)(x.data.floating.op) * (uint32_t)43789879;
|
||||
case ZigLLVMFnIdFMA:
|
||||
return (uint32_t)(x.data.floating.bit_count) * ((uint32_t)x.id + 1025) +
|
||||
(uint32_t)(x.data.floating.vector_len) * (((uint32_t)x.id << 5) + 1025);
|
||||
case ZigLLVMFnIdBswap:
|
||||
return (uint32_t)(x.data.bswap.bit_count) * (uint32_t)3661994335;
|
||||
case ZigLLVMFnIdBitReverse:
|
||||
@ -5769,10 +5770,13 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {
|
||||
return a.data.bswap.bit_count == b.data.bswap.bit_count;
|
||||
case ZigLLVMFnIdBitReverse:
|
||||
return a.data.bit_reverse.bit_count == b.data.bit_reverse.bit_count;
|
||||
case ZigLLVMFnIdFloor:
|
||||
case ZigLLVMFnIdCeil:
|
||||
case ZigLLVMFnIdSqrt:
|
||||
return a.data.floating.bit_count == b.data.floating.bit_count;
|
||||
case ZigLLVMFnIdFloatOp:
|
||||
return a.data.floating.bit_count == b.data.floating.bit_count &&
|
||||
a.data.floating.vector_len == b.data.floating.vector_len &&
|
||||
a.data.floating.op == b.data.floating.op;
|
||||
case ZigLLVMFnIdFMA:
|
||||
return a.data.floating.bit_count == b.data.floating.bit_count &&
|
||||
a.data.floating.vector_len == b.data.floating.vector_len;
|
||||
case ZigLLVMFnIdOverflowArithmetic:
|
||||
return (a.data.overflow_arithmetic.bit_count == b.data.overflow_arithmetic.bit_count) &&
|
||||
(a.data.overflow_arithmetic.add_sub_mul == b.data.overflow_arithmetic.add_sub_mul) &&
|
||||
@ -5839,11 +5843,6 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
// Deprecated. Reference the parent field directly.
|
||||
ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) {
|
||||
return &value->parent;
|
||||
}
|
||||
|
||||
static const ZigTypeId all_type_ids[] = {
|
||||
ZigTypeIdMetaType,
|
||||
ZigTypeIdVoid,
|
||||
@ -7277,6 +7276,6 @@ void src_assert(bool ok, AstNode *source_node) {
|
||||
buf_ptr(source_node->owner->data.structure.root_struct->path),
|
||||
(unsigned)source_node->line + 1, (unsigned)source_node->column + 1);
|
||||
}
|
||||
const char *msg = "assertion failed";
|
||||
const char *msg = "assertion failed. This is a bug in the Zig compiler.";
|
||||
stage2_panic(msg, strlen(msg));
|
||||
}
|
||||
|
||||
@ -180,7 +180,6 @@ void init_const_undefined(CodeGen *g, ConstExprValue *const_val);
|
||||
ConstExprValue *create_const_vals(size_t count);
|
||||
|
||||
ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits);
|
||||
ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value);
|
||||
void expand_undef_array(CodeGen *g, ConstExprValue *const_val);
|
||||
void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value);
|
||||
|
||||
|
||||
@ -165,8 +165,8 @@ static const char *node_type_str(NodeType node_type) {
|
||||
return "Parens";
|
||||
case NodeTypeBinOpExpr:
|
||||
return "BinOpExpr";
|
||||
case NodeTypeUnwrapErrorExpr:
|
||||
return "UnwrapErrorExpr";
|
||||
case NodeTypeCatchExpr:
|
||||
return "CatchExpr";
|
||||
case NodeTypeFnCallExpr:
|
||||
return "FnCallExpr";
|
||||
case NodeTypeArrayAccessExpr:
|
||||
@ -1107,7 +1107,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
fprintf(ar->f, "]");
|
||||
break;
|
||||
}
|
||||
case NodeTypeUnwrapErrorExpr:
|
||||
case NodeTypeCatchExpr:
|
||||
{
|
||||
render_node_ungrouped(ar, node->data.unwrap_err_expr.op1);
|
||||
fprintf(ar->f, " catch ");
|
||||
|
||||
726
src/codegen.cpp
726
src/codegen.cpp
File diff suppressed because it is too large
Load Diff
5192
src/ir.cpp
5192
src/ir.cpp
File diff suppressed because it is too large
Load Diff
@ -26,5 +26,6 @@ bool ir_has_side_effects(IrInstruction *instruction);
|
||||
struct IrAnalyze;
|
||||
ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprValue *const_val,
|
||||
AstNode *source_node);
|
||||
const char *float_op_to_name(BuiltinFnId op, bool llvm_name);
|
||||
|
||||
#endif
|
||||
|
||||
373
src/ir_print.cpp
373
src/ir_print.cpp
@ -57,13 +57,18 @@ static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction)
|
||||
}
|
||||
|
||||
static void ir_print_other_block(IrPrint *irp, IrBasicBlock *bb) {
|
||||
fprintf(irp->f, "$%s_%" ZIG_PRI_usize "", bb->name_hint, bb->debug_id);
|
||||
if (bb == nullptr) {
|
||||
fprintf(irp->f, "(null block)");
|
||||
} else {
|
||||
fprintf(irp->f, "$%s_%" ZIG_PRI_usize "", bb->name_hint, bb->debug_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void ir_print_return(IrPrint *irp, IrInstructionReturn *return_instruction) {
|
||||
assert(return_instruction->value);
|
||||
fprintf(irp->f, "return ");
|
||||
ir_print_other_instruction(irp, return_instruction->value);
|
||||
if (return_instruction->value != nullptr) {
|
||||
ir_print_other_instruction(irp, return_instruction->value);
|
||||
}
|
||||
}
|
||||
|
||||
static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction) {
|
||||
@ -188,7 +193,7 @@ static void ir_print_decl_var_src(IrPrint *irp, IrInstructionDeclVarSrc *decl_va
|
||||
fprintf(irp->f, " ");
|
||||
}
|
||||
fprintf(irp->f, "= ");
|
||||
ir_print_other_instruction(irp, decl_var_instruction->init_value);
|
||||
ir_print_other_instruction(irp, decl_var_instruction->ptr);
|
||||
if (decl_var_instruction->var->is_comptime != nullptr) {
|
||||
fprintf(irp->f, " // comptime = ");
|
||||
ir_print_other_instruction(irp, decl_var_instruction->var->is_comptime);
|
||||
@ -201,7 +206,56 @@ static void ir_print_cast(IrPrint *irp, IrInstructionCast *cast_instruction) {
|
||||
fprintf(irp->f, " to %s", buf_ptr(&cast_instruction->dest_type->name));
|
||||
}
|
||||
|
||||
static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {
|
||||
static void ir_print_result_loc_var(IrPrint *irp, ResultLocVar *result_loc_var) {
|
||||
fprintf(irp->f, "var(");
|
||||
ir_print_other_instruction(irp, result_loc_var->base.source_instruction);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_result_loc_instruction(IrPrint *irp, ResultLocInstruction *result_loc_inst) {
|
||||
fprintf(irp->f, "inst(");
|
||||
ir_print_other_instruction(irp, result_loc_inst->base.source_instruction);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_result_loc_peer(IrPrint *irp, ResultLocPeer *result_loc_peer) {
|
||||
fprintf(irp->f, "peer(next=");
|
||||
ir_print_other_block(irp, result_loc_peer->next_bb);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_result_loc_bit_cast(IrPrint *irp, ResultLocBitCast *result_loc_bit_cast) {
|
||||
fprintf(irp->f, "bitcast(ty=");
|
||||
ir_print_other_instruction(irp, result_loc_bit_cast->base.source_instruction);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) {
|
||||
switch (result_loc->id) {
|
||||
case ResultLocIdInvalid:
|
||||
zig_unreachable();
|
||||
case ResultLocIdNone:
|
||||
fprintf(irp->f, "none");
|
||||
return;
|
||||
case ResultLocIdReturn:
|
||||
fprintf(irp->f, "return");
|
||||
return;
|
||||
case ResultLocIdVar:
|
||||
return ir_print_result_loc_var(irp, (ResultLocVar *)result_loc);
|
||||
case ResultLocIdInstruction:
|
||||
return ir_print_result_loc_instruction(irp, (ResultLocInstruction *)result_loc);
|
||||
case ResultLocIdPeer:
|
||||
return ir_print_result_loc_peer(irp, (ResultLocPeer *)result_loc);
|
||||
case ResultLocIdBitCast:
|
||||
return ir_print_result_loc_bit_cast(irp, (ResultLocBitCast *)result_loc);
|
||||
case ResultLocIdPeerParent:
|
||||
fprintf(irp->f, "peer_parent");
|
||||
return;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static void ir_print_call_src(IrPrint *irp, IrInstructionCallSrc *call_instruction) {
|
||||
if (call_instruction->is_async) {
|
||||
fprintf(irp->f, "async");
|
||||
if (call_instruction->async_allocator != nullptr) {
|
||||
@ -224,7 +278,35 @@ static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {
|
||||
fprintf(irp->f, ", ");
|
||||
ir_print_other_instruction(irp, arg);
|
||||
}
|
||||
fprintf(irp->f, ")");
|
||||
fprintf(irp->f, ")result=");
|
||||
ir_print_result_loc(irp, call_instruction->result_loc);
|
||||
}
|
||||
|
||||
static void ir_print_call_gen(IrPrint *irp, IrInstructionCallGen *call_instruction) {
|
||||
if (call_instruction->is_async) {
|
||||
fprintf(irp->f, "async");
|
||||
if (call_instruction->async_allocator != nullptr) {
|
||||
fprintf(irp->f, "<");
|
||||
ir_print_other_instruction(irp, call_instruction->async_allocator);
|
||||
fprintf(irp->f, ">");
|
||||
}
|
||||
fprintf(irp->f, " ");
|
||||
}
|
||||
if (call_instruction->fn_entry) {
|
||||
fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name));
|
||||
} else {
|
||||
assert(call_instruction->fn_ref);
|
||||
ir_print_other_instruction(irp, call_instruction->fn_ref);
|
||||
}
|
||||
fprintf(irp->f, "(");
|
||||
for (size_t i = 0; i < call_instruction->arg_count; i += 1) {
|
||||
IrInstruction *arg = call_instruction->args[i];
|
||||
if (i != 0)
|
||||
fprintf(irp->f, ", ");
|
||||
ir_print_other_instruction(irp, arg);
|
||||
}
|
||||
fprintf(irp->f, ")result=");
|
||||
ir_print_other_instruction(irp, call_instruction->result_loc);
|
||||
}
|
||||
|
||||
static void ir_print_cond_br(IrPrint *irp, IrInstructionCondBr *cond_br_instruction) {
|
||||
@ -270,10 +352,10 @@ static void ir_print_container_init_list(IrPrint *irp, IrInstructionContainerIni
|
||||
fprintf(irp->f, "...(%" ZIG_PRI_usize " items)...", instruction->item_count);
|
||||
} else {
|
||||
for (size_t i = 0; i < instruction->item_count; i += 1) {
|
||||
IrInstruction *item = instruction->items[i];
|
||||
IrInstruction *result_loc = instruction->elem_result_loc_list[i];
|
||||
if (i != 0)
|
||||
fprintf(irp->f, ", ");
|
||||
ir_print_other_instruction(irp, item);
|
||||
ir_print_other_instruction(irp, result_loc);
|
||||
}
|
||||
}
|
||||
fprintf(irp->f, "}");
|
||||
@ -286,32 +368,11 @@ static void ir_print_container_init_fields(IrPrint *irp, IrInstructionContainerI
|
||||
IrInstructionContainerInitFieldsField *field = &instruction->fields[i];
|
||||
const char *comma = (i == 0) ? "" : ", ";
|
||||
fprintf(irp->f, "%s.%s = ", comma, buf_ptr(field->name));
|
||||
ir_print_other_instruction(irp, field->value);
|
||||
ir_print_other_instruction(irp, field->result_loc);
|
||||
}
|
||||
fprintf(irp->f, "} // container init");
|
||||
}
|
||||
|
||||
static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruction) {
|
||||
fprintf(irp->f, "%s {", buf_ptr(&instruction->struct_type->name));
|
||||
for (size_t i = 0; i < instruction->field_count; i += 1) {
|
||||
IrInstructionStructInitField *field = &instruction->fields[i];
|
||||
Buf *field_name = field->type_struct_field->name;
|
||||
const char *comma = (i == 0) ? "" : ", ";
|
||||
fprintf(irp->f, "%s.%s = ", comma, buf_ptr(field_name));
|
||||
ir_print_other_instruction(irp, field->value);
|
||||
}
|
||||
fprintf(irp->f, "} // struct init");
|
||||
}
|
||||
|
||||
static void ir_print_union_init(IrPrint *irp, IrInstructionUnionInit *instruction) {
|
||||
Buf *field_name = instruction->field->enum_field->name;
|
||||
|
||||
fprintf(irp->f, "%s {", buf_ptr(&instruction->union_type->name));
|
||||
fprintf(irp->f, ".%s = ", buf_ptr(field_name));
|
||||
ir_print_other_instruction(irp, instruction->init_value);
|
||||
fprintf(irp->f, "} // union init");
|
||||
}
|
||||
|
||||
static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) {
|
||||
fprintf(irp->f, "unreachable");
|
||||
}
|
||||
@ -331,14 +392,20 @@ static void ir_print_var_ptr(IrPrint *irp, IrInstructionVarPtr *instruction) {
|
||||
fprintf(irp->f, "&%s", buf_ptr(&instruction->var->name));
|
||||
}
|
||||
|
||||
static void ir_print_return_ptr(IrPrint *irp, IrInstructionReturnPtr *instruction) {
|
||||
fprintf(irp->f, "@ReturnPtr");
|
||||
}
|
||||
|
||||
static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) {
|
||||
ir_print_other_instruction(irp, instruction->ptr);
|
||||
fprintf(irp->f, ".*");
|
||||
}
|
||||
|
||||
static void ir_print_load_ptr_gen(IrPrint *irp, IrInstructionLoadPtrGen *instruction) {
|
||||
fprintf(irp->f, "loadptr(");
|
||||
ir_print_other_instruction(irp, instruction->ptr);
|
||||
fprintf(irp->f, ".*");
|
||||
fprintf(irp->f, ")result=");
|
||||
ir_print_other_instruction(irp, instruction->result_loc);
|
||||
}
|
||||
|
||||
static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) {
|
||||
@ -354,18 +421,6 @@ static void ir_print_typeof(IrPrint *irp, IrInstructionTypeOf *instruction) {
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_to_ptr_type(IrPrint *irp, IrInstructionToPtrType *instruction) {
|
||||
fprintf(irp->f, "@toPtrType(");
|
||||
ir_print_other_instruction(irp, instruction->ptr);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_ptr_type_child(IrPrint *irp, IrInstructionPtrTypeChild *instruction) {
|
||||
fprintf(irp->f, "@ptrTypeChild(");
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_field_ptr(IrPrint *irp, IrInstructionFieldPtr *instruction) {
|
||||
if (instruction->field_name_buffer) {
|
||||
fprintf(irp->f, "fieldptr ");
|
||||
@ -618,6 +673,13 @@ static void ir_print_ref(IrPrint *irp, IrInstructionRef *instruction) {
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
}
|
||||
|
||||
static void ir_print_ref_gen(IrPrint *irp, IrInstructionRefGen *instruction) {
|
||||
fprintf(irp->f, "@ref(");
|
||||
ir_print_other_instruction(irp, instruction->operand);
|
||||
fprintf(irp->f, ")result=");
|
||||
ir_print_other_instruction(irp, instruction->result_loc);
|
||||
}
|
||||
|
||||
static void ir_print_compile_err(IrPrint *irp, IrInstructionCompileErr *instruction) {
|
||||
fprintf(irp->f, "@compileError(");
|
||||
ir_print_other_instruction(irp, instruction->msg);
|
||||
@ -682,7 +744,8 @@ static void ir_print_cmpxchg_src(IrPrint *irp, IrInstructionCmpxchgSrc *instruct
|
||||
ir_print_other_instruction(irp, instruction->success_order_value);
|
||||
fprintf(irp->f, ", ");
|
||||
ir_print_other_instruction(irp, instruction->failure_order_value);
|
||||
fprintf(irp->f, ")");
|
||||
fprintf(irp->f, ")result=");
|
||||
ir_print_result_loc(irp, instruction->result_loc);
|
||||
}
|
||||
|
||||
static void ir_print_cmpxchg_gen(IrPrint *irp, IrInstructionCmpxchgGen *instruction) {
|
||||
@ -692,7 +755,8 @@ static void ir_print_cmpxchg_gen(IrPrint *irp, IrInstructionCmpxchgGen *instruct
|
||||
ir_print_other_instruction(irp, instruction->cmp_value);
|
||||
fprintf(irp->f, ", ");
|
||||
ir_print_other_instruction(irp, instruction->new_value);
|
||||
fprintf(irp->f, ", TODO print atomic orders)");
|
||||
fprintf(irp->f, ", TODO print atomic orders)result=");
|
||||
ir_print_other_instruction(irp, instruction->result_loc);
|
||||
}
|
||||
|
||||
static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) {
|
||||
@ -810,14 +874,26 @@ static void ir_print_memcpy(IrPrint *irp, IrInstructionMemcpy *instruction) {
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_slice(IrPrint *irp, IrInstructionSlice *instruction) {
|
||||
static void ir_print_slice_src(IrPrint *irp, IrInstructionSliceSrc *instruction) {
|
||||
ir_print_other_instruction(irp, instruction->ptr);
|
||||
fprintf(irp->f, "[");
|
||||
ir_print_other_instruction(irp, instruction->start);
|
||||
fprintf(irp->f, "..");
|
||||
if (instruction->end)
|
||||
ir_print_other_instruction(irp, instruction->end);
|
||||
fprintf(irp->f, "]");
|
||||
fprintf(irp->f, "]result=");
|
||||
ir_print_result_loc(irp, instruction->result_loc);
|
||||
}
|
||||
|
||||
static void ir_print_slice_gen(IrPrint *irp, IrInstructionSliceGen *instruction) {
|
||||
ir_print_other_instruction(irp, instruction->ptr);
|
||||
fprintf(irp->f, "[");
|
||||
ir_print_other_instruction(irp, instruction->start);
|
||||
fprintf(irp->f, "..");
|
||||
if (instruction->end)
|
||||
ir_print_other_instruction(irp, instruction->end);
|
||||
fprintf(irp->f, "]result=");
|
||||
ir_print_other_instruction(irp, instruction->result_loc);
|
||||
}
|
||||
|
||||
static void ir_print_member_count(IrPrint *irp, IrInstructionMemberCount *instruction) {
|
||||
@ -889,43 +965,49 @@ static void ir_print_overflow_op(IrPrint *irp, IrInstructionOverflowOp *instruct
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_test_err(IrPrint *irp, IrInstructionTestErr *instruction) {
|
||||
static void ir_print_test_err_src(IrPrint *irp, IrInstructionTestErrSrc *instruction) {
|
||||
fprintf(irp->f, "@testError(");
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
ir_print_other_instruction(irp, instruction->base_ptr);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_test_err_gen(IrPrint *irp, IrInstructionTestErrGen *instruction) {
|
||||
fprintf(irp->f, "@testError(");
|
||||
ir_print_other_instruction(irp, instruction->err_union);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_unwrap_err_code(IrPrint *irp, IrInstructionUnwrapErrCode *instruction) {
|
||||
fprintf(irp->f, "UnwrapErrorCode(");
|
||||
ir_print_other_instruction(irp, instruction->err_union);
|
||||
ir_print_other_instruction(irp, instruction->err_union_ptr);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayload *instruction) {
|
||||
fprintf(irp->f, "ErrorUnionFieldPayload(");
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
fprintf(irp->f, ")");
|
||||
if (!instruction->safety_check_on) {
|
||||
fprintf(irp->f, " // no safety");
|
||||
}
|
||||
fprintf(irp->f, ")safety=%d,init=%d",instruction->safety_check_on, instruction->initializing);
|
||||
}
|
||||
|
||||
static void ir_print_maybe_wrap(IrPrint *irp, IrInstructionOptionalWrap *instruction) {
|
||||
fprintf(irp->f, "@maybeWrap(");
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
fprintf(irp->f, ")");
|
||||
static void ir_print_optional_wrap(IrPrint *irp, IrInstructionOptionalWrap *instruction) {
|
||||
fprintf(irp->f, "@optionalWrap(");
|
||||
ir_print_other_instruction(irp, instruction->operand);
|
||||
fprintf(irp->f, ")result=");
|
||||
ir_print_other_instruction(irp, instruction->result_loc);
|
||||
}
|
||||
|
||||
static void ir_print_err_wrap_code(IrPrint *irp, IrInstructionErrWrapCode *instruction) {
|
||||
fprintf(irp->f, "@errWrapCode(");
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
fprintf(irp->f, ")");
|
||||
ir_print_other_instruction(irp, instruction->operand);
|
||||
fprintf(irp->f, ")result=");
|
||||
ir_print_other_instruction(irp, instruction->result_loc);
|
||||
}
|
||||
|
||||
static void ir_print_err_wrap_payload(IrPrint *irp, IrInstructionErrWrapPayload *instruction) {
|
||||
fprintf(irp->f, "@errWrapPayload(");
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
fprintf(irp->f, ")");
|
||||
ir_print_other_instruction(irp, instruction->operand);
|
||||
fprintf(irp->f, ")result=");
|
||||
ir_print_other_instruction(irp, instruction->result_loc);
|
||||
}
|
||||
|
||||
static void ir_print_fn_proto(IrPrint *irp, IrInstructionFnProto *instruction) {
|
||||
@ -971,12 +1053,11 @@ static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruc
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) {
|
||||
static void ir_print_bit_cast_src(IrPrint *irp, IrInstructionBitCastSrc *instruction) {
|
||||
fprintf(irp->f, "@bitCast(");
|
||||
ir_print_other_instruction(irp, instruction->dest_type);
|
||||
fprintf(irp->f, ",");
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
fprintf(irp->f, ")");
|
||||
ir_print_other_instruction(irp, instruction->operand);
|
||||
fprintf(irp->f, ")result=");
|
||||
ir_print_result_loc(irp, &instruction->result_loc_bit_cast->base);
|
||||
}
|
||||
|
||||
static void ir_print_bit_cast_gen(IrPrint *irp, IrInstructionBitCastGen *instruction) {
|
||||
@ -1043,7 +1124,15 @@ static void ir_print_array_to_vector(IrPrint *irp, IrInstructionArrayToVector *i
|
||||
static void ir_print_vector_to_array(IrPrint *irp, IrInstructionVectorToArray *instruction) {
|
||||
fprintf(irp->f, "VectorToArray(");
|
||||
ir_print_other_instruction(irp, instruction->vector);
|
||||
fprintf(irp->f, ")");
|
||||
fprintf(irp->f, ")result=");
|
||||
ir_print_other_instruction(irp, instruction->result_loc);
|
||||
}
|
||||
|
||||
static void ir_print_ptr_of_array_to_slice(IrPrint *irp, IrInstructionPtrOfArrayToSlice *instruction) {
|
||||
fprintf(irp->f, "PtrOfArrayToSlice(");
|
||||
ir_print_other_instruction(irp, instruction->operand);
|
||||
fprintf(irp->f, ")result=");
|
||||
ir_print_other_instruction(irp, instruction->result_loc);
|
||||
}
|
||||
|
||||
static void ir_print_assert_zero(IrPrint *irp, IrInstructionAssertZero *instruction) {
|
||||
@ -1061,6 +1150,25 @@ static void ir_print_assert_non_null(IrPrint *irp, IrInstructionAssertNonNull *i
|
||||
static void ir_print_resize_slice(IrPrint *irp, IrInstructionResizeSlice *instruction) {
|
||||
fprintf(irp->f, "@resizeSlice(");
|
||||
ir_print_other_instruction(irp, instruction->operand);
|
||||
fprintf(irp->f, ")result=");
|
||||
ir_print_other_instruction(irp, instruction->result_loc);
|
||||
}
|
||||
|
||||
static void ir_print_alloca_src(IrPrint *irp, IrInstructionAllocaSrc *instruction) {
|
||||
fprintf(irp->f, "Alloca(align=");
|
||||
ir_print_other_instruction(irp, instruction->align);
|
||||
fprintf(irp->f, ",name=%s)", instruction->name_hint);
|
||||
}
|
||||
|
||||
static void ir_print_alloca_gen(IrPrint *irp, IrInstructionAllocaGen *instruction) {
|
||||
fprintf(irp->f, "Alloca(align=%" PRIu32 ",name=%s)", instruction->align, instruction->name_hint);
|
||||
}
|
||||
|
||||
static void ir_print_end_expr(IrPrint *irp, IrInstructionEndExpr *instruction) {
|
||||
fprintf(irp->f, "EndExpr(result=");
|
||||
ir_print_result_loc(irp, instruction->result_loc);
|
||||
fprintf(irp->f, ",value=");
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
@ -1186,6 +1294,34 @@ static void ir_print_align_cast(IrPrint *irp, IrInstructionAlignCast *instructio
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_implicit_cast(IrPrint *irp, IrInstructionImplicitCast *instruction) {
|
||||
fprintf(irp->f, "@implicitCast(");
|
||||
ir_print_other_instruction(irp, instruction->dest_type);
|
||||
fprintf(irp->f, ",");
|
||||
ir_print_other_instruction(irp, instruction->target);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_resolve_result(IrPrint *irp, IrInstructionResolveResult *instruction) {
|
||||
fprintf(irp->f, "ResolveResult(");
|
||||
ir_print_result_loc(irp, instruction->result_loc);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_reset_result(IrPrint *irp, IrInstructionResetResult *instruction) {
|
||||
fprintf(irp->f, "ResetResult(");
|
||||
ir_print_result_loc(irp, instruction->result_loc);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_result_ptr(IrPrint *irp, IrInstructionResultPtr *instruction) {
|
||||
fprintf(irp->f, "ResultPtr(");
|
||||
ir_print_result_loc(irp, instruction->result_loc);
|
||||
fprintf(irp->f, ",");
|
||||
ir_print_other_instruction(irp, instruction->result);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruction) {
|
||||
fprintf(irp->f, "@OpaqueType()");
|
||||
}
|
||||
@ -1427,15 +1563,32 @@ static void ir_print_mark_err_ret_trace_ptr(IrPrint *irp, IrInstructionMarkErrRe
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) {
|
||||
fprintf(irp->f, "@sqrt(");
|
||||
static void ir_print_float_op(IrPrint *irp, IrInstructionFloatOp *instruction) {
|
||||
|
||||
fprintf(irp->f, "@%s(", float_op_to_name(instruction->op, false));
|
||||
if (instruction->type != nullptr) {
|
||||
ir_print_other_instruction(irp, instruction->type);
|
||||
} else {
|
||||
fprintf(irp->f, "null");
|
||||
}
|
||||
fprintf(irp->f, ",");
|
||||
ir_print_other_instruction(irp, instruction->op);
|
||||
ir_print_other_instruction(irp, instruction->op1);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_mul_add(IrPrint *irp, IrInstructionMulAdd *instruction) {
|
||||
fprintf(irp->f, "@mulAdd(");
|
||||
if (instruction->type_value != nullptr) {
|
||||
ir_print_other_instruction(irp, instruction->type_value);
|
||||
} else {
|
||||
fprintf(irp->f, "null");
|
||||
}
|
||||
fprintf(irp->f, ",");
|
||||
ir_print_other_instruction(irp, instruction->op1);
|
||||
fprintf(irp->f, ",");
|
||||
ir_print_other_instruction(irp, instruction->op2);
|
||||
fprintf(irp->f, ",");
|
||||
ir_print_other_instruction(irp, instruction->op3);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
@ -1446,7 +1599,7 @@ static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *decl_va
|
||||
fprintf(irp->f, "%s %s: %s align(%u) = ", var_or_const, name, buf_ptr(&var->var_type->name),
|
||||
var->align_bytes);
|
||||
|
||||
ir_print_other_instruction(irp, decl_var_instruction->init_value);
|
||||
ir_print_other_instruction(irp, decl_var_instruction->var_ptr);
|
||||
if (decl_var_instruction->var->is_comptime != nullptr) {
|
||||
fprintf(irp->f, " // comptime = ");
|
||||
ir_print_other_instruction(irp, decl_var_instruction->var->is_comptime);
|
||||
@ -1485,8 +1638,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdCast:
|
||||
ir_print_cast(irp, (IrInstructionCast *)instruction);
|
||||
break;
|
||||
case IrInstructionIdCall:
|
||||
ir_print_call(irp, (IrInstructionCall *)instruction);
|
||||
case IrInstructionIdCallSrc:
|
||||
ir_print_call_src(irp, (IrInstructionCallSrc *)instruction);
|
||||
break;
|
||||
case IrInstructionIdCallGen:
|
||||
ir_print_call_gen(irp, (IrInstructionCallGen *)instruction);
|
||||
break;
|
||||
case IrInstructionIdUnOp:
|
||||
ir_print_un_op(irp, (IrInstructionUnOp *)instruction);
|
||||
@ -1506,12 +1662,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdContainerInitFields:
|
||||
ir_print_container_init_fields(irp, (IrInstructionContainerInitFields *)instruction);
|
||||
break;
|
||||
case IrInstructionIdStructInit:
|
||||
ir_print_struct_init(irp, (IrInstructionStructInit *)instruction);
|
||||
break;
|
||||
case IrInstructionIdUnionInit:
|
||||
ir_print_union_init(irp, (IrInstructionUnionInit *)instruction);
|
||||
break;
|
||||
case IrInstructionIdUnreachable:
|
||||
ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction);
|
||||
break;
|
||||
@ -1521,6 +1671,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdVarPtr:
|
||||
ir_print_var_ptr(irp, (IrInstructionVarPtr *)instruction);
|
||||
break;
|
||||
case IrInstructionIdReturnPtr:
|
||||
ir_print_return_ptr(irp, (IrInstructionReturnPtr *)instruction);
|
||||
break;
|
||||
case IrInstructionIdLoadPtr:
|
||||
ir_print_load_ptr(irp, (IrInstructionLoadPtr *)instruction);
|
||||
break;
|
||||
@ -1533,12 +1686,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdTypeOf:
|
||||
ir_print_typeof(irp, (IrInstructionTypeOf *)instruction);
|
||||
break;
|
||||
case IrInstructionIdToPtrType:
|
||||
ir_print_to_ptr_type(irp, (IrInstructionToPtrType *)instruction);
|
||||
break;
|
||||
case IrInstructionIdPtrTypeChild:
|
||||
ir_print_ptr_type_child(irp, (IrInstructionPtrTypeChild *)instruction);
|
||||
break;
|
||||
case IrInstructionIdFieldPtr:
|
||||
ir_print_field_ptr(irp, (IrInstructionFieldPtr *)instruction);
|
||||
break;
|
||||
@ -1617,6 +1764,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdRef:
|
||||
ir_print_ref(irp, (IrInstructionRef *)instruction);
|
||||
break;
|
||||
case IrInstructionIdRefGen:
|
||||
ir_print_ref_gen(irp, (IrInstructionRefGen *)instruction);
|
||||
break;
|
||||
case IrInstructionIdCompileErr:
|
||||
ir_print_compile_err(irp, (IrInstructionCompileErr *)instruction);
|
||||
break;
|
||||
@ -1692,8 +1842,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdMemcpy:
|
||||
ir_print_memcpy(irp, (IrInstructionMemcpy *)instruction);
|
||||
break;
|
||||
case IrInstructionIdSlice:
|
||||
ir_print_slice(irp, (IrInstructionSlice *)instruction);
|
||||
case IrInstructionIdSliceSrc:
|
||||
ir_print_slice_src(irp, (IrInstructionSliceSrc *)instruction);
|
||||
break;
|
||||
case IrInstructionIdSliceGen:
|
||||
ir_print_slice_gen(irp, (IrInstructionSliceGen *)instruction);
|
||||
break;
|
||||
case IrInstructionIdMemberCount:
|
||||
ir_print_member_count(irp, (IrInstructionMemberCount *)instruction);
|
||||
@ -1722,8 +1875,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdOverflowOp:
|
||||
ir_print_overflow_op(irp, (IrInstructionOverflowOp *)instruction);
|
||||
break;
|
||||
case IrInstructionIdTestErr:
|
||||
ir_print_test_err(irp, (IrInstructionTestErr *)instruction);
|
||||
case IrInstructionIdTestErrSrc:
|
||||
ir_print_test_err_src(irp, (IrInstructionTestErrSrc *)instruction);
|
||||
break;
|
||||
case IrInstructionIdTestErrGen:
|
||||
ir_print_test_err_gen(irp, (IrInstructionTestErrGen *)instruction);
|
||||
break;
|
||||
case IrInstructionIdUnwrapErrCode:
|
||||
ir_print_unwrap_err_code(irp, (IrInstructionUnwrapErrCode *)instruction);
|
||||
@ -1732,7 +1888,7 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
ir_print_unwrap_err_payload(irp, (IrInstructionUnwrapErrPayload *)instruction);
|
||||
break;
|
||||
case IrInstructionIdOptionalWrap:
|
||||
ir_print_maybe_wrap(irp, (IrInstructionOptionalWrap *)instruction);
|
||||
ir_print_optional_wrap(irp, (IrInstructionOptionalWrap *)instruction);
|
||||
break;
|
||||
case IrInstructionIdErrWrapCode:
|
||||
ir_print_err_wrap_code(irp, (IrInstructionErrWrapCode *)instruction);
|
||||
@ -1752,8 +1908,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdPtrCastGen:
|
||||
ir_print_ptr_cast_gen(irp, (IrInstructionPtrCastGen *)instruction);
|
||||
break;
|
||||
case IrInstructionIdBitCast:
|
||||
ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction);
|
||||
case IrInstructionIdBitCastSrc:
|
||||
ir_print_bit_cast_src(irp, (IrInstructionBitCastSrc *)instruction);
|
||||
break;
|
||||
case IrInstructionIdBitCastGen:
|
||||
ir_print_bit_cast_gen(irp, (IrInstructionBitCastGen *)instruction);
|
||||
@ -1818,6 +1974,18 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdAlignCast:
|
||||
ir_print_align_cast(irp, (IrInstructionAlignCast *)instruction);
|
||||
break;
|
||||
case IrInstructionIdImplicitCast:
|
||||
ir_print_implicit_cast(irp, (IrInstructionImplicitCast *)instruction);
|
||||
break;
|
||||
case IrInstructionIdResolveResult:
|
||||
ir_print_resolve_result(irp, (IrInstructionResolveResult *)instruction);
|
||||
break;
|
||||
case IrInstructionIdResetResult:
|
||||
ir_print_reset_result(irp, (IrInstructionResetResult *)instruction);
|
||||
break;
|
||||
case IrInstructionIdResultPtr:
|
||||
ir_print_result_ptr(irp, (IrInstructionResultPtr *)instruction);
|
||||
break;
|
||||
case IrInstructionIdOpaqueType:
|
||||
ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction);
|
||||
break;
|
||||
@ -1902,8 +2070,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdMarkErrRetTracePtr:
|
||||
ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction);
|
||||
break;
|
||||
case IrInstructionIdSqrt:
|
||||
ir_print_sqrt(irp, (IrInstructionSqrt *)instruction);
|
||||
case IrInstructionIdFloatOp:
|
||||
ir_print_float_op(irp, (IrInstructionFloatOp *)instruction);
|
||||
break;
|
||||
case IrInstructionIdMulAdd:
|
||||
ir_print_mul_add(irp, (IrInstructionMulAdd *)instruction);
|
||||
break;
|
||||
case IrInstructionIdAtomicLoad:
|
||||
ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction);
|
||||
@ -1923,6 +2094,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdVectorToArray:
|
||||
ir_print_vector_to_array(irp, (IrInstructionVectorToArray *)instruction);
|
||||
break;
|
||||
case IrInstructionIdPtrOfArrayToSlice:
|
||||
ir_print_ptr_of_array_to_slice(irp, (IrInstructionPtrOfArrayToSlice *)instruction);
|
||||
break;
|
||||
case IrInstructionIdAssertZero:
|
||||
ir_print_assert_zero(irp, (IrInstructionAssertZero *)instruction);
|
||||
break;
|
||||
@ -1938,6 +2112,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdUndeclaredIdent:
|
||||
ir_print_undeclared_ident(irp, (IrInstructionUndeclaredIdent *)instruction);
|
||||
break;
|
||||
case IrInstructionIdAllocaSrc:
|
||||
ir_print_alloca_src(irp, (IrInstructionAllocaSrc *)instruction);
|
||||
break;
|
||||
case IrInstructionIdAllocaGen:
|
||||
ir_print_alloca_gen(irp, (IrInstructionAllocaGen *)instruction);
|
||||
break;
|
||||
case IrInstructionIdEndExpr:
|
||||
ir_print_end_expr(irp, (IrInstructionEndExpr *)instruction);
|
||||
break;
|
||||
}
|
||||
fprintf(irp->f, "\n");
|
||||
}
|
||||
|
||||
16
src/main.cpp
16
src/main.cpp
@ -913,8 +913,20 @@ int main(int argc, char **argv) {
|
||||
get_native_target(&target);
|
||||
} else {
|
||||
if ((err = target_parse_triple(&target, target_string))) {
|
||||
fprintf(stderr, "invalid target: %s\n", err_str(err));
|
||||
return print_error_usage(arg0);
|
||||
if (err == ErrorUnknownArchitecture && target.arch != ZigLLVM_UnknownArch) {
|
||||
fprintf(stderr, "'%s' requires a sub-architecture. Try one of these:\n",
|
||||
target_arch_name(target.arch));
|
||||
SubArchList sub_arch_list = target_subarch_list(target.arch);
|
||||
size_t subarch_count = target_subarch_count(sub_arch_list);
|
||||
for (size_t sub_i = 0; sub_i < subarch_count; sub_i += 1) {
|
||||
ZigLLVM_SubArchType sub = target_subarch_enum(sub_arch_list, sub_i);
|
||||
fprintf(stderr, " %s%s\n", target_arch_name(target.arch), target_subarch_name(sub));
|
||||
}
|
||||
return print_error_usage(arg0);
|
||||
} else {
|
||||
fprintf(stderr, "invalid target: %s\n", err_str(err));
|
||||
return print_error_usage(arg0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -344,7 +344,7 @@ static AstNode *ast_parse_bin_op_expr(
|
||||
op->data.bin_op_expr.op1 = left;
|
||||
op->data.bin_op_expr.op2 = right;
|
||||
break;
|
||||
case NodeTypeUnwrapErrorExpr:
|
||||
case NodeTypeCatchExpr:
|
||||
op->data.unwrap_err_expr.op1 = left;
|
||||
op->data.unwrap_err_expr.op2 = right;
|
||||
break;
|
||||
@ -2404,7 +2404,7 @@ static AstNode *ast_parse_bitwise_op(ParseContext *pc) {
|
||||
Token *catch_token = eat_token_if(pc, TokenIdKeywordCatch);
|
||||
if (catch_token != nullptr) {
|
||||
Token *payload = ast_parse_payload(pc);
|
||||
AstNode *res = ast_create_node(pc, NodeTypeUnwrapErrorExpr, catch_token);
|
||||
AstNode *res = ast_create_node(pc, NodeTypeCatchExpr, catch_token);
|
||||
if (payload != nullptr)
|
||||
res->data.unwrap_err_expr.symbol = token_symbol(pc, payload);
|
||||
|
||||
@ -2897,7 +2897,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
|
||||
visit_field(&node->data.bin_op_expr.op1, visit, context);
|
||||
visit_field(&node->data.bin_op_expr.op2, visit, context);
|
||||
break;
|
||||
case NodeTypeUnwrapErrorExpr:
|
||||
case NodeTypeCatchExpr:
|
||||
visit_field(&node->data.unwrap_err_expr.op1, visit, context);
|
||||
visit_field(&node->data.unwrap_err_expr.symbol, visit, context);
|
||||
visit_field(&node->data.unwrap_err_expr.op2, visit, context);
|
||||
|
||||
@ -486,17 +486,17 @@ void get_native_target(ZigTarget *target) {
|
||||
Error target_parse_archsub(ZigLLVM_ArchType *out_arch, ZigLLVM_SubArchType *out_sub,
|
||||
const char *archsub_ptr, size_t archsub_len)
|
||||
{
|
||||
*out_arch = ZigLLVM_UnknownArch;
|
||||
*out_sub = ZigLLVM_NoSubArch;
|
||||
for (size_t arch_i = 0; arch_i < array_length(arch_list); arch_i += 1) {
|
||||
ZigLLVM_ArchType arch = arch_list[arch_i];
|
||||
SubArchList sub_arch_list = target_subarch_list(arch);
|
||||
size_t subarch_count = target_subarch_count(sub_arch_list);
|
||||
if (subarch_count == 0) {
|
||||
if (mem_eql_str(archsub_ptr, archsub_len, target_arch_name(arch))) {
|
||||
*out_arch = arch;
|
||||
*out_sub = ZigLLVM_NoSubArch;
|
||||
if (mem_eql_str(archsub_ptr, archsub_len, target_arch_name(arch))) {
|
||||
*out_arch = arch;
|
||||
if (subarch_count == 0) {
|
||||
return ErrorNone;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
for (size_t sub_i = 0; sub_i < subarch_count; sub_i += 1) {
|
||||
ZigLLVM_SubArchType sub = target_subarch_enum(sub_arch_list, sub_i);
|
||||
|
||||
@ -1290,10 +1290,9 @@ pub fn Watch(comptime V: type) type {
|
||||
error.FileDescriptorAlreadyPresentInSet => unreachable,
|
||||
error.OperationCausesCircularLoop => unreachable,
|
||||
error.FileDescriptorNotRegistered => unreachable,
|
||||
error.SystemResources => error.SystemResources,
|
||||
error.UserResourceLimitReached => error.UserResourceLimitReached,
|
||||
error.FileDescriptorIncompatibleWithEpoll => unreachable,
|
||||
error.Unexpected => unreachable,
|
||||
else => |e| e,
|
||||
};
|
||||
await (async channel.put(transformed_err) catch unreachable);
|
||||
};
|
||||
|
||||
@ -123,7 +123,8 @@ pub const Lock = struct {
|
||||
};
|
||||
|
||||
test "std.event.Lock" {
|
||||
// https://github.com/ziglang/zig/issues/1908
|
||||
// TODO https://github.com/ziglang/zig/issues/2377
|
||||
if (true) return error.SkipZigTest;
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
|
||||
const allocator = std.heap.direct_allocator;
|
||||
|
||||
@ -263,8 +263,8 @@ pub async fn connect(loop: *Loop, _address: *const std.net.Address) !File {
|
||||
}
|
||||
|
||||
test "listen on a port, send bytes, receive bytes" {
|
||||
// https://github.com/ziglang/zig/issues/1908
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
// https://github.com/ziglang/zig/issues/2377
|
||||
if (true) return error.SkipZigTest;
|
||||
|
||||
if (builtin.os != builtin.Os.linux) {
|
||||
// TODO build abstractions for other operating systems
|
||||
|
||||
@ -212,8 +212,8 @@ pub const RwLock = struct {
|
||||
};
|
||||
|
||||
test "std.event.RwLock" {
|
||||
// https://github.com/ziglang/zig/issues/1908
|
||||
if (builtin.single_threaded or builtin.os != builtin.Os.linux) return error.SkipZigTest;
|
||||
// https://github.com/ziglang/zig/issues/2377
|
||||
if (true) return error.SkipZigTest;
|
||||
|
||||
const allocator = std.heap.direct_allocator;
|
||||
|
||||
|
||||
752
std/fmt.zig
752
std/fmt.zig
File diff suppressed because it is too large
Load Diff
@ -8,6 +8,8 @@ const builtin = @import("builtin");
|
||||
const c = std.c;
|
||||
const maxInt = std.math.maxInt;
|
||||
|
||||
pub const LoggingAllocator = @import("heap/logging_allocator.zig").LoggingAllocator;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
pub const c_allocator = &c_allocator_state;
|
||||
@ -360,9 +362,9 @@ pub const ArenaAllocator = struct {
|
||||
var it = self.buffer_list.first;
|
||||
while (it) |node| {
|
||||
// this has to occur before the free because the free frees node
|
||||
it = node.next;
|
||||
|
||||
const next_it = node.next;
|
||||
self.child_allocator.free(node.data);
|
||||
it = next_it;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
53
std/heap/logging_allocator.zig
Normal file
53
std/heap/logging_allocator.zig
Normal file
@ -0,0 +1,53 @@
|
||||
const std = @import("../std.zig");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const AnyErrorOutStream = std.io.OutStream(anyerror);
|
||||
|
||||
/// This allocator is used in front of another allocator and logs to the provided stream
|
||||
/// on every call to the allocator. Stream errors are ignored.
|
||||
/// If https://github.com/ziglang/zig/issues/2586 is implemented, this API can be improved.
|
||||
pub const LoggingAllocator = struct {
|
||||
allocator: Allocator,
|
||||
parent_allocator: *Allocator,
|
||||
out_stream: *AnyErrorOutStream,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn init(parent_allocator: *Allocator, out_stream: *AnyErrorOutStream) Self {
|
||||
return Self{
|
||||
.allocator = Allocator{
|
||||
.reallocFn = realloc,
|
||||
.shrinkFn = shrink,
|
||||
},
|
||||
.parent_allocator = parent_allocator,
|
||||
.out_stream = out_stream,
|
||||
};
|
||||
}
|
||||
|
||||
fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {
|
||||
const self = @fieldParentPtr(Self, "allocator", allocator);
|
||||
if (old_mem.len == 0) {
|
||||
self.out_stream.print("allocation of {} ", new_size) catch {};
|
||||
} else {
|
||||
self.out_stream.print("resize from {} to {} ", old_mem.len, new_size) catch {};
|
||||
}
|
||||
const result = self.parent_allocator.reallocFn(self.parent_allocator, old_mem, old_align, new_size, new_align);
|
||||
if (result) |buff| {
|
||||
self.out_stream.print("success!\n") catch {};
|
||||
} else |err| {
|
||||
self.out_stream.print("failure!\n") catch {};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {
|
||||
const self = @fieldParentPtr(Self, "allocator", allocator);
|
||||
const result = self.parent_allocator.shrinkFn(self.parent_allocator, old_mem, old_align, new_size, new_align);
|
||||
if (new_size == 0) {
|
||||
self.out_stream.print("free of {} bytes success!\n", old_mem.len) catch {};
|
||||
} else {
|
||||
self.out_stream.print("shrink from {} bytes to {} bytes success!\n", old_mem.len, new_size) catch {};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
5
std/http.zig
Normal file
5
std/http.zig
Normal file
@ -0,0 +1,5 @@
|
||||
test "std.http" {
|
||||
_ = @import("http/headers.zig");
|
||||
}
|
||||
|
||||
pub const Headers = @import("http/headers.zig").Headers;
|
||||
614
std/http/headers.zig
Normal file
614
std/http/headers.zig
Normal file
@ -0,0 +1,614 @@
|
||||
// HTTP Header data structure/type
|
||||
// Based on lua-http's http.header module
|
||||
//
|
||||
// Design criteria:
|
||||
// - the same header field is allowed more than once
|
||||
// - must be able to fetch separate occurrences (important for some headers e.g. Set-Cookie)
|
||||
// - optionally available as comma separated list
|
||||
// - http2 adds flag to headers that they should never be indexed
|
||||
// - header order should be recoverable
|
||||
//
|
||||
// Headers are implemented as an array of entries.
|
||||
// An index of field name => array indices is kept.
|
||||
|
||||
const std = @import("../std.zig");
|
||||
const debug = std.debug;
|
||||
const assert = debug.assert;
|
||||
const testing = std.testing;
|
||||
const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
fn never_index_default(name: []const u8) bool {
|
||||
if (mem.eql(u8, "authorization", name)) return true;
|
||||
if (mem.eql(u8, "proxy-authorization", name)) return true;
|
||||
if (mem.eql(u8, "cookie", name)) return true;
|
||||
if (mem.eql(u8, "set-cookie", name)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
const HeaderEntry = struct {
|
||||
allocator: *Allocator,
|
||||
pub name: []const u8,
|
||||
pub value: []u8,
|
||||
pub never_index: bool,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
fn init(allocator: *Allocator, name: []const u8, value: []const u8, never_index: ?bool) !Self {
|
||||
return Self{
|
||||
.allocator = allocator,
|
||||
.name = name, // takes reference
|
||||
.value = try mem.dupe(allocator, u8, value),
|
||||
.never_index = never_index orelse never_index_default(name),
|
||||
};
|
||||
}
|
||||
|
||||
fn deinit(self: Self) void {
|
||||
self.allocator.free(self.value);
|
||||
}
|
||||
|
||||
pub fn modify(self: *Self, value: []const u8, never_index: ?bool) !void {
|
||||
const old_len = self.value.len;
|
||||
if (value.len > old_len) {
|
||||
self.value = try self.allocator.realloc(self.value, value.len);
|
||||
} else if (value.len < old_len) {
|
||||
self.value = self.allocator.shrink(self.value, value.len);
|
||||
}
|
||||
mem.copy(u8, self.value, value);
|
||||
self.never_index = never_index orelse never_index_default(self.name);
|
||||
}
|
||||
|
||||
fn compare(a: HeaderEntry, b: HeaderEntry) bool {
|
||||
if (a.name.ptr != b.name.ptr and a.name.len != b.name.len) {
|
||||
// Things beginning with a colon *must* be before others
|
||||
const a_is_colon = a.name[0] == ':';
|
||||
const b_is_colon = b.name[0] == ':';
|
||||
if (a_is_colon and !b_is_colon) {
|
||||
return true;
|
||||
} else if (!a_is_colon and b_is_colon) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sort lexicographically on header name
|
||||
return mem.compare(u8, a.name, b.name) == mem.Compare.LessThan;
|
||||
}
|
||||
|
||||
// Sort lexicographically on header value
|
||||
if (!mem.eql(u8, a.value, b.value)) {
|
||||
return mem.compare(u8, a.value, b.value) == mem.Compare.LessThan;
|
||||
}
|
||||
|
||||
// Doesn't matter here; need to pick something for sort consistency
|
||||
return a.never_index;
|
||||
}
|
||||
};
|
||||
|
||||
var test_memory: [32 * 1024]u8 = undefined;
|
||||
var test_fba_state = std.heap.FixedBufferAllocator.init(&test_memory);
|
||||
const test_allocator = &test_fba_state.allocator;
|
||||
|
||||
test "HeaderEntry" {
|
||||
var e = try HeaderEntry.init(test_allocator, "foo", "bar", null);
|
||||
defer e.deinit();
|
||||
testing.expectEqualSlices(u8, "foo", e.name);
|
||||
testing.expectEqualSlices(u8, "bar", e.value);
|
||||
testing.expectEqual(false, e.never_index);
|
||||
|
||||
try e.modify("longer value", null);
|
||||
testing.expectEqualSlices(u8, "longer value", e.value);
|
||||
|
||||
// shorter value
|
||||
try e.modify("x", null);
|
||||
testing.expectEqualSlices(u8, "x", e.value);
|
||||
}
|
||||
|
||||
const HeaderList = std.ArrayList(HeaderEntry);
|
||||
const HeaderIndexList = std.ArrayList(usize);
|
||||
const HeaderIndex = std.AutoHashMap([]const u8, HeaderIndexList);
|
||||
|
||||
pub const Headers = struct {
|
||||
// the owned header field name is stored in the index as part of the key
|
||||
allocator: *Allocator,
|
||||
data: HeaderList,
|
||||
index: HeaderIndex,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn init(allocator: *Allocator) Self {
|
||||
return Self{
|
||||
.allocator = allocator,
|
||||
.data = HeaderList.init(allocator),
|
||||
.index = HeaderIndex.init(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: Self) void {
|
||||
{
|
||||
var it = self.index.iterator();
|
||||
while (it.next()) |kv| {
|
||||
var dex = &kv.value;
|
||||
dex.deinit();
|
||||
self.allocator.free(kv.key);
|
||||
}
|
||||
self.index.deinit();
|
||||
}
|
||||
{
|
||||
var it = self.data.iterator();
|
||||
while (it.next()) |entry| {
|
||||
entry.deinit();
|
||||
}
|
||||
self.data.deinit();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clone(self: Self, allocator: *Allocator) !Self {
|
||||
var other = Headers.init(allocator);
|
||||
errdefer other.deinit();
|
||||
try other.data.ensureCapacity(self.data.count());
|
||||
try other.index.initCapacity(self.index.entries.len);
|
||||
var it = self.data.iterator();
|
||||
while (it.next()) |entry| {
|
||||
try other.append(entry.name, entry.value, entry.never_index);
|
||||
}
|
||||
return other;
|
||||
}
|
||||
|
||||
pub fn count(self: Self) usize {
|
||||
return self.data.count();
|
||||
}
|
||||
|
||||
pub const Iterator = HeaderList.Iterator;
|
||||
|
||||
pub fn iterator(self: Self) Iterator {
|
||||
return self.data.iterator();
|
||||
}
|
||||
|
||||
pub fn append(self: *Self, name: []const u8, value: []const u8, never_index: ?bool) !void {
|
||||
const n = self.data.count() + 1;
|
||||
try self.data.ensureCapacity(n);
|
||||
var entry: HeaderEntry = undefined;
|
||||
if (self.index.get(name)) |kv| {
|
||||
entry = try HeaderEntry.init(self.allocator, kv.key, value, never_index);
|
||||
errdefer entry.deinit();
|
||||
var dex = &kv.value;
|
||||
try dex.append(n - 1);
|
||||
} else {
|
||||
const name_dup = try mem.dupe(self.allocator, u8, name);
|
||||
errdefer self.allocator.free(name_dup);
|
||||
entry = try HeaderEntry.init(self.allocator, name_dup, value, never_index);
|
||||
errdefer entry.deinit();
|
||||
var dex = HeaderIndexList.init(self.allocator);
|
||||
try dex.append(n - 1);
|
||||
errdefer dex.deinit();
|
||||
_ = try self.index.put(name, dex);
|
||||
}
|
||||
self.data.appendAssumeCapacity(entry);
|
||||
}
|
||||
|
||||
/// If the header already exists, replace the current value, otherwise append it to the list of headers.
|
||||
/// If the header has multiple entries then returns an error.
|
||||
pub fn upsert(self: *Self, name: []const u8, value: []const u8, never_index: ?bool) !void {
|
||||
if (self.index.get(name)) |kv| {
|
||||
const dex = kv.value;
|
||||
if (dex.count() != 1)
|
||||
return error.CannotUpsertMultiValuedField;
|
||||
var e = &self.data.at(dex.at(0));
|
||||
try e.modify(value, never_index);
|
||||
} else {
|
||||
try self.append(name, value, never_index);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns boolean indicating if the field is present.
|
||||
pub fn contains(self: Self, name: []const u8) bool {
|
||||
return self.index.contains(name);
|
||||
}
|
||||
|
||||
/// Returns boolean indicating if something was deleted.
|
||||
pub fn delete(self: *Self, name: []const u8) bool {
|
||||
if (self.index.remove(name)) |kv| {
|
||||
var dex = &kv.value;
|
||||
// iterate backwards
|
||||
var i = dex.count();
|
||||
while (i > 0) {
|
||||
i -= 1;
|
||||
const data_index = dex.at(i);
|
||||
const removed = self.data.orderedRemove(data_index);
|
||||
assert(mem.eql(u8, removed.name, name));
|
||||
removed.deinit();
|
||||
}
|
||||
dex.deinit();
|
||||
self.allocator.free(kv.key);
|
||||
self.rebuild_index();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the element at the specified index.
|
||||
/// Moves items down to fill the empty space.
|
||||
pub fn orderedRemove(self: *Self, i: usize) void {
|
||||
const removed = self.data.orderedRemove(i);
|
||||
const kv = self.index.get(removed.name).?;
|
||||
var dex = &kv.value;
|
||||
if (dex.count() == 1) {
|
||||
// was last item; delete the index
|
||||
_ = self.index.remove(kv.key);
|
||||
dex.deinit();
|
||||
removed.deinit();
|
||||
self.allocator.free(kv.key);
|
||||
} else {
|
||||
dex.shrink(dex.count() - 1);
|
||||
removed.deinit();
|
||||
}
|
||||
// if it was the last item; no need to rebuild index
|
||||
if (i != self.data.count()) {
|
||||
self.rebuild_index();
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the element at the specified index.
|
||||
/// The empty slot is filled from the end of the list.
|
||||
pub fn swapRemove(self: *Self, i: usize) void {
|
||||
const removed = self.data.swapRemove(i);
|
||||
const kv = self.index.get(removed.name).?;
|
||||
var dex = &kv.value;
|
||||
if (dex.count() == 1) {
|
||||
// was last item; delete the index
|
||||
_ = self.index.remove(kv.key);
|
||||
dex.deinit();
|
||||
removed.deinit();
|
||||
self.allocator.free(kv.key);
|
||||
} else {
|
||||
dex.shrink(dex.count() - 1);
|
||||
removed.deinit();
|
||||
}
|
||||
// if it was the last item; no need to rebuild index
|
||||
if (i != self.data.count()) {
|
||||
self.rebuild_index();
|
||||
}
|
||||
}
|
||||
|
||||
/// Access the header at the specified index.
|
||||
pub fn at(self: Self, i: usize) HeaderEntry {
|
||||
return self.data.at(i);
|
||||
}
|
||||
|
||||
/// Returns a list of indices containing headers with the given name.
|
||||
/// The returned list should not be modified by the caller.
|
||||
pub fn getIndices(self: Self, name: []const u8) ?HeaderIndexList {
|
||||
if (self.index.get(name)) |kv| {
|
||||
return kv.value;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a slice containing each header with the given name.
|
||||
pub fn get(self: Self, allocator: *Allocator, name: []const u8) !?[]const HeaderEntry {
|
||||
const dex = self.getIndices(name) orelse return null;
|
||||
|
||||
const buf = try allocator.alloc(HeaderEntry, dex.count());
|
||||
var it = dex.iterator();
|
||||
var n: usize = 0;
|
||||
while (it.next()) |idx| {
|
||||
buf[n] = self.data.at(idx);
|
||||
n += 1;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/// Returns all headers with the given name as a comma seperated string.
|
||||
///
|
||||
/// Useful for HTTP headers that follow RFC-7230 section 3.2.2:
|
||||
/// A recipient MAY combine multiple header fields with the same field
|
||||
/// name into one "field-name: field-value" pair, without changing the
|
||||
/// semantics of the message, by appending each subsequent field value to
|
||||
/// the combined field value in order, separated by a comma. The order
|
||||
/// in which header fields with the same field name are received is
|
||||
/// therefore significant to the interpretation of the combined field
|
||||
/// value
|
||||
pub fn getCommaSeparated(self: Self, allocator: *Allocator, name: []const u8) !?[]u8 {
|
||||
const dex = self.getIndices(name) orelse return null;
|
||||
|
||||
// adapted from mem.join
|
||||
const total_len = blk: {
|
||||
var sum: usize = dex.count() - 1; // space for separator(s)
|
||||
var it = dex.iterator();
|
||||
while (it.next()) |idx|
|
||||
sum += self.data.at(idx).value.len;
|
||||
break :blk sum;
|
||||
};
|
||||
|
||||
const buf = try allocator.alloc(u8, total_len);
|
||||
errdefer allocator.free(buf);
|
||||
|
||||
const first_value = self.data.at(dex.at(0)).value;
|
||||
mem.copy(u8, buf, first_value);
|
||||
var buf_index: usize = first_value.len;
|
||||
for (dex.toSlice()[1..]) |idx| {
|
||||
const value = self.data.at(idx).value;
|
||||
buf[buf_index] = ',';
|
||||
buf_index += 1;
|
||||
mem.copy(u8, buf[buf_index..], value);
|
||||
buf_index += value.len;
|
||||
}
|
||||
|
||||
// No need for shrink since buf is exactly the correct size.
|
||||
return buf;
|
||||
}
|
||||
|
||||
fn rebuild_index(self: *Self) void {
|
||||
{ // clear out the indexes
|
||||
var it = self.index.iterator();
|
||||
while (it.next()) |kv| {
|
||||
var dex = &kv.value;
|
||||
dex.len = 0; // keeps capacity available
|
||||
}
|
||||
}
|
||||
{ // fill up indexes again; we know capacity is fine from before
|
||||
var it = self.data.iterator();
|
||||
while (it.next()) |entry| {
|
||||
var dex = &self.index.get(entry.name).?.value;
|
||||
dex.appendAssumeCapacity(it.count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sort(self: *Self) void {
|
||||
std.sort.sort(HeaderEntry, self.data.toSlice(), HeaderEntry.compare);
|
||||
self.rebuild_index();
|
||||
}
|
||||
|
||||
pub fn format(
|
||||
self: Self,
|
||||
comptime fmt: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
context: var,
|
||||
comptime Errors: type,
|
||||
output: fn (@typeOf(context), []const u8) Errors!void,
|
||||
) Errors!void {
|
||||
var it = self.iterator();
|
||||
while (it.next()) |entry| {
|
||||
try output(context, entry.name);
|
||||
try output(context, ": ");
|
||||
try output(context, entry.value);
|
||||
try output(context, "\n");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
test "Headers.iterator" {
|
||||
var h = Headers.init(test_allocator);
|
||||
defer h.deinit();
|
||||
try h.append("foo", "bar", null);
|
||||
try h.append("cookie", "somevalue", null);
|
||||
|
||||
var count: i32 = 0;
|
||||
var it = h.iterator();
|
||||
while (it.next()) |e| {
|
||||
if (count == 0) {
|
||||
testing.expectEqualSlices(u8, "foo", e.name);
|
||||
testing.expectEqualSlices(u8, "bar", e.value);
|
||||
testing.expectEqual(false, e.never_index);
|
||||
} else if (count == 1) {
|
||||
testing.expectEqualSlices(u8, "cookie", e.name);
|
||||
testing.expectEqualSlices(u8, "somevalue", e.value);
|
||||
testing.expectEqual(true, e.never_index);
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
testing.expectEqual(i32(2), count);
|
||||
}
|
||||
|
||||
test "Headers.contains" {
|
||||
var h = Headers.init(test_allocator);
|
||||
defer h.deinit();
|
||||
try h.append("foo", "bar", null);
|
||||
try h.append("cookie", "somevalue", null);
|
||||
|
||||
testing.expectEqual(true, h.contains("foo"));
|
||||
testing.expectEqual(false, h.contains("flooble"));
|
||||
}
|
||||
|
||||
test "Headers.delete" {
|
||||
var h = Headers.init(test_allocator);
|
||||
defer h.deinit();
|
||||
try h.append("foo", "bar", null);
|
||||
try h.append("baz", "qux", null);
|
||||
try h.append("cookie", "somevalue", null);
|
||||
|
||||
testing.expectEqual(false, h.delete("not-present"));
|
||||
testing.expectEqual(usize(3), h.count());
|
||||
|
||||
testing.expectEqual(true, h.delete("foo"));
|
||||
testing.expectEqual(usize(2), h.count());
|
||||
{
|
||||
const e = h.at(0);
|
||||
testing.expectEqualSlices(u8, "baz", e.name);
|
||||
testing.expectEqualSlices(u8, "qux", e.value);
|
||||
testing.expectEqual(false, e.never_index);
|
||||
}
|
||||
{
|
||||
const e = h.at(1);
|
||||
testing.expectEqualSlices(u8, "cookie", e.name);
|
||||
testing.expectEqualSlices(u8, "somevalue", e.value);
|
||||
testing.expectEqual(true, e.never_index);
|
||||
}
|
||||
|
||||
testing.expectEqual(false, h.delete("foo"));
|
||||
}
|
||||
|
||||
test "Headers.orderedRemove" {
|
||||
var h = Headers.init(test_allocator);
|
||||
defer h.deinit();
|
||||
try h.append("foo", "bar", null);
|
||||
try h.append("baz", "qux", null);
|
||||
try h.append("cookie", "somevalue", null);
|
||||
|
||||
h.orderedRemove(0);
|
||||
testing.expectEqual(usize(2), h.count());
|
||||
{
|
||||
const e = h.at(0);
|
||||
testing.expectEqualSlices(u8, "baz", e.name);
|
||||
testing.expectEqualSlices(u8, "qux", e.value);
|
||||
testing.expectEqual(false, e.never_index);
|
||||
}
|
||||
{
|
||||
const e = h.at(1);
|
||||
testing.expectEqualSlices(u8, "cookie", e.name);
|
||||
testing.expectEqualSlices(u8, "somevalue", e.value);
|
||||
testing.expectEqual(true, e.never_index);
|
||||
}
|
||||
}
|
||||
|
||||
test "Headers.swapRemove" {
|
||||
var h = Headers.init(test_allocator);
|
||||
defer h.deinit();
|
||||
try h.append("foo", "bar", null);
|
||||
try h.append("baz", "qux", null);
|
||||
try h.append("cookie", "somevalue", null);
|
||||
|
||||
h.swapRemove(0);
|
||||
testing.expectEqual(usize(2), h.count());
|
||||
{
|
||||
const e = h.at(0);
|
||||
testing.expectEqualSlices(u8, "cookie", e.name);
|
||||
testing.expectEqualSlices(u8, "somevalue", e.value);
|
||||
testing.expectEqual(true, e.never_index);
|
||||
}
|
||||
{
|
||||
const e = h.at(1);
|
||||
testing.expectEqualSlices(u8, "baz", e.name);
|
||||
testing.expectEqualSlices(u8, "qux", e.value);
|
||||
testing.expectEqual(false, e.never_index);
|
||||
}
|
||||
}
|
||||
|
||||
test "Headers.at" {
|
||||
var h = Headers.init(test_allocator);
|
||||
defer h.deinit();
|
||||
try h.append("foo", "bar", null);
|
||||
try h.append("cookie", "somevalue", null);
|
||||
|
||||
{
|
||||
const e = h.at(0);
|
||||
testing.expectEqualSlices(u8, "foo", e.name);
|
||||
testing.expectEqualSlices(u8, "bar", e.value);
|
||||
testing.expectEqual(false, e.never_index);
|
||||
}
|
||||
{
|
||||
const e = h.at(1);
|
||||
testing.expectEqualSlices(u8, "cookie", e.name);
|
||||
testing.expectEqualSlices(u8, "somevalue", e.value);
|
||||
testing.expectEqual(true, e.never_index);
|
||||
}
|
||||
}
|
||||
|
||||
test "Headers.getIndices" {
|
||||
var h = Headers.init(test_allocator);
|
||||
defer h.deinit();
|
||||
try h.append("foo", "bar", null);
|
||||
try h.append("set-cookie", "x=1", null);
|
||||
try h.append("set-cookie", "y=2", null);
|
||||
|
||||
testing.expect(null == h.getIndices("not-present"));
|
||||
testing.expectEqualSlices(usize, [_]usize{0}, h.getIndices("foo").?.toSliceConst());
|
||||
testing.expectEqualSlices(usize, [_]usize{ 1, 2 }, h.getIndices("set-cookie").?.toSliceConst());
|
||||
}
|
||||
|
||||
test "Headers.get" {
|
||||
var h = Headers.init(test_allocator);
|
||||
defer h.deinit();
|
||||
try h.append("foo", "bar", null);
|
||||
try h.append("set-cookie", "x=1", null);
|
||||
try h.append("set-cookie", "y=2", null);
|
||||
|
||||
{
|
||||
const v = try h.get(test_allocator, "not-present");
|
||||
testing.expect(null == v);
|
||||
}
|
||||
{
|
||||
const v = (try h.get(test_allocator, "foo")).?;
|
||||
defer test_allocator.free(v);
|
||||
const e = v[0];
|
||||
testing.expectEqualSlices(u8, "foo", e.name);
|
||||
testing.expectEqualSlices(u8, "bar", e.value);
|
||||
testing.expectEqual(false, e.never_index);
|
||||
}
|
||||
{
|
||||
const v = (try h.get(test_allocator, "set-cookie")).?;
|
||||
defer test_allocator.free(v);
|
||||
{
|
||||
const e = v[0];
|
||||
testing.expectEqualSlices(u8, "set-cookie", e.name);
|
||||
testing.expectEqualSlices(u8, "x=1", e.value);
|
||||
testing.expectEqual(true, e.never_index);
|
||||
}
|
||||
{
|
||||
const e = v[1];
|
||||
testing.expectEqualSlices(u8, "set-cookie", e.name);
|
||||
testing.expectEqualSlices(u8, "y=2", e.value);
|
||||
testing.expectEqual(true, e.never_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test "Headers.getCommaSeparated" {
|
||||
var h = Headers.init(test_allocator);
|
||||
defer h.deinit();
|
||||
try h.append("foo", "bar", null);
|
||||
try h.append("set-cookie", "x=1", null);
|
||||
try h.append("set-cookie", "y=2", null);
|
||||
|
||||
{
|
||||
const v = try h.getCommaSeparated(test_allocator, "not-present");
|
||||
testing.expect(null == v);
|
||||
}
|
||||
{
|
||||
const v = (try h.getCommaSeparated(test_allocator, "foo")).?;
|
||||
defer test_allocator.free(v);
|
||||
testing.expectEqualSlices(u8, "bar", v);
|
||||
}
|
||||
{
|
||||
const v = (try h.getCommaSeparated(test_allocator, "set-cookie")).?;
|
||||
defer test_allocator.free(v);
|
||||
testing.expectEqualSlices(u8, "x=1,y=2", v);
|
||||
}
|
||||
}
|
||||
|
||||
test "Headers.sort" {
|
||||
var h = Headers.init(test_allocator);
|
||||
defer h.deinit();
|
||||
try h.append("foo", "bar", null);
|
||||
try h.append("cookie", "somevalue", null);
|
||||
|
||||
h.sort();
|
||||
{
|
||||
const e = h.at(0);
|
||||
testing.expectEqualSlices(u8, "cookie", e.name);
|
||||
testing.expectEqualSlices(u8, "somevalue", e.value);
|
||||
testing.expectEqual(true, e.never_index);
|
||||
}
|
||||
{
|
||||
const e = h.at(1);
|
||||
testing.expectEqualSlices(u8, "foo", e.name);
|
||||
testing.expectEqualSlices(u8, "bar", e.value);
|
||||
testing.expectEqual(false, e.never_index);
|
||||
}
|
||||
}
|
||||
|
||||
test "Headers.format" {
|
||||
var h = Headers.init(test_allocator);
|
||||
defer h.deinit();
|
||||
try h.append("foo", "bar", null);
|
||||
try h.append("cookie", "somevalue", null);
|
||||
|
||||
var buf: [100]u8 = undefined;
|
||||
testing.expectEqualSlices(u8,
|
||||
\\foo: bar
|
||||
\\cookie: somevalue
|
||||
\\
|
||||
, try std.fmt.bufPrint(buf[0..], "{}", h));
|
||||
}
|
||||
20
std/io.zig
20
std/io.zig
@ -164,32 +164,32 @@ pub fn InStream(comptime ReadError: type) type {
|
||||
|
||||
/// Reads a native-endian integer
|
||||
pub fn readIntNative(self: *Self, comptime T: type) !T {
|
||||
var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
try self.readNoEof(bytes[0..]);
|
||||
return mem.readIntNative(T, &bytes);
|
||||
}
|
||||
|
||||
/// Reads a foreign-endian integer
|
||||
pub fn readIntForeign(self: *Self, comptime T: type) !T {
|
||||
var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
try self.readNoEof(bytes[0..]);
|
||||
return mem.readIntForeign(T, &bytes);
|
||||
}
|
||||
|
||||
pub fn readIntLittle(self: *Self, comptime T: type) !T {
|
||||
var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
try self.readNoEof(bytes[0..]);
|
||||
return mem.readIntLittle(T, &bytes);
|
||||
}
|
||||
|
||||
pub fn readIntBig(self: *Self, comptime T: type) !T {
|
||||
var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
try self.readNoEof(bytes[0..]);
|
||||
return mem.readIntBig(T, &bytes);
|
||||
}
|
||||
|
||||
pub fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {
|
||||
var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
try self.readNoEof(bytes[0..]);
|
||||
return mem.readInt(T, &bytes, endian);
|
||||
}
|
||||
@ -249,32 +249,32 @@ pub fn OutStream(comptime WriteError: type) type {
|
||||
|
||||
/// Write a native-endian integer.
|
||||
pub fn writeIntNative(self: *Self, comptime T: type, value: T) Error!void {
|
||||
var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
mem.writeIntNative(T, &bytes, value);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
|
||||
/// Write a foreign-endian integer.
|
||||
pub fn writeIntForeign(self: *Self, comptime T: type, value: T) Error!void {
|
||||
var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
mem.writeIntForeign(T, &bytes, value);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
|
||||
pub fn writeIntLittle(self: *Self, comptime T: type, value: T) Error!void {
|
||||
var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
mem.writeIntLittle(T, &bytes, value);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
|
||||
pub fn writeIntBig(self: *Self, comptime T: type, value: T) Error!void {
|
||||
var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
mem.writeIntBig(T, &bytes, value);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
|
||||
pub fn writeInt(self: *Self, comptime T: type, value: T, endian: builtin.Endian) Error!void {
|
||||
var bytes: [(T.bit_count + 7 )/ 8]u8 = undefined;
|
||||
var bytes: [(T.bit_count + 7) / 8]u8 = undefined;
|
||||
mem.writeInt(T, &bytes, value, endian);
|
||||
return self.writeFn(self, bytes);
|
||||
}
|
||||
|
||||
@ -597,7 +597,10 @@ test "c out stream" {
|
||||
|
||||
const filename = c"tmp_io_test_file.txt";
|
||||
const out_file = std.c.fopen(filename, c"w") orelse return error.UnableToOpenTestFile;
|
||||
defer fs.deleteFileC(filename) catch {};
|
||||
defer {
|
||||
_ = std.c.fclose(out_file);
|
||||
fs.deleteFileC(filename) catch {};
|
||||
}
|
||||
|
||||
const out_stream = &io.COutStream.init(out_file).stream;
|
||||
try out_stream.print("hi: {}\n", i32(123));
|
||||
|
||||
@ -876,8 +876,9 @@ pub const TokenStream = struct {
|
||||
|
||||
pub fn next(self: *TokenStream) !?Token {
|
||||
if (self.token) |token| {
|
||||
const copy = token;
|
||||
self.token = null;
|
||||
return token;
|
||||
return copy;
|
||||
}
|
||||
|
||||
var t1: ?Token = undefined;
|
||||
|
||||
@ -519,6 +519,7 @@ pub const Int = struct {
|
||||
pub fn format(
|
||||
self: Int,
|
||||
comptime fmt: []const u8,
|
||||
comptime options: std.fmt.FormatOptions,
|
||||
context: var,
|
||||
comptime FmtError: type,
|
||||
output: fn (@typeOf(context), []const u8) FmtError!void,
|
||||
|
||||
@ -1481,6 +1481,7 @@ test "subArrayPtr" {
|
||||
}
|
||||
|
||||
/// Round an address up to the nearest aligned address
|
||||
/// The alignment must be a power of 2 and greater than 0.
|
||||
pub fn alignForward(addr: usize, alignment: usize) usize {
|
||||
return alignBackward(addr + (alignment - 1), alignment);
|
||||
}
|
||||
@ -1500,13 +1501,18 @@ test "alignForward" {
|
||||
testing.expect(alignForward(17, 8) == 24);
|
||||
}
|
||||
|
||||
/// Round an address up to the previous aligned address
|
||||
/// The alignment must be a power of 2 and greater than 0.
|
||||
pub fn alignBackward(addr: usize, alignment: usize) usize {
|
||||
assert(@popCount(usize, alignment) == 1);
|
||||
// 000010000 // example addr
|
||||
// 000001111 // subtract 1
|
||||
// 111110000 // binary not
|
||||
return addr & ~(alignment - 1);
|
||||
}
|
||||
|
||||
/// Given an address and an alignment, return true if the address is a multiple of the alignment
|
||||
/// The alignment must be a power of 2 and greater than 0.
|
||||
pub fn isAligned(addr: usize, alignment: usize) bool {
|
||||
return alignBackward(addr, alignment) == addr;
|
||||
}
|
||||
|
||||
@ -33,7 +33,6 @@ pub const Address = struct {
|
||||
|
||||
pub fn initIp6(ip6: *const Ip6Addr, _port: u16) Address {
|
||||
return Address{
|
||||
.family = os.AF_INET6,
|
||||
.os_addr = os.sockaddr{
|
||||
.in6 = os.sockaddr_in6{
|
||||
.family = os.AF_INET6,
|
||||
|
||||
@ -348,6 +348,7 @@ pub const DeleteFileError = error{
|
||||
FileNotFound,
|
||||
AccessDenied,
|
||||
NameTooLong,
|
||||
FileBusy,
|
||||
Unexpected,
|
||||
};
|
||||
|
||||
@ -363,6 +364,7 @@ pub fn DeleteFileW(filename: [*]const u16) DeleteFileError!void {
|
||||
ERROR.ACCESS_DENIED => return error.AccessDenied,
|
||||
ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
|
||||
ERROR.INVALID_PARAMETER => return error.NameTooLong,
|
||||
ERROR.SHARING_VIOLATION => return error.FileBusy,
|
||||
else => |err| return unexpectedError(err),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
// This file is in a package which has the root source file exposed as "@root".
|
||||
// It is included in the compilation unit when exporting an executable.
|
||||
// This file is included in the compilation unit when exporting an executable.
|
||||
|
||||
const root = @import("@root");
|
||||
const root = @import("root");
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const assert = std.debug.assert;
|
||||
@ -114,20 +113,20 @@ extern fn main(c_argc: i32, c_argv: [*][*]u8, c_envp: [*]?[*]u8) i32 {
|
||||
// and we want fewer call frames in stack traces.
|
||||
inline fn callMain() u8 {
|
||||
switch (@typeId(@typeOf(root.main).ReturnType)) {
|
||||
builtin.TypeId.NoReturn => {
|
||||
.NoReturn => {
|
||||
root.main();
|
||||
},
|
||||
builtin.TypeId.Void => {
|
||||
.Void => {
|
||||
root.main();
|
||||
return 0;
|
||||
},
|
||||
builtin.TypeId.Int => {
|
||||
.Int => {
|
||||
if (@typeOf(root.main).ReturnType.bit_count != 8) {
|
||||
@compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'");
|
||||
}
|
||||
return root.main();
|
||||
},
|
||||
builtin.TypeId.ErrorUnion => {
|
||||
.ErrorUnion => {
|
||||
root.main() catch |err| {
|
||||
std.debug.warn("error: {}\n", @errorName(err));
|
||||
if (builtin.os != builtin.Os.zen) {
|
||||
|
||||
@ -167,7 +167,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {
|
||||
|
||||
const allocator = builder.allocator;
|
||||
for (builder.top_level_steps.toSliceConst()) |top_level_step| {
|
||||
try out_stream.print(" {s22} {}\n", top_level_step.step.name, top_level_step.description);
|
||||
try out_stream.print(" {s:22} {}\n", top_level_step.step.name, top_level_step.description);
|
||||
}
|
||||
|
||||
try out_stream.write(
|
||||
@ -188,7 +188,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {
|
||||
for (builder.available_options_list.toSliceConst()) |option| {
|
||||
const name = try fmt.allocPrint(allocator, " -D{}=[{}]", option.name, Builder.typeIdName(option.type_id));
|
||||
defer allocator.free(name);
|
||||
try out_stream.print("{s24} {}\n", name, option.description);
|
||||
try out_stream.print("{s:24} {}\n", name, option.description);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -254,19 +254,32 @@ export fn fmod(x: f64, y: f64) f64 {
|
||||
|
||||
// TODO add intrinsics for these (and probably the double version too)
|
||||
// and have the math stuff use the intrinsic. same as @mod and @rem
|
||||
export fn floorf(x: f32) f32 {
|
||||
return math.floor(x);
|
||||
}
|
||||
export fn ceilf(x: f32) f32 {
|
||||
return math.ceil(x);
|
||||
}
|
||||
export fn floor(x: f64) f64 {
|
||||
return math.floor(x);
|
||||
}
|
||||
export fn ceil(x: f64) f64 {
|
||||
return math.ceil(x);
|
||||
}
|
||||
|
||||
export fn floorf(x: f32) f32 {return math.floor(x);}
|
||||
export fn ceilf(x: f32) f32 {return math.ceil(x);}
|
||||
export fn floor(x: f64) f64 {return math.floor(x);}
|
||||
export fn ceil(x: f64) f64 {return math.ceil(x);}
|
||||
export fn fma(a: f64, b: f64, c: f64) f64 {return math.fma(f64, a, b, c);}
|
||||
export fn fmaf(a: f32, b: f32, c: f32) f32 {return math.fma(f32, a, b, c);}
|
||||
export fn sin(a: f64) f64 {return math.sin(a);}
|
||||
export fn sinf(a: f32) f32 {return math.sin(a);}
|
||||
export fn cos(a: f64) f64 {return math.cos(a);}
|
||||
export fn cosf(a: f32) f32 {return math.cos(a);}
|
||||
export fn exp(a: f64) f64 {return math.exp(a);}
|
||||
export fn expf(a: f32) f32 {return math.exp(a);}
|
||||
export fn exp2(a: f64) f64 {return math.exp2(a);}
|
||||
export fn exp2f(a: f32) f32 {return math.exp2(a);}
|
||||
export fn log(a: f64) f64 {return math.ln(a);}
|
||||
export fn logf(a: f32) f32 {return math.ln(a);}
|
||||
export fn log2(a: f64) f64 {return math.log2(a);}
|
||||
export fn log2f(a: f32) f32 {return math.log2(a);}
|
||||
export fn log10(a: f64) f64 {return math.log10(a);}
|
||||
export fn log10f(a: f32) f32 {return math.log10(a);}
|
||||
export fn fabs(a: f64) f64 {return math.fabs(a);}
|
||||
export fn fabsf(a: f32) f32 {return math.fabs(a);}
|
||||
export fn trunc(a: f64) f64 {return math.trunc(a);}
|
||||
export fn truncf(a: f32) f32 {return math.trunc(a);}
|
||||
export fn round(a: f64) f64 {return math.round(a);}
|
||||
export fn roundf(a: f32) f32 {return math.round(a);}
|
||||
fn generic_fmod(comptime T: type, x: T, y: T) T {
|
||||
@setRuntimeSafety(false);
|
||||
|
||||
|
||||
@ -405,15 +405,15 @@ const use_thumb_1 = usesThumb1(builtin.arch);
|
||||
|
||||
fn usesThumb1(arch: builtin.Arch) bool {
|
||||
return switch (arch) {
|
||||
.arm => switch (arch.arm) {
|
||||
.arm => |sub_arch| switch (sub_arch) {
|
||||
.v6m => true,
|
||||
else => false,
|
||||
},
|
||||
.armeb => switch (arch.armeb) {
|
||||
.armeb => |sub_arch| switch (sub_arch) {
|
||||
.v6m => true,
|
||||
else => false,
|
||||
},
|
||||
.thumb => switch (arch.thumb) {
|
||||
.thumb => |sub_arch| switch (sub_arch) {
|
||||
.v5,
|
||||
.v5te,
|
||||
.v4t,
|
||||
@ -423,7 +423,7 @@ fn usesThumb1(arch: builtin.Arch) bool {
|
||||
=> true,
|
||||
else => false,
|
||||
},
|
||||
.thumbeb => switch (arch.thumbeb) {
|
||||
.thumbeb => |sub_arch| switch (sub_arch) {
|
||||
.v5,
|
||||
.v5te,
|
||||
.v4t,
|
||||
@ -471,6 +471,22 @@ test "usesThumb1" {
|
||||
//etc.
|
||||
}
|
||||
|
||||
const use_thumb_1_pre_armv6 = usesThumb1PreArmv6(builtin.arch);
|
||||
|
||||
fn usesThumb1PreArmv6(arch: builtin.Arch) bool {
|
||||
return switch (arch) {
|
||||
.thumb => |sub_arch| switch (sub_arch) {
|
||||
.v5, .v5te, .v4t => true,
|
||||
else => false,
|
||||
},
|
||||
.thumbeb => |sub_arch| switch (sub_arch) {
|
||||
.v5, .v5te, .v4t => true,
|
||||
else => false,
|
||||
},
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
nakedcc fn __aeabi_memcpy() noreturn {
|
||||
@setRuntimeSafety(false);
|
||||
if (use_thumb_1) {
|
||||
@ -505,7 +521,16 @@ nakedcc fn __aeabi_memmove() noreturn {
|
||||
|
||||
nakedcc fn __aeabi_memset() noreturn {
|
||||
@setRuntimeSafety(false);
|
||||
if (use_thumb_1) {
|
||||
if (use_thumb_1_pre_armv6) {
|
||||
asm volatile (
|
||||
\\ eors r1, r2
|
||||
\\ eors r2, r1
|
||||
\\ eors r1, r2
|
||||
\\ push {r7, lr}
|
||||
\\ b memset
|
||||
\\ pop {r7, pc}
|
||||
);
|
||||
} else if (use_thumb_1) {
|
||||
asm volatile (
|
||||
\\ mov r3, r1
|
||||
\\ mov r1, r2
|
||||
@ -527,7 +552,15 @@ nakedcc fn __aeabi_memset() noreturn {
|
||||
|
||||
nakedcc fn __aeabi_memclr() noreturn {
|
||||
@setRuntimeSafety(false);
|
||||
if (use_thumb_1) {
|
||||
if (use_thumb_1_pre_armv6) {
|
||||
asm volatile (
|
||||
\\ adds r2, r1, #0
|
||||
\\ movs r1, #0
|
||||
\\ push {r7, lr}
|
||||
\\ bl memset
|
||||
\\ pop {r7, pc}
|
||||
);
|
||||
} else if (use_thumb_1) {
|
||||
asm volatile (
|
||||
\\ mov r2, r1
|
||||
\\ movs r1, #0
|
||||
|
||||
@ -73,12 +73,15 @@ pub extern fn __getf2(a: f128, b: f128) c_int {
|
||||
|
||||
if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED;
|
||||
if ((aAbs | bAbs) == 0) return GE_EQUAL;
|
||||
return if ((aInt & bInt) >= 0) if (aInt < bInt)
|
||||
GE_LESS
|
||||
else if (aInt == bInt)
|
||||
GE_EQUAL
|
||||
else
|
||||
GE_GREATER else if (aInt > bInt)
|
||||
// zig fmt issue here, see https://github.com/ziglang/zig/issues/2661
|
||||
return if ((aInt & bInt) >= 0)
|
||||
if (aInt < bInt)
|
||||
GE_LESS
|
||||
else if (aInt == bInt)
|
||||
GE_EQUAL
|
||||
else
|
||||
GE_GREATER
|
||||
else if (aInt > bInt)
|
||||
GE_LESS
|
||||
else if (aInt == bInt)
|
||||
GE_EQUAL
|
||||
|
||||
@ -9,16 +9,15 @@ const std = @import("std");
|
||||
pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn {
|
||||
@setCold(true);
|
||||
switch (builtin.os) {
|
||||
// TODO: fix panic in zen
|
||||
builtin.Os.freestanding, builtin.Os.zen => {
|
||||
.freestanding => {
|
||||
while (true) {}
|
||||
},
|
||||
builtin.Os.wasi => {
|
||||
.wasi => {
|
||||
std.debug.warn("{}", msg);
|
||||
_ = std.os.wasi.proc_raise(std.os.wasi.SIGABRT);
|
||||
unreachable;
|
||||
},
|
||||
builtin.Os.uefi => {
|
||||
.uefi => {
|
||||
// TODO look into using the debug info and logging helpful messages
|
||||
std.os.abort();
|
||||
},
|
||||
|
||||
@ -37,6 +37,7 @@ pub const fs = @import("fs.zig");
|
||||
pub const hash = @import("hash.zig");
|
||||
pub const hash_map = @import("hash_map.zig");
|
||||
pub const heap = @import("heap.zig");
|
||||
pub const http = @import("http.zig");
|
||||
pub const io = @import("io.zig");
|
||||
pub const json = @import("json.zig");
|
||||
pub const lazyInit = @import("lazy_init.zig").lazyInit;
|
||||
@ -89,6 +90,7 @@ test "std" {
|
||||
_ = @import("fs.zig");
|
||||
_ = @import("hash.zig");
|
||||
_ = @import("heap.zig");
|
||||
_ = @import("http.zig");
|
||||
_ = @import("io.zig");
|
||||
_ = @import("json.zig");
|
||||
_ = @import("lazy_init.zig");
|
||||
|
||||
@ -2833,8 +2833,8 @@ fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: Node
|
||||
|
||||
const else_token = eatToken(it, .Keyword_else) orelse return node;
|
||||
const payload = try parsePayload(arena, it, tree);
|
||||
const else_expr = try expectNode(arena, it, tree, parseExpr, AstError{
|
||||
.ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
|
||||
const else_expr = try expectNode(arena, it, tree, bodyParseFn, AstError{
|
||||
.InvalidToken = AstError.InvalidToken{ .token = it.index },
|
||||
});
|
||||
const else_node = try arena.create(Node.Else);
|
||||
else_node.* = Node.Else{
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// TODO remove `use` keyword eventually
|
||||
// TODO remove `use` keyword eventually: https://github.com/ziglang/zig/issues/2591
|
||||
test "zig fmt: change use to usingnamespace" {
|
||||
try testTransform(
|
||||
\\use @import("std");
|
||||
@ -1105,7 +1105,7 @@ test "zig fmt: first line comment in struct initializer" {
|
||||
try testCanonical(
|
||||
\\pub async fn acquire(self: *Self) HeldLock {
|
||||
\\ return HeldLock{
|
||||
\\ // TODO guaranteed allocation elision
|
||||
\\ // guaranteed allocation elision
|
||||
\\ .held = await (async self.lock.acquire() catch unreachable),
|
||||
\\ .value = &self.private_data,
|
||||
\\ };
|
||||
@ -2234,6 +2234,18 @@ test "zig fmt: multiline string in array" {
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: if type expr" {
|
||||
try testCanonical(
|
||||
\\const mycond = true;
|
||||
\\pub fn foo() if (mycond) i32 else void {
|
||||
\\ if (mycond) {
|
||||
\\ return 42;
|
||||
\\ }
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const warn = std.debug.warn;
|
||||
|
||||
@ -939,10 +939,10 @@ fn renderExpression(
|
||||
}
|
||||
|
||||
switch (container_decl.init_arg_expr) {
|
||||
ast.Node.ContainerDecl.InitArg.None => {
|
||||
.None => {
|
||||
try renderToken(tree, stream, container_decl.kind_token, indent, start_col, Space.Space); // union
|
||||
},
|
||||
ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| {
|
||||
.Enum => |enum_tag_type| {
|
||||
try renderToken(tree, stream, container_decl.kind_token, indent, start_col, Space.None); // union
|
||||
|
||||
const lparen = tree.nextToken(container_decl.kind_token);
|
||||
@ -962,7 +962,7 @@ fn renderExpression(
|
||||
try renderToken(tree, stream, tree.nextToken(enum_token), indent, start_col, Space.Space); // )
|
||||
}
|
||||
},
|
||||
ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
|
||||
.Type => |type_expr| {
|
||||
try renderToken(tree, stream, container_decl.kind_token, indent, start_col, Space.None); // union
|
||||
|
||||
const lparen = tree.nextToken(container_decl.kind_token);
|
||||
|
||||
@ -122,7 +122,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
|
||||
\\
|
||||
\\pub fn main() void {
|
||||
\\ const stdout = &(io.getStdOut() catch unreachable).outStream().stream;
|
||||
\\ stdout.print("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable;
|
||||
\\ stdout.print("Hello, world!\n{d:4} {x:3} {c}\n", u32(12), u16(0x12), u8('a')) catch unreachable;
|
||||
\\}
|
||||
, "Hello, world!\n0012 012 a\n");
|
||||
|
||||
|
||||
@ -2,13 +2,22 @@ const tests = @import("tests.zig");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
cases.add(
|
||||
"slice passed as array init type with elems",
|
||||
\\export fn entry() void {
|
||||
\\ const x = []u8{1, 2};
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:2:15: error: expected array type or [_], found slice",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
"slice passed as array init type",
|
||||
\\export fn entry() void {
|
||||
\\ const x = []u8{};
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:2:19: error: expected array type or [_], found slice",
|
||||
"tmp.zig:2:15: error: expected array type or [_], found slice",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -49,16 +58,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\const Foo = struct {
|
||||
\\ a: undefined,
|
||||
\\};
|
||||
\\const Bar = union {
|
||||
\\ a: undefined,
|
||||
\\};
|
||||
\\pub fn main() void {
|
||||
\\export fn entry1() void {
|
||||
\\ const foo: Foo = undefined;
|
||||
\\ const bar: Bar = undefined;
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:2:8: error: expected type 'type', found '(undefined)'",
|
||||
"tmp.zig:5:8: error: expected type 'type', found '(undefined)'",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -461,13 +465,25 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\const G = packed struct {
|
||||
\\ x: Enum,
|
||||
\\};
|
||||
\\export fn entry() void {
|
||||
\\export fn entry1() void {
|
||||
\\ var a: A = undefined;
|
||||
\\}
|
||||
\\export fn entry2() void {
|
||||
\\ var b: B = undefined;
|
||||
\\}
|
||||
\\export fn entry3() void {
|
||||
\\ var r: C = undefined;
|
||||
\\}
|
||||
\\export fn entry4() void {
|
||||
\\ var d: D = undefined;
|
||||
\\}
|
||||
\\export fn entry5() void {
|
||||
\\ var e: E = undefined;
|
||||
\\}
|
||||
\\export fn entry6() void {
|
||||
\\ var f: F = undefined;
|
||||
\\}
|
||||
\\export fn entry7() void {
|
||||
\\ var g: G = undefined;
|
||||
\\}
|
||||
\\const S = struct {
|
||||
@ -489,7 +505,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
"tmp.zig:14:5: error: non-packed, non-extern struct 'U' not allowed in packed struct; no guaranteed in-memory representation",
|
||||
"tmp.zig:17:5: error: type '?anyerror' not allowed in packed struct; no guaranteed in-memory representation",
|
||||
"tmp.zig:20:5: error: type 'Enum' not allowed in packed struct; no guaranteed in-memory representation",
|
||||
"tmp.zig:38:14: note: enum declaration does not specify an integer tag type",
|
||||
"tmp.zig:50:14: note: enum declaration does not specify an integer tag type",
|
||||
);
|
||||
|
||||
cases.addCase(x: {
|
||||
@ -721,7 +737,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ var oops = @bitCast(u7, byte);
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:2:16: error: destination type 'u7' has 7 bits but source type 'u8' has 8 bits",
|
||||
"tmp.zig:2:25: error: destination type 'u7' has 7 bits but source type 'u8' has 8 bits",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -1381,7 +1397,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ for (xx) |f| {}
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:7:15: error: variable of type 'Foo' must be const or comptime",
|
||||
"tmp.zig:7:5: error: values of type 'Foo' must be comptime known, but index value is runtime known",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2250,6 +2266,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\}
|
||||
\\
|
||||
\\extern fn bar(x: *void) void { }
|
||||
\\export fn entry2() void {
|
||||
\\ bar(&{});
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:1:30: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'ccc'",
|
||||
"tmp.zig:7:18: error: parameter of type '*void' has 0 bits; not allowed in function with calling convention 'ccc'",
|
||||
@ -2576,7 +2595,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\
|
||||
\\fn b() void {}
|
||||
,
|
||||
"tmp.zig:3:5: error: unreachable code",
|
||||
"tmp.zig:3:6: error: unreachable code",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2596,7 +2615,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:3:5: error: use of undeclared identifier 'b'",
|
||||
"tmp.zig:4:5: error: use of undeclared identifier 'c'",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2662,7 +2680,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ const a: noreturn = {};
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:2:14: error: variable of type 'noreturn' not allowed",
|
||||
"tmp.zig:2:25: error: expected type 'noreturn', found 'void'",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2725,9 +2743,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ var bad : bool = undefined;
|
||||
\\ bad[bad] = bad[bad];
|
||||
\\}
|
||||
\\export fn g() void {
|
||||
\\ var bad : bool = undefined;
|
||||
\\ _ = bad[bad];
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:3:8: error: array access of non-array type 'bool'",
|
||||
"tmp.zig:3:19: error: array access of non-array type 'bool'",
|
||||
"tmp.zig:7:12: error: array access of non-array type 'bool'",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2737,9 +2759,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ var bad = false;
|
||||
\\ array[bad] = array[bad];
|
||||
\\}
|
||||
\\export fn g() void {
|
||||
\\ var array = "aoeu";
|
||||
\\ var bad = false;
|
||||
\\ _ = array[bad];
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:4:11: error: expected type 'usize', found 'bool'",
|
||||
"tmp.zig:4:24: error: expected type 'usize', found 'bool'",
|
||||
"tmp.zig:9:15: error: expected type 'usize', found 'bool'",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2757,12 +2784,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
"missing else clause",
|
||||
\\fn f(b: bool) void {
|
||||
\\ const x : i32 = if (b) h: { break :h 1; };
|
||||
\\}
|
||||
\\fn g(b: bool) void {
|
||||
\\ const y = if (b) h: { break :h i32(1); };
|
||||
\\}
|
||||
\\export fn entry() void { f(true); }
|
||||
\\export fn entry() void { f(true); g(true); }
|
||||
,
|
||||
"tmp.zig:2:42: error: integer value 1 cannot be implicitly casted to type 'void'",
|
||||
"tmp.zig:3:15: error: incompatible types: 'i32' and 'void'",
|
||||
"tmp.zig:5:15: error: incompatible types: 'i32' and 'void'",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2773,9 +2802,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ a.foo = 1;
|
||||
\\ const y = a.bar;
|
||||
\\}
|
||||
\\export fn g() void {
|
||||
\\ var a : A = undefined;
|
||||
\\ const y = a.bar;
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:4:6: error: no member named 'foo' in struct 'A'",
|
||||
"tmp.zig:5:16: error: no member named 'bar' in struct 'A'",
|
||||
"tmp.zig:9:16: error: no member named 'bar' in struct 'A'",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2920,7 +2953,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = foo;
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:1:19: error: type '[3]u16' does not support struct initialization syntax",
|
||||
"tmp.zig:1:21: error: type '[3]u16' does not support struct initialization syntax",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3239,7 +3272,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\
|
||||
\\export fn entry() usize { return @sizeOf(@typeOf(Foo)); }
|
||||
,
|
||||
"tmp.zig:5:25: error: unable to evaluate constant expression",
|
||||
"tmp.zig:5:18: error: unable to evaluate constant expression",
|
||||
"tmp.zig:2:12: note: called from here",
|
||||
"tmp.zig:2:8: note: called from here",
|
||||
);
|
||||
@ -3856,7 +3889,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ return 2;
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:2:15: error: values of type 'comptime_int' must be comptime known",
|
||||
"tmp.zig:5:17: error: cannot store runtime value in type 'comptime_int'",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -5108,7 +5141,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ const array = [2]u8{1, 2, 3};
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:2:24: error: expected [2]u8 literal, found [3]u8 literal",
|
||||
"tmp.zig:2:31: error: index 2 outside array of size 2",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -5125,36 +5158,47 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
|
||||
cases.add(
|
||||
"non-const variables of things that require const variables",
|
||||
\\const Opaque = @OpaqueType();
|
||||
\\
|
||||
\\export fn entry(opaque: *Opaque) void {
|
||||
\\export fn entry1() void {
|
||||
\\ var m2 = &2;
|
||||
\\ const y: u32 = m2.*;
|
||||
\\
|
||||
\\}
|
||||
\\export fn entry2() void {
|
||||
\\ var a = undefined;
|
||||
\\}
|
||||
\\export fn entry3() void {
|
||||
\\ var b = 1;
|
||||
\\}
|
||||
\\export fn entry4() void {
|
||||
\\ var c = 1.0;
|
||||
\\}
|
||||
\\export fn entry5() void {
|
||||
\\ var d = null;
|
||||
\\}
|
||||
\\export fn entry6(opaque: *Opaque) void {
|
||||
\\ var e = opaque.*;
|
||||
\\}
|
||||
\\export fn entry7() void {
|
||||
\\ var f = i32;
|
||||
\\}
|
||||
\\export fn entry8() void {
|
||||
\\ var h = (Foo {}).bar;
|
||||
\\
|
||||
\\}
|
||||
\\export fn entry9() void {
|
||||
\\ var z: noreturn = return;
|
||||
\\}
|
||||
\\
|
||||
\\const Opaque = @OpaqueType();
|
||||
\\const Foo = struct {
|
||||
\\ fn bar(self: *const Foo) void {}
|
||||
\\};
|
||||
,
|
||||
"tmp.zig:4:4: error: variable of type '*comptime_int' must be const or comptime",
|
||||
"tmp.zig:7:4: error: variable of type '(undefined)' must be const or comptime",
|
||||
"tmp.zig:2:4: error: variable of type '*comptime_int' must be const or comptime",
|
||||
"tmp.zig:5:4: error: variable of type '(undefined)' must be const or comptime",
|
||||
"tmp.zig:8:4: error: variable of type 'comptime_int' must be const or comptime",
|
||||
"tmp.zig:9:4: error: variable of type 'comptime_float' must be const or comptime",
|
||||
"tmp.zig:10:4: error: variable of type '(null)' must be const or comptime",
|
||||
"tmp.zig:11:4: error: variable of type 'Opaque' not allowed",
|
||||
"tmp.zig:12:4: error: variable of type 'type' must be const or comptime",
|
||||
"tmp.zig:13:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",
|
||||
"tmp.zig:15:4: error: unreachable code",
|
||||
"tmp.zig:11:4: error: variable of type 'comptime_float' must be const or comptime",
|
||||
"tmp.zig:14:4: error: variable of type '(null)' must be const or comptime",
|
||||
"tmp.zig:17:4: error: variable of type 'Opaque' not allowed",
|
||||
"tmp.zig:20:4: error: variable of type 'type' must be const or comptime",
|
||||
"tmp.zig:23:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime",
|
||||
"tmp.zig:26:4: error: unreachable code",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -5300,7 +5344,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ }
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:37:16: error: cannot store runtime value in compile time variable",
|
||||
"tmp.zig:37:29: error: cannot store runtime value in compile time variable",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -5924,7 +5968,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ const foo = Foo { .Bar = x, .Baz = u8 };
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:7:30: error: unable to evaluate constant expression",
|
||||
"tmp.zig:7:23: error: unable to evaluate constant expression",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -5938,7 +5982,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ const foo = Foo { .Bar = x };
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:7:30: error: unable to evaluate constant expression",
|
||||
"tmp.zig:7:23: error: unable to evaluate constant expression",
|
||||
);
|
||||
|
||||
cases.addTest(
|
||||
|
||||
@ -69,6 +69,8 @@ comptime {
|
||||
_ = @import("behavior/optional.zig");
|
||||
_ = @import("behavior/pointers.zig");
|
||||
_ = @import("behavior/popcount.zig");
|
||||
_ = @import("behavior/muladd.zig");
|
||||
_ = @import("behavior/floatop.zig");
|
||||
_ = @import("behavior/ptrcast.zig");
|
||||
_ = @import("behavior/pub_enum.zig");
|
||||
_ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
|
||||
|
||||
@ -172,6 +172,12 @@ fn plusOne(x: u32) u32 {
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
test "runtime initialize array elem and then implicit cast to slice" {
|
||||
var two: i32 = 2;
|
||||
const x: []const i32 = [_]i32{two};
|
||||
expect(x[0] == 2);
|
||||
}
|
||||
|
||||
test "array literal as argument to function" {
|
||||
const S = struct {
|
||||
fn entry(two: i32) void {
|
||||
@ -227,7 +233,7 @@ test "double nested array to const slice cast in array literal" {
|
||||
|
||||
const cases2 = [_][]const i32{
|
||||
[_]i32{1},
|
||||
[_]i32{ two, 3 },
|
||||
&[_]i32{ two, 3 },
|
||||
};
|
||||
expect(cases2.len == 2);
|
||||
expect(cases2[0].len == 1);
|
||||
@ -238,7 +244,7 @@ test "double nested array to const slice cast in array literal" {
|
||||
|
||||
const cases3 = [_][]const []const i32{
|
||||
[_][]const i32{[_]i32{1}},
|
||||
[_][]const i32{[_]i32{ two, 3 }},
|
||||
&[_][]const i32{&[_]i32{ two, 3 }},
|
||||
[_][]const i32{
|
||||
[_]i32{4},
|
||||
[_]i32{ 5, 6, 7 },
|
||||
|
||||
@ -112,3 +112,16 @@ test "bitcast packed struct to integer and back" {
|
||||
S.doTheTest();
|
||||
comptime S.doTheTest();
|
||||
}
|
||||
|
||||
test "implicit cast to error union by returning" {
|
||||
const S = struct {
|
||||
fn entry() void {
|
||||
expect((func(-1) catch unreachable) == maxInt(u64));
|
||||
}
|
||||
pub fn func(sz: i64) anyerror!u64 {
|
||||
return @bitCast(u64, sz);
|
||||
}
|
||||
};
|
||||
S.entry();
|
||||
comptime S.entry();
|
||||
}
|
||||
|
||||
@ -482,3 +482,40 @@ test "@intCast to u0 and use the result" {
|
||||
S.doTheTest(0, 1, 0);
|
||||
comptime S.doTheTest(0, 1, 0);
|
||||
}
|
||||
|
||||
test "peer type resolution: unreachable, null, slice" {
|
||||
const S = struct {
|
||||
fn doTheTest(num: usize, word: []const u8) void {
|
||||
const result = switch (num) {
|
||||
0 => null,
|
||||
1 => word,
|
||||
else => unreachable,
|
||||
};
|
||||
expect(mem.eql(u8, result.?, "hi"));
|
||||
}
|
||||
};
|
||||
S.doTheTest(1, "hi");
|
||||
}
|
||||
|
||||
test "peer type resolution: unreachable, error set, unreachable" {
|
||||
const Error = error {
|
||||
FileDescriptorAlreadyPresentInSet,
|
||||
OperationCausesCircularLoop,
|
||||
FileDescriptorNotRegistered,
|
||||
SystemResources,
|
||||
UserResourceLimitReached,
|
||||
FileDescriptorIncompatibleWithEpoll,
|
||||
Unexpected,
|
||||
};
|
||||
var err = Error.SystemResources;
|
||||
const transformed_err = switch (err) {
|
||||
error.FileDescriptorAlreadyPresentInSet => unreachable,
|
||||
error.OperationCausesCircularLoop => unreachable,
|
||||
error.FileDescriptorNotRegistered => unreachable,
|
||||
error.SystemResources => error.SystemResources,
|
||||
error.UserResourceLimitReached => error.UserResourceLimitReached,
|
||||
error.FileDescriptorIncompatibleWithEpoll => unreachable,
|
||||
error.Unexpected => unreachable,
|
||||
};
|
||||
expect(transformed_err == error.SystemResources);
|
||||
}
|
||||
|
||||
@ -76,3 +76,20 @@ fn testNestedFnErrDefer() anyerror!void {
|
||||
};
|
||||
return S.baz();
|
||||
}
|
||||
|
||||
test "return variable while defer expression in scope to modify it" {
|
||||
const S = struct {
|
||||
fn doTheTest() void {
|
||||
expect(notNull().? == 1);
|
||||
}
|
||||
|
||||
fn notNull() ?u8 {
|
||||
var res: ?u8 = 1;
|
||||
defer res = null;
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
S.doTheTest();
|
||||
comptime S.doTheTest();
|
||||
}
|
||||
|
||||
@ -335,3 +335,43 @@ test "debug info for optional error set" {
|
||||
const SomeError = error{Hello};
|
||||
var a_local_variable: ?SomeError = null;
|
||||
}
|
||||
|
||||
test "nested catch" {
|
||||
const S = struct {
|
||||
fn entry() void {
|
||||
expectError(error.Bad, func());
|
||||
}
|
||||
fn fail() anyerror!Foo {
|
||||
return error.Wrong;
|
||||
}
|
||||
fn func() anyerror!Foo {
|
||||
const x = fail() catch
|
||||
fail() catch
|
||||
return error.Bad;
|
||||
unreachable;
|
||||
}
|
||||
const Foo = struct {
|
||||
field: i32,
|
||||
};
|
||||
};
|
||||
S.entry();
|
||||
comptime S.entry();
|
||||
}
|
||||
|
||||
test "implicit cast to optional to error union to return result loc" {
|
||||
const S = struct {
|
||||
fn entry() void {
|
||||
if (func(undefined)) |opt| {
|
||||
expect(opt != null);
|
||||
} else |_| @panic("expected non error");
|
||||
}
|
||||
fn func(f: *Foo) anyerror!?*Foo {
|
||||
return f;
|
||||
}
|
||||
const Foo = struct {
|
||||
field: i32,
|
||||
};
|
||||
};
|
||||
S.entry();
|
||||
//comptime S.entry(); TODO
|
||||
}
|
||||
|
||||
@ -190,6 +190,17 @@ fn testTryToTrickEvalWithRuntimeIf(b: bool) usize {
|
||||
}
|
||||
}
|
||||
|
||||
test "inlined loop has array literal with elided runtime scope on first iteration but not second iteration" {
|
||||
var runtime = [1]i32{3};
|
||||
comptime var i: usize = 0;
|
||||
inline while (i < 2) : (i += 1) {
|
||||
const result = if (i == 0) [1]i32{2} else runtime;
|
||||
}
|
||||
comptime {
|
||||
expect(i == 2);
|
||||
}
|
||||
}
|
||||
|
||||
fn max(comptime T: type, a: T, b: T) T {
|
||||
if (T == bool) {
|
||||
return a or b;
|
||||
@ -756,8 +767,7 @@ test "comptime bitwise operators" {
|
||||
test "*align(1) u16 is the same as *align(1:0:2) u16" {
|
||||
comptime {
|
||||
expect(*align(1:0:2) u16 == *align(1) u16);
|
||||
// TODO add parsing support for this syntax
|
||||
//expect(*align(:0:2) u16 == *u16);
|
||||
expect(*align(:0:2) u16 == *u16);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
243
test/stage1/behavior/floatop.zig
Normal file
243
test/stage1/behavior/floatop.zig
Normal file
@ -0,0 +1,243 @@
|
||||
const expect = @import("std").testing.expect;
|
||||
const pi = @import("std").math.pi;
|
||||
const e = @import("std").math.e;
|
||||
|
||||
test "@sqrt" {
|
||||
comptime testSqrt();
|
||||
testSqrt();
|
||||
}
|
||||
|
||||
fn testSqrt() void {
|
||||
{
|
||||
var a: f16 = 4;
|
||||
expect(@sqrt(f16, a) == 2);
|
||||
}
|
||||
{
|
||||
var a: f32 = 9;
|
||||
expect(@sqrt(f32, a) == 3);
|
||||
}
|
||||
{
|
||||
var a: f64 = 25;
|
||||
expect(@sqrt(f64, a) == 5);
|
||||
}
|
||||
{
|
||||
const a: comptime_float = 25.0;
|
||||
expect(@sqrt(comptime_float, a) == 5.0);
|
||||
}
|
||||
// Waiting on a c.zig implementation
|
||||
//{
|
||||
// var a: f128 = 49;
|
||||
// expect(@sqrt(f128, a) == 7);
|
||||
//}
|
||||
}
|
||||
|
||||
test "@sin" {
|
||||
comptime testSin();
|
||||
testSin();
|
||||
}
|
||||
|
||||
fn testSin() void {
|
||||
// TODO - this is actually useful and should be implemented
|
||||
// (all the trig functions for f16)
|
||||
// but will probably wait till self-hosted
|
||||
//{
|
||||
// var a: f16 = pi;
|
||||
// expect(@sin(f16, a/2) == 1);
|
||||
//}
|
||||
{
|
||||
var a: f32 = 0;
|
||||
expect(@sin(f32, a) == 0);
|
||||
}
|
||||
{
|
||||
var a: f64 = 0;
|
||||
expect(@sin(f64, a) == 0);
|
||||
}
|
||||
// TODO
|
||||
//{
|
||||
// var a: f16 = pi;
|
||||
// expect(@sqrt(f128, a/2) == 1);
|
||||
//}
|
||||
}
|
||||
|
||||
test "@cos" {
|
||||
comptime testCos();
|
||||
testCos();
|
||||
}
|
||||
|
||||
fn testCos() void {
|
||||
{
|
||||
var a: f32 = 0;
|
||||
expect(@cos(f32, a) == 1);
|
||||
}
|
||||
{
|
||||
var a: f64 = 0;
|
||||
expect(@cos(f64, a) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
test "@exp" {
|
||||
comptime testExp();
|
||||
testExp();
|
||||
}
|
||||
|
||||
fn testExp() void {
|
||||
{
|
||||
var a: f32 = 0;
|
||||
expect(@exp(f32, a) == 1);
|
||||
}
|
||||
{
|
||||
var a: f64 = 0;
|
||||
expect(@exp(f64, a) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
test "@exp2" {
|
||||
comptime testExp2();
|
||||
testExp2();
|
||||
}
|
||||
|
||||
fn testExp2() void {
|
||||
{
|
||||
var a: f32 = 2;
|
||||
expect(@exp2(f32, a) == 4);
|
||||
}
|
||||
{
|
||||
var a: f64 = 2;
|
||||
expect(@exp2(f64, a) == 4);
|
||||
}
|
||||
}
|
||||
|
||||
test "@ln" {
|
||||
// Old musl (and glibc?), and our current math.ln implementation do not return 1
|
||||
// so also accept those values.
|
||||
comptime testLn();
|
||||
testLn();
|
||||
}
|
||||
|
||||
fn testLn() void {
|
||||
{
|
||||
var a: f32 = e;
|
||||
expect(@ln(f32, a) == 1 or @ln(f32, a) == @bitCast(f32, u32(0x3f7fffff)));
|
||||
}
|
||||
{
|
||||
var a: f64 = e;
|
||||
expect(@ln(f64, a) == 1 or @ln(f64, a) == @bitCast(f64, u64(0x3ff0000000000000)));
|
||||
}
|
||||
}
|
||||
|
||||
test "@log2" {
|
||||
comptime testLog2();
|
||||
testLog2();
|
||||
}
|
||||
|
||||
fn testLog2() void {
|
||||
{
|
||||
var a: f32 = 4;
|
||||
expect(@log2(f32, a) == 2);
|
||||
}
|
||||
{
|
||||
var a: f64 = 4;
|
||||
expect(@log2(f64, a) == 2);
|
||||
}
|
||||
}
|
||||
|
||||
test "@log10" {
|
||||
comptime testLog10();
|
||||
testLog10();
|
||||
}
|
||||
|
||||
fn testLog10() void {
|
||||
{
|
||||
var a: f32 = 100;
|
||||
expect(@log10(f32, a) == 2);
|
||||
}
|
||||
{
|
||||
var a: f64 = 1000;
|
||||
expect(@log10(f64, a) == 3);
|
||||
}
|
||||
}
|
||||
|
||||
test "@fabs" {
|
||||
comptime testFabs();
|
||||
testFabs();
|
||||
}
|
||||
|
||||
fn testFabs() void {
|
||||
{
|
||||
var a: f32 = -2.5;
|
||||
var b: f32 = 2.5;
|
||||
expect(@fabs(f32, a) == 2.5);
|
||||
expect(@fabs(f32, b) == 2.5);
|
||||
}
|
||||
{
|
||||
var a: f64 = -2.5;
|
||||
var b: f64 = 2.5;
|
||||
expect(@fabs(f64, a) == 2.5);
|
||||
expect(@fabs(f64, b) == 2.5);
|
||||
}
|
||||
}
|
||||
|
||||
test "@floor" {
|
||||
comptime testFloor();
|
||||
testFloor();
|
||||
}
|
||||
|
||||
fn testFloor() void {
|
||||
{
|
||||
var a: f32 = 2.1;
|
||||
expect(@floor(f32, a) == 2);
|
||||
}
|
||||
{
|
||||
var a: f64 = 3.5;
|
||||
expect(@floor(f64, a) == 3);
|
||||
}
|
||||
}
|
||||
|
||||
test "@ceil" {
|
||||
comptime testCeil();
|
||||
testCeil();
|
||||
}
|
||||
|
||||
fn testCeil() void {
|
||||
{
|
||||
var a: f32 = 2.1;
|
||||
expect(@ceil(f32, a) == 3);
|
||||
}
|
||||
{
|
||||
var a: f64 = 3.5;
|
||||
expect(@ceil(f64, a) == 4);
|
||||
}
|
||||
}
|
||||
|
||||
test "@trunc" {
|
||||
comptime testTrunc();
|
||||
testTrunc();
|
||||
}
|
||||
|
||||
fn testTrunc() void {
|
||||
{
|
||||
var a: f32 = 2.1;
|
||||
expect(@trunc(f32, a) == 2);
|
||||
}
|
||||
{
|
||||
var a: f64 = -3.5;
|
||||
expect(@trunc(f64, a) == -3);
|
||||
}
|
||||
}
|
||||
|
||||
// This is waiting on library support for the Windows build (not sure why the other's don't need it)
|
||||
//test "@nearbyInt" {
|
||||
// comptime testNearbyInt();
|
||||
// testNearbyInt();
|
||||
//}
|
||||
|
||||
//fn testNearbyInt() void {
|
||||
// {
|
||||
// var a: f32 = 2.1;
|
||||
// expect(@nearbyInt(f32, a) == 2);
|
||||
// }
|
||||
// {
|
||||
// var a: f64 = -3.75;
|
||||
// expect(@nearbyInt(f64, a) == -4);
|
||||
// }
|
||||
//}
|
||||
@ -205,3 +205,26 @@ test "extern struct with stdcallcc fn pointer" {
|
||||
s.ptr = S.foo;
|
||||
expect(s.ptr() == 1234);
|
||||
}
|
||||
|
||||
test "implicit cast fn call result to optional in field result" {
|
||||
const S = struct {
|
||||
fn entry() void {
|
||||
var x = Foo{
|
||||
.field = optionalPtr(),
|
||||
};
|
||||
expect(x.field.?.* == 999);
|
||||
}
|
||||
|
||||
const glob: i32 = 999;
|
||||
|
||||
fn optionalPtr() *const i32 {
|
||||
return &glob;
|
||||
}
|
||||
|
||||
const Foo = struct {
|
||||
field: ?*const i32,
|
||||
};
|
||||
};
|
||||
S.entry();
|
||||
comptime S.entry();
|
||||
}
|
||||
|
||||
@ -110,3 +110,35 @@ fn testContinueOuter() void {
|
||||
}
|
||||
expect(counter == array.len);
|
||||
}
|
||||
|
||||
test "2 break statements and an else" {
|
||||
const S = struct {
|
||||
fn entry(t: bool, f: bool) void {
|
||||
var buf: [10]u8 = undefined;
|
||||
var ok = false;
|
||||
ok = for (buf) |item| {
|
||||
if (f) break false;
|
||||
if (t) break true;
|
||||
} else false;
|
||||
expect(ok);
|
||||
}
|
||||
};
|
||||
S.entry(true, false);
|
||||
comptime S.entry(true, false);
|
||||
}
|
||||
|
||||
test "for with null and T peer types and inferred result location type" {
|
||||
const S = struct {
|
||||
fn doTheTest(slice: []const u8) void {
|
||||
if (for (slice) |item| {
|
||||
if (item == 10) {
|
||||
break item;
|
||||
}
|
||||
} else null) |v| {
|
||||
@panic("fail");
|
||||
}
|
||||
}
|
||||
};
|
||||
S.doTheTest([_]u8{ 1, 2 });
|
||||
comptime S.doTheTest([_]u8{ 1, 2 });
|
||||
}
|
||||
|
||||
@ -52,3 +52,14 @@ test "unwrap mutable global var" {
|
||||
expect(e == error.SomeError);
|
||||
}
|
||||
}
|
||||
|
||||
test "labeled break inside comptime if inside runtime if" {
|
||||
var answer: i32 = 0;
|
||||
var c = true;
|
||||
if (c) {
|
||||
answer = if (true) blk: {
|
||||
break :blk i32(42);
|
||||
};
|
||||
}
|
||||
expect(answer == 42);
|
||||
}
|
||||
|
||||
@ -698,3 +698,11 @@ test "unicode escape in character literal" {
|
||||
var a: u24 = '\U01f4a9';
|
||||
expect(a == 128169);
|
||||
}
|
||||
|
||||
test "result location zero sized array inside struct field implicit cast to slice" {
|
||||
const E = struct {
|
||||
entries: []u32,
|
||||
};
|
||||
var foo = E{ .entries = [_]u32{} };
|
||||
expect(foo.entries.len == 0);
|
||||
}
|
||||
|
||||
34
test/stage1/behavior/muladd.zig
Normal file
34
test/stage1/behavior/muladd.zig
Normal file
@ -0,0 +1,34 @@
|
||||
const expect = @import("std").testing.expect;
|
||||
|
||||
test "@mulAdd" {
|
||||
comptime testMulAdd();
|
||||
testMulAdd();
|
||||
}
|
||||
|
||||
fn testMulAdd() void {
|
||||
{
|
||||
var a: f16 = 5.5;
|
||||
var b: f16 = 2.5;
|
||||
var c: f16 = 6.25;
|
||||
expect(@mulAdd(f16, a, b, c) == 20);
|
||||
}
|
||||
{
|
||||
var a: f32 = 5.5;
|
||||
var b: f32 = 2.5;
|
||||
var c: f32 = 6.25;
|
||||
expect(@mulAdd(f32, a, b, c) == 20);
|
||||
}
|
||||
{
|
||||
var a: f64 = 5.5;
|
||||
var b: f64 = 2.5;
|
||||
var c: f64 = 6.25;
|
||||
expect(@mulAdd(f64, a, b, c) == 20);
|
||||
}
|
||||
// Awaits implementation in libm.zig
|
||||
//{
|
||||
// var a: f16 = 5.5;
|
||||
// var b: f128 = 2.5;
|
||||
// var c: f128 = 6.25;
|
||||
// expect(@mulAdd(f128, a, b, c) == 20);
|
||||
//}
|
||||
}
|
||||
@ -76,6 +76,27 @@ test "unwrap function call with optional pointer return value" {
|
||||
}
|
||||
};
|
||||
S.entry();
|
||||
// TODO https://github.com/ziglang/zig/issues/1901
|
||||
//comptime S.entry();
|
||||
comptime S.entry();
|
||||
}
|
||||
|
||||
test "nested orelse" {
|
||||
const S = struct {
|
||||
fn entry() void {
|
||||
expect(func() == null);
|
||||
}
|
||||
fn maybe() ?Foo {
|
||||
return null;
|
||||
}
|
||||
fn func() ?Foo {
|
||||
const x = maybe() orelse
|
||||
maybe() orelse
|
||||
return null;
|
||||
unreachable;
|
||||
}
|
||||
const Foo = struct {
|
||||
field: i32,
|
||||
};
|
||||
};
|
||||
S.entry();
|
||||
comptime S.entry();
|
||||
}
|
||||
|
||||
@ -578,3 +578,24 @@ test "default struct initialization fields" {
|
||||
};
|
||||
expectEqual(1239, x.a + x.b);
|
||||
}
|
||||
|
||||
test "extern fn returns struct by value" {
|
||||
const S = struct {
|
||||
fn entry() void {
|
||||
var x = makeBar(10);
|
||||
expectEqual(i32(10), x.handle);
|
||||
}
|
||||
|
||||
const ExternBar = extern struct {
|
||||
handle: i32,
|
||||
};
|
||||
|
||||
extern fn makeBar(t: i32) ExternBar {
|
||||
return ExternBar{
|
||||
.handle = t,
|
||||
};
|
||||
}
|
||||
};
|
||||
S.entry();
|
||||
comptime S.entry();
|
||||
}
|
||||
|
||||
@ -360,3 +360,34 @@ test "switch prongs with error set cases make a new error set type for capture v
|
||||
S.doTheTest();
|
||||
comptime S.doTheTest();
|
||||
}
|
||||
|
||||
test "return result loc and then switch with range implicit casted to error union" {
|
||||
const S = struct {
|
||||
fn doTheTest() void {
|
||||
expect((func(0xb) catch unreachable) == 0xb);
|
||||
}
|
||||
fn func(d: u8) anyerror!u8 {
|
||||
return switch (d) {
|
||||
0xa...0xf => d,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
};
|
||||
S.doTheTest();
|
||||
comptime S.doTheTest();
|
||||
}
|
||||
|
||||
test "switch with null and T peer types and inferred result location type" {
|
||||
const S = struct {
|
||||
fn doTheTest(c: u8) void {
|
||||
if (switch (c) {
|
||||
0 => true,
|
||||
else => null,
|
||||
}) |v| {
|
||||
@panic("fail");
|
||||
}
|
||||
}
|
||||
};
|
||||
S.doTheTest(1);
|
||||
comptime S.doTheTest(1);
|
||||
}
|
||||
|
||||
@ -402,3 +402,23 @@ test "comptime union field value equality" {
|
||||
expect(a0 != a1);
|
||||
expect(b0 != b1);
|
||||
}
|
||||
|
||||
test "return union init with void payload" {
|
||||
const S = struct {
|
||||
fn entry() void {
|
||||
expect(func().state == State.one);
|
||||
}
|
||||
const Outer = union(enum) {
|
||||
state: State,
|
||||
};
|
||||
const State = union(enum) {
|
||||
one: void,
|
||||
two: u32,
|
||||
};
|
||||
fn func() Outer {
|
||||
return Outer{ .state = State{ .one = {} }};
|
||||
}
|
||||
};
|
||||
S.entry();
|
||||
comptime S.entry();
|
||||
}
|
||||
|
||||
@ -61,3 +61,16 @@ test "vector bit operators" {
|
||||
S.doTheTest();
|
||||
comptime S.doTheTest();
|
||||
}
|
||||
|
||||
test "implicit cast vector to array" {
|
||||
const S = struct {
|
||||
fn doTheTest() void {
|
||||
var a: @Vector(4, i32) = [_]i32{ 1, 2, 3, 4 };
|
||||
var result_array: [4]i32 = a;
|
||||
result_array = a;
|
||||
expect(mem.eql(i32, result_array, [4]i32{ 1, 2, 3, 4 }));
|
||||
}
|
||||
};
|
||||
S.doTheTest();
|
||||
comptime S.doTheTest();
|
||||
}
|
||||
|
||||
@ -226,3 +226,48 @@ fn returnFalse() bool {
|
||||
fn returnTrue() bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
test "while bool 2 break statements and an else" {
|
||||
const S = struct {
|
||||
fn entry(t: bool, f: bool) void {
|
||||
var ok = false;
|
||||
ok = while (t) {
|
||||
if (f) break false;
|
||||
if (t) break true;
|
||||
} else false;
|
||||
expect(ok);
|
||||
}
|
||||
};
|
||||
S.entry(true, false);
|
||||
comptime S.entry(true, false);
|
||||
}
|
||||
|
||||
test "while optional 2 break statements and an else" {
|
||||
const S = struct {
|
||||
fn entry(opt_t: ?bool, f: bool) void {
|
||||
var ok = false;
|
||||
ok = while (opt_t) |t| {
|
||||
if (f) break false;
|
||||
if (t) break true;
|
||||
} else false;
|
||||
expect(ok);
|
||||
}
|
||||
};
|
||||
S.entry(true, false);
|
||||
comptime S.entry(true, false);
|
||||
}
|
||||
|
||||
test "while error 2 break statements and an else" {
|
||||
const S = struct {
|
||||
fn entry(opt_t: anyerror!bool, f: bool) void {
|
||||
var ok = false;
|
||||
ok = while (opt_t) |t| {
|
||||
if (f) break false;
|
||||
if (t) break true;
|
||||
} else |_| false;
|
||||
expect(ok);
|
||||
}
|
||||
};
|
||||
S.entry(true, false);
|
||||
comptime S.entry(true, false);
|
||||
}
|
||||
|
||||
@ -811,23 +811,21 @@ pub const CompileErrorContext = struct {
|
||||
pub fn addCase(self: *CompileErrorContext, case: *const TestCase) void {
|
||||
const b = self.b;
|
||||
|
||||
for (self.modes) |mode| {
|
||||
const annotated_case_name = fmt.allocPrint(self.b.allocator, "compile-error {} ({})", case.name, @tagName(mode)) catch unreachable;
|
||||
if (self.test_filter) |filter| {
|
||||
if (mem.indexOf(u8, annotated_case_name, filter) == null) continue;
|
||||
}
|
||||
const annotated_case_name = fmt.allocPrint(self.b.allocator, "compile-error {}", case.name) catch unreachable;
|
||||
if (self.test_filter) |filter| {
|
||||
if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
|
||||
}
|
||||
|
||||
const compile_and_cmp_errors = CompileCmpOutputStep.create(self, annotated_case_name, case, mode);
|
||||
self.step.dependOn(&compile_and_cmp_errors.step);
|
||||
const compile_and_cmp_errors = CompileCmpOutputStep.create(self, annotated_case_name, case, .Debug);
|
||||
self.step.dependOn(&compile_and_cmp_errors.step);
|
||||
|
||||
for (case.sources.toSliceConst()) |src_file| {
|
||||
const expanded_src_path = fs.path.join(
|
||||
b.allocator,
|
||||
[_][]const u8{ b.cache_root, src_file.filename },
|
||||
) catch unreachable;
|
||||
const write_src = b.addWriteFile(expanded_src_path, src_file.source);
|
||||
compile_and_cmp_errors.step.dependOn(&write_src.step);
|
||||
}
|
||||
for (case.sources.toSliceConst()) |src_file| {
|
||||
const expanded_src_path = fs.path.join(
|
||||
b.allocator,
|
||||
[_][]const u8{ b.cache_root, src_file.filename },
|
||||
) catch unreachable;
|
||||
const write_src = b.addWriteFile(expanded_src_path, src_file.source);
|
||||
compile_and_cmp_errors.step.dependOn(&write_src.step);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user