Merge branch 'master' into translate-c-userland

This commit is contained in:
hryx 2019-06-27 22:12:34 -07:00
commit 2060c7c39b
No known key found for this signature in database
GPG Key ID: 6A2784E15D7D95D6
63 changed files with 6631 additions and 2698 deletions

View File

@ -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"

View File

@ -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);

View File

@ -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#}

View File

@ -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]});

View File

@ -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;
};

View File

@ -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));
}

View File

@ -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);

View File

@ -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 ");

File diff suppressed because it is too large Load Diff

5192
src/ir.cpp

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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");
}

View File

@ -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);
}
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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);
};

View File

@ -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;

View File

@ -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

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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;
}
}

View 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
View 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
View 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));
}

View File

@ -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);
}

View File

@ -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));

View File

@ -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;

View File

@ -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,

View File

@ -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;
}

View File

@ -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,

View File

@ -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),
}
}

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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();
},

View File

@ -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");

View File

@ -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{

View File

@ -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;

View File

@ -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);

View File

@ -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");

View File

@ -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(

View File

@ -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");

View File

@ -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 },

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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
}

View File

@ -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);
}
}

View 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);
// }
//}

View File

@ -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();
}

View File

@ -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 });
}

View File

@ -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);
}

View File

@ -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);
}

View 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);
//}
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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);
}
}
};