diff --git a/doc/langref.html.in b/doc/langref.html.in
index 6e03d3ec6d67..9860cf061b83 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -5905,13 +5905,13 @@ fn add(a: i32, b: i32) i32 { return a + b; }
This function is a low level intrinsic with no safety mechanisms. Most code
should not use this function, instead using something like this:
- {#syntax#}for (source[0...byte_count]) |b, i| dest[i] = b;{#endsyntax#}
+ {#syntax#}for (source[0..byte_count]) |b, i| dest[i] = b;{#endsyntax#}
The optimizer is intelligent enough to turn the above snippet into a memcpy.
There is also a standard library function for this:
{#syntax#}const mem = @import("std").mem;
-mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}
+mem.copy(u8, dest[0..byte_count], source[0..byte_count]);{#endsyntax#}
{#header_close#}
{#header_open|@memset#}
@@ -5923,7 +5923,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}
This function is a low level intrinsic with no safety mechanisms. Most
code should not use this function, instead using something like this:
- {#syntax#}for (dest[0...byte_count]) |*b| b.* = c;{#endsyntax#}
+ {#syntax#}for (dest[0..byte_count]) |*b| b.* = c;{#endsyntax#}
The optimizer is intelligent enough to turn the above snippet into a memset.
@@ -6592,9 +6592,10 @@ pub const TypeInfo = union(TypeId) {
{#header_close#}
{#header_open|@typeName#}
- {#syntax#}@typeName(T: type) []u8{#endsyntax#}
+ {#syntax#}@typeName(T: type) [N]u8{#endsyntax#}
- This function returns the string representation of a type.
+ This function returns the string representation of a type, as
+ an array. It is equivalent to a string literal of the type name.
{#header_close#}
diff --git a/src/all_types.hpp b/src/all_types.hpp
index 91b24e311059..e169b84020c2 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -33,7 +33,8 @@ struct TypeStructField;
struct CodeGen;
struct ConstExprValue;
struct IrInstruction;
-struct IrInstructionCast;
+struct IrInstructionAllocaGen;
+struct IrInstructionResultPtrCast;
struct IrBasicBlock;
struct ScopeDecls;
struct ZigWindowsSDK;
@@ -56,9 +57,6 @@ struct IrExecutable {
size_t next_debug_id;
size_t *backward_branch_count;
size_t backward_branch_quota;
- bool invalid;
- bool is_inline;
- bool is_generic_instantiation;
ZigFn *fn_entry;
Buf *c_import_buf;
AstNode *source_node;
@@ -78,6 +76,10 @@ struct IrExecutable {
IrBasicBlock *coro_suspend_block;
IrBasicBlock *coro_final_cleanup_block;
ZigVar *coro_allocator_var;
+
+ bool invalid;
+ bool is_inline;
+ bool is_generic_instantiation;
};
enum OutType {
@@ -90,6 +92,9 @@ enum OutType {
enum ConstParentId {
ConstParentIdNone,
ConstParentIdStruct,
+ ConstParentIdErrUnionCode,
+ ConstParentIdErrUnionPayload,
+ ConstParentIdOptionalPayload,
ConstParentIdArray,
ConstParentIdUnion,
ConstParentIdScalar,
@@ -107,6 +112,15 @@ struct ConstParent {
ConstExprValue *struct_val;
size_t field_index;
} p_struct;
+ struct {
+ ConstExprValue *err_union_val;
+ } p_err_union_code;
+ struct {
+ ConstExprValue *err_union_val;
+ } p_err_union_payload;
+ struct {
+ ConstExprValue *optional_val;
+ } p_optional_payload;
struct {
ConstExprValue *union_val;
} p_union;
@@ -118,13 +132,11 @@ struct ConstParent {
struct ConstStructValue {
ConstExprValue *fields;
- ConstParent parent;
};
struct ConstUnionValue {
BigInt tag;
ConstExprValue *payload;
- ConstParent parent;
};
enum ConstArraySpecial {
@@ -138,7 +150,6 @@ struct ConstArrayValue {
union {
struct {
ConstExprValue *elements;
- ConstParent parent;
} s_none;
Buf *s_buf;
} data;
@@ -153,19 +164,29 @@ enum ConstPtrSpecial {
ConstPtrSpecialBaseArray,
// The pointer points to a field in an underlying struct.
ConstPtrSpecialBaseStruct,
+ // The pointer points to the error set field of an error union
+ ConstPtrSpecialBaseErrorUnionCode,
+ // The pointer points to the payload field of an error union
+ ConstPtrSpecialBaseErrorUnionPayload,
+ // The pointer points to the payload field of an optional
+ ConstPtrSpecialBaseOptionalPayload,
// This means that we did a compile-time pointer reinterpret and we cannot
// understand the value of pointee at compile time. However, we will still
// emit a binary with a compile time known address.
// In this case index is the numeric address value.
- // We also use this for null pointer. We need the data layout for ConstCastOnly == true
- // types to be the same, so all optionals of pointer types use x_ptr
- // instead of x_optional
ConstPtrSpecialHardCodedAddr,
// This means that the pointer represents memory of assigning to _.
// That is, storing discards the data, and loading is invalid.
ConstPtrSpecialDiscard,
// This is actually a function.
ConstPtrSpecialFunction,
+ // This means the pointer is null. This is only allowed when the type is ?*T.
+ // We use this instead of ConstPtrSpecialHardCodedAddr because often we check
+ // for that value to avoid doing comptime work.
+ // We need the data layout for ConstCastOnly == true
+ // types to be the same, so all optionals of pointer types use x_ptr
+ // instead of x_optional.
+ ConstPtrSpecialNull,
};
enum ConstPtrMut {
@@ -178,6 +199,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 {
@@ -199,6 +223,15 @@ struct ConstPtrValue {
ConstExprValue *struct_val;
size_t field_index;
} base_struct;
+ struct {
+ ConstExprValue *err_union_val;
+ } base_err_union_code;
+ struct {
+ ConstExprValue *err_union_val;
+ } base_err_union_payload;
+ struct {
+ ConstExprValue *optional_val;
+ } base_optional_payload;
struct {
uint64_t addr;
} hard_coded_addr;
@@ -209,7 +242,7 @@ struct ConstPtrValue {
};
struct ConstErrValue {
- ErrorTableEntry *err;
+ ConstExprValue *error_set;
ConstExprValue *payload;
};
@@ -265,6 +298,7 @@ struct ConstGlobalRefs {
struct ConstExprValue {
ZigType *type;
ConstValSpecial special;
+ ConstParent parent;
ConstGlobalRefs *global_refs;
union {
@@ -433,13 +467,14 @@ enum NodeType {
NodeTypeArrayType,
NodeTypeErrorType,
NodeTypeIfErrorExpr,
- NodeTypeTestExpr,
+ NodeTypeIfOptional,
NodeTypeErrorSetDecl,
NodeTypeCancel,
NodeTypeResume,
NodeTypeAwaitExpr,
NodeTypeSuspend,
NodeTypePromiseType,
+ NodeTypeErrorLiteral,
};
enum CallingConvention {
@@ -604,11 +639,9 @@ enum CastOp {
CastOpIntToFloat,
CastOpFloatToInt,
CastOpBoolToInt,
- CastOpResizeSlice,
CastOpNumLitToConcrete,
CastOpErrSet,
CastOpBitCast,
- CastOpPtrOfArrayToSlice,
};
struct AstNodeFnCallExpr {
@@ -677,7 +710,7 @@ struct AstNodeUse {
AstNode *expr;
TldResolution resolution;
- IrInstruction *value;
+ ConstExprValue *value;
};
struct AstNodeIfBoolExpr {
@@ -910,6 +943,10 @@ struct AstNodePromiseType {
AstNode *payload_type; // can be NULL
};
+struct AstNodeErrorLiteral {
+ Buf *name;
+};
+
struct AstNode {
enum NodeType type;
size_t line;
@@ -970,6 +1007,7 @@ struct AstNode {
AstNodeAwaitExpr await_expr;
AstNodeSuspend suspend;
AstNodePromiseType promise_type;
+ AstNodeErrorLiteral error_literal;
} data;
};
@@ -1313,7 +1351,7 @@ struct ZigFn {
AstNode *fn_no_inline_set_node;
AstNode *fn_static_eval_set_node;
- ZigList alloca_list;
+ ZigList alloca_list;
ZigList variable_list;
Buf *section_name;
@@ -1610,7 +1648,7 @@ struct CodeGen {
HashMap fn_type_table;
HashMap error_table;
HashMap generic_table;
- HashMap memoized_fn_eval_table;
+ HashMap memoized_fn_eval_table;
HashMap llvm_fn_table;
HashMap exported_symbol_names;
HashMap external_prototypes;
@@ -1646,6 +1684,7 @@ struct CodeGen {
ZigType *entry_c_int[CIntTypeCount];
ZigType *entry_c_longdouble;
ZigType *entry_c_void;
+ ZigType *entry_infer;
ZigType *entry_u8;
ZigType *entry_u16;
ZigType *entry_u32;
@@ -1802,10 +1841,9 @@ enum VarLinkage {
struct ZigVar {
Buf name;
- ConstExprValue *value;
+ ConstExprValue *const_value;
+ ZigType *var_type;
LLVMValueRef value_ref;
- bool src_is_const;
- bool gen_is_const;
IrInstruction *is_comptime;
// which node is the declaration of the variable
AstNode *decl_node;
@@ -1815,17 +1853,21 @@ struct ZigVar {
Scope *parent_scope;
Scope *child_scope;
LLVMValueRef param_value_ref;
- bool shadowable;
size_t mem_slot_index;
IrExecutable *owner_exec;
size_t ref_count;
- VarLinkage linkage;
- uint32_t align_bytes;
// In an inline loop, multiple variables may be created,
// In this case, a reference to a variable should follow
// this pointer to the redefined variable.
ZigVar *next_var;
+
+ uint32_t align_bytes;
+ VarLinkage linkage;
+
+ bool shadowable;
+ bool src_is_const;
+ bool gen_is_const;
};
struct ErrorTableEntry {
@@ -1838,6 +1880,22 @@ struct ErrorTableEntry {
ConstExprValue *cached_error_name_val;
};
+enum LVal {
+ // The instruction must return the actual value.
+ LValNone,
+ // The instruction must return a pointer to the actual value.
+ LValPtr,
+ // The instruction must populate the result location, which is
+ // an error union, and return the optional error code value.
+ LValErrorUnionVal,
+ // The instruction must populate the result location, which is
+ // an error union, and return a pointer to optional error code value.
+ LValErrorUnionPtr,
+ // The instruction must populate the result location, which is
+ // an optional, and return non-null bool value.
+ LValOptional,
+};
+
enum ScopeId {
ScopeIdDecls,
ScopeIdBlock,
@@ -1888,13 +1946,16 @@ struct ScopeBlock {
Buf *name;
IrBasicBlock *end_block;
IrInstruction *is_comptime;
+ IrInstruction *result_loc;
ZigList *incoming_values;
ZigList *incoming_blocks;
- bool safety_off;
AstNode *safety_set_node;
- bool fast_math_on;
AstNode *fast_math_set_node;
+
+ LVal lval;
+ bool safety_off;
+ bool fast_math_on;
};
// This scope is created from every defer expression.
@@ -1940,6 +2001,7 @@ struct ScopeLoop {
IrBasicBlock *break_block;
IrBasicBlock *continue_block;
IrInstruction *is_comptime;
+ IrInstruction *result_loc;
ZigList *incoming_values;
ZigList *incoming_blocks;
};
@@ -2030,8 +2092,19 @@ struct IrBasicBlock {
IrInstruction *must_be_comptime_source_instr;
};
+// These instructions are in transition to having "pass 1" instructions
+// and "pass 2" instructions. The pass 1 instructions are suffixed with Src
+// and pass 2 are suffixed with Gen.
+// Once all instructions are separated in this way, they'll have different
+// base types for better type safety.
+// Src instructions are generated by ir_gen_* functions in ir.cpp from AST.
+// ir_analyze_* functions consume Src instructions and produce Gen instructions.
+// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR.
+// Src instructions do not have type information; Gen instructions do.
enum IrInstructionId {
IrInstructionIdInvalid,
+ IrInstructionIdDeclVarSrc,
+ IrInstructionIdDeclVarGen,
IrInstructionIdBr,
IrInstructionIdCondBr,
IrInstructionIdSwitchBr,
@@ -2040,7 +2113,6 @@ enum IrInstructionId {
IrInstructionIdPhi,
IrInstructionIdUnOp,
IrInstructionIdBinOp,
- IrInstructionIdDeclVar,
IrInstructionIdLoadPtr,
IrInstructionIdStorePtr,
IrInstructionIdFieldPtr,
@@ -2054,8 +2126,6 @@ enum IrInstructionId {
IrInstructionIdCast,
IrInstructionIdContainerInitList,
IrInstructionIdContainerInitFields,
- IrInstructionIdStructInit,
- IrInstructionIdUnionInit,
IrInstructionIdUnreachable,
IrInstructionIdTypeOf,
IrInstructionIdToPtrType,
@@ -2069,7 +2139,8 @@ enum IrInstructionId {
IrInstructionIdAsm,
IrInstructionIdSizeOf,
IrInstructionIdTestNonNull,
- IrInstructionIdUnwrapOptional,
+ IrInstructionIdOptionalUnwrapPtr,
+ IrInstructionIdOptionalUnwrapVal,
IrInstructionIdOptionalWrap,
IrInstructionIdUnionTag,
IrInstructionIdClz,
@@ -2085,7 +2156,8 @@ enum IrInstructionId {
IrInstructionIdCompileLog,
IrInstructionIdErrName,
IrInstructionIdEmbedFile,
- IrInstructionIdCmpxchg,
+ IrInstructionIdCmpxchgSrc,
+ IrInstructionIdCmpxchgGen,
IrInstructionIdFence,
IrInstructionIdTruncate,
IrInstructionIdIntCast,
@@ -2114,8 +2186,8 @@ enum IrInstructionId {
IrInstructionIdErrWrapPayload,
IrInstructionIdFnProto,
IrInstructionIdTestComptime,
- IrInstructionIdPtrCast,
- IrInstructionIdBitCast,
+ IrInstructionIdPtrCastSrc,
+ IrInstructionIdPtrCastGen,
IrInstructionIdWidenOrShorten,
IrInstructionIdIntToPtr,
IrInstructionIdPtrToInt,
@@ -2170,9 +2242,35 @@ enum IrInstructionId {
IrInstructionIdBswap,
IrInstructionIdBitReverse,
IrInstructionIdErrSetCast,
- IrInstructionIdToBytes,
- IrInstructionIdFromBytes,
IrInstructionIdCheckRuntimeScope,
+ IrInstructionIdResultOptionalPayload,
+ IrInstructionIdResultErrorUnionPayload,
+ IrInstructionIdResultErrorUnionCode,
+ IrInstructionIdResultSlicePtr,
+ IrInstructionIdResultReturn,
+ IrInstructionIdResultChild,
+ IrInstructionIdResultBytesToSlice,
+ IrInstructionIdResultSliceToBytesSrc,
+ IrInstructionIdResultSliceToBytesPlaceholder,
+ IrInstructionIdResultSliceToBytesGen,
+ IrInstructionIdResultPtrCast,
+ IrInstructionIdResultCast,
+ IrInstructionIdAllocaSrc,
+ IrInstructionIdAllocaGen,
+ IrInstructionIdAssertNonError,
+ IrInstructionIdAssertNonNull,
+ IrInstructionIdErrorUnionFieldErrorSet,
+ IrInstructionIdFirstArgResultLoc,
+ IrInstructionIdInferArrayType,
+ IrInstructionIdInferCompTime,
+ IrInstructionIdFromBytesLenSrc,
+ IrInstructionIdFromBytesLenGen,
+ IrInstructionIdToBytesLenSrc,
+ IrInstructionIdToBytesLenGen,
+ IrInstructionIdSetNonNullBit,
+ IrInstructionIdErrorLiteral,
+ IrInstructionIdPtrOfArrayToSlice,
+ IrInstructionIdArrayToSlice,
};
struct IrInstruction {
@@ -2194,6 +2292,22 @@ struct IrInstruction {
bool is_gen;
};
+struct IrInstructionDeclVarSrc {
+ IrInstruction base;
+
+ ZigVar *var;
+ IrInstruction *var_type;
+ IrInstruction *align_value;
+ IrInstruction *ptr;
+};
+
+struct IrInstructionDeclVarGen {
+ IrInstruction base;
+
+ ZigVar *var;
+ IrInstruction *var_ptr;
+};
+
struct IrInstructionCondBr {
IrInstruction base;
@@ -2201,6 +2315,7 @@ struct IrInstructionCondBr {
IrBasicBlock *then_block;
IrBasicBlock *else_block;
IrInstruction *is_comptime;
+ IrInstruction *result_loc;
};
struct IrInstructionBr {
@@ -2224,6 +2339,7 @@ struct IrInstructionSwitchBr {
IrInstructionSwitchBrCase *cases;
IrInstruction *is_comptime;
IrInstruction *switch_prongs_void;
+ IrInstruction *result_loc;
};
struct IrInstructionSwitchVar {
@@ -2302,24 +2418,16 @@ struct IrInstructionBinOp {
IrInstruction base;
IrInstruction *op1;
- IrBinOp op_id;
IrInstruction *op2;
+ IrBinOp op_id;
bool safety_check_on;
};
-struct IrInstructionDeclVar {
- IrInstruction base;
-
- ZigVar *var;
- IrInstruction *var_type;
- IrInstruction *align_value;
- IrInstruction *init_value;
-};
-
struct IrInstructionLoadPtr {
IrInstruction base;
IrInstruction *ptr;
+ IrInstruction *result_loc;
};
struct IrInstructionStorePtr {
@@ -2335,7 +2443,8 @@ struct IrInstructionFieldPtr {
IrInstruction *container_ptr;
Buf *field_name_buffer;
IrInstruction *field_name_expr;
- bool is_const;
+ IrInstruction *container_type;
+ bool initialize;
};
struct IrInstructionStructFieldPtr {
@@ -2346,12 +2455,18 @@ struct IrInstructionStructFieldPtr {
bool is_const;
};
+enum IrInstructionUnionFieldPtrId {
+ IrInstructionUnionFieldPtrIdRef,
+ IrInstructionUnionFieldPtrIdSwitch,
+ IrInstructionUnionFieldPtrIdResultPtr,
+};
+
struct IrInstructionUnionFieldPtr {
IrInstruction base;
IrInstruction *union_ptr;
TypeUnionField *field;
- bool is_const;
+ IrInstructionUnionFieldPtrId id;
};
struct IrInstructionElemPtr {
@@ -2378,13 +2493,14 @@ struct IrInstructionCall {
ZigFn *fn_entry;
size_t arg_count;
IrInstruction **args;
- bool is_comptime;
- LLVMValueRef tmp_ptr;
- FnInline fn_inline;
- bool is_async;
-
IrInstruction *async_allocator;
IrInstruction *new_stack;
+ IrInstruction *result_loc;
+ IrInstruction *first_arg_result_loc;
+ FnInline fn_inline;
+ LVal lval;
+ bool is_async;
+ bool is_comptime;
};
struct IrInstructionConst {
@@ -2398,6 +2514,7 @@ struct IrInstructionReturn {
IrInstruction base;
IrInstruction *value;
+ IrInstruction *result_loc;
};
// TODO get rid of this instruction, replace with instructions for each op code
@@ -2405,23 +2522,37 @@ struct IrInstructionCast {
IrInstruction base;
IrInstruction *value;
+ IrInstruction *result_loc;
ZigType *dest_type;
CastOp cast_op;
- LLVMValueRef tmp_ptr;
+};
+
+struct IrInstructionPtrOfArrayToSlice {
+ IrInstruction base;
+
+ IrInstruction *value;
+ IrInstruction *result_loc;
+};
+
+struct IrInstructionArrayToSlice {
+ IrInstruction base;
+
+ IrInstruction *array;
+ IrInstruction *result_loc;
};
struct IrInstructionContainerInitList {
IrInstruction base;
IrInstruction *container_type;
- size_t item_count;
- IrInstruction **items;
- LLVMValueRef tmp_ptr;
+ IrInstruction *result_loc;
+ size_t elem_count;
+ IrInstruction **elem_result_loc_list;
};
struct IrInstructionContainerInitFieldsField {
Buf *name;
- IrInstruction *value;
+ IrInstruction *result_loc;
AstNode *source_node;
TypeStructField *type_struct_field;
};
@@ -2432,29 +2563,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 {
@@ -2527,9 +2636,9 @@ struct IrInstructionSliceType {
IrInstruction base;
IrInstruction *align_value;
+ IrInstruction *child_type;
bool is_const;
bool is_volatile;
- IrInstruction *child_type;
};
struct IrInstructionAsm {
@@ -2557,10 +2666,20 @@ struct IrInstructionTestNonNull {
IrInstruction *value;
};
-struct IrInstructionUnwrapOptional {
+// Takes a pointer to an optional value, returns a pointer
+// to the payload.
+struct IrInstructionOptionalUnwrapPtr {
IrInstruction base;
- IrInstruction *value;
+ IrInstruction *base_ptr;
+ bool safety_check_on;
+};
+
+// Takes an optional value, returns the payload.
+struct IrInstructionOptionalUnwrapVal {
+ IrInstruction base;
+
+ IrInstruction *opt;
bool safety_check_on;
};
@@ -2598,7 +2717,7 @@ struct IrInstructionRef {
IrInstruction base;
IrInstruction *value;
- LLVMValueRef tmp_ptr;
+ IrInstruction *result_loc;
bool is_const;
bool is_volatile;
};
@@ -2651,7 +2770,7 @@ struct IrInstructionEmbedFile {
IrInstruction *name;
};
-struct IrInstructionCmpxchg {
+struct IrInstructionCmpxchgSrc {
IrInstruction base;
IrInstruction *type_value;
@@ -2660,15 +2779,24 @@ struct IrInstructionCmpxchg {
IrInstruction *new_value;
IrInstruction *success_order_value;
IrInstruction *failure_order_value;
+ IrInstruction *result_loc;
+
+ bool is_weak;
+};
+
+struct IrInstructionCmpxchgGen {
+ IrInstruction base;
- // if this instruction gets to runtime then we know these values:
ZigType *type;
+ IrInstruction *ptr;
+ IrInstruction *cmp_value;
+ IrInstruction *new_value;
+ IrInstruction *result_loc;
+
AtomicOrder success_order;
AtomicOrder failure_order;
bool is_weak;
-
- LLVMValueRef tmp_ptr;
};
struct IrInstructionFence {
@@ -2708,19 +2836,6 @@ struct IrInstructionErrSetCast {
IrInstruction *target;
};
-struct IrInstructionToBytes {
- IrInstruction base;
-
- IrInstruction *target;
-};
-
-struct IrInstructionFromBytes {
- IrInstruction base;
-
- IrInstruction *dest_child_type;
- IrInstruction *target;
-};
-
struct IrInstructionIntToFloat {
IrInstruction base;
@@ -2776,8 +2891,8 @@ struct IrInstructionSlice {
IrInstruction *ptr;
IrInstruction *start;
IrInstruction *end;
+ IrInstruction *result_loc;
bool safety_check_on;
- LLVMValueRef tmp_ptr;
};
struct IrInstructionMemberCount {
@@ -2851,13 +2966,21 @@ struct IrInstructionTestErr {
struct IrInstructionUnwrapErrCode {
IrInstruction base;
- IrInstruction *value;
+ IrInstruction *err_union;
+};
+
+struct IrInstructionErrorUnionFieldErrorSet {
+ IrInstruction base;
+
+ IrInstruction *ptr;
+ bool safety_check_on;
};
struct IrInstructionUnwrapErrPayload {
IrInstruction base;
IrInstruction *value;
+ IrInstruction *result_loc;
bool safety_check_on;
};
@@ -2865,21 +2988,21 @@ struct IrInstructionOptionalWrap {
IrInstruction base;
IrInstruction *value;
- LLVMValueRef tmp_ptr;
+ IrInstruction *result_loc;
};
struct IrInstructionErrWrapPayload {
IrInstruction base;
IrInstruction *value;
- LLVMValueRef tmp_ptr;
+ IrInstruction *result_loc;
};
struct IrInstructionErrWrapCode {
IrInstruction base;
IrInstruction *value;
- LLVMValueRef tmp_ptr;
+ IrInstruction *result_loc;
};
struct IrInstructionFnProto {
@@ -2899,18 +3022,24 @@ struct IrInstructionTestComptime {
IrInstruction *value;
};
-struct IrInstructionPtrCast {
+struct IrInstructionPtrCastSrc {
IrInstruction base;
IrInstruction *dest_type;
IrInstruction *ptr;
};
-struct IrInstructionBitCast {
+struct IrInstructionPtrCastGen {
IrInstruction base;
- IrInstruction *dest_type;
- IrInstruction *value;
+ IrInstruction *ptr;
+
+ // This instruction supports being created with the child
+ // type of the pointer being "infer" which means that a later
+ // instruction will replace this one.
+ // so we have a reference here to the pass-1 instruction so that
+ // the child pointer can be updated to the new pass-2 instruction.
+ IrInstruction *pass1_parent;
};
struct IrInstructionWidenOrShorten {
@@ -2983,16 +3112,10 @@ struct IrInstructionTypeName {
IrInstruction *type_value;
};
-enum LVal {
- LValNone,
- LValPtr,
-};
-
struct IrInstructionDeclRef {
IrInstruction base;
Tld *tld;
- LVal lval;
};
struct IrInstructionPanic {
@@ -3262,6 +3385,181 @@ struct IrInstructionCheckRuntimeScope {
IrInstruction *is_comptime;
};
+struct IrInstructionResultErrorUnionPayload {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+};
+
+struct IrInstructionResultErrorUnionCode {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+};
+
+struct IrInstructionResultOptionalPayload {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+ IrInstruction *payload_type;
+ bool make_non_null;
+};
+
+struct IrInstructionResultBytesToSlice {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+};
+
+struct IrInstructionResultSliceToBytesSrc {
+ IrInstruction base;
+
+ IrInstruction *elem_type;
+ IrInstruction *prev_result_loc;
+};
+
+struct IrInstructionResultSliceToBytesPlaceholder {
+ IrInstruction base;
+
+ ZigType *elem_type;
+ IrInstruction *prev_result_loc;
+ IrInstruction *pass1_parent;
+};
+
+struct IrInstructionResultSliceToBytesGen {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+};
+
+struct IrInstructionResultSlicePtr {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+ IrInstruction *array_loc;
+ uint64_t len;
+};
+
+struct IrInstructionResultReturn {
+ IrInstruction base;
+};
+
+struct IrInstructionResultChild {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+ LVal lval;
+};
+
+struct IrInstructionResultPtrCast {
+ IrInstruction base;
+
+ IrInstruction *elem_type;
+ IrInstruction *prev_result_loc;
+};
+
+struct IrInstructionResultCast {
+ IrInstruction base;
+
+ IrInstruction *elem_type;
+ IrInstruction *prev_result_loc;
+};
+
+struct IrInstructionAllocaSrc {
+ IrInstruction base;
+
+ // TODO: remove this field. use implicit casts instead.
+ IrInstruction *child_type;
+ IrInstruction *align;
+ IrInstruction *is_comptime;
+ const char *name_hint;
+};
+
+struct IrInstructionAllocaGen {
+ IrInstruction base;
+
+ uint32_t align;
+ const char *name_hint;
+};
+
+struct IrInstructionAssertNonError {
+ IrInstruction base;
+
+ IrInstruction *err_code;
+};
+
+// This is the safety check when using `.?`.
+struct IrInstructionAssertNonNull {
+ IrInstruction base;
+
+ IrInstruction *is_non_null;
+};
+
+struct IrInstructionFirstArgResultLoc {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+ IrInstruction *fn_ref;
+};
+
+struct IrInstructionInferArrayType {
+ IrInstruction base;
+
+ IrInstruction *src_type;
+ size_t elem_count;
+};
+
+struct IrInstructionInferCompTime {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+ IrInstruction *new_result_loc;
+};
+
+struct IrInstructionSetNonNullBit {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+ IrInstruction *non_null_bit;
+ IrInstruction *new_result_loc;
+};
+
+// This is the instruction for the syntax:
+// `error.Foo`
+struct IrInstructionErrorLiteral {
+ IrInstruction base;
+
+ Buf *name;
+};
+
+struct IrInstructionFromBytesLenSrc {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+ IrInstruction *new_result_loc;
+};
+
+struct IrInstructionFromBytesLenGen {
+ IrInstruction base;
+
+ ZigType *elem_type;
+ IrInstruction *prev_result_loc;
+};
+
+struct IrInstructionToBytesLenSrc {
+ IrInstruction base;
+
+ IrInstruction *prev_result_loc;
+ IrInstruction *new_result_loc;
+};
+
+struct IrInstructionToBytesLenGen {
+ IrInstruction base;
+
+ ZigType *elem_type;
+ IrInstruction *prev_result_loc;
+};
+
struct IrInstructionBswap {
IrInstruction base;
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 00eb38de9e19..9f416a486c7b 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -405,7 +405,9 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
uint32_t bit_offset_in_host, uint32_t host_int_bytes)
{
assert(!type_is_invalid(child_type));
- assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque);
+ assert(ptr_len == PtrLenSingle ||
+ child_type->id != ZigTypeIdOpaque ||
+ child_type == g->builtin_types.entry_infer);
if (byte_alignment != 0) {
uint32_t abi_alignment = get_abi_alignment(g, child_type);
@@ -570,7 +572,7 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type) {
if (child_type->zero_bits) {
entry->type_ref = LLVMInt1Type();
entry->di_type = g->builtin_types.entry_bool->di_type;
- } else if (type_is_codegen_pointer(child_type)) {
+ } else if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) {
assert(child_type->di_type);
// this is an optimization but also is necessary for calling C
// functions where all pointers are maybe pointers
@@ -1137,6 +1139,24 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
ZigType *gen_return_type;
if (is_async) {
gen_return_type = get_pointer_to_type(g, g->builtin_types.entry_u8, false);
+ } else if (fn_type_id->return_type->id == ZigTypeIdErrorUnion) {
+ ZigType *payload_type = fn_type_id->return_type->data.error_union.payload_type;
+ if (type_has_bits(payload_type)) {
+ ZigType *gen_type = get_pointer_to_type(g, payload_type, false);
+ gen_param_types.append(gen_type->type_ref);
+ param_di_types.append(gen_type->di_type);
+ }
+ gen_return_type = g->builtin_types.entry_global_error_set;
+ } else if (fn_type_id->return_type->id == ZigTypeIdOptional) {
+ if (handle_is_ptr(fn_type_id->return_type)) {
+ ZigType *payload_type = fn_type_id->return_type->data.maybe.child_type;
+ ZigType *gen_type = get_pointer_to_type(g, payload_type, false);
+ gen_param_types.append(gen_type->type_ref);
+ param_di_types.append(gen_type->di_type);
+ gen_return_type = g->builtin_types.entry_bool;
+ } else {
+ gen_return_type = fn_type_id->return_type;
+ }
} else if (!type_has_bits(fn_type_id->return_type)) {
gen_return_type = g->builtin_types.entry_void;
} else if (first_arg_return) {
@@ -1278,7 +1298,9 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind
return entry;
}
-static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name) {
+static ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry,
+ Buf *type_name)
+{
size_t backward_branch_count = 0;
return ir_eval_const_value(g, scope, node, type_entry,
&backward_branch_count, default_backward_branch_quota,
@@ -1286,12 +1308,12 @@ static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *nod
}
ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) {
- IrInstruction *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr);
- if (result->value.type->id == ZigTypeIdInvalid)
+ ConstExprValue *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr);
+ if (type_is_invalid(result->type))
return g->builtin_types.entry_invalid;
- assert(result->value.special != ConstValSpecialRuntime);
- return result->value.data.x_type;
+ assert(result->special != ConstValSpecialRuntime);
+ return result->data.x_type;
}
ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
@@ -1342,11 +1364,11 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou
}
static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_t *result) {
- IrInstruction *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr);
- if (type_is_invalid(align_result->value.type))
+ ConstExprValue *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr);
+ if (type_is_invalid(align_result->type))
return false;
- uint32_t align_bytes = bigint_as_unsigned(&align_result->value.data.x_bigint);
+ uint32_t align_bytes = bigint_as_unsigned(&align_result->data.x_bigint);
if (align_bytes == 0) {
add_node_error(g, node, buf_sprintf("alignment must be >= 1"));
return false;
@@ -1364,12 +1386,12 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **
ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
PtrLenUnknown, 0, 0, 0);
ZigType *str_type = get_slice_type(g, ptr_type);
- IrInstruction *instr = analyze_const_value(g, scope, node, str_type, nullptr);
- if (type_is_invalid(instr->value.type))
+ ConstExprValue *result_val = analyze_const_value(g, scope, node, str_type, nullptr);
+ if (type_is_invalid(result_val->type))
return false;
- ConstExprValue *ptr_field = &instr->value.data.x_struct.fields[slice_ptr_index];
- ConstExprValue *len_field = &instr->value.data.x_struct.fields[slice_len_index];
+ ConstExprValue *ptr_field = &result_val->data.x_struct.fields[slice_ptr_index];
+ ConstExprValue *len_field = &result_val->data.x_struct.fields[slice_len_index];
assert(ptr_field->data.x_ptr.special == ConstPtrSpecialBaseArray);
ConstExprValue *array_val = ptr_field->data.x_ptr.data.base_array.array_val;
@@ -2504,20 +2526,20 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
// In this first pass we resolve explicit tag values.
// In a second pass we will fill in the unspecified ones.
if (tag_value != nullptr) {
- IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
- if (result_inst->value.type->id == ZigTypeIdInvalid) {
+ ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
+ if (type_is_invalid(result->type)) {
enum_type->data.enumeration.is_invalid = true;
continue;
}
- assert(result_inst->value.special != ConstValSpecialRuntime);
- assert(result_inst->value.type->id == ZigTypeIdInt ||
- result_inst->value.type->id == ZigTypeIdComptimeInt);
- auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);
+ assert(result->special != ConstValSpecialRuntime);
+ assert(result->type->id == ZigTypeIdInt ||
+ result->type->id == ZigTypeIdComptimeInt);
+ auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value);
if (entry == nullptr) {
- bigint_init_bigint(&type_enum_field->value, &result_inst->value.data.x_bigint);
+ bigint_init_bigint(&type_enum_field->value, &result->data.x_bigint);
} else {
Buf *val_buf = buf_alloc();
- bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10);
+ bigint_append_buf(val_buf, &result->data.x_bigint, 10);
ErrorMsg *msg = add_node_error(g, tag_value,
buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf)));
@@ -2944,19 +2966,19 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
// In a second pass we will fill in the unspecified ones.
if (tag_value != nullptr) {
ZigType *tag_int_type = tag_type->data.enumeration.tag_int_type;
- IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
- if (result_inst->value.type->id == ZigTypeIdInvalid) {
+ ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
+ if (result->type->id == ZigTypeIdInvalid) {
union_type->data.unionation.is_invalid = true;
continue;
}
- assert(result_inst->value.special != ConstValSpecialRuntime);
- assert(result_inst->value.type->id == ZigTypeIdInt);
- auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);
+ assert(result->special != ConstValSpecialRuntime);
+ assert(result->type->id == ZigTypeIdInt);
+ auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value);
if (entry == nullptr) {
- bigint_init_bigint(&union_field->enum_field->value, &result_inst->value.data.x_bigint);
+ bigint_init_bigint(&union_field->enum_field->value, &result->data.x_bigint);
} else {
Buf *val_buf = buf_alloc();
- bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10);
+ bigint_append_buf(val_buf, &result->data.x_bigint, 10);
ErrorMsg *msg = add_node_error(g, tag_value,
buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf)));
@@ -3419,7 +3441,8 @@ void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value) {
resolve_top_level_decl(g, tld, false, tld->source_node);
assert(tld->id == TldIdVar);
TldVar *tld_var = (TldVar *)tld;
- tld_var->var->value = value;
+ tld_var->var->const_value = value;
+ tld_var->var->var_type = value->type;
tld_var->var->align_bytes = get_abi_alignment(g, value->type);
}
@@ -3513,13 +3536,14 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
case NodeTypeArrayType:
case NodeTypeErrorType:
case NodeTypeIfErrorExpr:
- case NodeTypeTestExpr:
+ case NodeTypeIfOptional:
case NodeTypeErrorSetDecl:
case NodeTypeCancel:
case NodeTypeResume:
case NodeTypeAwaitExpr:
case NodeTypeSuspend:
case NodeTypePromiseType:
+ case NodeTypeErrorLiteral:
zig_unreachable();
}
}
@@ -3582,13 +3606,15 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry
// Set name to nullptr to make the variable anonymous (not visible to programmer).
// TODO merge with definition of add_local_var in ir.cpp
ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,
- bool is_const, ConstExprValue *value, Tld *src_tld)
+ bool is_const, ConstExprValue *const_value, Tld *src_tld, ZigType *var_type)
{
Error err;
- assert(value);
+ assert(const_value != nullptr);
+ assert(var_type != nullptr);
ZigVar *variable_entry = allocate(1);
- variable_entry->value = value;
+ variable_entry->const_value = const_value;
+ variable_entry->var_type = var_type;
variable_entry->parent_scope = parent_scope;
variable_entry->shadowable = false;
variable_entry->mem_slot_index = SIZE_MAX;
@@ -3597,23 +3623,23 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf
assert(name);
buf_init_from_buf(&variable_entry->name, name);
- if ((err = type_resolve(g, value->type, ResolveStatusAlignmentKnown))) {
- variable_entry->value->type = g->builtin_types.entry_invalid;
+ if ((err = type_resolve(g, var_type, ResolveStatusAlignmentKnown))) {
+ variable_entry->var_type = g->builtin_types.entry_invalid;
} else {
- variable_entry->align_bytes = get_abi_alignment(g, value->type);
+ variable_entry->align_bytes = get_abi_alignment(g, var_type);
ZigVar *existing_var = find_variable(g, parent_scope, name, nullptr);
if (existing_var && !existing_var->shadowable) {
ErrorMsg *msg = add_node_error(g, source_node,
buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
- variable_entry->value->type = g->builtin_types.entry_invalid;
+ variable_entry->var_type = g->builtin_types.entry_invalid;
} else {
ZigType *type;
if (get_primitive_type(g, name, &type) != ErrorPrimitiveTypeNotFound) {
add_node_error(g, source_node,
buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name)));
- variable_entry->value->type = g->builtin_types.entry_invalid;
+ variable_entry->var_type = g->builtin_types.entry_invalid;
} else {
Scope *search_scope = nullptr;
if (src_tld == nullptr) {
@@ -3627,7 +3653,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf
ErrorMsg *msg = add_node_error(g, source_node,
buf_sprintf("redefinition of '%s'", buf_ptr(name)));
add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition is here"));
- variable_entry->value->type = g->builtin_types.entry_invalid;
+ variable_entry->var_type = g->builtin_types.entry_invalid;
}
}
}
@@ -3677,7 +3703,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
linkage = VarLinkageInternal;
}
- IrInstruction *init_value = nullptr;
+ ConstExprValue *init_value = nullptr;
// TODO more validation for types that can't be used for export/extern variables
ZigType *implicit_type = nullptr;
@@ -3686,7 +3712,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
} else if (var_decl->expr) {
init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, var_decl->symbol);
assert(init_value);
- implicit_type = init_value->value.type;
+ implicit_type = init_value->type;
if (implicit_type->id == ZigTypeIdUnreachable) {
add_node_error(g, source_node, buf_sprintf("variable initialization is unreachable"));
@@ -3704,7 +3730,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant"));
implicit_type = g->builtin_types.entry_invalid;
}
- assert(implicit_type->id == ZigTypeIdInvalid || init_value->value.special != ConstValSpecialRuntime);
+ assert(implicit_type->id == ZigTypeIdInvalid || init_value->special != ConstValSpecialRuntime);
} else if (linkage != VarLinkageExternal) {
add_node_error(g, source_node, buf_sprintf("variables must be initialized"));
implicit_type = g->builtin_types.entry_invalid;
@@ -3713,19 +3739,19 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
ZigType *type = explicit_type ? explicit_type : implicit_type;
assert(type != nullptr); // should have been caught by the parser
- ConstExprValue *init_val = init_value ? &init_value->value : create_const_runtime(type);
+ ConstExprValue *init_val = (init_value != nullptr) ? init_value : create_const_runtime(type);
tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope, var_decl->symbol,
- is_const, init_val, &tld_var->base);
+ is_const, init_val, &tld_var->base, type);
tld_var->var->linkage = linkage;
if (implicit_type != nullptr && type_is_invalid(implicit_type)) {
- tld_var->var->value->type = g->builtin_types.entry_invalid;
+ tld_var->var->var_type = g->builtin_types.entry_invalid;
}
if (var_decl->align_expr != nullptr) {
if (!analyze_const_align(g, tld_var->base.parent_scope, var_decl->align_expr, &tld_var->var->align_bytes)) {
- tld_var->var->value->type = g->builtin_types.entry_invalid;
+ tld_var->var->var_type = g->builtin_types.entry_invalid;
}
}
@@ -4090,7 +4116,7 @@ static void define_local_param_variables(CodeGen *g, ZigFn *fn_table_entry) {
}
ZigVar *var = add_variable(g, param_decl_node, fn_table_entry->child_scope,
- param_name, true, create_const_runtime(param_type), nullptr);
+ param_name, true, create_const_runtime(param_type), nullptr, param_type);
var->src_arg_index = i;
fn_table_entry->child_scope = var->child_scope;
var->shadowable = var->shadowable || is_var_args;
@@ -4132,11 +4158,11 @@ void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node)
assert(!fn_type->data.fn.is_generic);
FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
- ZigType *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable,
- &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node);
- fn_table_entry->src_implicit_return_type = block_return_type;
+ ConstExprValue *block_result = ir_analyze(g, &fn_table_entry->ir_executable,
+ &fn_table_entry->analyzed_executable, fn_type_id->return_type, return_type_node, nullptr);
+ fn_table_entry->src_implicit_return_type = block_result->type;
- if (type_is_invalid(block_return_type) || fn_table_entry->analyzed_executable.invalid) {
+ if (type_is_invalid(block_result->type) || fn_table_entry->analyzed_executable.invalid) {
assert(g->errors.length > 0);
fn_table_entry->anal_state = FnAnalStateInvalid;
return;
@@ -4150,6 +4176,10 @@ void analyze_fn_ir(CodeGen *g, ZigFn *fn_table_entry, AstNode *return_type_node)
inferred_err_set_type = fn_table_entry->src_implicit_return_type;
} else if (fn_table_entry->src_implicit_return_type->id == ZigTypeIdErrorUnion) {
inferred_err_set_type = fn_table_entry->src_implicit_return_type->data.error_union.err_set_type;
+ } else if (fn_table_entry->src_implicit_return_type->id == ZigTypeIdOptional &&
+ fn_table_entry->src_implicit_return_type->data.maybe.child_type->id == ZigTypeIdErrorSet)
+ {
+ inferred_err_set_type = fn_table_entry->src_implicit_return_type->data.maybe.child_type;
} else {
add_node_error(g, return_type_node,
buf_sprintf("function with inferred error set must return at least one possible error"));
@@ -4228,18 +4258,17 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *
preview_use_decl(g, src_use_node);
}
- IrInstruction *use_target_value = src_use_node->data.use.value;
- if (use_target_value->value.type->id == ZigTypeIdInvalid) {
+ ConstExprValue *use_target_value = src_use_node->data.use.value;
+ if (use_target_value->type->id == ZigTypeIdInvalid) {
dst_use_node->owner->any_imports_failed = true;
return;
}
dst_use_node->data.use.resolution = TldResolutionOk;
- ConstExprValue *const_val = &use_target_value->value;
- assert(const_val->special != ConstValSpecialRuntime);
+ assert(use_target_value->special != ConstValSpecialRuntime);
- ImportTableEntry *target_import = const_val->data.x_import;
+ ImportTableEntry *target_import = use_target_value->data.x_import;
assert(target_import);
if (target_import->any_imports_failed) {
@@ -4302,10 +4331,10 @@ void preview_use_decl(CodeGen *g, AstNode *node) {
}
node->data.use.resolution = TldResolutionResolving;
- IrInstruction *result = analyze_const_value(g, &node->owner->decls_scope->base,
+ ConstExprValue *result = analyze_const_value(g, &node->owner->decls_scope->base,
node->data.use.expr, g->builtin_types.entry_namespace, nullptr);
- if (result->value.type->id == ZigTypeIdInvalid)
+ if (type_is_invalid(result->type))
node->owner->any_imports_failed = true;
node->data.use.value = result;
@@ -4486,7 +4515,8 @@ bool handle_is_ptr(ZigType *type_entry) {
return type_has_bits(type_entry->data.error_union.payload_type);
case ZigTypeIdOptional:
return type_has_bits(type_entry->data.maybe.child_type) &&
- !type_is_codegen_pointer(type_entry->data.maybe.child_type);
+ !type_is_codegen_pointer(type_entry->data.maybe.child_type) &&
+ type_entry->data.maybe.child_type->id != ZigTypeIdErrorSet;
case ZigTypeIdUnion:
assert(type_entry->data.unionation.zero_bits_known);
if (type_entry->data.unionation.gen_field_count == 0)
@@ -4732,6 +4762,11 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) {
return true;
}
+static uint32_t hash_const_val_error_set(ConstExprValue *const_val) {
+ assert(const_val->data.x_err_set != nullptr);
+ return const_val->data.x_err_set->value ^ 2630160122;
+}
+
static uint32_t hash_const_val_ptr(ConstExprValue *const_val) {
uint32_t hash_val = 0;
switch (const_val->data.x_ptr.mut) {
@@ -4744,6 +4779,8 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) {
case ConstPtrMutComptimeVar:
hash_val += (uint32_t)1103195694;
break;
+ case ConstPtrMutInfer:
+ zig_unreachable();
}
switch (const_val->data.x_ptr.special) {
case ConstPtrSpecialInvalid:
@@ -4763,6 +4800,18 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) {
hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val);
hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index);
return hash_val;
+ case ConstPtrSpecialBaseErrorUnionCode:
+ hash_val += (uint32_t)2994743799;
+ hash_val += hash_ptr(const_val->data.x_ptr.data.base_err_union_code.err_union_val);
+ return hash_val;
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ hash_val += (uint32_t)3456080131;
+ hash_val += hash_ptr(const_val->data.x_ptr.data.base_err_union_payload.err_union_val);
+ return hash_val;
+ case ConstPtrSpecialBaseOptionalPayload:
+ hash_val += (uint32_t)3163140517;
+ hash_val += hash_ptr(const_val->data.x_ptr.data.base_optional_payload.optional_val);
+ return hash_val;
case ConstPtrSpecialHardCodedAddr:
hash_val += (uint32_t)4048518294;
hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr);
@@ -4774,6 +4823,9 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) {
hash_val += (uint32_t)2590901619;
hash_val += hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);
return hash_val;
+ case ConstPtrSpecialNull:
+ hash_val += (uint32_t)1486246455;
+ return hash_val;
}
zig_unreachable();
}
@@ -4872,7 +4924,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
return 2709806591;
case ZigTypeIdOptional:
if (get_codegen_ptr_type(const_val->type) != nullptr) {
- return hash_const_val(const_val) * 1992916303;
+ return hash_const_val_ptr(const_val) * 1992916303;
+ } else if (const_val->type->data.maybe.child_type->id == ZigTypeIdErrorSet) {
+ return hash_const_val_error_set(const_val) * 3147031929;
} else {
if (const_val->data.x_optional) {
return hash_const_val(const_val->data.x_optional) * 1992916303;
@@ -4884,8 +4938,7 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
// TODO better hashing algorithm
return 3415065496;
case ZigTypeIdErrorSet:
- assert(const_val->data.x_err_set != nullptr);
- return const_val->data.x_err_set->value ^ 2630160122;
+ return hash_const_val_error_set(const_val);
case ZigTypeIdNamespace:
return hash_ptr(const_val->data.x_import);
case ZigTypeIdBoundFn:
@@ -4987,7 +5040,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) {
return can_mutate_comptime_var_state(value->data.x_optional);
case ZigTypeIdErrorUnion:
- if (value->data.x_err_union.err != nullptr)
+ if (value->data.x_err_union.error_set->data.x_err_set != nullptr)
return false;
assert(value->data.x_err_union.payload != nullptr);
return can_mutate_comptime_var_state(value->data.x_err_union.payload);
@@ -5048,9 +5101,9 @@ bool fn_eval_cacheable(Scope *scope, ZigType *return_type) {
while (scope) {
if (scope->id == ScopeIdVarDecl) {
ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
- if (type_is_invalid(var_scope->var->value->type))
+ if (type_is_invalid(var_scope->var->var_type))
return false;
- if (can_mutate_comptime_var_state(var_scope->var->value))
+ if (can_mutate_comptime_var_state(var_scope->var->const_value))
return false;
} else if (scope->id == ScopeIdFnDef) {
return true;
@@ -5068,7 +5121,7 @@ uint32_t fn_eval_hash(Scope* scope) {
while (scope) {
if (scope->id == ScopeIdVarDecl) {
ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
- result += hash_const_val(var_scope->var->value);
+ result += hash_const_val(var_scope->var->const_value);
} else if (scope->id == ScopeIdFnDef) {
ScopeFnDef *fn_scope = (ScopeFnDef *)scope;
result += hash_ptr(fn_scope->fn_entry);
@@ -5092,10 +5145,16 @@ bool fn_eval_eql(Scope *a, Scope *b) {
if (a->id == ScopeIdVarDecl) {
ScopeVarDecl *a_var_scope = (ScopeVarDecl *)a;
ScopeVarDecl *b_var_scope = (ScopeVarDecl *)b;
- if (a_var_scope->var->value->type != b_var_scope->var->value->type)
- return false;
- if (!const_values_equal(a->codegen, a_var_scope->var->value, b_var_scope->var->value))
+ if (a_var_scope->var->var_type != b_var_scope->var->var_type)
return false;
+ if (a_var_scope->var->var_type == a_var_scope->var->const_value->type &&
+ b_var_scope->var->var_type == b_var_scope->var->const_value->type)
+ {
+ if (!const_values_equal(a->codegen, a_var_scope->var->const_value, b_var_scope->var->const_value))
+ return false;
+ } else {
+ zig_panic("TODO comptime ptr reinterpret for fn_eval_eql");
+ }
} else if (a->id == ScopeIdFnDef) {
ScopeFnDef *a_fn_scope = (ScopeFnDef *)a;
ScopeFnDef *b_fn_scope = (ScopeFnDef *)b;
@@ -5113,6 +5172,7 @@ bool fn_eval_eql(Scope *a, Scope *b) {
return false;
}
+// Whether the type has bits at runtime.
bool type_has_bits(ZigType *type_entry) {
assert(type_entry);
assert(!type_is_invalid(type_entry));
@@ -5120,6 +5180,65 @@ bool type_has_bits(ZigType *type_entry) {
return !type_entry->zero_bits;
}
+// Whether you can infer the value based solely on the type.
+OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) {
+ assert(type_entry != nullptr);
+ Error err;
+ if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
+ return OnePossibleValueInvalid;
+ switch (type_entry->id) {
+ case ZigTypeIdInvalid:
+ zig_unreachable();
+ case ZigTypeIdOpaque:
+ case ZigTypeIdComptimeFloat:
+ case ZigTypeIdComptimeInt:
+ case ZigTypeIdMetaType:
+ case ZigTypeIdNamespace:
+ case ZigTypeIdBoundFn:
+ case ZigTypeIdArgTuple:
+ case ZigTypeIdOptional:
+ case ZigTypeIdFn:
+ case ZigTypeIdBool:
+ case ZigTypeIdFloat:
+ case ZigTypeIdPromise:
+ case ZigTypeIdErrorUnion:
+ return OnePossibleValueNo;
+ case ZigTypeIdUndefined:
+ case ZigTypeIdNull:
+ case ZigTypeIdVoid:
+ case ZigTypeIdUnreachable:
+ return OnePossibleValueYes;
+ case ZigTypeIdArray:
+ if (type_entry->data.array.len == 0)
+ return OnePossibleValueYes;
+ return type_has_one_possible_value(g, type_entry->data.array.child_type);
+ case ZigTypeIdStruct:
+ for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
+ TypeStructField *field = &type_entry->data.structure.fields[i];
+ switch (type_has_one_possible_value(g, field->type_entry)) {
+ case OnePossibleValueInvalid:
+ return OnePossibleValueInvalid;
+ case OnePossibleValueNo:
+ return OnePossibleValueNo;
+ case OnePossibleValueYes:
+ continue;
+ }
+ }
+ return OnePossibleValueYes;
+ case ZigTypeIdErrorSet:
+ case ZigTypeIdEnum:
+ case ZigTypeIdInt:
+ return type_has_bits(type_entry) ? OnePossibleValueNo : OnePossibleValueYes;
+ case ZigTypeIdPointer:
+ return type_has_one_possible_value(g, type_entry->data.pointer.child_type);
+ case ZigTypeIdUnion:
+ if (type_entry->data.unionation.src_field_count > 1)
+ return OnePossibleValueNo;
+ return type_has_one_possible_value(g, type_entry->data.unionation.fields[0].type_entry);
+ }
+ zig_unreachable();
+}
+
ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) {
Error err;
if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
@@ -5574,6 +5693,33 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) {
if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index)
return false;
return true;
+ case ConstPtrSpecialBaseErrorUnionCode:
+ if (a->data.x_ptr.data.base_err_union_code.err_union_val !=
+ b->data.x_ptr.data.base_err_union_code.err_union_val &&
+ a->data.x_ptr.data.base_err_union_code.err_union_val->global_refs !=
+ b->data.x_ptr.data.base_err_union_code.err_union_val->global_refs)
+ {
+ return false;
+ }
+ return true;
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ if (a->data.x_ptr.data.base_err_union_payload.err_union_val !=
+ b->data.x_ptr.data.base_err_union_payload.err_union_val &&
+ a->data.x_ptr.data.base_err_union_payload.err_union_val->global_refs !=
+ b->data.x_ptr.data.base_err_union_payload.err_union_val->global_refs)
+ {
+ return false;
+ }
+ return true;
+ case ConstPtrSpecialBaseOptionalPayload:
+ if (a->data.x_ptr.data.base_optional_payload.optional_val !=
+ b->data.x_ptr.data.base_optional_payload.optional_val &&
+ a->data.x_ptr.data.base_optional_payload.optional_val->global_refs !=
+ b->data.x_ptr.data.base_optional_payload.optional_val->global_refs)
+ {
+ return false;
+ }
+ return true;
case ConstPtrSpecialHardCodedAddr:
if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr)
return false;
@@ -5582,6 +5728,8 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) {
return true;
case ConstPtrSpecialFunction:
return a->data.x_ptr.data.fn.fn_entry == b->data.x_ptr.data.fn.fn_entry;
+ case ConstPtrSpecialNull:
+ return true;
}
zig_unreachable();
}
@@ -5750,15 +5898,22 @@ void eval_min_max_value(CodeGen *g, ZigType *type_entry, ConstExprValue *const_v
}
}
-void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) {
+static void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) {
switch (const_val->data.x_ptr.special) {
case ConstPtrSpecialInvalid:
zig_unreachable();
case ConstPtrSpecialRef:
case ConstPtrSpecialBaseStruct:
+ case ConstPtrSpecialBaseErrorUnionCode:
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ case ConstPtrSpecialBaseOptionalPayload:
buf_appendf(buf, "*");
- // TODO we need a source node for const_ptr_pointee because it can generate compile errors
- render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr));
+ if (const_val->type->id == ZigTypeIdPointer) {
+ // TODO we need a source node for const_ptr_pointee because it can generate compile errors
+ render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr));
+ } else {
+ buf_appendf(buf, "(TODO print this pointer)");
+ }
return;
case ConstPtrSpecialBaseArray:
if (const_val->data.x_ptr.data.base_array.is_cstr) {
@@ -5777,6 +5932,9 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy
case ConstPtrSpecialDiscard:
buf_append_str(buf, "*_");
return;
+ case ConstPtrSpecialNull:
+ buf_append_str(buf, "null");
+ return;
case ConstPtrSpecialFunction:
{
ZigFn *fn_entry = const_val->data.x_ptr.data.fn.fn_entry;
@@ -5787,6 +5945,14 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy
zig_unreachable();
}
+static void render_const_val_err_set(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) {
+ if (const_val->data.x_err_set == nullptr) {
+ buf_append_str(buf, "null");
+ } else {
+ buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name));
+ }
+}
+
void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
switch (const_val->special) {
case ConstValSpecialRuntime:
@@ -5914,6 +6080,8 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
{
if (get_codegen_ptr_type(const_val->type) != nullptr)
return render_const_val_ptr(g, buf, const_val, type_entry->data.maybe.child_type);
+ if (type_entry->data.maybe.child_type->id == ZigTypeIdErrorSet)
+ return render_const_val_err_set(g, buf, const_val, type_entry->data.maybe.child_type);
if (const_val->data.x_optional) {
render_const_value(g, buf, const_val->data.x_optional);
} else {
@@ -5951,11 +6119,12 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
case ZigTypeIdErrorUnion:
{
buf_appendf(buf, "%s(", buf_ptr(&type_entry->name));
- if (const_val->data.x_err_union.err == nullptr) {
+ ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set;
+ if (err_set == nullptr) {
render_const_value(g, buf, const_val->data.x_err_union.payload);
} else {
buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->data.error_union.err_set_type->name),
- buf_ptr(&const_val->data.x_err_union.err->name));
+ buf_ptr(&err_set->name));
}
buf_appendf(buf, ")");
return;
@@ -5970,10 +6139,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
return;
}
case ZigTypeIdErrorSet:
- {
- buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name));
- return;
- }
+ return render_const_val_err_set(g, buf, const_val, type_entry);
case ZigTypeIdArgTuple:
{
buf_appendf(buf, "(args value)");
@@ -6165,6 +6331,10 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {
// Canonicalize the array value as ConstArraySpecialNone
void expand_undef_array(CodeGen *g, ConstExprValue *const_val) {
assert(const_val->type->id == ZigTypeIdArray);
+ if (const_val->special == ConstValSpecialUndef) {
+ const_val->special = ConstValSpecialStatic;
+ const_val->data.x_array.special = ConstArraySpecialUndef;
+ }
switch (const_val->data.x_array.special) {
case ConstArraySpecialNone:
return;
@@ -6208,17 +6378,7 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) {
}
ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) {
- assert(value->type);
- ZigType *type_entry = value->type;
- if (type_entry->id == ZigTypeIdArray) {
- expand_undef_array(g, value);
- return &value->data.x_array.data.s_none.parent;
- } else if (type_entry->id == ZigTypeIdStruct) {
- return &value->data.x_struct.parent;
- } else if (type_entry->id == ZigTypeIdUnion) {
- return &value->data.x_union.parent;
- }
- return nullptr;
+ return &value->parent;
}
static const ZigTypeId all_type_ids[] = {
@@ -6446,7 +6606,7 @@ ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) {
resolve_top_level_decl(codegen, tld, false, nullptr);
assert(tld->id == TldIdVar);
TldVar *tld_var = (TldVar *)tld;
- ConstExprValue *var_value = tld_var->var->value;
+ ConstExprValue *var_value = tld_var->var->const_value;
assert(var_value != nullptr);
return var_value;
}
diff --git a/src/analyze.hpp b/src/analyze.hpp
index efbc065a633a..1bac15ebcce7 100644
--- a/src/analyze.hpp
+++ b/src/analyze.hpp
@@ -81,7 +81,7 @@ ZigFn *scope_fn_entry(Scope *scope);
ImportTableEntry *get_scope_import(Scope *scope);
void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope);
ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name,
- bool is_const, ConstExprValue *init_value, Tld *src_tld);
+ bool is_const, ConstExprValue *init_value, Tld *src_tld, ZigType *var_type);
ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node);
ZigFn *create_fn(CodeGen *g, AstNode *proto_node);
ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value);
@@ -222,6 +222,13 @@ enum ReqCompTime {
};
ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry);
+enum OnePossibleValue {
+ OnePossibleValueInvalid,
+ OnePossibleValueNo,
+ OnePossibleValueYes,
+};
+OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry);
+
Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node,
ConstExprValue *const_val, ZigType *wanted_type);
diff --git a/src/ast_render.cpp b/src/ast_render.cpp
index f7eb646e16d7..904018a66845 100644
--- a/src/ast_render.cpp
+++ b/src/ast_render.cpp
@@ -233,8 +233,8 @@ static const char *node_type_str(NodeType node_type) {
return "ErrorType";
case NodeTypeIfErrorExpr:
return "IfErrorExpr";
- case NodeTypeTestExpr:
- return "TestExpr";
+ case NodeTypeIfOptional:
+ return "IfOptional";
case NodeTypeErrorSetDecl:
return "ErrorSetDecl";
case NodeTypeCancel:
@@ -249,6 +249,8 @@ static const char *node_type_str(NodeType node_type) {
return "PromiseType";
case NodeTypePointerType:
return "PointerType";
+ case NodeTypeErrorLiteral:
+ return "ErrorLiteral";
}
zig_unreachable();
}
@@ -387,7 +389,7 @@ static bool statement_terminates_without_semicolon(AstNode *node) {
if (node->data.if_err_expr.else_node)
return statement_terminates_without_semicolon(node->data.if_err_expr.else_node);
return node->data.if_err_expr.then_node->type == NodeTypeBlock;
- case NodeTypeTestExpr:
+ case NodeTypeIfOptional:
if (node->data.test_expr.else_node)
return statement_terminates_without_semicolon(node->data.test_expr.else_node);
return node->data.test_expr.then_node->type == NodeTypeBlock;
@@ -974,7 +976,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
}
break;
}
- case NodeTypeTestExpr:
+ case NodeTypeIfOptional:
{
fprintf(ar->f, "if (");
render_node_grouped(ar, node->data.test_expr.target_node);
@@ -1145,6 +1147,11 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
}
break;
}
+ case NodeTypeErrorLiteral:
+ {
+ fprintf(ar->f, "error.%s", buf_ptr(node->data.error_literal.name));
+ break;
+ }
case NodeTypeParamDecl:
case NodeTypeTestDecl:
case NodeTypeStructField:
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 47f2aa103fde..4731804b710a 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -461,6 +461,21 @@ static void maybe_import_dll(CodeGen *g, LLVMValueRef global_value, GlobalLinkag
}
}
+static bool cc_want_sret_attr(CallingConvention cc) {
+ switch (cc) {
+ case CallingConventionNaked:
+ zig_unreachable();
+ case CallingConventionC:
+ case CallingConventionCold:
+ case CallingConventionStdcall:
+ return true;
+ case CallingConventionAsync:
+ case CallingConventionUnspecified:
+ return false;
+ }
+ zig_unreachable();
+}
+
static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
if (fn_table_entry->llvm_value)
return fn_table_entry->llvm_value;
@@ -598,10 +613,21 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
} else if (type_is_codegen_pointer(return_type)) {
addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");
} else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) {
- addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull");
- if (cc == CallingConventionC) {
+ if (cc_want_sret_attr(cc)) {
+ addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
addLLVMArgAttr(fn_table_entry->llvm_value, 0, "noalias");
+ } else {
+ ZigType *ret_type = fn_type->data.fn.fn_type_id.return_type;
+ if (ret_type->id == ZigTypeIdErrorUnion) {
+ uint64_t sz = type_size(g, ret_type->data.error_union.payload_type);
+ addLLVMArgAttrInt(fn_table_entry->llvm_value, 0, "dereferenceable", sz);
+ } else if (ret_type->id == ZigTypeIdOptional) {
+ uint64_t sz = type_size(g, ret_type->data.maybe.child_type);
+ addLLVMArgAttrInt(fn_table_entry->llvm_value, 0, "dereferenceable", sz);
+ } else {
+ addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
+ }
}
init_gen_i = 1;
}
@@ -2200,10 +2226,10 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
assert(variable);
assert(variable->value_ref);
- if (!handle_is_ptr(variable->value->type)) {
+ if (!handle_is_ptr(variable->var_type)) {
clear_debug_source_node(g);
- gen_store_untyped(g, LLVMGetParam(llvm_fn, (unsigned)variable->gen_arg_index), variable->value_ref,
- variable->align_bytes, false);
+ gen_store_untyped(g, LLVMGetParam(llvm_fn, (unsigned)variable->gen_arg_index),
+ variable->value_ref, variable->align_bytes, false);
}
if (variable->decl_node) {
@@ -2239,20 +2265,19 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut
}
static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
- LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
ZigType *return_type = return_instruction->value->value.type;
-
- if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) {
- assert(g->cur_ret_ptr);
- gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value);
+ if (!type_has_bits(return_type)) {
+ LLVMBuildRetVoid(g->builder);
+ return nullptr;
+ }
+ LLVMValueRef value = ir_llvm_value(g, return_instruction->value);
+ if (handle_is_ptr(return_type)) {
LLVMBuildRetVoid(g->builder);
- } else if (handle_is_ptr(return_type)) {
- LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, "");
- LLVMBuildRet(g->builder, by_val_value);
+ return nullptr;
} else {
LLVMBuildRet(g->builder, value);
+ return nullptr;
}
- return nullptr;
}
static LLVMValueRef gen_overflow_shl_op(CodeGen *g, ZigType *type_entry,
@@ -2817,69 +2842,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
zig_unreachable();
case CastOpNoop:
return expr_val;
- case CastOpResizeSlice:
- {
- assert(cast_instruction->tmp_ptr);
- assert(wanted_type->id == ZigTypeIdStruct);
- assert(wanted_type->data.structure.is_slice);
- assert(actual_type->id == ZigTypeIdStruct);
- assert(actual_type->data.structure.is_slice);
-
- ZigType *actual_pointer_type = actual_type->data.structure.fields[0].type_entry;
- ZigType *actual_child_type = actual_pointer_type->data.pointer.child_type;
- ZigType *wanted_pointer_type = wanted_type->data.structure.fields[0].type_entry;
- ZigType *wanted_child_type = wanted_pointer_type->data.pointer.child_type;
-
-
- size_t actual_ptr_index = actual_type->data.structure.fields[slice_ptr_index].gen_index;
- size_t actual_len_index = actual_type->data.structure.fields[slice_len_index].gen_index;
- size_t wanted_ptr_index = wanted_type->data.structure.fields[slice_ptr_index].gen_index;
- size_t wanted_len_index = wanted_type->data.structure.fields[slice_len_index].gen_index;
-
- LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, expr_val, (unsigned)actual_ptr_index, "");
- LLVMValueRef src_ptr = gen_load_untyped(g, src_ptr_ptr, 0, false, "");
- LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr,
- wanted_type->data.structure.fields[0].type_entry->type_ref, "");
- LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
- (unsigned)wanted_ptr_index, "");
- gen_store_untyped(g, src_ptr_casted, dest_ptr_ptr, 0, false);
-
- LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, expr_val, (unsigned)actual_len_index, "");
- LLVMValueRef src_len = gen_load_untyped(g, src_len_ptr, 0, false, "");
- uint64_t src_size = type_size(g, actual_child_type);
- uint64_t dest_size = type_size(g, wanted_child_type);
-
- LLVMValueRef new_len;
- if (dest_size == 1) {
- LLVMValueRef src_size_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, src_size, false);
- new_len = LLVMBuildMul(g->builder, src_len, src_size_val, "");
- } else if (src_size == 1) {
- LLVMValueRef dest_size_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, dest_size, false);
- if (ir_want_runtime_safety(g, &cast_instruction->base)) {
- LLVMValueRef remainder_val = LLVMBuildURem(g->builder, src_len, dest_size_val, "");
- LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_usize->type_ref);
- LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
- LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenOk");
- LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenFail");
- LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
-
- LLVMPositionBuilderAtEnd(g->builder, fail_block);
- gen_safety_crash(g, PanicMsgIdSliceWidenRemainder);
-
- LLVMPositionBuilderAtEnd(g->builder, ok_block);
- }
- new_len = LLVMBuildExactUDiv(g->builder, src_len, dest_size_val, "");
- } else {
- zig_unreachable();
- }
-
- LLVMValueRef dest_len_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
- (unsigned)wanted_len_index, "");
- gen_store_untyped(g, new_len, dest_len_ptr, 0, false);
-
-
- return cast_instruction->tmp_ptr;
- }
case CastOpIntToFloat:
assert(actual_type->id == ZigTypeIdInt);
if (actual_type->data.integral.is_signed) {
@@ -2933,35 +2895,12 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
return expr_val;
case CastOpBitCast:
return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
- case CastOpPtrOfArrayToSlice: {
- assert(cast_instruction->tmp_ptr);
- assert(actual_type->id == ZigTypeIdPointer);
- ZigType *array_type = actual_type->data.pointer.child_type;
- assert(array_type->id == ZigTypeIdArray);
-
- LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
- slice_ptr_index, "");
- LLVMValueRef indices[] = {
- LLVMConstNull(g->builtin_types.entry_usize->type_ref),
- LLVMConstInt(g->builtin_types.entry_usize->type_ref, 0, false),
- };
- LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, "");
- gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
-
- LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
- slice_len_index, "");
- LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
- array_type->data.array.len, false);
- gen_store_untyped(g, len_value, len_field_ptr, 0, false);
-
- return cast_instruction->tmp_ptr;
- }
}
zig_unreachable();
}
static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable,
- IrInstructionPtrCast *instruction)
+ IrInstructionPtrCastGen *instruction)
{
ZigType *wanted_type = instruction->base.value.type;
if (!type_has_bits(wanted_type)) {
@@ -2971,14 +2910,6 @@ static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable,
return LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, "");
}
-static LLVMValueRef ir_render_bit_cast(CodeGen *g, IrExecutable *executable,
- IrInstructionBitCast *instruction)
-{
- ZigType *wanted_type = instruction->base.value.type;
- LLVMValueRef value = ir_llvm_value(g, instruction->value);
- return LLVMBuildBitCast(g->builder, value, wanted_type->type_ref, "");
-}
-
static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executable,
IrInstructionWidenOrShorten *instruction)
{
@@ -3148,49 +3079,16 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI
return LLVMBuildICmp(g->builder, LLVMIntEQ, value, zero, "");
}
-static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
- IrInstructionDeclVar *decl_var_instruction)
-{
- ZigVar *var = decl_var_instruction->var;
+static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrInstructionDeclVarGen *instruction) {
+ ZigVar *var = instruction->var;
- if (!type_has_bits(var->value->type))
+ if (!type_has_bits(var->var_type))
return nullptr;
if (var->ref_count == 0 && g->build_mode != BuildModeDebug)
return nullptr;
- IrInstruction *init_value = decl_var_instruction->init_value;
-
- bool have_init_expr = false;
-
- ConstExprValue *const_val = &init_value->value;
- if (const_val->special == ConstValSpecialRuntime || const_val->special == ConstValSpecialStatic)
- have_init_expr = true;
-
- if (have_init_expr) {
- assert(var->value->type == init_value->value.type);
- ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->value->type, false, false,
- PtrLenSingle, var->align_bytes, 0, 0);
- LLVMValueRef llvm_init_val = ir_llvm_value(g, init_value);
- gen_assign_raw(g, var->value_ref, var_ptr_type, llvm_init_val);
- } else {
- bool want_safe = ir_want_runtime_safety(g, &decl_var_instruction->base);
- if (want_safe) {
- ZigType *usize = g->builtin_types.entry_usize;
- uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, var->value->type->type_ref);
- assert(size_bytes > 0);
-
- assert(var->align_bytes > 0);
-
- // memset uninitialized memory to 0xa
- LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
- LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
- LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, var->value_ref, ptr_u8, "");
- LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false);
- ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, var->align_bytes, false);
- }
- }
-
+ var->value_ref = ir_llvm_value(g, instruction->var_ptr);
gen_var_debug_decl(g, var);
return nullptr;
}
@@ -3225,21 +3123,77 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, "");
}
-static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) {
- LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
- LLVMValueRef value = ir_llvm_value(g, instruction->value);
+static bool value_is_all_undef(ConstExprValue *const_val) {
+ switch (const_val->special) {
+ case ConstValSpecialRuntime:
+ return false;
+ case ConstValSpecialUndef:
+ return true;
+ case ConstValSpecialStatic:
+ if (const_val->type->id == ZigTypeIdStruct) {
+ for (size_t i = 0; i < const_val->type->data.structure.src_field_count; i += 1) {
+ if (!value_is_all_undef(&const_val->data.x_struct.fields[i]))
+ return false;
+ }
+ return true;
+ } else if (const_val->type->id == ZigTypeIdArray) {
+ switch (const_val->data.x_array.special) {
+ case ConstArraySpecialUndef:
+ return true;
+ case ConstArraySpecialBuf:
+ return false;
+ case ConstArraySpecialNone:
+ for (size_t i = 0; i < const_val->type->data.array.len; i += 1) {
+ if (!value_is_all_undef(&const_val->data.x_array.data.s_none.elements[i]))
+ return false;
+ }
+ return true;
+ }
+ zig_unreachable();
+ } else {
+ return false;
+ }
+ }
+ zig_unreachable();
+}
+
+static void gen_undef_init(CodeGen *g, uint32_t ptr_align_bytes, ZigType *value_type, LLVMValueRef ptr) {
+ assert(type_has_bits(value_type));
+ uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, value_type->type_ref);
+ assert(size_bytes > 0);
+ assert(ptr_align_bytes > 0);
+ // memset uninitialized memory to 0xaa
+ LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
+ LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
+ LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, ptr, ptr_u8, "");
+ ZigType *usize = g->builtin_types.entry_usize;
+ LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false);
+ ZigLLVMBuildMemSet(g->builder, dest_ptr, fill_char, byte_count, ptr_align_bytes, false);
+}
- assert(instruction->ptr->value.type->id == ZigTypeIdPointer);
+static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) {
ZigType *ptr_type = instruction->ptr->value.type;
+ assert(ptr_type->id == ZigTypeIdPointer);
+ if (!type_has_bits(ptr_type))
+ return nullptr;
+
+ bool have_init_expr = !value_is_all_undef(&instruction->value->value);
+ if (have_init_expr) {
+ LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
+ LLVMValueRef value = ir_llvm_value(g, instruction->value);
- gen_assign_raw(g, ptr, ptr_type, value);
+ gen_assign_raw(g, ptr, ptr_type, value);
+ } else if (ir_want_runtime_safety(g, &instruction->base)) {
+ gen_undef_init(g, get_ptr_align(g, ptr_type), instruction->value->value.type,
+ ir_llvm_value(g, instruction->ptr));
+ }
return nullptr;
}
static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) {
ZigVar *var = instruction->var;
- if (type_has_bits(var->value->type)) {
+ if (type_has_bits(var->var_type)) {
assert(var->value_ref);
return var->value_ref;
} else {
@@ -3415,12 +3369,20 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
CallingConvention cc = fn_type->data.fn.fn_type_id.cc;
- bool first_arg_ret = ret_has_bits && want_first_arg_sret(g, fn_type_id);
+ bool is_error_union = src_return_type->id == ZigTypeIdErrorUnion;
+ bool is_optional = src_return_type->id == ZigTypeIdOptional;
+ bool first_arg_ret = (is_error_union && type_has_bits(src_return_type->data.error_union.payload_type)) ||
+ (ret_has_bits && want_first_arg_sret(g, fn_type_id));
bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id);
bool is_var_args = fn_type_id->is_var_args;
ZigList gen_param_values = {};
+ LLVMValueRef result_ptr = nullptr;
+ if (first_arg_ret || instruction->is_async) {
+ result_ptr = ir_llvm_value(g, instruction->result_loc);
+ }
+
if (first_arg_ret) {
- gen_param_values.append(instruction->tmp_ptr);
+ gen_param_values.append(result_ptr);
}
if (prefix_arg_err_ret_stack) {
gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope));
@@ -3428,7 +3390,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
if (instruction->is_async) {
gen_param_values.append(ir_llvm_value(g, instruction->async_allocator));
- LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, "");
+ LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, result_ptr, err_union_err_index, "");
gen_param_values.append(err_val_ptr);
}
FnWalk fn_walk = {};
@@ -3471,9 +3433,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
if (instruction->is_async) {
- LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");
+ LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, result_ptr, err_union_payload_index, "");
LLVMBuildStore(g->builder, result, payload_ptr);
- return instruction->tmp_ptr;
+ return result_ptr;
}
if (src_return_type->id == ZigTypeIdUnreachable) {
@@ -3481,12 +3443,14 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
} else if (!ret_has_bits) {
return nullptr;
} else if (first_arg_ret) {
- set_call_instr_sret(g, result);
- return instruction->tmp_ptr;
+ if (cc_want_sret_attr(cc) || (!is_error_union && !is_optional)) {
+ set_call_instr_sret(g, result);
+ }
+ return (is_error_union || is_optional) ? result : result_ptr;
} else if (handle_is_ptr(src_return_type)) {
- auto store_instr = LLVMBuildStore(g->builder, result, instruction->tmp_ptr);
- LLVMSetAlignment(store_instr, LLVMGetAlignment(instruction->tmp_ptr));
- return instruction->tmp_ptr;
+ auto store_instr = LLVMBuildStore(g->builder, result, result_ptr);
+ LLVMSetAlignment(store_instr, LLVMGetAlignment(result_ptr));
+ return result_ptr;
} else {
return result;
}
@@ -3535,7 +3499,10 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab
return bitcasted_union_field_ptr;
}
- if (ir_want_runtime_safety(g, &instruction->base)) {
+ bool safety_check_on = instruction->id == IrInstructionUnionFieldPtrIdRef &&
+ ir_want_runtime_safety(g, &instruction->base);
+
+ if (safety_check_on) {
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_tag_index, "");
LLVMValueRef tag_value = gen_load_untyped(g, tag_field_ptr, 0, false, "");
@@ -3553,7 +3520,16 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab
LLVMPositionBuilderAtEnd(g->builder, ok_block);
}
- LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_union_index, "");
+ if (instruction->id == IrInstructionUnionFieldPtrIdResultPtr) {
+ LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr,
+ union_type->data.unionation.gen_tag_index, "");
+ LLVMValueRef tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref,
+ &field->enum_field->value);
+ gen_store_untyped(g, tag_value, tag_field_ptr, 0, false);
+ }
+
+ LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr,
+ union_type->data.unionation.gen_union_index, "");
LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, "");
return bitcasted_union_field_ptr;
}
@@ -3715,8 +3691,8 @@ static LLVMValueRef gen_non_null_bit(CodeGen *g, ZigType *maybe_type, LLVMValueR
if (child_type->zero_bits) {
return maybe_handle;
} else {
- bool maybe_is_ptr = type_is_codegen_pointer(child_type);
- if (maybe_is_ptr) {
+ bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet;
+ if (is_scalar) {
return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), "");
} else {
LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_handle, maybe_null_index, "");
@@ -3731,17 +3707,17 @@ static LLVMValueRef ir_render_test_non_null(CodeGen *g, IrExecutable *executable
return gen_non_null_bit(g, instruction->value->value.type, ir_llvm_value(g, instruction->value));
}
-static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
- IrInstructionUnwrapOptional *instruction)
+static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *executable,
+ IrInstructionOptionalUnwrapPtr *instruction)
{
- ZigType *ptr_type = instruction->value->value.type;
+ ZigType *ptr_type = instruction->base_ptr->value.type;
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *maybe_type = ptr_type->data.pointer.child_type;
assert(maybe_type->id == ZigTypeIdOptional);
ZigType *child_type = maybe_type->data.maybe.child_type;
- LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value);
- LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type);
+ LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->base_ptr);
if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) {
+ LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type);
LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle);
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk");
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail");
@@ -3755,8 +3731,8 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
if (child_type->zero_bits) {
return nullptr;
} else {
- bool maybe_is_ptr = type_is_codegen_pointer(child_type);
- if (maybe_is_ptr) {
+ bool is_scalar = type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet;
+ if (is_scalar) {
return maybe_ptr;
} else {
LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type, ptr_type);
@@ -3765,6 +3741,31 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
}
}
+static LLVMValueRef ir_render_optional_unwrap_val(CodeGen *g, IrExecutable *executable,
+ IrInstructionOptionalUnwrapVal *instruction)
+{
+ ZigType *opt_type = instruction->opt->value.type;
+ assert(opt_type->id == ZigTypeIdOptional);
+ LLVMValueRef opt_handle = ir_llvm_value(g, instruction->opt);
+ if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) {
+ LLVMValueRef non_null_bit = gen_non_null_bit(g, opt_type, opt_handle);
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk");
+ LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail");
+ LLVMBuildCondBr(g->builder, non_null_bit, ok_block, fail_block);
+
+ LLVMPositionBuilderAtEnd(g->builder, fail_block);
+ gen_safety_crash(g, PanicMsgIdUnwrapOptionalFail);
+
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ }
+ ZigType *payload_type = opt_type->data.maybe.child_type;
+ if (!type_has_bits(payload_type))
+ return nullptr;
+ if (!handle_is_ptr(opt_type))
+ return opt_handle;
+ return LLVMBuildStructGEP(g->builder, opt_handle, maybe_child_index, "");
+}
+
static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnId fn_id) {
ZigLLVMFnKey key = {};
const char *fn_name;
@@ -3891,9 +3892,10 @@ static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstru
if (handle_is_ptr(instruction->value->value.type)) {
return value;
} else {
- assert(instruction->tmp_ptr);
- gen_store_untyped(g, value, instruction->tmp_ptr, 0, false);
- return instruction->tmp_ptr;
+ assert(instruction->result_loc != nullptr);
+ LLVMValueRef result_ptr = ir_llvm_value(g, instruction->result_loc);
+ gen_store_untyped(g, value, result_ptr, 0, false);
+ return result_ptr;
}
}
@@ -4174,39 +4176,52 @@ static LLVMAtomicRMWBinOp to_LLVMAtomicRMWBinOp(AtomicRmwOp op, bool is_signed)
zig_unreachable();
}
-static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrInstructionCmpxchg *instruction) {
+static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrInstructionCmpxchgGen *instruction) {
LLVMValueRef ptr_val = ir_llvm_value(g, instruction->ptr);
LLVMValueRef cmp_val = ir_llvm_value(g, instruction->cmp_value);
LLVMValueRef new_val = ir_llvm_value(g, instruction->new_value);
+ assert(type_has_bits(instruction->type));
+ ZigType *ptr_type = instruction->result_loc->value.type;
+ assert(ptr_type->id == ZigTypeIdPointer);
+ ZigType *child_type = ptr_type->data.pointer.child_type;
+ bool is_scalar = !handle_is_ptr(child_type);
+
LLVMAtomicOrdering success_order = to_LLVMAtomicOrdering(instruction->success_order);
LLVMAtomicOrdering failure_order = to_LLVMAtomicOrdering(instruction->failure_order);
- LLVMValueRef result_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val,
+ LLVMValueRef cmpxchg_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val,
success_order, failure_order, instruction->is_weak);
- ZigType *maybe_type = instruction->base.value.type;
- assert(maybe_type->id == ZigTypeIdOptional);
- ZigType *child_type = maybe_type->data.maybe.child_type;
+ LLVMValueRef result_ptr = ir_llvm_value(g, instruction->result_loc);
+ LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, cmpxchg_val, 1, "");
+ LLVMBasicBlockRef null_block = is_scalar ? LLVMAppendBasicBlock(g->cur_fn_val, "CmpXchgNull") :
+ LLVMGetInsertBlock(g->builder);
+ LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(g->cur_fn_val, "CmpXchgNonNull");
+ LLVMBasicBlockRef phi_block = LLVMAppendBasicBlock(g->cur_fn_val, "CmpXchgPhi");
- if (type_is_codegen_pointer(child_type)) {
- LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
- LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
- return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(child_type->type_ref), payload_val, "");
- }
+ if (is_scalar) {
+ LLVMBuildCondBr(g->builder, success_bit, null_block, non_null_block);
- assert(instruction->tmp_ptr != nullptr);
- assert(type_has_bits(instruction->type));
+ LLVMPositionBuilderAtEnd(g->builder, null_block);
+ LLVMValueRef zeroes = LLVMConstNull(child_type->type_ref);
+ gen_assign_raw(g, result_ptr, instruction->result_loc->value.type, zeroes);
+ LLVMBuildBr(g->builder, phi_block);
+ } else {
+ LLVMBuildCondBr(g->builder, success_bit, phi_block, non_null_block);
+ }
- LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, "");
- LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");
- gen_assign_raw(g, val_ptr, get_pointer_to_type(g, instruction->type, false), payload_val);
+ LLVMPositionBuilderAtEnd(g->builder, non_null_block);
+ LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, cmpxchg_val, 0, "");
+ gen_assign_raw(g, result_ptr, instruction->result_loc->value.type, payload_val);
+ LLVMBuildBr(g->builder, phi_block);
- LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, "");
- LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, "");
- LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, "");
- gen_store_untyped(g, nonnull_bit, maybe_ptr, 0, false);
- return instruction->tmp_ptr;
+ LLVMPositionBuilderAtEnd(g->builder, phi_block);
+ LLVMValueRef non_null_bit = LLVMBuildPhi(g->builder, LLVMInt1Type(), "");
+ LLVMValueRef incoming_values[] = {LLVMConstAllOnes(LLVMInt1Type()), LLVMConstNull(LLVMInt1Type())};
+ LLVMBasicBlockRef incoming_blocks[] = {non_null_block, null_block};
+ LLVMAddIncoming(non_null_bit, incoming_values, incoming_blocks, 2);
+ return non_null_bit;
}
static LLVMValueRef ir_render_fence(CodeGen *g, IrExecutable *executable, IrInstructionFence *instruction) {
@@ -4269,15 +4284,11 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutable *executable, IrIns
}
static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInstructionSlice *instruction) {
- assert(instruction->tmp_ptr);
-
- LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->ptr);
- ZigType *array_ptr_type = instruction->ptr->value.type;
- assert(array_ptr_type->id == ZigTypeIdPointer);
- ZigType *array_type = array_ptr_type->data.pointer.child_type;
- LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type);
+ LLVMValueRef array_ptr = ir_llvm_value(g, instruction->ptr);
+ ZigType *array_type = instruction->ptr->value.type;
- LLVMValueRef tmp_struct_ptr = instruction->tmp_ptr;
+ LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
+ assert(LLVMGetTypeKind(LLVMTypeOf(tmp_struct_ptr)) == LLVMPointerTypeKind);
bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base);
@@ -4351,6 +4362,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
assert(array_type->data.structure.is_slice);
assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);
+ assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(tmp_struct_ptr))) == LLVMStructTypeKind);
size_t ptr_index = array_type->data.structure.fields[slice_ptr_index].gen_index;
assert(ptr_index != SIZE_MAX);
@@ -4540,13 +4552,13 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI
return LLVMBuildICmp(g->builder, LLVMIntNE, err_val, zero, "");
}
-static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrCode *instruction) {
- ZigType *ptr_type = instruction->value->value.type;
- assert(ptr_type->id == ZigTypeIdPointer);
- ZigType *err_union_type = ptr_type->data.pointer.child_type;
+static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable,
+ IrInstructionUnwrapErrCode *instruction)
+{
+ ZigType *err_union_type = instruction->err_union->value.type;
+ assert(err_union_type->id == ZigTypeIdErrorUnion);
ZigType *payload_type = err_union_type->data.error_union.payload_type;
- LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
- LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type);
+ LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->err_union);
if (type_has_bits(payload_type)) {
LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
@@ -4556,7 +4568,30 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab
}
}
-static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrPayload *instruction) {
+static LLVMValueRef ir_render_error_union_field_error_set(CodeGen *g, IrExecutable *executable,
+ IrInstructionErrorUnionFieldErrorSet *instruction)
+{
+ ZigType *ptr_type = instruction->ptr->value.type;
+ assert(ptr_type->id == ZigTypeIdPointer);
+ ZigType *err_union_type = ptr_type->data.pointer.child_type;
+ assert(err_union_type->id == ZigTypeIdErrorUnion);
+ ZigType *payload_type = err_union_type->data.error_union.payload_type;
+ LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->ptr);
+
+ if (type_has_bits(payload_type)) {
+ return LLVMBuildStructGEP(g->builder, err_union_ptr, err_union_err_index, "");
+ } else {
+ return err_union_ptr;
+ }
+}
+
+static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable,
+ IrInstructionUnwrapErrPayload *instruction)
+{
+ bool want_safety = ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on &&
+ g->errors_by_index.length > 1;
+ if (!want_safety && !type_has_bits(instruction->base.value.type))
+ return nullptr;
ZigType *ptr_type = instruction->value->value.type;
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *err_union_type = ptr_type->data.pointer.child_type;
@@ -4568,7 +4603,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu
return err_union_handle;
}
- if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && g->errors_by_index.length > 1) {
+ if (want_safety) {
LLVMValueRef err_val;
if (type_has_bits(payload_type)) {
LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
@@ -4607,19 +4642,19 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
}
LLVMValueRef payload_val = ir_llvm_value(g, instruction->value);
- if (type_is_codegen_pointer(child_type)) {
+ if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) {
return payload_val;
}
- assert(instruction->tmp_ptr);
+ LLVMValueRef result_ptr = ir_llvm_value(g, instruction->result_loc);
- LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");
+ LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_ptr, maybe_child_index, "");
// child_type and instruction->value->value.type may differ by constness
gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val);
- LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, "");
+ LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, result_ptr, maybe_null_index, "");
gen_store_untyped(g, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr, 0, false);
- return instruction->tmp_ptr;
+ return result_ptr;
}
static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable, IrInstructionErrWrapCode *instruction) {
@@ -4635,12 +4670,12 @@ static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable
if (!type_has_bits(payload_type) || !type_has_bits(err_set_type))
return err_val;
- assert(instruction->tmp_ptr);
+ LLVMValueRef result_ptr = ir_llvm_value(g, instruction->result_loc);
- LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, "");
+ LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, result_ptr, err_union_err_index, "");
gen_store_untyped(g, err_val, err_tag_ptr, 0, false);
- return instruction->tmp_ptr;
+ return result_ptr;
}
static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executable, IrInstructionErrWrapPayload *instruction) {
@@ -4660,17 +4695,17 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
if (!type_has_bits(payload_type))
return ok_err_val;
- assert(instruction->tmp_ptr);
+ LLVMValueRef result_ptr = ir_llvm_value(g, instruction->result_loc);
LLVMValueRef payload_val = ir_llvm_value(g, instruction->value);
- LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, "");
+ LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, result_ptr, err_union_err_index, "");
gen_store_untyped(g, ok_err_val, err_tag_ptr, 0, false);
- LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");
+ LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, result_ptr, err_union_payload_index, "");
gen_assign_raw(g, payload_ptr, get_pointer_to_type(g, payload_type, false), payload_val);
- return instruction->tmp_ptr;
+ return result_ptr;
}
static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, IrInstructionUnionTag *instruction) {
@@ -4691,90 +4726,6 @@ static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, Ir
return get_handle_value(g, tag_field_ptr, tag_type, ptr_type);
}
-static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, IrInstructionStructInit *instruction) {
- for (size_t i = 0; i < instruction->field_count; i += 1) {
- IrInstructionStructInitField *field = &instruction->fields[i];
- TypeStructField *type_struct_field = field->type_struct_field;
- if (!type_has_bits(type_struct_field->type_entry))
- continue;
-
- LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
- (unsigned)type_struct_field->gen_index, "");
- LLVMValueRef value = ir_llvm_value(g, field->value);
-
- uint32_t field_align_bytes = get_abi_alignment(g, type_struct_field->type_entry);
- uint32_t host_int_bytes = get_host_int_bytes(g, instruction->struct_type, type_struct_field);
-
- ZigType *ptr_type = get_pointer_to_type_extra(g, type_struct_field->type_entry,
- false, false, PtrLenSingle, field_align_bytes,
- (uint32_t)type_struct_field->bit_offset_in_host, host_int_bytes);
-
- gen_assign_raw(g, field_ptr, ptr_type, value);
- }
- return instruction->tmp_ptr;
-}
-
-static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, IrInstructionUnionInit *instruction) {
- TypeUnionField *type_union_field = instruction->field;
-
- if (!type_has_bits(type_union_field->type_entry))
- return nullptr;
-
- uint32_t field_align_bytes = get_abi_alignment(g, type_union_field->type_entry);
- ZigType *ptr_type = get_pointer_to_type_extra(g, type_union_field->type_entry,
- false, false, PtrLenSingle, field_align_bytes,
- 0, 0);
-
- LLVMValueRef uncasted_union_ptr;
- // Even if safety is off in this block, if the union type has the safety field, we have to populate it
- // correctly. Otherwise safety code somewhere other than here could fail.
- ZigType *union_type = instruction->union_type;
- if (union_type->data.unionation.gen_tag_index != SIZE_MAX) {
- LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
- union_type->data.unionation.gen_tag_index, "");
-
- LLVMValueRef tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref,
- &type_union_field->enum_field->value);
- gen_store_untyped(g, tag_value, tag_field_ptr, 0, false);
-
- uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
- (unsigned)union_type->data.unionation.gen_union_index, "");
- } else {
- uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, (unsigned)0, "");
- }
-
- LLVMValueRef field_ptr = LLVMBuildBitCast(g->builder, uncasted_union_ptr, ptr_type->type_ref, "");
- LLVMValueRef value = ir_llvm_value(g, instruction->init_value);
-
- gen_assign_raw(g, field_ptr, ptr_type, value);
-
- return instruction->tmp_ptr;
-}
-
-static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *executable,
- IrInstructionContainerInitList *instruction)
-{
- ZigType *array_type = instruction->base.value.type;
- assert(array_type->id == ZigTypeIdArray);
- LLVMValueRef tmp_array_ptr = instruction->tmp_ptr;
- assert(tmp_array_ptr);
-
- size_t field_count = instruction->item_count;
-
- ZigType *child_type = array_type->data.array.child_type;
- for (size_t i = 0; i < field_count; i += 1) {
- LLVMValueRef elem_val = ir_llvm_value(g, instruction->items[i]);
- LLVMValueRef indices[] = {
- LLVMConstNull(g->builtin_types.entry_usize->type_ref),
- LLVMConstInt(g->builtin_types.entry_usize->type_ref, i, false),
- };
- LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP(g->builder, tmp_array_ptr, indices, 2, "");
- gen_assign_raw(g, elem_ptr, get_pointer_to_type(g, child_type, false), elem_val);
- }
-
- return tmp_array_ptr;
-}
-
static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) {
gen_panic(g, ir_llvm_value(g, instruction->msg), get_cur_err_ret_trace_val(g, instruction->base.scope));
return nullptr;
@@ -4959,9 +4910,7 @@ static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_f
args.append(alignment_val);
LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, alloc_fn_val, args.items, args.length,
get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
- set_call_instr_sret(g, call_instruction);
- LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, sret_ptr, err_union_err_index, "");
- LLVMValueRef err_val = LLVMBuildLoad(g->builder, err_val_ptr, "");
+ LLVMValueRef err_val = call_instruction;
LLVMBuildStore(g->builder, err_val, err_code_ptr);
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, LLVMConstNull(LLVMTypeOf(err_val)), "");
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(fn_val, "AllocOk");
@@ -4969,7 +4918,7 @@ static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_f
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
LLVMPositionBuilderAtEnd(g->builder, ok_block);
- LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, sret_ptr, err_union_payload_index, "");
+ LLVMValueRef payload_ptr = sret_ptr;
ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, false, false,
PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
ZigType *slice_type = get_slice_type(g, u8_ptr_type);
@@ -5078,6 +5027,188 @@ static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstr
return LLVMBuildCall(g->builder, fn_val, &op, 1, "");
}
+static LLVMValueRef ir_render_result_return(CodeGen *g, IrExecutable *executable,
+ IrInstructionResultReturn *instruction)
+{
+ assert(g->cur_ret_ptr != nullptr || !type_has_bits(instruction->base.value.type));
+ return g->cur_ret_ptr;
+}
+
+static LLVMValueRef ir_render_result_optional_payload(CodeGen *g, IrExecutable *executable,
+ IrInstructionResultOptionalPayload *instruction)
+{
+ LLVMValueRef prev_result_loc = ir_llvm_value(g, instruction->prev_result_loc);
+ ZigType *ptr_type = instruction->base.value.type;
+ assert(ptr_type->id == ZigTypeIdPointer);
+ ZigType *child_type = ptr_type->data.pointer.child_type;
+ if (!type_has_bits(child_type)) {
+ if (instruction->make_non_null) {
+ LLVMValueRef non_null_bit = LLVMConstInt(LLVMInt1Type(), 1, true);
+ gen_store_untyped(g, non_null_bit, prev_result_loc, 0, false);
+ }
+ return prev_result_loc;
+ } else if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) {
+ return prev_result_loc;
+ } else {
+ if (instruction->make_non_null) {
+ LLVMValueRef nonnull_ptr = LLVMBuildStructGEP(g->builder, prev_result_loc, maybe_null_index, "");
+ gen_store_untyped(g, LLVMConstInt(LLVMInt1Type(), 1, true), nonnull_ptr, 0, false);
+ }
+ return LLVMBuildStructGEP(g->builder, prev_result_loc, maybe_child_index, "");
+ }
+}
+
+static LLVMValueRef ir_render_result_slice_ptr(CodeGen *g, IrExecutable *executable,
+ IrInstructionResultSlicePtr *instruction)
+{
+ LLVMValueRef prev_result_loc = ir_llvm_value(g, instruction->prev_result_loc);
+ assert(instruction->prev_result_loc->value.type->id == ZigTypeIdPointer);
+ ZigType *slice_type = instruction->prev_result_loc->value.type->data.pointer.child_type;
+ assert(slice_type->id == ZigTypeIdStruct && slice_type->data.structure.is_slice);
+ size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
+
+ LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, prev_result_loc, (unsigned)len_field_index, "");
+ LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, instruction->len, false);
+ gen_store_untyped(g, len_val, len_field_ptr, 0, false);
+
+ size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
+ LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, prev_result_loc, (unsigned)ptr_field_index, "");
+ if (instruction->array_loc == nullptr)
+ return ptr_field_ptr;
+
+ LLVMValueRef array_loc = ir_llvm_value(g, instruction->array_loc);
+ LLVMValueRef indices[] = {
+ LLVMConstNull(g->builtin_types.entry_usize->type_ref),
+ LLVMConstInt(g->builtin_types.entry_usize->type_ref, 0, false),
+ };
+ LLVMValueRef casted_array_loc = LLVMBuildInBoundsGEP(g->builder, array_loc, indices, 2, "");
+ gen_store_untyped(g, casted_array_loc, ptr_field_ptr, 0, false);
+
+ return ptr_field_ptr;
+}
+
+static LLVMValueRef ir_render_result_error_union_payload(CodeGen *g, IrExecutable *executable,
+ IrInstructionResultErrorUnionPayload *instruction)
+{
+ LLVMValueRef prev_result_loc = ir_llvm_value(g, instruction->prev_result_loc);
+ LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, prev_result_loc, err_union_err_index, "");
+ LLVMTypeRef err_type_ref = g->builtin_types.entry_global_error_set->type_ref;
+ gen_store_untyped(g, LLVMConstInt(err_type_ref, 0, false), err_val_ptr, 0, false);
+ return LLVMBuildStructGEP(g->builder, prev_result_loc, err_union_payload_index, "");
+}
+
+static LLVMValueRef ir_render_result_error_union_code(CodeGen *g, IrExecutable *executable,
+ IrInstructionResultErrorUnionCode *instruction)
+{
+ LLVMValueRef prev_result_loc = ir_llvm_value(g, instruction->prev_result_loc);
+ ZigType *ptr_to_error_union_type = instruction->prev_result_loc->value.type;
+ assert(ptr_to_error_union_type->id == ZigTypeIdPointer);
+ ZigType *error_union_type = ptr_to_error_union_type->data.pointer.child_type;
+ assert(error_union_type->id == ZigTypeIdErrorUnion);
+ if (type_has_bits(error_union_type->data.error_union.payload_type)) {
+ return LLVMBuildStructGEP(g->builder, prev_result_loc, err_union_err_index, "");
+ } else {
+ return prev_result_loc;
+ }
+}
+
+static LLVMValueRef ir_render_assert_non_error(CodeGen *g, IrExecutable *executable,
+ IrInstructionAssertNonError *instruction)
+{
+ if (!ir_want_runtime_safety(g, &instruction->base) || g->errors_by_index.length <= 1) {
+ return nullptr;
+ }
+ LLVMValueRef err_val = ir_llvm_value(g, instruction->err_code);
+ LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref);
+ LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, "");
+ LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrError");
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrOk");
+ LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block);
+
+ LLVMPositionBuilderAtEnd(g->builder, err_block);
+ gen_safety_crash_for_err(g, err_val, instruction->base.scope);
+
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ return nullptr;
+}
+
+static LLVMValueRef ir_render_assert_non_null(CodeGen *g, IrExecutable *executable,
+ IrInstructionAssertNonNull *instruction)
+{
+ if (!ir_want_runtime_safety(g, &instruction->base)) {
+ return nullptr;
+ }
+ LLVMValueRef is_non_null = ir_llvm_value(g, instruction->is_non_null);
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk");
+ LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail");
+ LLVMBuildCondBr(g->builder, is_non_null, ok_block, fail_block);
+
+ LLVMPositionBuilderAtEnd(g->builder, fail_block);
+ gen_safety_crash(g, PanicMsgIdUnwrapOptionalFail);
+
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ return nullptr;
+}
+
+static LLVMValueRef ir_render_set_non_null_bit(CodeGen *g, IrExecutable *executable,
+ IrInstructionSetNonNullBit *instruction)
+{
+ LLVMValueRef ptr_to_optional = ir_llvm_value(g, instruction->prev_result_loc);
+ LLVMValueRef non_null_bit = ir_llvm_value(g, instruction->non_null_bit);
+
+ LLVMValueRef nonnull_ptr = LLVMBuildStructGEP(g->builder, ptr_to_optional, maybe_null_index, "");
+ gen_store_untyped(g, non_null_bit, nonnull_ptr, 0, false);
+ return nullptr;
+}
+
+static LLVMValueRef ir_render_result_slice_to_bytes(CodeGen *g, IrExecutable *executable,
+ IrInstructionResultSliceToBytesGen *instruction)
+{
+ LLVMValueRef prev_result_loc = ir_llvm_value(g, instruction->prev_result_loc);
+ LLVMValueRef new_result_loc = LLVMBuildBitCast(g->builder, prev_result_loc,
+ instruction->base.value.type->type_ref, "");
+ return new_result_loc;
+}
+
+static LLVMValueRef ir_render_from_bytes_len(CodeGen *g, IrExecutable *executable,
+ IrInstructionFromBytesLenGen *instruction)
+{
+ LLVMValueRef prev_result_loc = ir_llvm_value(g, instruction->prev_result_loc);
+ LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, prev_result_loc, slice_len_index, "");
+ LLVMValueRef prev_len = LLVMBuildLoad(g->builder, len_ptr, "");
+ uint64_t elem_size = type_size(g, instruction->elem_type);
+ LLVMValueRef elem_size_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, elem_size, false);
+ if (ir_want_runtime_safety(g, &instruction->base)) {
+ LLVMValueRef remainder_val = LLVMBuildURem(g->builder, prev_len, elem_size_val, "");
+ LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_usize->type_ref);
+ LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
+ LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenFail");
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "SliceWidenOk");
+ LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
+
+ LLVMPositionBuilderAtEnd(g->builder, fail_block);
+ gen_safety_crash(g, PanicMsgIdSliceWidenRemainder);
+
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ }
+ LLVMValueRef new_len = LLVMBuildExactUDiv(g->builder, prev_len, elem_size_val, "");
+ LLVMBuildStore(g->builder, new_len, len_ptr);
+ return nullptr;
+}
+
+static LLVMValueRef ir_render_to_bytes_len(CodeGen *g, IrExecutable *executable,
+ IrInstructionToBytesLenGen *instruction)
+{
+ LLVMValueRef prev_result_loc = ir_llvm_value(g, instruction->prev_result_loc);
+ LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, prev_result_loc, slice_len_index, "");
+ LLVMValueRef prev_len = LLVMBuildLoad(g->builder, len_ptr, "");
+ uint64_t elem_size = type_size(g, instruction->elem_type);
+ LLVMValueRef elem_size_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, elem_size, false);
+ LLVMValueRef new_len = LLVMBuildMul(g->builder, prev_len, elem_size_val, "");
+ LLVMBuildStore(g->builder, new_len, len_ptr);
+ return nullptr;
+}
+
static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInstructionBswap *instruction) {
LLVMValueRef op = ir_llvm_value(g, instruction->op);
ZigType *int_type = instruction->base.value.type;
@@ -5101,6 +5232,53 @@ static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInst
return LLVMBuildTrunc(g->builder, shifted, int_type->type_ref, "");
}
+static LLVMValueRef gen_array_to_slice(CodeGen *g, LLVMValueRef result_ptr, LLVMValueRef array_ptr,
+ ZigType *array_type)
+{
+ LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, result_ptr,
+ slice_ptr_index, "");
+ LLVMValueRef indices[] = {
+ LLVMConstNull(g->builtin_types.entry_usize->type_ref),
+ LLVMConstInt(g->builtin_types.entry_usize->type_ref, 0, false),
+ };
+ LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");
+ gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
+
+ LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, result_ptr, slice_len_index, "");
+ LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
+ array_type->data.array.len, false);
+ gen_store_untyped(g, len_value, len_field_ptr, 0, false);
+
+ return result_ptr;
+}
+
+static LLVMValueRef ir_render_ptr_of_array_to_slice(CodeGen *g, IrExecutable *executable,
+ IrInstructionPtrOfArrayToSlice *instruction)
+{
+ ZigType *actual_type = instruction->value->value.type;
+ LLVMValueRef array_ptr = ir_llvm_value(g, instruction->value);
+ assert(array_ptr);
+
+ assert(actual_type->id == ZigTypeIdPointer);
+ ZigType *array_type = actual_type->data.pointer.child_type;
+ assert(array_type->id == ZigTypeIdArray);
+
+ LLVMValueRef result_ptr = ir_llvm_value(g, instruction->result_loc);
+ return gen_array_to_slice(g, result_ptr, array_ptr, array_type);
+}
+
+static LLVMValueRef ir_render_array_to_slice(CodeGen *g, IrExecutable *executable,
+ IrInstructionArrayToSlice *instruction)
+{
+ ZigType *array_type = instruction->array->value.type;
+ assert(array_type->id == ZigTypeIdArray);
+ assert(handle_is_ptr(array_type));
+ LLVMValueRef result_ptr = ir_llvm_value(g, instruction->result_loc);
+ LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array);
+
+ return gen_array_to_slice(g, result_ptr, array_ptr, array_type);
+}
+
static LLVMValueRef ir_render_bit_reverse(CodeGen *g, IrExecutable *executable, IrInstructionBitReverse *instruction) {
LLVMValueRef op = ir_llvm_value(g, instruction->op);
ZigType *int_type = instruction->base.value.type;
@@ -5180,16 +5358,32 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdFloatToInt:
case IrInstructionIdBoolToInt:
case IrInstructionIdErrSetCast:
- case IrInstructionIdFromBytes:
- case IrInstructionIdToBytes:
case IrInstructionIdEnumToInt:
case IrInstructionIdCheckRuntimeScope:
+ case IrInstructionIdDeclVarSrc:
+ case IrInstructionIdAllocaSrc:
+ case IrInstructionIdAllocaGen:
+ case IrInstructionIdFirstArgResultLoc:
+ case IrInstructionIdResultCast:
+ case IrInstructionIdContainerInitList:
+ case IrInstructionIdInferArrayType:
+ case IrInstructionIdPtrCastSrc:
+ case IrInstructionIdInferCompTime:
+ case IrInstructionIdResultPtrCast:
+ case IrInstructionIdCmpxchgSrc:
+ case IrInstructionIdErrorLiteral:
+ case IrInstructionIdResultSliceToBytesSrc:
+ case IrInstructionIdResultSliceToBytesPlaceholder:
+ case IrInstructionIdResultBytesToSlice:
+ case IrInstructionIdFromBytesLenSrc:
+ case IrInstructionIdToBytesLenSrc:
+ case IrInstructionIdResultChild:
zig_unreachable();
+ case IrInstructionIdDeclVarGen:
+ return ir_render_decl_var(g, executable, (IrInstructionDeclVarGen *)instruction);
case IrInstructionIdReturn:
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
- case IrInstructionIdDeclVar:
- return ir_render_decl_var(g, executable, (IrInstructionDeclVar *)instruction);
case IrInstructionIdBinOp:
return ir_render_bin_op(g, executable, (IrInstructionBinOp *)instruction);
case IrInstructionIdCast:
@@ -5220,8 +5414,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);
case IrInstructionIdTestNonNull:
return ir_render_test_non_null(g, executable, (IrInstructionTestNonNull *)instruction);
- case IrInstructionIdUnwrapOptional:
- return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapOptional *)instruction);
+ case IrInstructionIdOptionalUnwrapPtr:
+ return ir_render_optional_unwrap_ptr(g, executable, (IrInstructionOptionalUnwrapPtr *)instruction);
+ case IrInstructionIdOptionalUnwrapVal:
+ return ir_render_optional_unwrap_val(g, executable, (IrInstructionOptionalUnwrapVal *)instruction);
case IrInstructionIdClz:
return ir_render_clz(g, executable, (IrInstructionClz *)instruction);
case IrInstructionIdCtz:
@@ -5236,8 +5432,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_ref(g, executable, (IrInstructionRef *)instruction);
case IrInstructionIdErrName:
return ir_render_err_name(g, executable, (IrInstructionErrName *)instruction);
- case IrInstructionIdCmpxchg:
- return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchg *)instruction);
+ case IrInstructionIdCmpxchgGen:
+ return ir_render_cmpxchg(g, executable, (IrInstructionCmpxchgGen *)instruction);
case IrInstructionIdFence:
return ir_render_fence(g, executable, (IrInstructionFence *)instruction);
case IrInstructionIdTruncate:
@@ -5262,6 +5458,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_overflow_op(g, executable, (IrInstructionOverflowOp *)instruction);
case IrInstructionIdTestErr:
return ir_render_test_err(g, executable, (IrInstructionTestErr *)instruction);
+ case IrInstructionIdErrorUnionFieldErrorSet:
+ return ir_render_error_union_field_error_set(g, executable, (IrInstructionErrorUnionFieldErrorSet *)instruction);
case IrInstructionIdUnwrapErrCode:
return ir_render_unwrap_err_code(g, executable, (IrInstructionUnwrapErrCode *)instruction);
case IrInstructionIdUnwrapErrPayload:
@@ -5274,14 +5472,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction);
case IrInstructionIdUnionTag:
return ir_render_union_tag(g, executable, (IrInstructionUnionTag *)instruction);
- case IrInstructionIdStructInit:
- return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction);
- case IrInstructionIdUnionInit:
- return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction);
- case IrInstructionIdPtrCast:
- return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction);
- case IrInstructionIdBitCast:
- return ir_render_bit_cast(g, executable, (IrInstructionBitCast *)instruction);
+ case IrInstructionIdPtrCastGen:
+ return ir_render_ptr_cast(g, executable, (IrInstructionPtrCastGen *)instruction);
case IrInstructionIdWidenOrShorten:
return ir_render_widen_or_shorten(g, executable, (IrInstructionWidenOrShorten *)instruction);
case IrInstructionIdPtrToInt:
@@ -5294,8 +5486,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_int_to_err(g, executable, (IrInstructionIntToErr *)instruction);
case IrInstructionIdErrToInt:
return ir_render_err_to_int(g, executable, (IrInstructionErrToInt *)instruction);
- case IrInstructionIdContainerInitList:
- return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction);
case IrInstructionIdPanic:
return ir_render_panic(g, executable, (IrInstructionPanic *)instruction);
case IrInstructionIdTagName:
@@ -5346,8 +5536,34 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction);
case IrInstructionIdSqrt:
return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction);
+ case IrInstructionIdResultReturn:
+ return ir_render_result_return(g, executable, (IrInstructionResultReturn *)instruction);
+ case IrInstructionIdResultOptionalPayload:
+ return ir_render_result_optional_payload(g, executable, (IrInstructionResultOptionalPayload *)instruction);
+ case IrInstructionIdResultSlicePtr:
+ return ir_render_result_slice_ptr(g, executable, (IrInstructionResultSlicePtr *)instruction);
+ case IrInstructionIdResultErrorUnionPayload:
+ return ir_render_result_error_union_payload(g, executable, (IrInstructionResultErrorUnionPayload *)instruction);
+ case IrInstructionIdResultErrorUnionCode:
+ return ir_render_result_error_union_code(g, executable, (IrInstructionResultErrorUnionCode *)instruction);
+ case IrInstructionIdAssertNonError:
+ return ir_render_assert_non_error(g, executable, (IrInstructionAssertNonError *)instruction);
+ case IrInstructionIdAssertNonNull:
+ return ir_render_assert_non_null(g, executable, (IrInstructionAssertNonNull *)instruction);
+ case IrInstructionIdSetNonNullBit:
+ return ir_render_set_non_null_bit(g, executable, (IrInstructionSetNonNullBit *)instruction);
+ case IrInstructionIdResultSliceToBytesGen:
+ return ir_render_result_slice_to_bytes(g, executable, (IrInstructionResultSliceToBytesGen *)instruction);
+ case IrInstructionIdFromBytesLenGen:
+ return ir_render_from_bytes_len(g, executable, (IrInstructionFromBytesLenGen *)instruction);
+ case IrInstructionIdToBytesLenGen:
+ return ir_render_to_bytes_len(g, executable, (IrInstructionToBytesLenGen *)instruction);
case IrInstructionIdBswap:
return ir_render_bswap(g, executable, (IrInstructionBswap *)instruction);
+ case IrInstructionIdPtrOfArrayToSlice:
+ return ir_render_ptr_of_array_to_slice(g, executable, (IrInstructionPtrOfArrayToSlice *)instruction);
+ case IrInstructionIdArrayToSlice:
+ return ir_render_array_to_slice(g, executable, (IrInstructionArrayToSlice *)instruction);
case IrInstructionIdBitReverse:
return ir_render_bit_reverse(g, executable, (IrInstructionBitReverse *)instruction);
}
@@ -5366,8 +5582,25 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) {
LLVMPositionBuilderAtEnd(g->builder, current_block->llvm_block);
for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) {
IrInstruction *instruction = current_block->instruction_list.at(instr_i);
- if (instruction->ref_count == 0 && !ir_has_side_effects(instruction))
- continue;
+ if (!ir_has_side_effects(instruction)) {
+ if (instruction->ref_count == 0)
+ continue;
+ if (instruction->value.special != ConstValSpecialRuntime) {
+ // If it's not a pointer, skip
+ if (get_codegen_ptr_type(instruction->value.type) == nullptr)
+ continue;
+ // If the const-ness isn't inferred, skip
+ if (instruction->value.data.x_ptr.mut != ConstPtrMutInfer)
+ continue;
+
+ // Follow the const ptr reference, see if the underlying value is runtime
+ if (const_ptr_pointee(nullptr, g, &instruction->value, nullptr)->special !=
+ ConstValSpecialRuntime)
+ {
+ continue;
+ }
+ }
+ }
instruction->llvm_value = ir_render_instruction(g, executable, instruction);
}
current_block->llvm_exit_block = LLVMGetInsertBlock(g->builder);
@@ -5377,6 +5610,9 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) {
static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index);
static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index);
static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val);
+static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ConstExprValue *err_union_const_val);
+static LLVMValueRef gen_const_ptr_err_union_payload_recursive(CodeGen *g, ConstExprValue *err_union_const_val);
+static LLVMValueRef gen_const_ptr_optional_payload_recursive(CodeGen *g, ConstExprValue *optional_const_val);
static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) {
switch (parent->id) {
@@ -5387,6 +5623,12 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent
case ConstParentIdStruct:
return gen_const_ptr_struct_recursive(g, parent->data.p_struct.struct_val,
parent->data.p_struct.field_index);
+ case ConstParentIdErrUnionCode:
+ return gen_const_ptr_err_union_code_recursive(g, parent->data.p_err_union_code.err_union_val);
+ case ConstParentIdErrUnionPayload:
+ return gen_const_ptr_err_union_payload_recursive(g, parent->data.p_err_union_payload.err_union_val);
+ case ConstParentIdOptionalPayload:
+ return gen_const_ptr_optional_payload_recursive(g, parent->data.p_optional_payload.optional_val);
case ConstParentIdArray:
return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val,
parent->data.p_array.elem_index);
@@ -5402,7 +5644,7 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent
static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index) {
expand_undef_array(g, array_const_val);
- ConstParent *parent = &array_const_val->data.x_array.data.s_none.parent;
+ ConstParent *parent = &array_const_val->parent;
LLVMValueRef base_ptr = gen_parent_ptr(g, array_const_val, parent);
LLVMTypeKind el_type = LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(base_ptr)));
@@ -5427,7 +5669,7 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar
}
static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index) {
- ConstParent *parent = &struct_const_val->data.x_struct.parent;
+ ConstParent *parent = &struct_const_val->parent;
LLVMValueRef base_ptr = gen_parent_ptr(g, struct_const_val, parent);
ZigType *u32 = g->builtin_types.entry_u32;
@@ -5438,8 +5680,44 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s
return LLVMConstInBoundsGEP(base_ptr, indices, 2);
}
+static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ConstExprValue *err_union_const_val) {
+ ConstParent *parent = &err_union_const_val->parent;
+ LLVMValueRef base_ptr = gen_parent_ptr(g, err_union_const_val, parent);
+
+ ZigType *u32 = g->builtin_types.entry_u32;
+ LLVMValueRef indices[] = {
+ LLVMConstNull(u32->type_ref),
+ LLVMConstInt(u32->type_ref, err_union_err_index, false),
+ };
+ return LLVMConstInBoundsGEP(base_ptr, indices, 2);
+}
+
+static LLVMValueRef gen_const_ptr_err_union_payload_recursive(CodeGen *g, ConstExprValue *err_union_const_val) {
+ ConstParent *parent = &err_union_const_val->parent;
+ LLVMValueRef base_ptr = gen_parent_ptr(g, err_union_const_val, parent);
+
+ ZigType *u32 = g->builtin_types.entry_u32;
+ LLVMValueRef indices[] = {
+ LLVMConstNull(u32->type_ref),
+ LLVMConstInt(u32->type_ref, err_union_payload_index, false),
+ };
+ return LLVMConstInBoundsGEP(base_ptr, indices, 2);
+}
+
+static LLVMValueRef gen_const_ptr_optional_payload_recursive(CodeGen *g, ConstExprValue *optional_const_val) {
+ ConstParent *parent = &optional_const_val->parent;
+ LLVMValueRef base_ptr = gen_parent_ptr(g, optional_const_val, parent);
+
+ ZigType *u32 = g->builtin_types.entry_u32;
+ LLVMValueRef indices[] = {
+ LLVMConstNull(u32->type_ref),
+ LLVMConstInt(u32->type_ref, maybe_child_index, false),
+ };
+ return LLVMConstInBoundsGEP(base_ptr, indices, 2);
+}
+
static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val) {
- ConstParent *parent = &union_const_val->data.x_union.parent;
+ ConstParent *parent = &union_const_val->parent;
LLVMValueRef base_ptr = gen_parent_ptr(g, union_const_val, parent);
ZigType *u32 = g->builtin_types.entry_u32;
@@ -5609,6 +5887,63 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con
render_const_val_global(g, const_val, "");
return ptr_val;
}
+ case ConstPtrSpecialBaseErrorUnionCode:
+ {
+ render_const_val_global(g, const_val, name);
+ ConstExprValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_code.err_union_val;
+ assert(err_union_const_val->type->id == ZigTypeIdErrorUnion);
+ if (err_union_const_val->type->zero_bits) {
+ // make this a null pointer
+ ZigType *usize = g->builtin_types.entry_usize;
+ const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
+ const_val->type->type_ref);
+ render_const_val_global(g, const_val, "");
+ return const_val->global_refs->llvm_value;
+ }
+ LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_code_recursive(g, err_union_const_val);
+ LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
+ const_val->global_refs->llvm_value = ptr_val;
+ render_const_val_global(g, const_val, "");
+ return ptr_val;
+ }
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ {
+ render_const_val_global(g, const_val, name);
+ ConstExprValue *err_union_const_val = const_val->data.x_ptr.data.base_err_union_payload.err_union_val;
+ assert(err_union_const_val->type->id == ZigTypeIdErrorUnion);
+ if (err_union_const_val->type->zero_bits) {
+ // make this a null pointer
+ ZigType *usize = g->builtin_types.entry_usize;
+ const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
+ const_val->type->type_ref);
+ render_const_val_global(g, const_val, "");
+ return const_val->global_refs->llvm_value;
+ }
+ LLVMValueRef uncasted_ptr_val = gen_const_ptr_err_union_payload_recursive(g, err_union_const_val);
+ LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
+ const_val->global_refs->llvm_value = ptr_val;
+ render_const_val_global(g, const_val, "");
+ return ptr_val;
+ }
+ case ConstPtrSpecialBaseOptionalPayload:
+ {
+ render_const_val_global(g, const_val, name);
+ ConstExprValue *optional_const_val = const_val->data.x_ptr.data.base_optional_payload.optional_val;
+ assert(optional_const_val->type->id == ZigTypeIdOptional);
+ if (optional_const_val->type->zero_bits) {
+ // make this a null pointer
+ ZigType *usize = g->builtin_types.entry_usize;
+ const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref),
+ const_val->type->type_ref);
+ render_const_val_global(g, const_val, "");
+ return const_val->global_refs->llvm_value;
+ }
+ LLVMValueRef uncasted_ptr_val = gen_const_ptr_optional_payload_recursive(g, optional_const_val);
+ LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref);
+ const_val->global_refs->llvm_value = ptr_val;
+ render_const_val_global(g, const_val, "");
+ return ptr_val;
+ }
case ConstPtrSpecialHardCodedAddr:
{
render_const_val_global(g, const_val, name);
@@ -5621,10 +5956,17 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con
}
case ConstPtrSpecialFunction:
return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), const_val->type->type_ref);
+ case ConstPtrSpecialNull:
+ return LLVMConstNull(const_val->type->type_ref);
}
zig_unreachable();
}
+static LLVMValueRef gen_const_val_err_set(CodeGen *g, ConstExprValue *const_val, const char *name) {
+ uint64_t value = (const_val->data.x_err_set == nullptr) ? 0 : const_val->data.x_err_set->value;
+ return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref, value, false);
+}
+
static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) {
Error err;
@@ -5644,9 +5986,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
case ZigTypeIdInt:
return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint);
case ZigTypeIdErrorSet:
- assert(const_val->data.x_err_set != nullptr);
- return LLVMConstInt(g->builtin_types.entry_global_error_set->type_ref,
- const_val->data.x_err_set->value, false);
+ return gen_const_val_err_set(g, const_val, name);
case ZigTypeIdFloat:
switch (type_entry->data.floating.bit_count) {
case 16:
@@ -5680,6 +6020,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
return LLVMConstInt(LLVMInt1Type(), const_val->data.x_optional ? 1 : 0, false);
} else if (type_is_codegen_pointer(child_type)) {
return gen_const_val_ptr(g, const_val, name);
+ } else if (child_type->id == ZigTypeIdErrorSet) {
+ return gen_const_val_err_set(g, const_val, name);
} else {
LLVMValueRef child_val;
LLVMValueRef maybe_val;
@@ -5914,7 +6256,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
ZigType *err_set_type = type_entry->data.error_union.err_set_type;
if (!type_has_bits(payload_type)) {
assert(type_has_bits(err_set_type));
- uint64_t value = const_val->data.x_err_union.err ? const_val->data.x_err_union.err->value : 0;
+ ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set;
+ uint64_t value = (err_set == nullptr) ? 0 : err_set->value;
return LLVMConstInt(g->err_tag_type->type_ref, value, false);
} else if (!type_has_bits(err_set_type)) {
assert(type_has_bits(payload_type));
@@ -5923,8 +6266,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
LLVMValueRef err_tag_value;
LLVMValueRef err_payload_value;
bool make_unnamed_struct;
- if (const_val->data.x_err_union.err) {
- err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err_union.err->value, false);
+ ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set;
+ if (err_set != nullptr) {
+ err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, err_set->value, false);
err_payload_value = LLVMConstNull(payload_type->type_ref);
make_unnamed_struct = false;
} else {
@@ -6130,10 +6474,13 @@ static void do_code_gen(CodeGen *g) {
TldVar *tld_var = g->global_vars.at(i);
ZigVar *var = tld_var->var;
- if (var->value->type->id == ZigTypeIdComptimeFloat) {
+ if (var->var_type->id == ZigTypeIdComptimeFloat) {
// Generate debug info for it but that's it.
- ConstExprValue *const_val = var->value;
+ ConstExprValue *const_val = var->const_value;
assert(const_val->special != ConstValSpecialRuntime);
+ if (const_val->type != var->var_type) {
+ zig_panic("TODO debug info for var with ptr casted value");
+ }
ZigType *var_type = g->builtin_types.entry_f128;
ConstExprValue coerced_value;
coerced_value.special = ConstValSpecialStatic;
@@ -6144,10 +6491,13 @@ static void do_code_gen(CodeGen *g) {
continue;
}
- if (var->value->type->id == ZigTypeIdComptimeInt) {
+ if (var->var_type->id == ZigTypeIdComptimeInt) {
// Generate debug info for it but that's it.
- ConstExprValue *const_val = var->value;
+ ConstExprValue *const_val = var->const_value;
assert(const_val->special != ConstValSpecialRuntime);
+ if (const_val->type != var->var_type) {
+ zig_panic("TODO debug info for var with ptr casted value");
+ }
size_t bits_needed = bigint_bits_needed(&const_val->data.x_bigint);
if (bits_needed < 8) {
bits_needed = 8;
@@ -6158,7 +6508,7 @@ static void do_code_gen(CodeGen *g) {
continue;
}
- if (!type_has_bits(var->value->type))
+ if (!type_has_bits(var->var_type))
continue;
assert(var->decl_node);
@@ -6167,9 +6517,9 @@ static void do_code_gen(CodeGen *g) {
if (var->linkage == VarLinkageExternal) {
LLVMValueRef existing_llvm_var = LLVMGetNamedGlobal(g->module, buf_ptr(&var->name));
if (existing_llvm_var) {
- global_value = LLVMConstBitCast(existing_llvm_var, LLVMPointerType(var->value->type->type_ref, 0));
+ global_value = LLVMConstBitCast(existing_llvm_var, LLVMPointerType(var->var_type->type_ref, 0));
} else {
- global_value = LLVMAddGlobal(g->module, var->value->type->type_ref, buf_ptr(&var->name));
+ global_value = LLVMAddGlobal(g->module, var->var_type->type_ref, buf_ptr(&var->name));
// TODO debug info for the extern variable
LLVMSetLinkage(global_value, LLVMExternalLinkage);
@@ -6180,9 +6530,9 @@ static void do_code_gen(CodeGen *g) {
} else {
bool exported = (var->linkage == VarLinkageExport);
const char *mangled_name = buf_ptr(get_mangled_name(g, &var->name, exported));
- render_const_val(g, var->value, mangled_name);
- render_const_val_global(g, var->value, mangled_name);
- global_value = var->value->global_refs->llvm_global;
+ render_const_val(g, var->const_value, mangled_name);
+ render_const_val_global(g, var->const_value, mangled_name);
+ global_value = var->const_value->global_refs->llvm_global;
if (exported) {
LLVMSetLinkage(global_value, LLVMExternalLinkage);
@@ -6194,8 +6544,10 @@ static void do_code_gen(CodeGen *g) {
LLVMSetAlignment(global_value, var->align_bytes);
// TODO debug info for function pointers
- if (var->gen_is_const && var->value->type->id != ZigTypeIdFn) {
- gen_global_var(g, var, var->value->global_refs->llvm_value, var->value->type);
+ // Here we use const_value->type because that's the type of the llvm global,
+ // which we const ptr cast upon use to whatever it needs to be.
+ if (var->gen_is_const && var->const_value->type->id != ZigTypeIdFn) {
+ gen_global_var(g, var, var->const_value->global_refs->llvm_value, var->const_value->type);
}
LLVMSetGlobalConstant(global_value, var->gen_is_const);
@@ -6246,48 +6598,25 @@ static void do_code_gen(CodeGen *g) {
// allocate temporary stack data
for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_list.length; alloca_i += 1) {
- IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i);
- LLVMValueRef *slot;
- ZigType *slot_type = instruction->value.type;
- if (instruction->id == IrInstructionIdCast) {
- IrInstructionCast *cast_instruction = (IrInstructionCast *)instruction;
- slot = &cast_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdRef) {
- IrInstructionRef *ref_instruction = (IrInstructionRef *)instruction;
- slot = &ref_instruction->tmp_ptr;
- assert(instruction->value.type->id == ZigTypeIdPointer);
- slot_type = instruction->value.type->data.pointer.child_type;
- } else if (instruction->id == IrInstructionIdContainerInitList) {
- IrInstructionContainerInitList *container_init_list_instruction = (IrInstructionContainerInitList *)instruction;
- slot = &container_init_list_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdStructInit) {
- IrInstructionStructInit *struct_init_instruction = (IrInstructionStructInit *)instruction;
- slot = &struct_init_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdUnionInit) {
- IrInstructionUnionInit *union_init_instruction = (IrInstructionUnionInit *)instruction;
- slot = &union_init_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdCall) {
- IrInstructionCall *call_instruction = (IrInstructionCall *)instruction;
- slot = &call_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdSlice) {
- IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction;
- slot = &slice_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdOptionalWrap) {
- IrInstructionOptionalWrap *maybe_wrap_instruction = (IrInstructionOptionalWrap *)instruction;
- slot = &maybe_wrap_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdErrWrapPayload) {
- IrInstructionErrWrapPayload *err_wrap_payload_instruction = (IrInstructionErrWrapPayload *)instruction;
- slot = &err_wrap_payload_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdErrWrapCode) {
- IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction;
- slot = &err_wrap_code_instruction->tmp_ptr;
- } else if (instruction->id == IrInstructionIdCmpxchg) {
- IrInstructionCmpxchg *cmpxchg_instruction = (IrInstructionCmpxchg *)instruction;
- slot = &cmpxchg_instruction->tmp_ptr;
- } else {
- zig_unreachable();
+ IrInstructionAllocaGen *instruction = fn_table_entry->alloca_list.at(alloca_i);
+ ZigType *ptr_type = instruction->base.value.type;
+ assert(ptr_type->id == ZigTypeIdPointer);
+ ZigType *child_type = ptr_type->data.pointer.child_type;
+ if (!type_has_bits(child_type))
+ continue;
+ if (child_type == g->builtin_types.entry_infer)
+ continue;
+ if (instruction->base.ref_count == 0)
+ continue;
+ if (instruction->base.value.special != ConstValSpecialRuntime) {
+ if (const_ptr_pointee(nullptr, g, &instruction->base.value, nullptr)->special !=
+ ConstValSpecialRuntime)
+ {
+ continue;
+ }
}
- *slot = build_alloca(g, slot_type, "", get_abi_alignment(g, slot_type));
+ instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint,
+ get_ptr_align(g, ptr_type));
}
ImportTableEntry *import = get_scope_import(&fn_table_entry->fndef_scope->base);
@@ -6304,12 +6633,12 @@ static void do_code_gen(CodeGen *g) {
for (size_t var_i = 0; var_i < fn_table_entry->variable_list.length; var_i += 1) {
ZigVar *var = fn_table_entry->variable_list.at(var_i);
- if (!type_has_bits(var->value->type)) {
+ if (!type_has_bits(var->var_type)) {
continue;
}
if (ir_get_var_is_comptime(var))
continue;
- switch (type_requires_comptime(g, var->value->type)) {
+ switch (type_requires_comptime(g, var->var_type)) {
case ReqCompTimeInvalid:
zig_unreachable();
case ReqCompTimeYes:
@@ -6319,11 +6648,9 @@ static void do_code_gen(CodeGen *g) {
}
if (var->src_arg_index == SIZE_MAX) {
- var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes);
-
var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
buf_ptr(&var->name), import->di_file, (unsigned)(var->decl_node->line + 1),
- var->value->type->di_type, !g->strip_debug_symbols, 0);
+ var->var_type->di_type, !g->strip_debug_symbols, 0);
} else if (is_c_abi) {
fn_walk_var.data.vars.var = var;
@@ -6333,16 +6660,16 @@ static void do_code_gen(CodeGen *g) {
ZigType *gen_type;
FnGenParamInfo *gen_info = &fn_table_entry->type_entry->data.fn.gen_param_info[var->src_arg_index];
- if (handle_is_ptr(var->value->type)) {
+ if (handle_is_ptr(var->var_type)) {
if (gen_info->is_byval) {
- gen_type = var->value->type;
+ gen_type = var->var_type;
} else {
gen_type = gen_info->type;
}
var->value_ref = LLVMGetParam(fn, (unsigned)var->gen_arg_index);
} else {
- gen_type = var->value->type;
- var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes);
+ gen_type = var->var_type;
+ var->value_ref = build_alloca(g, var->var_type, buf_ptr(&var->name), var->align_bytes);
}
if (var->decl_node) {
var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
@@ -6656,6 +6983,9 @@ static void define_builtin_types(CodeGen *g) {
g->builtin_types.entry_c_void = get_opaque_type(g, nullptr, nullptr, "c_void");
g->primitive_type_table.put(&g->builtin_types.entry_c_void->name, g->builtin_types.entry_c_void);
}
+ {
+ g->builtin_types.entry_infer = get_opaque_type(g, nullptr, nullptr, "(infer)");
+ }
{
ZigType *entry = new_type_table_entry(ZigTypeIdErrorSet);
@@ -7458,9 +7788,9 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
ConstExprValue *this_val = &test_fn_array->data.x_array.data.s_none.elements[i];
this_val->special = ConstValSpecialStatic;
this_val->type = struct_type;
- this_val->data.x_struct.parent.id = ConstParentIdArray;
- this_val->data.x_struct.parent.data.p_array.array_val = test_fn_array;
- this_val->data.x_struct.parent.data.p_array.elem_index = i;
+ this_val->parent.id = ConstParentIdArray;
+ this_val->parent.data.p_array.array_val = test_fn_array;
+ this_val->parent.data.p_array.elem_index = i;
this_val->data.x_struct.fields = create_const_vals(2);
ConstExprValue *name_field = &this_val->data.x_struct.fields[0];
diff --git a/src/ir.cpp b/src/ir.cpp
index c651f30dd54f..85df4a1af694 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -35,8 +35,11 @@ struct IrAnalyze {
size_t instruction_index;
ZigType *explicit_return_type;
AstNode *explicit_return_type_source_node;
+ ZigType *scalar_return_type;
+ ZigType *payload_return_type;
ZigList src_implicit_return_type_list;
IrBasicBlock *const_predecessor_bb;
+ ConstExprValue *result_value;
};
enum ConstCastResultId {
@@ -146,17 +149,16 @@ enum UndefAllowed {
UndefBad,
};
-static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
-static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval);
+static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope,
+ LVal lval, IrInstruction *result_loc);
static IrInstruction *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction);
static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, ZigType *expected_type);
static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr);
static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg);
static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name,
- IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type);
+ IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type, bool initialize);
static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var);
static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op);
-static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval);
static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align);
static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align);
static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ConstExprValue *val);
@@ -165,8 +167,24 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
ConstExprValue *out_val, ConstExprValue *ptr_val);
static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr,
ZigType *dest_type, IrInstruction *dest_type_src);
+static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *uncasted_ptr, IrInstruction *uncasted_value);
static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed);
+static IrInstruction *resolve_possible_alloca_inference(IrAnalyze *ira, IrInstruction *base, ZigType *child_type);
+static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *base_ptr, bool safety_check_on);
+static IrInstruction *ir_analyze_unwrap_err_payload(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *base_ptr, IrInstruction *result_loc, bool safety_check_on);
+static IrInstruction *ir_analyze_error_union_field_error_set(IrAnalyze *ira,
+ IrInstruction *source_instr, IrInstruction *base_ptr, bool safety_check_on);
+static ZigType *adjust_ptr_child(CodeGen *g, ZigType *ptr_type, ZigType *new_child);
+static IrInstruction *ir_analyze_result_slice_to_bytes(IrAnalyze *ira,
+ IrInstruction *source_inst, IrInstruction *prev_result_loc, ZigType *elem_type, ZigType *child_type);
+static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_inst, ZigType *child_type_inst,
+ uint32_t align, const char *name_hint, bool is_comptime);
static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs);
+static IrInstruction *ir_analyze_test_non_null(IrAnalyze *ira, IrInstruction *source_inst, IrInstruction *value);
+static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align);
static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) {
assert(get_src_ptr_type(const_val->type) != nullptr);
@@ -178,15 +196,28 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c
case ConstPtrSpecialRef:
result = const_val->data.x_ptr.data.ref.pointee;
break;
- case ConstPtrSpecialBaseArray:
- expand_undef_array(g, const_val->data.x_ptr.data.base_array.array_val);
- result = &const_val->data.x_ptr.data.base_array.array_val->data.x_array.data.s_none.elements[
- const_val->data.x_ptr.data.base_array.elem_index];
+ case ConstPtrSpecialBaseArray: {
+ ConstExprValue *array_val = const_val->data.x_ptr.data.base_array.array_val;
+ expand_undef_array(g, array_val);
+ result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index];
break;
+ }
case ConstPtrSpecialBaseStruct:
result = &const_val->data.x_ptr.data.base_struct.struct_val->data.x_struct.fields[
const_val->data.x_ptr.data.base_struct.field_index];
break;
+ case ConstPtrSpecialBaseErrorUnionCode:
+ result = const_val->data.x_ptr.data.base_err_union_code.err_union_val->data.x_err_union.error_set;
+ break;
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ result = const_val->data.x_ptr.data.base_err_union_payload.err_union_val->data.x_err_union.payload;
+ break;
+ case ConstPtrSpecialBaseOptionalPayload:
+ result = const_val->data.x_ptr.data.base_optional_payload.optional_val->data.x_optional;
+ break;
+ case ConstPtrSpecialNull:
+ result = const_val;
+ break;
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialDiscard:
@@ -198,25 +229,30 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c
return result;
}
+static bool is_opt_err_set(ZigType *ty) {
+ return ty->id == ZigTypeIdErrorSet ||
+ (ty->id == ZigTypeIdOptional && ty->data.maybe.child_type->id == ZigTypeIdErrorSet);
+}
+
static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) {
if (a == b)
return true;
- if (a->id == b->id)
- return true;
+ if (a->id == b->id) {
+ if (a->id == ZigTypeIdInt) {
+ return a->data.integral.is_signed == b->data.integral.is_signed;
+ } else {
+ return true;
+ }
+ }
if (get_codegen_ptr_type(a) != nullptr && get_codegen_ptr_type(b) != nullptr)
return true;
- return false;
-}
+ if (is_opt_err_set(a) && is_opt_err_set(b))
+ return true;
-ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
- ConstExprValue *result = const_ptr_pointee_unchecked(g, const_val);
- if (const_val->type->id == ZigTypeIdPointer) {
- assert(types_have_same_zig_comptime_repr(const_val->type->data.pointer.child_type, result->type));
- }
- return result;
+ return false;
}
static bool ir_should_inline(IrExecutable *exec, Scope *scope) {
@@ -305,6 +341,14 @@ static IrBasicBlock *ir_build_bb_from(IrBuilder *irb, IrBasicBlock *other_bb) {
return new_bb;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVarSrc *) {
+ return IrInstructionIdDeclVarSrc;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVarGen *) {
+ return IrInstructionIdDeclVarGen;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionCondBr *) {
return IrInstructionIdCondBr;
}
@@ -337,10 +381,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBinOp *) {
return IrInstructionIdBinOp;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVar *) {
- return IrInstructionIdDeclVar;
-}
-
static constexpr IrInstructionId ir_instruction_id(IrInstructionExport *) {
return IrInstructionIdExport;
}
@@ -389,6 +429,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCast *) {
return IrInstructionIdCast;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrOfArrayToSlice *) {
+ return IrInstructionIdPtrOfArrayToSlice;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayToSlice *) {
+ return IrInstructionIdArrayToSlice;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionContainerInitList *) {
return IrInstructionIdContainerInitList;
}
@@ -449,8 +497,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestNonNull *) {
return IrInstructionIdTestNonNull;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapOptional *) {
- return IrInstructionIdUnwrapOptional;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionOptionalUnwrapPtr *) {
+ return IrInstructionIdOptionalUnwrapPtr;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionOptionalUnwrapVal *) {
+ return IrInstructionIdOptionalUnwrapVal;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionClz *) {
@@ -493,14 +545,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionRef *) {
return IrInstructionIdRef;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) {
- return IrInstructionIdStructInit;
-}
-
-static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInit *) {
- return IrInstructionIdUnionInit;
-}
-
static constexpr IrInstructionId ir_instruction_id(IrInstructionCompileErr *) {
return IrInstructionIdCompileErr;
}
@@ -517,8 +561,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEmbedFile *) {
return IrInstructionIdEmbedFile;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchg *) {
- return IrInstructionIdCmpxchg;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchgSrc *) {
+ return IrInstructionIdCmpxchgSrc;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionCmpxchgGen *) {
+ return IrInstructionIdCmpxchgGen;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionFence *) {
@@ -541,14 +589,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrSetCast *) {
return IrInstructionIdErrSetCast;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionToBytes *) {
- return IrInstructionIdToBytes;
-}
-
-static constexpr IrInstructionId ir_instruction_id(IrInstructionFromBytes *) {
- return IrInstructionIdFromBytes;
-}
-
static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToFloat *) {
return IrInstructionIdIntToFloat;
}
@@ -649,12 +689,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestComptime *)
return IrInstructionIdTestComptime;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCast *) {
- return IrInstructionIdPtrCast;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastSrc *) {
+ return IrInstructionIdPtrCastSrc;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) {
- return IrInstructionIdBitCast;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastGen *) {
+ return IrInstructionIdPtrCastGen;
}
static constexpr IrInstructionId ir_instruction_id(IrInstructionWidenOrShorten *) {
@@ -869,6 +909,110 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScop
return IrInstructionIdCheckRuntimeScope;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultErrorUnionPayload *) {
+ return IrInstructionIdResultErrorUnionPayload;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultErrorUnionCode *) {
+ return IrInstructionIdResultErrorUnionCode;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultOptionalPayload *) {
+ return IrInstructionIdResultOptionalPayload;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultSlicePtr *) {
+ return IrInstructionIdResultSlicePtr;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultReturn *) {
+ return IrInstructionIdResultReturn;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultChild *) {
+ return IrInstructionIdResultChild;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultPtrCast *) {
+ return IrInstructionIdResultPtrCast;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultCast *) {
+ return IrInstructionIdResultCast;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultSliceToBytesSrc *) {
+ return IrInstructionIdResultSliceToBytesSrc;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultSliceToBytesPlaceholder *) {
+ return IrInstructionIdResultSliceToBytesPlaceholder;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultSliceToBytesGen *) {
+ return IrInstructionIdResultSliceToBytesGen;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionResultBytesToSlice *) {
+ return IrInstructionIdResultBytesToSlice;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionAllocaSrc *) {
+ return IrInstructionIdAllocaSrc;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionAllocaGen *) {
+ return IrInstructionIdAllocaGen;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionAssertNonError *) {
+ return IrInstructionIdAssertNonError;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionAssertNonNull *) {
+ return IrInstructionIdAssertNonNull;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorUnionFieldErrorSet *) {
+ return IrInstructionIdErrorUnionFieldErrorSet;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionFirstArgResultLoc *) {
+ return IrInstructionIdFirstArgResultLoc;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionInferArrayType *) {
+ return IrInstructionIdInferArrayType;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionInferCompTime *) {
+ return IrInstructionIdInferCompTime;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionFromBytesLenSrc *) {
+ return IrInstructionIdFromBytesLenSrc;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionFromBytesLenGen *) {
+ return IrInstructionIdFromBytesLenGen;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionToBytesLenSrc *) {
+ return IrInstructionIdToBytesLenSrc;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionToBytesLenGen *) {
+ return IrInstructionIdToBytesLenGen;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionSetNonNullBit *) {
+ return IrInstructionIdSetNonNullBit;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionErrorLiteral *) {
+ return IrInstructionIdErrorLiteral;
+}
+
template
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate(1);
@@ -901,8 +1045,39 @@ static IrInstruction *ir_build_cast(IrBuilder *irb, Scope *scope, AstNode *sourc
return &cast_instruction->base;
}
+static IrInstruction *ir_build_ptr_of_array_to_slice(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *value, IrInstruction *result_loc)
+{
+ IrInstructionPtrOfArrayToSlice *instruction = ir_build_instruction(
+ irb, scope, source_node);
+ instruction->value = value;
+ instruction->result_loc = result_loc;
+
+ ir_ref_instruction(value, irb->current_basic_block);
+ ir_ref_instruction(result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_array_to_slice(IrAnalyze *ira, IrInstruction *source_instr, ZigType *slice_type,
+ IrInstruction *array, IrInstruction *result_loc)
+{
+ IrInstructionArrayToSlice *instruction = ir_build_instruction(
+ &ira->new_irb, source_instr->scope, source_instr->source_node);
+ instruction->base.value.special = ConstValSpecialRuntime;
+ instruction->base.value.type = slice_type;
+
+ instruction->array = array;
+ instruction->result_loc = result_loc;
+
+ ir_ref_instruction(array, ira->new_irb.current_basic_block);
+ ir_ref_instruction(result_loc, ira->new_irb.current_basic_block);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *condition,
- IrBasicBlock *then_block, IrBasicBlock *else_block, IrInstruction *is_comptime)
+ IrBasicBlock *then_block, IrBasicBlock *else_block, IrInstruction *is_comptime, IrInstruction *result_loc)
{
IrInstructionCondBr *cond_br_instruction = ir_build_instruction(irb, scope, source_node);
cond_br_instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
@@ -911,36 +1086,32 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *so
cond_br_instruction->then_block = then_block;
cond_br_instruction->else_block = else_block;
cond_br_instruction->is_comptime = is_comptime;
+ cond_br_instruction->result_loc = result_loc;
ir_ref_instruction(condition, irb->current_basic_block);
ir_ref_bb(then_block);
ir_ref_bb(else_block);
- if (is_comptime) ir_ref_instruction(is_comptime, irb->current_basic_block);
+ if (is_comptime != nullptr) ir_ref_instruction(is_comptime, irb->current_basic_block);
+ if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
return &cond_br_instruction->base;
}
-static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *return_value) {
+static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *return_value,
+ IrInstruction *result_loc)
+{
IrInstructionReturn *return_instruction = ir_build_instruction(irb, scope, source_node);
return_instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
return_instruction->base.value.special = ConstValSpecialStatic;
return_instruction->value = return_value;
+ return_instruction->result_loc = result_loc;
ir_ref_instruction(return_value, irb->current_basic_block);
+ if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
return &return_instruction->base;
}
-static IrInstruction *ir_create_const(IrBuilder *irb, Scope *scope, AstNode *source_node,
- ZigType *type_entry)
-{
- assert(type_entry);
- IrInstructionConst *const_instruction = ir_create_instruction(irb, scope, source_node);
- const_instruction->base.value.type = type_entry;
- const_instruction->base.value.special = ConstValSpecialStatic;
- return &const_instruction->base;
-}
-
static IrInstruction *ir_build_const_void(IrBuilder *irb, Scope *scope, AstNode *source_node) {
IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node);
const_instruction->base.value.type = irb->codegen->builtin_types.entry_void;
@@ -1136,14 +1307,17 @@ static IrInstruction *ir_build_field_ptr_instruction(IrBuilder *irb, Scope *scop
}
static IrInstruction *ir_build_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *container_ptr, Buf *field_name)
+ IrInstruction *container_ptr, IrInstruction *container_type, Buf *field_name, bool initialize)
{
IrInstructionFieldPtr *instruction = ir_build_instruction(irb, scope, source_node);
instruction->container_ptr = container_ptr;
+ instruction->container_type = container_type;
instruction->field_name_buffer = field_name;
instruction->field_name_expr = nullptr;
+ instruction->initialize = initialize;
ir_ref_instruction(container_ptr, irb->current_basic_block);
+ if (container_type != nullptr) ir_ref_instruction(container_type, irb->current_basic_block);
return &instruction->base;
}
@@ -1161,11 +1335,12 @@ static IrInstruction *ir_build_struct_field_ptr(IrBuilder *irb, Scope *scope, As
}
static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *union_ptr, TypeUnionField *field)
+ IrInstruction *union_ptr, TypeUnionField *field, IrInstructionUnionFieldPtrId id)
{
IrInstructionUnionFieldPtr *instruction = ir_build_instruction(irb, scope, source_node);
instruction->union_ptr = union_ptr;
instruction->field = field;
+ instruction->id = id;
ir_ref_instruction(union_ptr, irb->current_basic_block);
@@ -1175,7 +1350,7 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast
static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,
ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args,
bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator,
- IrInstruction *new_stack)
+ IrInstruction *new_stack, IrInstruction *result_loc, IrInstruction *first_arg_result_loc, LVal lval)
{
IrInstructionCall *call_instruction = ir_build_instruction(irb, scope, source_node);
call_instruction->fn_entry = fn_entry;
@@ -1187,15 +1362,17 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc
call_instruction->is_async = is_async;
call_instruction->async_allocator = async_allocator;
call_instruction->new_stack = new_stack;
+ call_instruction->result_loc = result_loc;
+ call_instruction->first_arg_result_loc = first_arg_result_loc;
+ call_instruction->lval = lval;
- if (fn_ref)
- ir_ref_instruction(fn_ref, irb->current_basic_block);
+ if (fn_ref) ir_ref_instruction(fn_ref, irb->current_basic_block);
for (size_t i = 0; i < arg_count; i += 1)
ir_ref_instruction(args[i], irb->current_basic_block);
- if (async_allocator)
- ir_ref_instruction(async_allocator, irb->current_basic_block);
- if (new_stack != nullptr)
- ir_ref_instruction(new_stack, irb->current_basic_block);
+ if (async_allocator != nullptr) ir_ref_instruction(async_allocator, irb->current_basic_block);
+ if (new_stack != nullptr) ir_ref_instruction(new_stack, irb->current_basic_block);
+ if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
+ if (first_arg_result_loc != nullptr) ir_ref_instruction(first_arg_result_loc, irb->current_basic_block);
return &call_instruction->base;
}
@@ -1272,66 +1449,45 @@ static IrInstruction *ir_build_un_op(IrBuilder *irb, Scope *scope, AstNode *sour
}
static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *container_type, size_t item_count, IrInstruction **items)
+ IrInstruction *container_type, size_t elem_count, IrInstruction **elem_result_loc_list,
+ IrInstruction *result_loc)
{
IrInstructionContainerInitList *container_init_list_instruction =
ir_build_instruction(irb, scope, source_node);
container_init_list_instruction->container_type = container_type;
- container_init_list_instruction->item_count = item_count;
- container_init_list_instruction->items = items;
+ container_init_list_instruction->elem_count = elem_count;
+ container_init_list_instruction->elem_result_loc_list = elem_result_loc_list;
+ container_init_list_instruction->result_loc = result_loc;
+ ir_ref_instruction(result_loc, irb->current_basic_block);
ir_ref_instruction(container_type, irb->current_basic_block);
- for (size_t i = 0; i < item_count; i += 1) {
- ir_ref_instruction(items[i], irb->current_basic_block);
+ for (size_t i = 0; i < elem_count; i += 1) {
+ ir_ref_instruction(elem_result_loc_list[i], irb->current_basic_block);
}
return &container_init_list_instruction->base;
}
static IrInstruction *ir_build_container_init_fields(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *container_type, size_t field_count, IrInstructionContainerInitFieldsField *fields)
+ IrInstruction *container_type, size_t field_count, IrInstructionContainerInitFieldsField *fields,
+ IrInstruction *result_loc)
{
IrInstructionContainerInitFields *container_init_fields_instruction =
ir_build_instruction(irb, scope, source_node);
container_init_fields_instruction->container_type = container_type;
container_init_fields_instruction->field_count = field_count;
container_init_fields_instruction->fields = fields;
+ container_init_fields_instruction->result_loc = result_loc;
ir_ref_instruction(container_type, irb->current_basic_block);
for (size_t i = 0; i < field_count; i += 1) {
- ir_ref_instruction(fields[i].value, irb->current_basic_block);
+ ir_ref_instruction(fields[i].result_loc, irb->current_basic_block);
}
+ ir_ref_instruction(result_loc, irb->current_basic_block);
return &container_init_fields_instruction->base;
}
-static IrInstruction *ir_build_struct_init(IrBuilder *irb, Scope *scope, AstNode *source_node,
- ZigType *struct_type, size_t field_count, IrInstructionStructInitField *fields)
-{
- IrInstructionStructInit *struct_init_instruction = ir_build_instruction(irb, scope, source_node);
- struct_init_instruction->struct_type = struct_type;
- struct_init_instruction->field_count = field_count;
- struct_init_instruction->fields = fields;
-
- for (size_t i = 0; i < field_count; i += 1)
- ir_ref_instruction(fields[i].value, irb->current_basic_block);
-
- return &struct_init_instruction->base;
-}
-
-static IrInstruction *ir_build_union_init(IrBuilder *irb, Scope *scope, AstNode *source_node,
- ZigType *union_type, TypeUnionField *field, IrInstruction *init_value)
-{
- IrInstructionUnionInit *union_init_instruction = ir_build_instruction(irb, scope, source_node);
- union_init_instruction->union_type = union_type;
- union_init_instruction->field = field;
- union_init_instruction->init_value = init_value;
-
- ir_ref_instruction(init_value, irb->current_basic_block);
-
- return &union_init_instruction->base;
-}
-
static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node) {
IrInstructionUnreachable *unreachable_instruction =
ir_build_instruction(irb, scope, source_node);
@@ -1355,20 +1511,34 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode *
return &instruction->base;
}
-static IrInstruction *ir_build_var_decl(IrBuilder *irb, Scope *scope, AstNode *source_node,
- ZigVar *var, IrInstruction *var_type, IrInstruction *align_value, IrInstruction *init_value)
+static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ ZigVar *var, IrInstruction *var_type, IrInstruction *align_value, IrInstruction *ptr)
{
- IrInstructionDeclVar *decl_var_instruction = ir_build_instruction(irb, scope, source_node);
+ IrInstructionDeclVarSrc *decl_var_instruction = ir_build_instruction(irb, scope, source_node);
decl_var_instruction->base.value.special = ConstValSpecialStatic;
decl_var_instruction->base.value.type = irb->codegen->builtin_types.entry_void;
decl_var_instruction->var = var;
decl_var_instruction->var_type = var_type;
decl_var_instruction->align_value = align_value;
- decl_var_instruction->init_value = init_value;
+ decl_var_instruction->ptr = ptr;
if (var_type) ir_ref_instruction(var_type, irb->current_basic_block);
if (align_value) ir_ref_instruction(align_value, irb->current_basic_block);
- ir_ref_instruction(init_value, irb->current_basic_block);
+ ir_ref_instruction(ptr, irb->current_basic_block);
+
+ return &decl_var_instruction->base;
+}
+
+static IrInstruction *ir_build_var_decl_gen(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigVar *var,
+ IrInstruction *var_ptr)
+{
+ IrInstructionDeclVarGen *decl_var_instruction = ir_build_instruction(irb, scope, source_node);
+ decl_var_instruction->base.value.special = ConstValSpecialStatic;
+ decl_var_instruction->base.value.type = irb->codegen->builtin_types.entry_void;
+ decl_var_instruction->var = var;
+ decl_var_instruction->var_ptr = var_ptr;
+
+ ir_ref_instruction(var_ptr, irb->current_basic_block);
return &decl_var_instruction->base;
}
@@ -1391,11 +1561,15 @@ static IrInstruction *ir_build_export(IrBuilder *irb, Scope *scope, AstNode *sou
return &export_instruction->base;
}
-static IrInstruction *ir_build_load_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) {
+static IrInstruction *ir_build_load_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr,
+ IrInstruction *result_loc)
+{
IrInstructionLoadPtr *instruction = ir_build_instruction(irb, scope, source_node);
instruction->ptr = ptr;
+ instruction->result_loc = result_loc;
ir_ref_instruction(ptr, irb->current_basic_block);
+ if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
return &instruction->base;
}
@@ -1542,23 +1716,39 @@ static IrInstruction *ir_build_test_nonnull(IrBuilder *irb, Scope *scope, AstNod
return &instruction->base;
}
-static IrInstruction *ir_build_unwrap_maybe(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value,
- bool safety_check_on)
+static IrInstruction *ir_build_optional_unwrap_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *base_ptr, bool safety_check_on)
{
- IrInstructionUnwrapOptional *instruction = ir_build_instruction(irb, scope, source_node);
- instruction->value = value;
+ IrInstructionOptionalUnwrapPtr *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->base_ptr = base_ptr;
instruction->safety_check_on = safety_check_on;
- ir_ref_instruction(value, irb->current_basic_block);
+ ir_ref_instruction(base_ptr, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_optional_unwrap_val(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *opt, bool safety_check_on)
+{
+ IrInstructionOptionalUnwrapVal *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->opt = opt;
+ instruction->safety_check_on = safety_check_on;
+
+ ir_ref_instruction(opt, irb->current_basic_block);
return &instruction->base;
}
-static IrInstruction *ir_build_maybe_wrap(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
+static IrInstruction *ir_build_maybe_wrap(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *value, IrInstruction *result_loc)
+{
IrInstructionOptionalWrap *instruction = ir_build_instruction(irb, scope, source_node);
instruction->value = value;
+ instruction->result_loc = result_loc;
ir_ref_instruction(value, irb->current_basic_block);
+ if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
return &instruction->base;
}
@@ -1608,9 +1798,10 @@ static IrInstruction *ir_build_pop_count(IrBuilder *irb, Scope *scope, AstNode *
return &instruction->base;
}
-static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target_value,
- IrBasicBlock *else_block, size_t case_count, IrInstructionSwitchBrCase *cases, IrInstruction *is_comptime,
- IrInstruction *switch_prongs_void)
+static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *target_value, IrBasicBlock *else_block,
+ size_t case_count, IrInstructionSwitchBrCase *cases, IrInstruction *is_comptime,
+ IrInstruction *switch_prongs_void, IrInstruction *result_loc)
{
IrInstructionSwitchBr *instruction = ir_build_instruction(irb, scope, source_node);
instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable;
@@ -1621,11 +1812,13 @@ static IrInstruction *ir_build_switch_br(IrBuilder *irb, Scope *scope, AstNode *
instruction->cases = cases;
instruction->is_comptime = is_comptime;
instruction->switch_prongs_void = switch_prongs_void;
+ instruction->result_loc = result_loc;
ir_ref_instruction(target_value, irb->current_basic_block);
if (is_comptime) ir_ref_instruction(is_comptime, irb->current_basic_block);
ir_ref_bb(else_block);
if (switch_prongs_void) ir_ref_instruction(switch_prongs_void, irb->current_basic_block);
+ if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
for (size_t i = 0; i < case_count; i += 1) {
ir_ref_instruction(cases[i].value, irb->current_basic_block);
@@ -1678,14 +1871,16 @@ static IrInstruction *ir_build_import(IrBuilder *irb, Scope *scope, AstNode *sou
}
static IrInstruction *ir_build_ref(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value,
- bool is_const, bool is_volatile)
+ bool is_const, bool is_volatile, IrInstruction *result_loc)
{
IrInstructionRef *instruction = ir_build_instruction(irb, scope, source_node);
instruction->value = value;
instruction->is_const = is_const;
instruction->is_volatile = is_volatile;
+ instruction->result_loc = result_loc;
ir_ref_instruction(value, irb->current_basic_block);
+ if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
return &instruction->base;
}
@@ -1765,30 +1960,49 @@ static IrInstruction *ir_build_embed_file(IrBuilder *irb, Scope *scope, AstNode
return &instruction->base;
}
-static IrInstruction *ir_build_cmpxchg(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value,
- IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value,
- IrInstruction *success_order_value, IrInstruction *failure_order_value,
- bool is_weak,
- ZigType *type, AtomicOrder success_order, AtomicOrder failure_order)
+static IrInstruction *ir_build_cmpxchg_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *type_value, IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value,
+ IrInstruction *success_order_value, IrInstruction *failure_order_value, IrInstruction *result_loc, bool is_weak)
{
- IrInstructionCmpxchg *instruction = ir_build_instruction(irb, scope, source_node);
+ IrInstructionCmpxchgSrc *instruction = ir_build_instruction(irb, scope, source_node);
instruction->type_value = type_value;
instruction->ptr = ptr;
instruction->cmp_value = cmp_value;
instruction->new_value = new_value;
instruction->success_order_value = success_order_value;
instruction->failure_order_value = failure_order_value;
+ instruction->result_loc = result_loc;
instruction->is_weak = is_weak;
+
+ ir_ref_instruction(type_value, irb->current_basic_block);
+ ir_ref_instruction(ptr, irb->current_basic_block);
+ ir_ref_instruction(cmp_value, irb->current_basic_block);
+ ir_ref_instruction(new_value, irb->current_basic_block);
+ ir_ref_instruction(success_order_value, irb->current_basic_block);
+ ir_ref_instruction(failure_order_value, irb->current_basic_block);
+ ir_ref_instruction(result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_cmpxchg_gen(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ ZigType *type, IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value,
+ AtomicOrder success_order, AtomicOrder failure_order, IrInstruction *result_loc, bool is_weak)
+{
+ IrInstructionCmpxchgGen *instruction = ir_build_instruction(irb, scope, source_node);
instruction->type = type;
+ instruction->ptr = ptr;
+ instruction->cmp_value = cmp_value;
+ instruction->new_value = new_value;
instruction->success_order = success_order;
instruction->failure_order = failure_order;
+ instruction->result_loc = result_loc;
+ instruction->is_weak = is_weak;
- if (type_value != nullptr) ir_ref_instruction(type_value, irb->current_basic_block);
ir_ref_instruction(ptr, irb->current_basic_block);
ir_ref_instruction(cmp_value, irb->current_basic_block);
ir_ref_instruction(new_value, irb->current_basic_block);
- if (type_value != nullptr) ir_ref_instruction(success_order_value, irb->current_basic_block);
- if (type_value != nullptr) ir_ref_instruction(failure_order_value, irb->current_basic_block);
+ if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
return &instruction->base;
}
@@ -1847,26 +2061,6 @@ static IrInstruction *ir_build_err_set_cast(IrBuilder *irb, Scope *scope, AstNod
return &instruction->base;
}
-static IrInstruction *ir_build_to_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target) {
- IrInstructionToBytes *instruction = ir_build_instruction(irb, scope, source_node);
- instruction->target = target;
-
- ir_ref_instruction(target, irb->current_basic_block);
-
- return &instruction->base;
-}
-
-static IrInstruction *ir_build_from_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_child_type, IrInstruction *target) {
- IrInstructionFromBytes *instruction = ir_build_instruction(irb, scope, source_node);
- instruction->dest_child_type = dest_child_type;
- instruction->target = target;
-
- ir_ref_instruction(dest_child_type, irb->current_basic_block);
- ir_ref_instruction(target, irb->current_basic_block);
-
- return &instruction->base;
-}
-
static IrInstruction *ir_build_int_to_float(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *target) {
IrInstructionIntToFloat *instruction = ir_build_instruction(irb, scope, source_node);
instruction->dest_type = dest_type;
@@ -1949,16 +2143,18 @@ static IrInstruction *ir_build_memcpy(IrBuilder *irb, Scope *scope, AstNode *sou
}
static IrInstruction *ir_build_slice(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool safety_check_on)
+ IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool safety_check_on, IrInstruction *result_loc)
{
IrInstructionSlice *instruction = ir_build_instruction(irb, scope, source_node);
instruction->ptr = ptr;
instruction->start = start;
instruction->end = end;
+ instruction->result_loc = result_loc;
instruction->safety_check_on = safety_check_on;
ir_ref_instruction(ptr, irb->current_basic_block);
ir_ref_instruction(start, irb->current_basic_block);
+ ir_ref_instruction(result_loc, irb->current_basic_block);
if (end) ir_ref_instruction(end, irb->current_basic_block);
return &instruction->base;
@@ -2060,24 +2256,26 @@ static IrInstruction *ir_build_test_err(IrBuilder *irb, Scope *scope, AstNode *s
}
static IrInstruction *ir_build_unwrap_err_code(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *value)
+ IrInstruction *err_union)
{
IrInstructionUnwrapErrCode *instruction = ir_build_instruction(irb, scope, source_node);
- instruction->value = value;
+ instruction->err_union = err_union;
- ir_ref_instruction(value, irb->current_basic_block);
+ ir_ref_instruction(err_union, irb->current_basic_block);
return &instruction->base;
}
static IrInstruction *ir_build_unwrap_err_payload(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *value, bool safety_check_on)
+ IrInstruction *value, IrInstruction *result_loc, bool safety_check_on)
{
IrInstructionUnwrapErrPayload *instruction = ir_build_instruction(irb, scope, source_node);
instruction->value = value;
+ instruction->result_loc = result_loc;
instruction->safety_check_on = safety_check_on;
ir_ref_instruction(value, irb->current_basic_block);
+ if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block);
return &instruction->base;
}
@@ -2115,30 +2313,29 @@ static IrInstruction *ir_build_test_comptime(IrBuilder *irb, Scope *scope, AstNo
return &instruction->base;
}
-static IrInstruction *ir_build_ptr_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
+static IrInstruction *ir_build_ptr_cast_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
IrInstruction *dest_type, IrInstruction *ptr)
{
- IrInstructionPtrCast *instruction = ir_build_instruction(
+ IrInstructionPtrCastSrc *instruction = ir_build_instruction(
irb, scope, source_node);
instruction->dest_type = dest_type;
instruction->ptr = ptr;
- if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block);
+ ir_ref_instruction(dest_type, irb->current_basic_block);
ir_ref_instruction(ptr, irb->current_basic_block);
return &instruction->base;
}
-static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
- IrInstruction *dest_type, IrInstruction *value)
+static IrInstruction *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInstruction *source_instr,
+ ZigType *ptr_type, IrInstruction *ptr)
{
- IrInstructionBitCast *instruction = ir_build_instruction(
- irb, scope, source_node);
- instruction->dest_type = dest_type;
- instruction->value = value;
+ IrInstructionPtrCastGen *instruction = ir_build_instruction(
+ &ira->new_irb, source_instr->scope, source_instr->source_node);
+ instruction->ptr = ptr;
+ instruction->base.value.type = ptr_type;
- if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block);
- ir_ref_instruction(value, irb->current_basic_block);
+ ir_ref_instruction(ptr, ira->new_irb.current_basic_block);
return &instruction->base;
}
@@ -2277,13 +2474,10 @@ static IrInstruction *ir_build_type_name(IrBuilder *irb, Scope *scope, AstNode *
return &instruction->base;
}
-static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node,
- Tld *tld, LVal lval)
-{
+static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node, Tld *tld) {
IrInstructionDeclRef *instruction = ir_build_instruction(
irb, scope, source_node);
instruction->tld = tld;
- instruction->lval = lval;
return &instruction->base;
}
@@ -2747,71 +2941,401 @@ static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope,
return &instruction->base;
}
-static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
- results[ReturnKindUnconditional] = 0;
- results[ReturnKindError] = 0;
+static IrInstruction *ir_build_result_optional_payload(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc, IrInstruction *payload_type, bool make_non_null)
+{
+ IrInstructionResultOptionalPayload *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
+ instruction->payload_type = payload_type;
+ instruction->make_non_null = make_non_null;
- Scope *scope = inner_scope;
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+ if (payload_type != nullptr) ir_ref_instruction(payload_type, irb->current_basic_block);
- while (scope != outer_scope) {
- assert(scope);
- switch (scope->id) {
- case ScopeIdDefer: {
- AstNode *defer_node = scope->source_node;
- assert(defer_node->type == NodeTypeDefer);
- ReturnKind defer_kind = defer_node->data.defer.kind;
- results[defer_kind] += 1;
- scope = scope->parent;
- continue;
- }
- case ScopeIdDecls:
- case ScopeIdFnDef:
- return;
- case ScopeIdBlock:
- case ScopeIdVarDecl:
- case ScopeIdLoop:
- case ScopeIdSuspend:
- case ScopeIdCompTime:
- case ScopeIdRuntime:
- scope = scope->parent;
- continue;
- case ScopeIdDeferExpr:
- case ScopeIdCImport:
- case ScopeIdCoroPrelude:
- zig_unreachable();
- }
- }
+ return &instruction->base;
}
-static IrInstruction *ir_mark_gen(IrInstruction *instruction) {
- instruction->is_gen = true;
- return instruction;
+static IrInstruction *ir_build_result_slice_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc, uint64_t len, IrInstruction *array_loc)
+{
+ IrInstructionResultSlicePtr *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
+ instruction->len = len;
+ instruction->array_loc = array_loc;
+
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+ if (array_loc != nullptr) ir_ref_instruction(array_loc, irb->current_basic_block);
+
+ return &instruction->base;
}
-static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, bool gen_error_defers) {
- Scope *scope = inner_scope;
- bool is_noreturn = false;
- while (scope != outer_scope) {
- if (!scope)
- return is_noreturn;
+static IrInstruction *ir_build_result_error_union_payload(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc)
+{
+ IrInstructionResultErrorUnionPayload *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
- switch (scope->id) {
- case ScopeIdDefer: {
- AstNode *defer_node = scope->source_node;
- assert(defer_node->type == NodeTypeDefer);
- ReturnKind defer_kind = defer_node->data.defer.kind;
- if (defer_kind == ReturnKindUnconditional ||
- (gen_error_defers && defer_kind == ReturnKindError))
- {
- AstNode *defer_expr_node = defer_node->data.defer.expr;
- Scope *defer_expr_scope = defer_node->data.defer.expr_scope;
- IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope);
- if (defer_expr_value != irb->codegen->invalid_instruction) {
- if (defer_expr_value->value.type != nullptr && defer_expr_value->value.type->id == ZigTypeIdUnreachable) {
- is_noreturn = true;
- } else {
- ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value));
- }
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_result_error_union_code(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc)
+{
+ IrInstructionResultErrorUnionCode *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
+
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_result_return(IrBuilder *irb, Scope *scope, AstNode *source_node) {
+ IrInstructionResultReturn *instruction = ir_build_instruction(irb, scope, source_node);
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_result_child(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc, LVal lval)
+{
+ IrInstructionResultChild *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
+ instruction->lval = lval;
+
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_result_ptr_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *elem_type, IrInstruction *prev_result_loc)
+{
+ IrInstructionResultPtrCast *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->elem_type = elem_type;
+ instruction->prev_result_loc = prev_result_loc;
+
+ ir_ref_instruction(elem_type, irb->current_basic_block);
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_result_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *elem_type, IrInstruction *prev_result_loc)
+{
+ IrInstructionResultCast *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->elem_type = elem_type;
+ instruction->prev_result_loc = prev_result_loc;
+
+ ir_ref_instruction(elem_type, irb->current_basic_block);
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_result_slice_to_bytes_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *elem_type, IrInstruction *prev_result_loc)
+{
+ IrInstructionResultSliceToBytesSrc *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->elem_type = elem_type;
+ instruction->prev_result_loc = prev_result_loc;
+
+ ir_ref_instruction(elem_type, irb->current_basic_block);
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_result_slice_to_bytes_placeholder(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *prev_result_loc, ZigType *elem_type)
+{
+ IrInstructionResultSliceToBytesPlaceholder *instruction =
+ ir_build_instruction(
+ &ira->new_irb, source_instr->scope, source_instr->source_node);
+ instruction->base.value.type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_infer, false);
+ instruction->prev_result_loc = prev_result_loc;
+ instruction->elem_type = elem_type;
+ instruction->pass1_parent = source_instr;
+
+ ir_ref_instruction(prev_result_loc, ira->new_irb.current_basic_block);
+ // no ref for pass1_parent
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_result_slice_to_bytes_gen(IrAnalyze *ira, IrInstruction *source_instr,
+ ZigType *result_type, IrInstruction *prev_result_loc)
+{
+ IrInstructionResultSliceToBytesGen *instruction = ir_build_instruction(
+ &ira->new_irb, source_instr->scope, source_instr->source_node);
+ instruction->base.value.type = result_type;
+ instruction->prev_result_loc = prev_result_loc;
+
+ ir_ref_instruction(prev_result_loc, ira->new_irb.current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_result_bytes_to_slice(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc)
+{
+ IrInstructionResultBytesToSlice *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
+
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_alloca_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *child_type, IrInstruction *align, const char *name_hint, IrInstruction *is_comptime)
+{
+ IrInstructionAllocaSrc *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->base.is_gen = true;
+ instruction->child_type = child_type;
+ instruction->align = align;
+ instruction->name_hint = name_hint;
+ instruction->is_comptime = is_comptime;
+
+ if (child_type != nullptr) ir_ref_instruction(child_type, irb->current_basic_block);
+ if (align != nullptr) ir_ref_instruction(align, irb->current_basic_block);
+ if (is_comptime != nullptr) ir_ref_instruction(is_comptime, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstructionAllocaGen *ir_create_alloca_gen(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ uint32_t align, const char *name_hint)
+{
+ IrInstructionAllocaGen *instruction = ir_create_instruction(irb, scope, source_node);
+ instruction->align = align;
+ instruction->name_hint = name_hint;
+
+ return instruction;
+}
+
+static IrInstruction *ir_build_assert_non_error(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *err_code)
+{
+ IrInstructionAssertNonError *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->err_code = err_code;
+
+ ir_ref_instruction(err_code, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_assert_non_null(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *is_non_null)
+{
+ IrInstructionAssertNonNull *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->is_non_null = is_non_null;
+
+ ir_ref_instruction(is_non_null, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_error_union_field_error_set(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *ptr, bool safety_check_on)
+{
+ IrInstructionErrorUnionFieldErrorSet *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->ptr = ptr;
+ instruction->safety_check_on = safety_check_on;
+
+ ir_ref_instruction(ptr, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_first_arg_result_loc(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc, IrInstruction *fn_ref)
+{
+ IrInstructionFirstArgResultLoc *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
+ instruction->fn_ref = fn_ref;
+
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+ ir_ref_instruction(fn_ref, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_infer_array_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *src_type, size_t elem_count)
+{
+ IrInstructionInferArrayType *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->src_type = src_type;
+ instruction->elem_count = elem_count;
+
+ ir_ref_instruction(src_type, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_infer_comptime(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc, IrInstruction *new_result_loc)
+{
+ IrInstructionInferCompTime *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
+ instruction->new_result_loc = new_result_loc;
+
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+ ir_ref_instruction(new_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_from_bytes_len_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc, IrInstruction *new_result_loc)
+{
+ IrInstructionFromBytesLenSrc *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
+ instruction->new_result_loc = new_result_loc;
+
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+ ir_ref_instruction(new_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_from_bytes_len_gen(IrAnalyze *ira, IrInstruction *source_inst,
+ IrInstruction *prev_result_loc, ZigType *elem_type)
+{
+ IrInstructionFromBytesLenGen *instruction = ir_build_instruction(
+ &ira->new_irb, source_inst->scope, source_inst->source_node);
+ instruction->base.value.special = ConstValSpecialStatic;
+ instruction->base.value.type = ira->codegen->builtin_types.entry_void;
+
+ instruction->prev_result_loc = prev_result_loc;
+ instruction->elem_type = elem_type;
+
+ ir_ref_instruction(prev_result_loc, ira->new_irb.current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_to_bytes_len_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc, IrInstruction *new_result_loc)
+{
+ IrInstructionToBytesLenSrc *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
+ instruction->new_result_loc = new_result_loc;
+
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+ ir_ref_instruction(new_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_to_bytes_len_gen(IrAnalyze *ira, IrInstruction *source_inst,
+ IrInstruction *prev_result_loc, ZigType *elem_type)
+{
+ IrInstructionToBytesLenGen *instruction = ir_build_instruction(
+ &ira->new_irb, source_inst->scope, source_inst->source_node);
+ instruction->base.value.special = ConstValSpecialStatic;
+ instruction->base.value.type = ira->codegen->builtin_types.entry_void;
+
+ instruction->prev_result_loc = prev_result_loc;
+ instruction->elem_type = elem_type;
+
+ ir_ref_instruction(prev_result_loc, ira->new_irb.current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_set_nonnull_bit(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *prev_result_loc, IrInstruction *non_null_bit, IrInstruction *new_result_loc)
+{
+ IrInstructionSetNonNullBit *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->prev_result_loc = prev_result_loc;
+ instruction->non_null_bit = non_null_bit;
+ instruction->new_result_loc = new_result_loc;
+
+ ir_ref_instruction(prev_result_loc, irb->current_basic_block);
+ ir_ref_instruction(non_null_bit, irb->current_basic_block);
+ if (new_result_loc != nullptr) ir_ref_instruction(new_result_loc, irb->current_basic_block);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_error_literal(IrBuilder *irb, Scope *scope, AstNode *source_node, Buf *name) {
+ IrInstructionErrorLiteral *instruction = ir_build_instruction(irb, scope, source_node);
+ instruction->name = name;
+
+ return &instruction->base;
+}
+
+static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
+ results[ReturnKindUnconditional] = 0;
+ results[ReturnKindError] = 0;
+
+ Scope *scope = inner_scope;
+
+ while (scope != outer_scope) {
+ assert(scope);
+ switch (scope->id) {
+ case ScopeIdDefer: {
+ AstNode *defer_node = scope->source_node;
+ assert(defer_node->type == NodeTypeDefer);
+ ReturnKind defer_kind = defer_node->data.defer.kind;
+ results[defer_kind] += 1;
+ scope = scope->parent;
+ continue;
+ }
+ case ScopeIdDecls:
+ case ScopeIdFnDef:
+ return;
+ case ScopeIdBlock:
+ case ScopeIdVarDecl:
+ case ScopeIdLoop:
+ case ScopeIdSuspend:
+ case ScopeIdCompTime:
+ case ScopeIdRuntime:
+ scope = scope->parent;
+ continue;
+ case ScopeIdDeferExpr:
+ case ScopeIdCImport:
+ case ScopeIdCoroPrelude:
+ zig_unreachable();
+ }
+ }
+}
+
+static IrInstruction *ir_mark_gen(IrInstruction *instruction) {
+ instruction->is_gen = true;
+ return instruction;
+}
+
+static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, bool gen_error_defers) {
+ Scope *scope = inner_scope;
+ bool is_noreturn = false;
+ while (scope != outer_scope) {
+ if (!scope)
+ return is_noreturn;
+
+ switch (scope->id) {
+ case ScopeIdDefer: {
+ AstNode *defer_node = scope->source_node;
+ assert(defer_node->type == NodeTypeDefer);
+ ReturnKind defer_kind = defer_node->data.defer.kind;
+ if (defer_kind == ReturnKindUnconditional ||
+ (gen_error_defers && defer_kind == ReturnKindError))
+ {
+ AstNode *defer_expr_node = defer_node->data.defer.expr;
+ Scope *defer_expr_scope = defer_node->data.defer.expr_scope;
+ IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope,
+ LValNone, nullptr);
+ if (defer_expr_value != irb->codegen->invalid_instruction) {
+ if (defer_expr_value->value.type != nullptr &&
+ defer_expr_value->value.type->id == ZigTypeIdUnreachable)
+ {
+ is_noreturn = true;
+ } else {
+ ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node,
+ defer_expr_value));
+ }
}
}
scope = scope->parent;
@@ -2878,13 +3402,13 @@ static bool exec_is_async(IrExecutable *exec) {
}
static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value,
- bool is_generated_code)
+ bool is_generated_code, IrInstruction *return_result_loc)
{
ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value));
bool is_async = exec_is_async(irb->exec);
if (!is_async) {
- IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value);
+ IrInstruction *return_inst = ir_build_return(irb, scope, node, return_value, return_result_loc);
return_inst->is_gen = is_generated_code;
return return_inst;
}
@@ -2910,7 +3434,7 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
IrInstruction *is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
- ir_build_cond_br(irb, scope, node, is_suspended_bool, suspended_block, not_suspended_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, is_suspended_bool, suspended_block, not_suspended_block, is_comptime, nullptr);
ir_set_cursor_at_end_and_append_block(irb, suspended_block);
ir_build_unreachable(irb, scope, node);
@@ -2919,7 +3443,7 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
// if we ever add null checking safety to the ptrtoint instruction, it needs to be disabled here
IrInstruction *have_await_handle = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false);
- ir_build_cond_br(irb, scope, node, have_await_handle, store_awaiter_block, check_canceled_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, have_await_handle, store_awaiter_block, check_canceled_block, is_comptime, nullptr);
ir_set_cursor_at_end_and_append_block(irb, store_awaiter_block);
IrInstruction *await_handle = ir_build_int_to_ptr(irb, scope, node, promise_type_val, await_handle_addr);
@@ -2929,10 +3453,176 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
ir_set_cursor_at_end_and_append_block(irb, check_canceled_block);
IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
- return ir_build_cond_br(irb, scope, node, is_canceled_bool, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, is_comptime);
+ return ir_build_cond_br(irb, scope, node, is_canceled_bool, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, is_comptime, nullptr);
+}
+
+static IrInstruction *ir_gen_result(IrBuilder *irb, Scope *scope, AstNode *node, LVal parent_lval,
+ IrInstruction *parent_result_loc, LVal child_lval, IrInstruction *child_result_loc)
+{
+ assert(child_result_loc != nullptr);
+ bool need_copy = (parent_result_loc != nullptr &&
+ parent_result_loc != child_result_loc && child_result_loc->id == IrInstructionIdAllocaSrc);
+ switch (parent_lval) {
+ case LValNone:
+ if (need_copy) {
+ IrInstruction *result = ir_build_load_ptr(irb, scope, node, child_result_loc, parent_result_loc);
+ ir_build_infer_comptime(irb, scope, node, parent_result_loc, child_result_loc);
+ return result;
+ } else {
+ return ir_build_load_ptr(irb, scope, node, child_result_loc, nullptr);
+ }
+ case LValPtr:
+ if (need_copy) {
+ ir_build_ref(irb, scope, node, child_result_loc, true, false, parent_result_loc);
+ ir_build_infer_comptime(irb, scope, node, parent_result_loc, child_result_loc);
+ return ir_build_const_void(irb, scope, node);
+ } else {
+ return child_result_loc;
+ }
+ case LValOptional: {
+ IrInstruction *loaded_ptr = ir_build_load_ptr(irb, scope, node, child_result_loc, nullptr);
+ if (need_copy) {
+ IrInstruction *payload_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, child_result_loc, false);
+ ir_build_load_ptr(irb, scope, node, payload_ptr, parent_result_loc);
+ ir_build_infer_comptime(irb, scope, node, parent_result_loc, child_result_loc);
+ }
+ return ir_build_test_nonnull(irb, scope, node, loaded_ptr);
+ }
+ case LValErrorUnionVal: {
+ if (need_copy) {
+ ir_build_unwrap_err_payload(irb, scope, node, child_result_loc, parent_result_loc, false);
+ ir_build_infer_comptime(irb, scope, node, parent_result_loc, child_result_loc);
+ }
+ IrInstruction *err_ptr = ir_build_error_union_field_error_set(irb, scope, node, child_result_loc, false);
+ return ir_build_load_ptr(irb, scope, node, err_ptr, nullptr);
+ }
+ case LValErrorUnionPtr:
+ if (need_copy) {
+ ir_build_unwrap_err_payload(irb, scope, node, child_result_loc, parent_result_loc, false);
+ ir_build_infer_comptime(irb, scope, node, parent_result_loc, child_result_loc);
+ }
+ return ir_build_error_union_field_error_set(irb, scope, node, child_result_loc, false);
+ }
+ zig_unreachable();
+}
+
+static IrInstruction *ensure_result_loc(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
+ if (result_loc != nullptr &&
+ (result_loc->value.special != ConstValSpecialStatic ||
+ result_loc->value.data.x_ptr.special != ConstPtrSpecialDiscard))
+ {
+ switch (lval) {
+ case LValNone:
+ case LValPtr:
+ return result_loc;
+ case LValErrorUnionVal:
+ case LValErrorUnionPtr:
+ case LValOptional:
+ if (result_loc->id == IrInstructionIdAllocaSrc ||
+ result_loc->id == IrInstructionIdFirstArgResultLoc ||
+ result_loc->id == IrInstructionIdFieldPtr)
+ {
+ break;
+ }
+ if (result_loc->id != IrInstructionIdResultChild) {
+ return ir_build_result_child(irb, scope, node, result_loc, lval);
+ }
+ break;
+ }
+ }
+ return ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "", nullptr);
+}
+
+static IrInstruction *ir_gen_value(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc, IrInstruction *value)
+{
+ if (value == irb->codegen->invalid_instruction)
+ return value;
+ if (instr_is_unreachable(value))
+ return value;
+ if (result_loc != nullptr) {
+ IrInstruction *store_inst = ir_build_store_ptr(irb, scope, node, result_loc, value);
+ store_inst->is_gen = value->is_gen || result_loc->is_gen;
+ switch (lval) {
+ case LValPtr:
+ zig_unreachable();
+ case LValNone:
+ return value;
+ case LValErrorUnionVal:
+ return ir_build_const_null(irb, scope, node);
+ case LValErrorUnionPtr: {
+ IrInstruction *null = ir_build_const_null(irb, scope, node);
+ return ir_build_ref(irb, scope, node, null, true, false, nullptr);
+ }
+ case LValOptional: {
+ return ir_build_const_bool(irb, scope, node, true);
+ }
+ }
+ zig_unreachable();
+ }
+ switch (lval) {
+ case LValPtr:
+ // We needed a pointer to a value, but we got a value. So we create
+ // an instruction which just makes a pointer of it.
+ return ir_build_ref(irb, scope, value->source_node, value, false, false, result_loc);
+ case LValNone:
+ return value;
+ case LValOptional:
+ case LValErrorUnionVal:
+ case LValErrorUnionPtr:
+ zig_panic("TODO");
+ }
+ zig_unreachable();
+}
+
+static IrInstruction *ir_gen_ptr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc, IrInstruction *ptr)
+{
+ switch (lval) {
+ case LValPtr:
+ if (result_loc != nullptr) {
+ IrInstruction *store_inst = ir_build_store_ptr(irb, scope, node, result_loc, ptr);
+ store_inst->is_gen = result_loc->is_gen || ptr->is_gen;
+ }
+ return ptr;
+ case LValNone: {
+ IrInstruction *load_inst = ir_build_load_ptr(irb, scope, node, ptr, result_loc);
+ load_inst->is_gen = (result_loc != nullptr && result_loc->is_gen) || ptr->is_gen;
+ return load_inst;
+ }
+ case LValErrorUnionPtr: {
+ // ptr points to an error union;
+ // result_loc points to the result payload
+ // must return pointer to the error code
+ ir_build_unwrap_err_payload(irb, scope, node, ptr, result_loc, false);
+ return ir_build_error_union_field_error_set(irb, scope, node, ptr, false);
+ }
+ case LValErrorUnionVal: {
+ // ptr points to an error union;
+ // result_loc points to the result payload
+ // must return the error code
+ ir_build_unwrap_err_payload(irb, scope, node, ptr, result_loc, false);
+ IrInstruction *err_ptr = ir_build_error_union_field_error_set(irb, scope, node, ptr, false);
+ return ir_build_load_ptr(irb, scope, node, err_ptr, nullptr);
+ }
+ case LValOptional: {
+ // ptr points to an optional;
+ // result_loc points to the result payload
+ // must return is_non_null bool
+ IrInstruction *payload_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, ptr, false);
+ ir_build_load_ptr(irb, scope, node, payload_ptr, result_loc);
+ IrInstruction *loaded_ptr = ir_build_load_ptr(irb, scope, node, ptr, nullptr);
+ return ir_build_test_nonnull(irb, scope, node, loaded_ptr);
+ }
+ }
+ zig_unreachable();
}
-static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
+static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeReturnExpr);
ZigFn *fn_entry = exec_fn_entry(irb->exec);
@@ -2957,14 +3647,32 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
case ReturnKindUnconditional:
{
IrInstruction *return_value;
+ ZigType *return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;
+ IrInstruction *return_result_loc = nullptr;
+ LVal expr_lval = LValNone;
if (expr_node) {
+ if (return_type != nullptr) {
+ if (return_type->id == ZigTypeIdErrorUnion) {
+ return_result_loc = ir_build_result_return(irb, scope, node);
+ expr_lval = LValErrorUnionVal;
+ } else if (return_type->id == ZigTypeIdOptional && handle_is_ptr(return_type)) {
+ return_result_loc = ir_build_result_return(irb, scope, node);
+ expr_lval = LValOptional;
+ } else if (type_has_bits(return_type) && handle_is_ptr(return_type)) {
+ return_result_loc = ir_build_result_return(irb, scope, node);
+ }
+ }
// Temporarily set this so that if we return a type it gets the name of the function
ZigFn *prev_name_fn = irb->exec->name_fn;
irb->exec->name_fn = exec_fn_entry(irb->exec);
- return_value = ir_gen_node(irb, expr_node, scope);
+ return_value = ir_gen_node(irb, expr_node, scope, expr_lval, return_result_loc);
irb->exec->name_fn = prev_name_fn;
if (return_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
+ } else if (return_type->id == ZigTypeIdErrorUnion &&
+ return_type->data.error_union.payload_type == irb->codegen->builtin_types.entry_void)
+ {
+ return_value = ir_build_const_null(irb, scope, node);
} else {
return_value = ir_build_const_void(irb, scope, node);
}
@@ -2972,14 +3680,23 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
size_t defer_counts[2];
ir_count_defers(irb, scope, outer_scope, defer_counts);
bool have_err_defers = defer_counts[ReturnKindError] > 0;
- if (have_err_defers || irb->codegen->have_err_ret_tracing) {
+ if (expr_node != nullptr && expr_lval != LValOptional &&
+ (have_err_defers || irb->codegen->have_err_ret_tracing))
+ {
IrBasicBlock *err_block = ir_create_basic_block(irb, scope, "ErrRetErr");
IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk");
if (!have_err_defers) {
ir_gen_defers_for_block(irb, scope, outer_scope, false);
}
- IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value);
+ IrInstruction *is_err;
+ if (expr_lval == LValNone) {
+ is_err = ir_build_test_err(irb, scope, node, return_value);
+ } else if (expr_lval == LValErrorUnionVal) {
+ is_err = ir_build_test_nonnull(irb, scope, node, return_value);
+ } else {
+ zig_unreachable();
+ }
bool should_inline = ir_should_inline(irb->exec, scope);
IrInstruction *is_comptime;
@@ -2989,7 +3706,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
is_comptime = ir_build_test_comptime(irb, scope, node, is_err);
}
- ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime));
+ ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime, nullptr));
IrBasicBlock *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt");
ir_set_cursor_at_end_and_append_block(irb, err_block);
@@ -3008,21 +3725,25 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block);
- return ir_gen_async_return(irb, scope, node, return_value, false);
+ return ir_gen_async_return(irb, scope, node, return_value, false, return_result_loc);
} else {
// generate unconditional defers
ir_gen_defers_for_block(irb, scope, outer_scope, false);
- return ir_gen_async_return(irb, scope, node, return_value, false);
+ return ir_gen_async_return(irb, scope, node, return_value, false, return_result_loc);
}
}
case ReturnKindError:
{
assert(expr_node);
- IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr);
- if (err_union_ptr == irb->codegen->invalid_instruction)
+ IrInstruction *ensured_result_loc = ensure_result_loc(irb, scope, expr_node, lval, result_loc);
+ if (ensured_result_loc == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *err_union_val = ir_build_load_ptr(irb, scope, node, err_union_ptr);
- IrInstruction *is_err_val = ir_build_test_err(irb, scope, node, err_union_val);
+ IrInstruction *opt_err_code = ir_gen_node(irb, expr_node, scope,
+ LValErrorUnionVal, ensured_result_loc);
+ if (opt_err_code == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+
+ IrInstruction *is_err_val = ir_build_test_nonnull(irb, scope, node, opt_err_code);
IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");
IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");
@@ -3033,23 +3754,20 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
} else {
is_comptime = ir_build_test_comptime(irb, scope, node, is_err_val);
}
- ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));
+ ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime, nullptr));
ir_set_cursor_at_end_and_append_block(irb, return_block);
+ IrInstruction *err_val = ir_build_optional_unwrap_val(irb, scope, node, opt_err_code, false);
if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) {
- IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
if (irb->codegen->have_err_ret_tracing && !should_inline) {
ir_build_save_err_ret_addr(irb, scope, node);
}
- ir_gen_async_return(irb, scope, node, err_val, false);
+ ir_gen_async_return(irb, scope, node, err_val, false, nullptr);
}
ir_set_cursor_at_end_and_append_block(irb, continue_block);
- IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false);
- if (lval == LValPtr)
- return unwrapped_ptr;
- else
- return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
+ return ir_gen_result(irb, scope, node, lval, result_loc, LValErrorUnionVal,
+ ensured_result_loc);
}
}
zig_unreachable();
@@ -3065,7 +3783,7 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s
variable_entry->mem_slot_index = SIZE_MAX;
variable_entry->is_comptime = is_comptime;
variable_entry->src_arg_index = SIZE_MAX;
- variable_entry->value = create_const_vals(1);
+ variable_entry->const_value = create_const_vals(1);
if (is_comptime != nullptr) {
is_comptime->ref_count += 1;
@@ -3080,20 +3798,20 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s
ErrorMsg *msg = add_node_error(codegen, node,
buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
- variable_entry->value->type = codegen->builtin_types.entry_invalid;
+ variable_entry->var_type = codegen->builtin_types.entry_invalid;
} else {
ZigType *type;
if (get_primitive_type(codegen, name, &type) != ErrorPrimitiveTypeNotFound) {
add_node_error(codegen, node,
buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name)));
- variable_entry->value->type = codegen->builtin_types.entry_invalid;
+ variable_entry->var_type = codegen->builtin_types.entry_invalid;
} else {
Tld *tld = find_decl(codegen, parent_scope, name);
if (tld != nullptr) {
ErrorMsg *msg = add_node_error(codegen, node,
buf_sprintf("redefinition of '%s'", buf_ptr(name)));
add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here"));
- variable_entry->value->type = codegen->builtin_types.entry_invalid;
+ variable_entry->var_type = codegen->builtin_types.entry_invalid;
}
}
}
@@ -3131,7 +3849,9 @@ static ZigVar *ir_create_var(IrBuilder *irb, AstNode *node, Scope *scope, Buf *n
return var;
}
-static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node) {
+static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(block_node->type == NodeTypeBlock);
ZigList incoming_values = {0};
@@ -3149,14 +3869,18 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
if (block_node->data.block.statements.length == 0) {
// {}
- return ir_build_const_void(irb, child_scope, block_node);
+ return ir_gen_value(irb, parent_scope, block_node, lval, result_loc,
+ ir_build_const_void(irb, child_scope, block_node));
}
if (block_node->data.block.name != nullptr) {
+ scope_block->result_loc = result_loc;
+ scope_block->lval = lval;
scope_block->incoming_blocks = &incoming_blocks;
scope_block->incoming_values = &incoming_values;
scope_block->end_block = ir_create_basic_block(irb, parent_scope, "BlockEnd");
- scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, ir_should_inline(irb->exec, parent_scope));
+ scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node,
+ ir_should_inline(irb->exec, parent_scope));
}
bool is_continuation_unreachable = false;
@@ -3164,7 +3888,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) {
AstNode *statement_node = block_node->data.block.statements.at(i);
- IrInstruction *statement_value = ir_gen_node(irb, statement_node, child_scope);
+ IrInstruction *statement_value = ir_gen_node(irb, statement_node, child_scope, LValNone, nullptr);
is_continuation_unreachable = instr_is_unreachable(statement_value);
if (is_continuation_unreachable) {
// keep the last noreturn statement value around in case we need to return it
@@ -3174,9 +3898,9 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
// defer starts a new scope
child_scope = statement_node->data.defer.child_scope;
assert(child_scope);
- } else if (statement_value->id == IrInstructionIdDeclVar) {
+ } else if (statement_value->id == IrInstructionIdDeclVarSrc) {
// variable declarations start a new scope
- IrInstructionDeclVar *decl_var_instruction = (IrInstructionDeclVar *)statement_value;
+ IrInstructionDeclVarSrc *decl_var_instruction = (IrInstructionDeclVarSrc *)statement_value;
child_scope = decl_var_instruction->var->child_scope;
} else if (statement_value != irb->codegen->invalid_instruction && !is_continuation_unreachable) {
// this statement's value must be void
@@ -3214,8 +3938,10 @@ static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *no
inner_scope = create_comptime_scope(irb->codegen, node, scope);
}
- IrInstruction *op1 = ir_gen_node(irb, node->data.bin_op_expr.op1, inner_scope);
- IrInstruction *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, inner_scope);
+ // All the binary ops operate either on scalar values or comptime values, so
+ // we do not need a result location.
+ IrInstruction *op1 = ir_gen_node(irb, node->data.bin_op_expr.op1, inner_scope, LValNone, nullptr);
+ IrInstruction *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, inner_scope, LValNone, nullptr);
if (op1 == irb->codegen->invalid_instruction || op2 == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -3224,22 +3950,23 @@ static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *no
}
static IrInstruction *ir_gen_assign(IrBuilder *irb, Scope *scope, AstNode *node) {
- IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPtr);
- IrInstruction *rvalue = ir_gen_node(irb, node->data.bin_op_expr.op2, scope);
+ IrInstruction *lvalue = ir_gen_node(irb, node->data.bin_op_expr.op1, scope, LValPtr, nullptr);
+ IrInstruction *rvalue = ir_gen_node(irb, node->data.bin_op_expr.op2, scope, LValNone, lvalue);
if (lvalue == irb->codegen->invalid_instruction || rvalue == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- ir_build_store_ptr(irb, scope, node, lvalue, rvalue);
return ir_build_const_void(irb, scope, node);
}
static IrInstruction *ir_gen_assign_op(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) {
- IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPtr);
+ // All the assign ops operate on scalar values or comptime values, so
+ // we do not need a result location.
+ IrInstruction *lvalue = ir_gen_node(irb, node->data.bin_op_expr.op1, scope, LValPtr, nullptr);
if (lvalue == irb->codegen->invalid_instruction)
return lvalue;
- IrInstruction *op1 = ir_build_load_ptr(irb, scope, node->data.bin_op_expr.op1, lvalue);
- IrInstruction *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope);
+ IrInstruction *op1 = ir_build_load_ptr(irb, scope, node->data.bin_op_expr.op1, lvalue, nullptr);
+ IrInstruction *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope, LValNone, nullptr);
if (op2 == irb->codegen->invalid_instruction)
return op2;
IrInstruction *result = ir_build_bin_op(irb, scope, node, op_id, op1, op2, true);
@@ -3250,7 +3977,7 @@ static IrInstruction *ir_gen_assign_op(IrBuilder *irb, Scope *scope, AstNode *no
static IrInstruction *ir_gen_bool_or(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypeBinOpExpr);
- IrInstruction *val1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope);
+ IrInstruction *val1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope, LValNone, nullptr);
if (val1 == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
IrBasicBlock *post_val1_block = irb->current_basic_block;
@@ -3267,10 +3994,10 @@ static IrInstruction *ir_gen_bool_or(IrBuilder *irb, Scope *scope, AstNode *node
// block for when val1 == true (don't even evaluate the second part)
IrBasicBlock *true_block = ir_create_basic_block(irb, scope, "BoolOrTrue");
- ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_comptime, nullptr);
ir_set_cursor_at_end_and_append_block(irb, false_block);
- IrInstruction *val2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope);
+ IrInstruction *val2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope, LValNone, nullptr);
if (val2 == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
IrBasicBlock *post_val2_block = irb->current_basic_block;
@@ -3292,7 +4019,7 @@ static IrInstruction *ir_gen_bool_or(IrBuilder *irb, Scope *scope, AstNode *node
static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypeBinOpExpr);
- IrInstruction *val1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope);
+ IrInstruction *val1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope, LValNone, nullptr);
if (val1 == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
IrBasicBlock *post_val1_block = irb->current_basic_block;
@@ -3309,10 +4036,10 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod
// block for when val1 == false (don't even evaluate the second part)
IrBasicBlock *false_block = ir_create_basic_block(irb, scope, "BoolAndFalse");
- ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_comptime, nullptr);
ir_set_cursor_at_end_and_append_block(irb, true_block);
- IrInstruction *val2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope);
+ IrInstruction *val2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope, LValNone, nullptr);
if (val2 == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
IrBasicBlock *post_val2_block = irb->current_basic_block;
@@ -3331,19 +4058,22 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod
return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
}
-static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
+static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval,
+ IrInstruction *old_result_loc)
+{
assert(node->type == NodeTypeBinOpExpr);
+ IrInstruction *new_result_loc = ensure_result_loc(irb, parent_scope, node, lval, old_result_loc);
+ if (new_result_loc == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+
AstNode *op1_node = node->data.bin_op_expr.op1;
AstNode *op2_node = node->data.bin_op_expr.op2;
- IrInstruction *maybe_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPtr);
- if (maybe_ptr == irb->codegen->invalid_instruction)
+ IrInstruction *is_non_null = ir_gen_node(irb, op1_node, parent_scope, LValOptional, new_result_loc);
+ if (is_non_null == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *maybe_val = ir_build_load_ptr(irb, parent_scope, node, maybe_ptr);
- IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_val);
-
IrInstruction *is_comptime;
if (ir_should_inline(irb->exec, parent_scope)) {
is_comptime = ir_build_const_bool(irb, parent_scope, node, true);
@@ -3351,33 +4081,19 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As
is_comptime = ir_build_test_comptime(irb, parent_scope, node, is_non_null);
}
- IrBasicBlock *ok_block = ir_create_basic_block(irb, parent_scope, "OptionalNonNull");
- IrBasicBlock *null_block = ir_create_basic_block(irb, parent_scope, "OptionalNull");
- IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "OptionalEnd");
- ir_build_cond_br(irb, parent_scope, node, is_non_null, ok_block, null_block, is_comptime);
+ IrBasicBlock *null_block = ir_create_basic_block(irb, parent_scope, "OrElseNull");
+ IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "OrElseEnd");
+ ir_build_cond_br(irb, parent_scope, node, is_non_null, end_block, null_block, is_comptime, new_result_loc);
ir_set_cursor_at_end_and_append_block(irb, null_block);
- IrInstruction *null_result = ir_gen_node(irb, op2_node, parent_scope);
+ IrInstruction *null_result = ir_gen_node(irb, op2_node, parent_scope, LValNone, new_result_loc);
if (null_result == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrBasicBlock *after_null_block = irb->current_basic_block;
if (!instr_is_unreachable(null_result))
ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime));
- ir_set_cursor_at_end_and_append_block(irb, ok_block);
- IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, parent_scope, node, maybe_ptr, false);
- IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr);
- IrBasicBlock *after_ok_block = irb->current_basic_block;
- ir_build_br(irb, parent_scope, node, end_block, is_comptime);
-
ir_set_cursor_at_end_and_append_block(irb, end_block);
- IrInstruction **incoming_values = allocate(2);
- incoming_values[0] = null_result;
- incoming_values[1] = unwrapped_payload;
- IrBasicBlock **incoming_blocks = allocate(2);
- incoming_blocks[0] = after_null_block;
- incoming_blocks[1] = after_ok_block;
- return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values);
+ return ir_gen_result(irb, parent_scope, node, lval, old_result_loc, LValOptional, new_result_loc);
}
static IrInstruction *ir_gen_error_union(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
@@ -3386,18 +4102,20 @@ static IrInstruction *ir_gen_error_union(IrBuilder *irb, Scope *parent_scope, As
AstNode *op1_node = node->data.bin_op_expr.op1;
AstNode *op2_node = node->data.bin_op_expr.op2;
- IrInstruction *err_set = ir_gen_node(irb, op1_node, parent_scope);
+ IrInstruction *err_set = ir_gen_node(irb, op1_node, parent_scope, LValNone, nullptr);
if (err_set == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *payload = ir_gen_node(irb, op2_node, parent_scope);
+ IrInstruction *payload = ir_gen_node(irb, op2_node, parent_scope, LValNone, nullptr);
if (payload == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
return ir_build_error_union(irb, parent_scope, node, err_set, payload);
}
-static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) {
+static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeBinOpExpr);
BinOpType bin_op_type = node->data.bin_op_expr.bin_op;
@@ -3405,87 +4123,125 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node)
case BinOpTypeInvalid:
zig_unreachable();
case BinOpTypeAssign:
- return ir_gen_assign(irb, scope, node);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_assign(irb, scope, node));
case BinOpTypeAssignTimes:
- return ir_gen_assign_op(irb, scope, node, IrBinOpMult);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpMult));
case BinOpTypeAssignTimesWrap:
- return ir_gen_assign_op(irb, scope, node, IrBinOpMultWrap);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpMultWrap));
case BinOpTypeAssignDiv:
- return ir_gen_assign_op(irb, scope, node, IrBinOpDivUnspecified);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpDivUnspecified));
case BinOpTypeAssignMod:
- return ir_gen_assign_op(irb, scope, node, IrBinOpRemUnspecified);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpRemUnspecified));
case BinOpTypeAssignPlus:
- return ir_gen_assign_op(irb, scope, node, IrBinOpAdd);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpAdd));
case BinOpTypeAssignPlusWrap:
- return ir_gen_assign_op(irb, scope, node, IrBinOpAddWrap);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpAddWrap));
case BinOpTypeAssignMinus:
- return ir_gen_assign_op(irb, scope, node, IrBinOpSub);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpSub));
case BinOpTypeAssignMinusWrap:
- return ir_gen_assign_op(irb, scope, node, IrBinOpSubWrap);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpSubWrap));
case BinOpTypeAssignBitShiftLeft:
- return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeftLossy);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeftLossy));
case BinOpTypeAssignBitShiftRight:
- return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRightLossy);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRightLossy));
case BinOpTypeAssignBitAnd:
- return ir_gen_assign_op(irb, scope, node, IrBinOpBinAnd);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpBinAnd));
case BinOpTypeAssignBitXor:
- return ir_gen_assign_op(irb, scope, node, IrBinOpBinXor);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpBinXor));
case BinOpTypeAssignBitOr:
- return ir_gen_assign_op(irb, scope, node, IrBinOpBinOr);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpBinOr));
case BinOpTypeAssignMergeErrorSets:
- return ir_gen_assign_op(irb, scope, node, IrBinOpMergeErrorSets);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_assign_op(irb, scope, node, IrBinOpMergeErrorSets));
case BinOpTypeBoolOr:
- return ir_gen_bool_or(irb, scope, node);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_bool_or(irb, scope, node));
case BinOpTypeBoolAnd:
- return ir_gen_bool_and(irb, scope, node);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_bool_and(irb, scope, node));
case BinOpTypeCmpEq:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpEq);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpEq));
case BinOpTypeCmpNotEq:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpNotEq);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpNotEq));
case BinOpTypeCmpLessThan:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessThan);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessThan));
case BinOpTypeCmpGreaterThan:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterThan);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterThan));
case BinOpTypeCmpLessOrEq:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessOrEq);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessOrEq));
case BinOpTypeCmpGreaterOrEq:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterOrEq);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterOrEq));
case BinOpTypeBinOr:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpBinOr);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpBinOr));
case BinOpTypeBinXor:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpBinXor);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpBinXor));
case BinOpTypeBinAnd:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpBinAnd);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpBinAnd));
case BinOpTypeBitShiftLeft:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeftLossy);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeftLossy));
case BinOpTypeBitShiftRight:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftRightLossy);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftRightLossy));
case BinOpTypeAdd:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpAdd);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpAdd));
case BinOpTypeAddWrap:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpAddWrap);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpAddWrap));
case BinOpTypeSub:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpSub);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpSub));
case BinOpTypeSubWrap:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpSubWrap);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpSubWrap));
case BinOpTypeMult:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpMult);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpMult));
case BinOpTypeMultWrap:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpMultWrap);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpMultWrap));
case BinOpTypeDiv:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpDivUnspecified);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpDivUnspecified));
case BinOpTypeMod:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpRemUnspecified);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpRemUnspecified));
case BinOpTypeArrayCat:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat));
case BinOpTypeArrayMult:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult));
case BinOpTypeMergeErrorSets:
- return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets);
- case BinOpTypeUnwrapOptional:
- return ir_gen_maybe_ok_or(irb, scope, node);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets));
case BinOpTypeErrorUnion:
- return ir_gen_error_union(irb, scope, node);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_error_union(irb, scope, node));
+
+ case BinOpTypeUnwrapOptional:
+ return ir_gen_orelse(irb, scope, node, lval, result_loc);
}
zig_unreachable();
}
@@ -3513,13 +4269,29 @@ static IrInstruction *ir_gen_char_lit(IrBuilder *irb, Scope *scope, AstNode *nod
return ir_build_const_uint(irb, scope, node, node->data.char_literal.value);
}
-static IrInstruction *ir_gen_null_literal(IrBuilder *irb, Scope *scope, AstNode *node) {
+static IrInstruction *ir_gen_null_literal(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeNullLiteral);
- return ir_build_const_null(irb, scope, node);
+ if (result_loc == nullptr) {
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_build_const_null(irb, scope, node));
+ }
+ switch (lval) {
+ case LValNone:
+ case LValPtr:
+ case LValErrorUnionVal:
+ case LValErrorUnionPtr:
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_build_const_null(irb, scope, node));
+ case LValOptional:
+ return ir_build_const_bool(irb, scope, node, false);
+ }
+ zig_unreachable();
}
-static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
+static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
Error err;
assert(node->type == NodeTypeSymbol);
@@ -3542,28 +4314,36 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
buf_ptr(variable_name)));
return irb->codegen->invalid_instruction;
}
+ assert(err == ErrorPrimitiveTypeNotFound);
} else {
IrInstruction *value = ir_build_const_type(irb, scope, node, primitive_type);
- if (lval == LValPtr) {
- return ir_build_ref(irb, scope, node, value, false, false);
- } else {
- return value;
- }
+ return ir_gen_value(irb, scope, node, lval, result_loc, value);
}
ScopeFnDef *crossed_fndef_scope;
ZigVar *var = find_variable(irb->codegen, scope, variable_name, &crossed_fndef_scope);
if (var) {
IrInstruction *var_ptr = ir_build_var_ptr_x(irb, scope, node, var, crossed_fndef_scope);
- if (lval == LValPtr)
- return var_ptr;
- else
- return ir_build_load_ptr(irb, scope, node, var_ptr);
+ return ir_gen_ptr(irb, scope, node, lval, result_loc, var_ptr);
}
Tld *tld = find_decl(irb->codegen, scope, variable_name);
- if (tld)
- return ir_build_decl_ref(irb, scope, node, tld, lval);
+ if (tld) {
+ switch (tld->id) {
+ case TldIdContainer:
+ case TldIdCompTime:
+ zig_unreachable();
+ case TldIdVar: {
+ IrInstruction *var_ptr = ir_build_decl_ref(irb, scope, node, tld);
+ return ir_gen_ptr(irb, scope, node, lval, result_loc, var_ptr);
+ }
+ case TldIdFn: {
+ IrInstruction *fn_inst = ir_build_decl_ref(irb, scope, node, tld);
+ return ir_gen_value(irb, scope, node, lval, result_loc, fn_inst);
+ }
+ }
+ zig_unreachable();
+ }
if (node->owner->any_imports_failed) {
// skip the error message since we had a failing import in this file
@@ -3577,38 +4357,42 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
return irb->codegen->invalid_instruction;
}
-static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
+static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeArrayAccessExpr);
AstNode *array_ref_node = node->data.array_access_expr.array_ref_expr;
- IrInstruction *array_ref_instruction = ir_gen_node_extra(irb, array_ref_node, scope, LValPtr);
+ IrInstruction *array_ref_instruction = ir_gen_node(irb, array_ref_node, scope, LValPtr, nullptr);
if (array_ref_instruction == irb->codegen->invalid_instruction)
return array_ref_instruction;
AstNode *subscript_node = node->data.array_access_expr.subscript;
- IrInstruction *subscript_instruction = ir_gen_node(irb, subscript_node, scope);
+ IrInstruction *subscript_instruction = ir_gen_node(irb, subscript_node, scope, LValNone, nullptr);
if (subscript_instruction == irb->codegen->invalid_instruction)
return subscript_instruction;
IrInstruction *ptr_instruction = ir_build_elem_ptr(irb, scope, node, array_ref_instruction,
subscript_instruction, true, PtrLenSingle);
- if (lval == LValPtr)
- return ptr_instruction;
- return ir_build_load_ptr(irb, scope, node, ptr_instruction);
+ return ir_gen_ptr(irb, scope, node, lval, result_loc, ptr_instruction);
}
-static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode *node) {
+static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeFieldAccessExpr);
AstNode *container_ref_node = node->data.field_access_expr.struct_expr;
Buf *field_name = node->data.field_access_expr.field_name;
- IrInstruction *container_ref_instruction = ir_gen_node_extra(irb, container_ref_node, scope, LValPtr);
+ IrInstruction *container_ref_instruction = ir_gen_node(irb, container_ref_node, scope, LValPtr, nullptr);
if (container_ref_instruction == irb->codegen->invalid_instruction)
return container_ref_instruction;
- return ir_build_field_ptr(irb, scope, node, container_ref_instruction, field_name);
+ IrInstruction *field_ptr = ir_build_field_ptr(irb, scope, node, container_ref_instruction, nullptr,
+ field_name, false);
+ return ir_gen_ptr(irb, scope, node, lval, result_loc, field_ptr);
}
static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *node, IrOverflowOp op) {
@@ -3619,20 +4403,19 @@ static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *
AstNode *op2_node = node->data.fn_call_expr.params.at(2);
AstNode *result_ptr_node = node->data.fn_call_expr.params.at(3);
-
- IrInstruction *type_value = ir_gen_node(irb, type_node, scope);
+ IrInstruction *type_value = ir_gen_node(irb, type_node, scope, LValNone, nullptr);
if (type_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *op1 = ir_gen_node(irb, op1_node, scope);
+ IrInstruction *op1 = ir_gen_node(irb, op1_node, scope, LValNone, nullptr);
if (op1 == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *op2 = ir_gen_node(irb, op2_node, scope);
+ IrInstruction *op2 = ir_gen_node(irb, op2_node, scope, LValNone, nullptr);
if (op2 == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *result_ptr = ir_gen_node(irb, result_ptr_node, scope);
+ IrInstruction *result_ptr = ir_gen_node(irb, result_ptr_node, scope, LValNone, nullptr);
if (result_ptr == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -3654,7 +4437,9 @@ static IrInstruction *ir_gen_this(IrBuilder *irb, Scope *orig_scope, AstNode *no
zig_unreachable();
}
-static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
+static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeFnCallExpr);
AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
@@ -3685,102 +4470,102 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
case BuiltinFnIdTypeof:
{
AstNode *arg_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg = ir_gen_node(irb, arg_node, scope);
+ IrInstruction *arg = ir_gen_node(irb, arg_node, scope, LValNone, nullptr);
if (arg == irb->codegen->invalid_instruction)
return arg;
IrInstruction *type_of = ir_build_typeof(irb, scope, node, arg);
- return ir_lval_wrap(irb, scope, type_of, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, type_of);
}
case BuiltinFnIdSetCold:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *set_cold = ir_build_set_cold(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, set_cold, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, set_cold);
}
case BuiltinFnIdSetRuntimeSafety:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *set_safety = ir_build_set_runtime_safety(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, set_safety, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, set_safety);
}
case BuiltinFnIdSetFloatMode:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *set_float_mode = ir_build_set_float_mode(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, set_float_mode, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, set_float_mode);
}
case BuiltinFnIdSizeof:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *size_of = ir_build_size_of(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, size_of, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, size_of);
}
case BuiltinFnIdCtz:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *ctz = ir_build_ctz(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, ctz, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ctz);
}
case BuiltinFnIdPopCount:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *instr = ir_build_pop_count(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, instr, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, instr);
}
case BuiltinFnIdClz:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *clz = ir_build_clz(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, clz, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, clz);
}
case BuiltinFnIdImport:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *import = ir_build_import(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, import, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, import);
}
case BuiltinFnIdCImport:
{
IrInstruction *c_import = ir_build_c_import(irb, scope, node);
- return ir_lval_wrap(irb, scope, c_import, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, c_import);
}
case BuiltinFnIdCInclude:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -3790,17 +4575,17 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
}
IrInstruction *c_include = ir_build_c_include(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, c_include, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, c_include);
}
case BuiltinFnIdCDefine:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
@@ -3810,12 +4595,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
}
IrInstruction *c_define = ir_build_c_define(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, c_define, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, c_define);
}
case BuiltinFnIdCUndef:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
@@ -3825,17 +4610,17 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
}
IrInstruction *c_undef = ir_build_c_undef(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, c_undef, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, c_undef);
}
case BuiltinFnIdCompileErr:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *compile_err = ir_build_compile_err(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, compile_err, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, compile_err);
}
case BuiltinFnIdCompileLog:
{
@@ -3843,449 +4628,472 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
for (size_t i = 0; i < actual_param_count; i += 1) {
AstNode *arg_node = node->data.fn_call_expr.params.at(i);
- args[i] = ir_gen_node(irb, arg_node, scope);
+ args[i] = ir_gen_node(irb, arg_node, scope, LValNone, nullptr);
if (args[i] == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
}
IrInstruction *compile_log = ir_build_compile_log(irb, scope, node, actual_param_count, args);
- return ir_lval_wrap(irb, scope, compile_log, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, compile_log);
}
case BuiltinFnIdErrName:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *err_name = ir_build_err_name(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, err_name, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, err_name);
}
case BuiltinFnIdEmbedFile:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *embed_file = ir_build_embed_file(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, embed_file, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, embed_file);
}
case BuiltinFnIdCmpxchgWeak:
case BuiltinFnIdCmpxchgStrong:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
- IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
+ IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope, LValNone, nullptr);
if (arg2_value == irb->codegen->invalid_instruction)
return arg2_value;
AstNode *arg3_node = node->data.fn_call_expr.params.at(3);
- IrInstruction *arg3_value = ir_gen_node(irb, arg3_node, scope);
+ IrInstruction *arg3_value = ir_gen_node(irb, arg3_node, scope, LValNone, nullptr);
if (arg3_value == irb->codegen->invalid_instruction)
return arg3_value;
AstNode *arg4_node = node->data.fn_call_expr.params.at(4);
- IrInstruction *arg4_value = ir_gen_node(irb, arg4_node, scope);
+ IrInstruction *arg4_value = ir_gen_node(irb, arg4_node, scope, LValNone, nullptr);
if (arg4_value == irb->codegen->invalid_instruction)
return arg4_value;
AstNode *arg5_node = node->data.fn_call_expr.params.at(5);
- IrInstruction *arg5_value = ir_gen_node(irb, arg5_node, scope);
+ IrInstruction *arg5_value = ir_gen_node(irb, arg5_node, scope, LValNone, nullptr);
if (arg5_value == irb->codegen->invalid_instruction)
return arg5_value;
- IrInstruction *cmpxchg = ir_build_cmpxchg(irb, scope, node, arg0_value, arg1_value,
- arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak),
- nullptr, AtomicOrderUnordered, AtomicOrderUnordered);
- return ir_lval_wrap(irb, scope, cmpxchg, lval);
+ IrInstruction *ensured_result_loc = ensure_result_loc(irb, scope, node, LValNone, result_loc);
+ if (ensured_result_loc == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+
+ IrInstruction *payload_ptr = (lval == LValOptional) ? ensured_result_loc :
+ ir_build_result_optional_payload(irb, scope, node, ensured_result_loc, arg0_value, false);
+
+ IrInstruction *cmpxchg = ir_build_cmpxchg_src(irb, scope, node, arg0_value, arg1_value,
+ arg2_value, arg3_value, arg4_value, arg5_value, payload_ptr,
+ (builtin_fn->id == BuiltinFnIdCmpxchgWeak));
+
+ if (lval == LValOptional)
+ return cmpxchg;
+
+ ir_build_set_nonnull_bit(irb, scope, node, ensured_result_loc, cmpxchg, payload_ptr);
+ return ir_gen_result(irb, scope, node, lval, result_loc, LValNone, ensured_result_loc);
}
case BuiltinFnIdFence:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *fence = ir_build_fence(irb, scope, node, arg0_value, AtomicOrderUnordered);
- return ir_lval_wrap(irb, scope, fence, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, fence);
}
case BuiltinFnIdDivExact:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivExact, arg0_value, arg1_value, true);
- return ir_lval_wrap(irb, scope, bin_op, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, bin_op);
}
case BuiltinFnIdDivTrunc:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivTrunc, arg0_value, arg1_value, true);
- return ir_lval_wrap(irb, scope, bin_op, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, bin_op);
}
case BuiltinFnIdDivFloor:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivFloor, arg0_value, arg1_value, true);
- return ir_lval_wrap(irb, scope, bin_op, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, bin_op);
}
case BuiltinFnIdRem:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpRemRem, arg0_value, arg1_value, true);
- return ir_lval_wrap(irb, scope, bin_op, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, bin_op);
}
case BuiltinFnIdMod:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpRemMod, arg0_value, arg1_value, true);
- return ir_lval_wrap(irb, scope, bin_op, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, bin_op);
}
case BuiltinFnIdSqrt:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *ir_sqrt = ir_build_sqrt(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, ir_sqrt, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_sqrt);
}
case BuiltinFnIdTruncate:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *truncate = ir_build_truncate(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, truncate, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, truncate);
}
case BuiltinFnIdIntCast:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *result = ir_build_int_cast(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdFloatCast:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *result = ir_build_float_cast(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdErrSetCast:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *result = ir_build_err_set_cast(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdFromBytes:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
+ IrInstruction *ensured_result_loc = ensure_result_loc(irb, scope, node, lval, result_loc);
+ if (ensured_result_loc == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+
+ IrInstruction *new_result_loc = ir_build_result_slice_to_bytes_src(irb, scope, node, arg0_value,
+ ensured_result_loc);
+
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, new_result_loc);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
- IrInstruction *result = ir_build_from_bytes(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ ir_build_from_bytes_len_src(irb, scope, node, ensured_result_loc, new_result_loc);
+
+ return ir_gen_result(irb, scope, node, lval, result_loc, LValNone, ensured_result_loc);
}
case BuiltinFnIdToBytes:
{
+ IrInstruction *ensured_result_loc = ensure_result_loc(irb, scope, node, lval, result_loc);
+ if (ensured_result_loc == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+
+ IrInstruction *new_result_loc = ir_build_result_bytes_to_slice(irb, scope, node, ensured_result_loc);
+
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, new_result_loc);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
- IrInstruction *result = ir_build_to_bytes(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ ir_build_to_bytes_len_src(irb, scope, node, ensured_result_loc, new_result_loc);
+
+ return ir_gen_result(irb, scope, node, lval, result_loc, LValNone, ensured_result_loc);
}
case BuiltinFnIdIntToFloat:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *result = ir_build_int_to_float(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdFloatToInt:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *result = ir_build_float_to_int(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdErrToInt:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *result = ir_build_err_to_int(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdIntToErr:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *result = ir_build_int_to_err(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdBoolToInt:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *result = ir_build_bool_to_int(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdIntType:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *int_type = ir_build_int_type(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, int_type, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, int_type);
}
case BuiltinFnIdMemcpy:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
- IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
+ IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope, LValNone, nullptr);
if (arg2_value == irb->codegen->invalid_instruction)
return arg2_value;
IrInstruction *ir_memcpy = ir_build_memcpy(irb, scope, node, arg0_value, arg1_value, arg2_value);
- return ir_lval_wrap(irb, scope, ir_memcpy, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_memcpy);
}
case BuiltinFnIdMemset:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
- IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
+ IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope, LValNone, nullptr);
if (arg2_value == irb->codegen->invalid_instruction)
return arg2_value;
IrInstruction *ir_memset = ir_build_memset(irb, scope, node, arg0_value, arg1_value, arg2_value);
- return ir_lval_wrap(irb, scope, ir_memset, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_memset);
}
case BuiltinFnIdMemberCount:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *member_count = ir_build_member_count(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, member_count, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, member_count);
}
case BuiltinFnIdMemberType:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *member_type = ir_build_member_type(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, member_type, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, member_type);
}
case BuiltinFnIdMemberName:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
-
IrInstruction *member_name = ir_build_member_name(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, member_name, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, member_name);
}
case BuiltinFnIdField:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node_extra(irb, arg0_node, scope, LValPtr);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValPtr, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
- IrInstruction *ptr_instruction = ir_build_field_ptr_instruction(irb, scope, node, arg0_value, arg1_value);
-
- if (lval == LValPtr)
- return ptr_instruction;
-
- return ir_build_load_ptr(irb, scope, node, ptr_instruction);
+ IrInstruction *ptr_instruction = ir_build_field_ptr_instruction(irb, scope, node,
+ arg0_value, arg1_value);
+ return ir_gen_ptr(irb, scope, node, lval, result_loc, ptr_instruction);
}
case BuiltinFnIdTypeInfo:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *type_info = ir_build_type_info(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, type_info, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, type_info);
}
case BuiltinFnIdBreakpoint:
- return ir_lval_wrap(irb, scope, ir_build_breakpoint(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_build_breakpoint(irb, scope, node));
case BuiltinFnIdReturnAddress:
- return ir_lval_wrap(irb, scope, ir_build_return_address(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_build_return_address(irb, scope, node));
case BuiltinFnIdFrameAddress:
- return ir_lval_wrap(irb, scope, ir_build_frame_address(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_build_frame_address(irb, scope, node));
case BuiltinFnIdHandle:
if (!irb->exec->fn_entry) {
add_node_error(irb->codegen, node, buf_sprintf("@handle() called outside of function definition"));
@@ -4295,170 +5103,183 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
add_node_error(irb->codegen, node, buf_sprintf("@handle() in non-async function"));
return irb->codegen->invalid_instruction;
}
- return ir_lval_wrap(irb, scope, ir_build_handle(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_build_handle(irb, scope, node));
case BuiltinFnIdAlignOf:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *align_of = ir_build_align_of(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, align_of, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, align_of);
}
case BuiltinFnIdAddWithOverflow:
- return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpAdd), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_overflow_op(irb, scope, node, IrOverflowOpAdd));
case BuiltinFnIdSubWithOverflow:
- return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpSub), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_overflow_op(irb, scope, node, IrOverflowOpSub));
case BuiltinFnIdMulWithOverflow:
- return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul));
case BuiltinFnIdShlWithOverflow:
- return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl));
case BuiltinFnIdTypeName:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *type_name = ir_build_type_name(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, type_name, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, type_name);
}
case BuiltinFnIdPanic:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *panic = ir_build_panic(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, panic, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, panic);
}
case BuiltinFnIdPtrCast:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
- IrInstruction *ptr_cast = ir_build_ptr_cast(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, ptr_cast, lval);
+ IrInstruction *ptr_cast = ir_build_ptr_cast_src(irb, scope, node, arg0_value, arg1_value);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ptr_cast);
}
case BuiltinFnIdBitCast:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
+ IrInstruction *ensured_result_loc = ensure_result_loc(irb, scope, node, lval, result_loc);
+ if (ensured_result_loc == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+
+ IrInstruction *new_result_loc = ir_build_result_ptr_cast(irb, scope, node, arg0_value,
+ ensured_result_loc);
+
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, new_result_loc);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
- IrInstruction *bit_cast = ir_build_bit_cast(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, bit_cast, lval);
+ ir_build_infer_comptime(irb, scope, node, ensured_result_loc, new_result_loc);
+
+ return ir_gen_result(irb, scope, node, lval, result_loc, LValNone, ensured_result_loc);
}
case BuiltinFnIdIntToPtr:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *int_to_ptr = ir_build_int_to_ptr(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, int_to_ptr, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, int_to_ptr);
}
case BuiltinFnIdPtrToInt:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *ptr_to_int = ir_build_ptr_to_int(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, ptr_to_int, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ptr_to_int);
}
case BuiltinFnIdTagName:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *actual_tag = ir_build_union_tag(irb, scope, node, arg0_value);
IrInstruction *tag_name = ir_build_tag_name(irb, scope, node, actual_tag);
- return ir_lval_wrap(irb, scope, tag_name, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, tag_name);
}
case BuiltinFnIdTagType:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *tag_type = ir_build_tag_type(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, tag_type, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, tag_type);
}
case BuiltinFnIdFieldParentPtr:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
- IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
+ IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope, LValNone, nullptr);
if (arg2_value == irb->codegen->invalid_instruction)
return arg2_value;
- IrInstruction *field_parent_ptr = ir_build_field_parent_ptr(irb, scope, node, arg0_value, arg1_value, arg2_value, nullptr);
- return ir_lval_wrap(irb, scope, field_parent_ptr, lval);
+ IrInstruction *field_parent_ptr = ir_build_field_parent_ptr(irb, scope, node,
+ arg0_value, arg1_value, arg2_value, nullptr);
+ return ir_gen_value(irb, scope, node, lval, result_loc, field_parent_ptr);
}
case BuiltinFnIdByteOffsetOf:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *offset_of = ir_build_byte_offset_of(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, offset_of, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, offset_of);
}
case BuiltinFnIdBitOffsetOf:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *offset_of = ir_build_bit_offset_of(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, offset_of, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, offset_of);
}
case BuiltinFnIdInlineCall:
case BuiltinFnIdNoInlineCall:
@@ -4469,7 +5290,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
}
AstNode *fn_ref_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope);
+ IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope, LValNone, nullptr);
if (fn_ref == irb->codegen->invalid_instruction)
return fn_ref;
@@ -4478,14 +5299,14 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
IrInstruction **args = allocate(arg_count);
for (size_t i = 0; i < arg_count; i += 1) {
AstNode *arg_node = node->data.fn_call_expr.params.at(i + 1);
- args[i] = ir_gen_node(irb, arg_node, scope);
+ args[i] = ir_gen_node(irb, arg_node, scope, LValNone, nullptr);
if (args[i] == irb->codegen->invalid_instruction)
return args[i];
}
FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever;
- IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr, nullptr);
- return ir_lval_wrap(irb, scope, call, lval);
+ return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
+ fn_inline, false, nullptr, nullptr, result_loc, nullptr, lval);
}
case BuiltinFnIdNewStackCall:
{
@@ -4495,12 +5316,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
}
AstNode *new_stack_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *new_stack = ir_gen_node(irb, new_stack_node, scope);
+ IrInstruction *new_stack = ir_gen_node(irb, new_stack_node, scope, LValNone, nullptr);
if (new_stack == irb->codegen->invalid_instruction)
return new_stack;
AstNode *fn_ref_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope);
+ IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope, LValNone, nullptr);
if (fn_ref == irb->codegen->invalid_instruction)
return fn_ref;
@@ -4509,291 +5330,314 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
IrInstruction **args = allocate(arg_count);
for (size_t i = 0; i < arg_count; i += 1) {
AstNode *arg_node = node->data.fn_call_expr.params.at(i + 2);
- args[i] = ir_gen_node(irb, arg_node, scope);
+ args[i] = ir_gen_node(irb, arg_node, scope, LValNone, nullptr);
if (args[i] == irb->codegen->invalid_instruction)
return args[i];
}
- IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, false, nullptr, new_stack);
- return ir_lval_wrap(irb, scope, call, lval);
+ return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args,
+ false, FnInlineAuto, false, nullptr, new_stack, result_loc, nullptr, lval);
}
case BuiltinFnIdTypeId:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *type_id = ir_build_type_id(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, type_id, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, type_id);
}
case BuiltinFnIdShlExact:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
- IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftLeftExact, arg0_value, arg1_value, true);
- return ir_lval_wrap(irb, scope, bin_op, lval);
+ IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftLeftExact,
+ arg0_value, arg1_value, true);
+ return ir_gen_value(irb, scope, node, lval, result_loc, bin_op);
}
case BuiltinFnIdShrExact:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
- IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftRightExact, arg0_value, arg1_value, true);
- return ir_lval_wrap(irb, scope, bin_op, lval);
+ IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftRightExact,
+ arg0_value, arg1_value, true);
+ return ir_gen_value(irb, scope, node, lval, result_loc, bin_op);
}
case BuiltinFnIdSetEvalBranchQuota:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *set_eval_branch_quota = ir_build_set_eval_branch_quota(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, set_eval_branch_quota, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, set_eval_branch_quota);
}
case BuiltinFnIdAlignCast:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *align_cast = ir_build_align_cast(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, align_cast, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, align_cast);
}
case BuiltinFnIdOpaqueType:
{
IrInstruction *opaque_type = ir_build_opaque_type(irb, scope, node);
- return ir_lval_wrap(irb, scope, opaque_type, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, opaque_type);
}
case BuiltinFnIdThis:
{
IrInstruction *this_inst = ir_gen_this(irb, scope, node);
- return ir_lval_wrap(irb, scope, this_inst, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, this_inst);
}
case BuiltinFnIdSetAlignStack:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *set_align_stack = ir_build_set_align_stack(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, set_align_stack, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, set_align_stack);
}
case BuiltinFnIdArgType:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *arg_type = ir_build_arg_type(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, arg_type, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, arg_type);
}
case BuiltinFnIdExport:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
- IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
+ IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope, LValNone, nullptr);
if (arg2_value == irb->codegen->invalid_instruction)
return arg2_value;
IrInstruction *ir_export = ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value);
- return ir_lval_wrap(irb, scope, ir_export, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_export);
}
case BuiltinFnIdErrorReturnTrace:
{
- IrInstruction *error_return_trace = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::Null);
- return ir_lval_wrap(irb, scope, error_return_trace, lval);
+ IrInstruction *error_return_trace = ir_build_error_return_trace(irb, scope, node,
+ IrInstructionErrorReturnTrace::Null);
+ return ir_gen_value(irb, scope, node, lval, result_loc, error_return_trace);
}
case BuiltinFnIdAtomicRmw:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
- IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
+ IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope, LValNone, nullptr);
if (arg2_value == irb->codegen->invalid_instruction)
return arg2_value;
AstNode *arg3_node = node->data.fn_call_expr.params.at(3);
- IrInstruction *arg3_value = ir_gen_node(irb, arg3_node, scope);
+ IrInstruction *arg3_value = ir_gen_node(irb, arg3_node, scope, LValNone, nullptr);
if (arg3_value == irb->codegen->invalid_instruction)
return arg3_value;
AstNode *arg4_node = node->data.fn_call_expr.params.at(4);
- IrInstruction *arg4_value = ir_gen_node(irb, arg4_node, scope);
+ IrInstruction *arg4_value = ir_gen_node(irb, arg4_node, scope, LValNone, nullptr);
if (arg4_value == irb->codegen->invalid_instruction)
return arg4_value;
- return ir_build_atomic_rmw(irb, scope, node, arg0_value, arg1_value, arg2_value, arg3_value,
- arg4_value,
+ IrInstruction *result = ir_build_atomic_rmw(irb, scope, node, arg0_value, arg1_value,
+ arg2_value, arg3_value, arg4_value,
// these 2 values don't mean anything since we passed non-null values for other args
AtomicRmwOp_xchg, AtomicOrderMonotonic);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdAtomicLoad:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
AstNode *arg2_node = node->data.fn_call_expr.params.at(2);
- IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope);
+ IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope, LValNone, nullptr);
if (arg2_value == irb->codegen->invalid_instruction)
return arg2_value;
- return ir_build_atomic_load(irb, scope, node, arg0_value, arg1_value, arg2_value,
+ IrInstruction *result = ir_build_atomic_load(irb, scope, node, arg0_value, arg1_value, arg2_value,
// this value does not mean anything since we passed non-null values for other arg
AtomicOrderMonotonic);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdIntToEnum:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *result = ir_build_int_to_enum(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdEnumToInt:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
IrInstruction *result = ir_build_enum_to_int(irb, scope, node, arg0_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdBswap:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *result = ir_build_bswap(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
case BuiltinFnIdBitReverse:
{
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
- IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
+ IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope, LValNone, nullptr);
if (arg0_value == irb->codegen->invalid_instruction)
return arg0_value;
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
- IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
+ IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope, LValNone, nullptr);
if (arg1_value == irb->codegen->invalid_instruction)
return arg1_value;
IrInstruction *result = ir_build_bit_reverse(irb, scope, node, arg0_value, arg1_value);
- return ir_lval_wrap(irb, scope, result, lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, result);
}
}
zig_unreachable();
}
-static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
+static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeFnCallExpr);
if (node->data.fn_call_expr.is_builtin)
- return ir_gen_builtin_fn_call(irb, scope, node, lval);
+ return ir_gen_builtin_fn_call(irb, scope, node, lval, result_loc);
AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
- IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope);
+ IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope, LValNone, nullptr);
if (fn_ref == irb->codegen->invalid_instruction)
return fn_ref;
+ // In pass 1, we can't tell the difference between a function call with a single argument
+ // and an implicit cast. So if there is only one argument, we emit a special instruction.
size_t arg_count = node->data.fn_call_expr.params.length;
IrInstruction **args = allocate(arg_count);
+ bool is_async = node->data.fn_call_expr.is_async;
+ if (arg_count == 1 && !is_async && result_loc != nullptr) {
+ AstNode *arg_node = node->data.fn_call_expr.params.at(0);
+ IrInstruction *arg_result_loc = ir_build_first_arg_result_loc(irb, scope, arg_node, result_loc, fn_ref);
+ args[0] = ir_gen_node(irb, arg_node, scope, LValNone, arg_result_loc);
+ if (args[0] == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+ // In the analysis, this call instruction will be a simple LoadPtr instruction if
+ // it turns out to be an implicit cast.
+ return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false,
+ FnInlineAuto, false, nullptr, nullptr, result_loc, arg_result_loc, lval);
+ }
+
for (size_t i = 0; i < arg_count; i += 1) {
AstNode *arg_node = node->data.fn_call_expr.params.at(i);
- args[i] = ir_gen_node(irb, arg_node, scope);
+ args[i] = ir_gen_node(irb, arg_node, scope, LValNone, nullptr);
if (args[i] == irb->codegen->invalid_instruction)
return args[i];
}
- bool is_async = node->data.fn_call_expr.is_async;
IrInstruction *async_allocator = nullptr;
if (is_async) {
if (node->data.fn_call_expr.async_allocator) {
- async_allocator = ir_gen_node(irb, node->data.fn_call_expr.async_allocator, scope);
+ async_allocator = ir_gen_node(irb, node->data.fn_call_expr.async_allocator, scope, LValNone, nullptr);
if (async_allocator == irb->codegen->invalid_instruction)
return async_allocator;
}
}
- IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator, nullptr);
- return ir_lval_wrap(irb, scope, fn_call, lval);
+ return ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto,
+ is_async, async_allocator, nullptr, result_loc, nullptr, lval);
}
-static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
+static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeIfBoolExpr);
- IrInstruction *condition = ir_gen_node(irb, node->data.if_bool_expr.condition, scope);
+ IrInstruction *condition = ir_gen_node(irb, node->data.if_bool_expr.condition, scope, LValNone, nullptr);
if (condition == irb->codegen->invalid_instruction)
- return condition;
+ return irb->codegen->invalid_instruction;
IrInstruction *is_comptime;
if (ir_should_inline(irb->exec, scope)) {
@@ -4809,14 +5653,14 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "Else");
IrBasicBlock *endif_block = ir_create_basic_block(irb, scope, "EndIf");
- ir_build_cond_br(irb, scope, condition->source_node, condition, then_block, else_block, is_comptime);
+ ir_build_cond_br(irb, scope, condition->source_node, condition, then_block, else_block, is_comptime, result_loc);
ir_set_cursor_at_end_and_append_block(irb, then_block);
Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime);
- IrInstruction *then_expr_result = ir_gen_node(irb, then_node, subexpr_scope);
+ IrInstruction *then_expr_result = ir_gen_node(irb, then_node, subexpr_scope, lval, result_loc);
if (then_expr_result == irb->codegen->invalid_instruction)
- return then_expr_result;
+ return irb->codegen->invalid_instruction;
IrBasicBlock *after_then_block = irb->current_basic_block;
if (!instr_is_unreachable(then_expr_result))
ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime));
@@ -4824,9 +5668,9 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
ir_set_cursor_at_end_and_append_block(irb, else_block);
IrInstruction *else_expr_result;
if (else_node) {
- else_expr_result = ir_gen_node(irb, else_node, subexpr_scope);
+ else_expr_result = ir_gen_node(irb, else_node, subexpr_scope, lval, result_loc);
if (else_expr_result == irb->codegen->invalid_instruction)
- return else_expr_result;
+ return irb->codegen->invalid_instruction;
} else {
else_expr_result = ir_build_const_void(irb, scope, node);
}
@@ -4845,32 +5689,17 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
}
-static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id, LVal lval) {
+static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id) {
assert(node->type == NodeTypePrefixOpExpr);
AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
- IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, lval);
+ IrInstruction *value = ir_gen_node(irb, expr_node, scope, LValNone, nullptr);
if (value == irb->codegen->invalid_instruction)
return value;
return ir_build_un_op(irb, scope, node, op_id, value);
}
-static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id) {
- return ir_gen_prefix_op_id_lval(irb, scope, node, op_id, LValNone);
-}
-
-static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval) {
- if (lval != LValPtr)
- return value;
- if (value == irb->codegen->invalid_instruction)
- return value;
-
- // We needed a pointer to a value, but we got a value. So we create
- // an instruction which just makes a const pointer of it.
- return ir_build_ref(irb, scope, value->source_node, value, false, false);
-}
-
static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypePointerType);
PtrLen ptr_len = (node->data.pointer_type.star_token->id == TokenIdStar ||
@@ -4882,14 +5711,14 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *align_value;
if (align_expr != nullptr) {
- align_value = ir_gen_node(irb, align_expr, scope);
+ align_value = ir_gen_node(irb, align_expr, scope, LValNone, nullptr);
if (align_value == irb->codegen->invalid_instruction)
return align_value;
} else {
align_value = nullptr;
}
- IrInstruction *child_type = ir_gen_node(irb, expr_node, scope);
+ IrInstruction *child_type = ir_gen_node(irb, expr_node, scope, LValNone, nullptr);
if (child_type == irb->codegen->invalid_instruction)
return child_type;
@@ -4927,35 +5756,36 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode
ptr_len, align_value, bit_offset_start, host_int_bytes);
}
-static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node,
- LVal lval)
+static IrInstruction *ir_gen_catch_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ AstNode *expr_node, LVal lval, IrInstruction *old_result_loc)
{
- IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr);
- if (err_union_ptr == irb->codegen->invalid_instruction)
+ IrInstruction *new_result_loc = ensure_result_loc(irb, scope, source_node, lval, old_result_loc);
+ if (new_result_loc == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, scope, source_node, err_union_ptr, true);
- if (payload_ptr == irb->codegen->invalid_instruction)
+ IrInstruction *opt_err_code = ir_gen_node(irb, expr_node, scope, LValErrorUnionVal, new_result_loc);
+ if (opt_err_code == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- if (lval == LValPtr)
- return payload_ptr;
+ ir_build_assert_non_error(irb, scope, source_node, opt_err_code);
- return ir_build_load_ptr(irb, scope, source_node, payload_ptr);
+ return ir_gen_result(irb, scope, source_node, lval, old_result_loc, LValErrorUnionVal, new_result_loc);
}
static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypePrefixOpExpr);
AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
- IrInstruction *value = ir_gen_node(irb, expr_node, scope);
+ IrInstruction *value = ir_gen_node(irb, expr_node, scope, LValNone, nullptr);
if (value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
return ir_build_bool_not(irb, scope, node, value);
}
-static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
+static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypePrefixOpExpr);
PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op;
@@ -4964,34 +5794,53 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
case PrefixOpInvalid:
zig_unreachable();
case PrefixOpBoolNot:
- return ir_lval_wrap(irb, scope, ir_gen_bool_not(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_bool_not(irb, scope, node));
case PrefixOpBinNot:
- return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpBinNot), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_prefix_op_id(irb, scope, node, IrUnOpBinNot));
case PrefixOpNegation:
- return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation));
case PrefixOpNegationWrap:
- return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap));
case PrefixOpOptional:
- return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc,
+ ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional));
case PrefixOpAddrOf: {
AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
- return ir_lval_wrap(irb, scope, ir_gen_node_extra(irb, expr_node, scope, LValPtr), lval);
+ IrInstruction *inst = ir_gen_node(irb, expr_node, scope, LValPtr, result_loc);
+ if (inst == irb->codegen->invalid_instruction)
+ return inst;
+ if (result_loc == nullptr) {
+ return ir_gen_value(irb, scope, expr_node, lval, nullptr, inst);
+ } else {
+ return ir_gen_result(irb, scope, expr_node, lval, result_loc, LValNone, result_loc);
+ }
}
}
zig_unreachable();
}
-static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
+static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *old_result_loc)
+{
assert(node->type == NodeTypeContainerInitExpr);
+ IrInstruction *ensured_result_loc = ensure_result_loc(irb, scope, node, lval, old_result_loc);
+ if (ensured_result_loc == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+
AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr;
ContainerInitKind kind = container_init_expr->kind;
- IrInstruction *container_type = ir_gen_node(irb, container_init_expr->type, scope);
+ IrInstruction *container_type = ir_gen_node(irb, container_init_expr->type, scope, LValNone, nullptr);
if (container_type == irb->codegen->invalid_instruction)
return container_type;
if (kind == ContainerInitKindStruct) {
+ IrInstruction *new_result_loc = ir_build_result_cast(irb, scope, node, container_type, ensured_result_loc);
+
size_t field_count = container_init_expr->entries.length;
IrInstructionContainerInitFieldsField *fields = allocate(field_count);
for (size_t i = 0; i < field_count; i += 1) {
@@ -4999,28 +5848,39 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A
assert(entry_node->type == NodeTypeStructValueField);
Buf *name = entry_node->data.struct_val_field.name;
+ IrInstruction *field_result_loc = ir_build_field_ptr(irb, scope, entry_node, new_result_loc,
+ container_type, name, true);
+
AstNode *expr_node = entry_node->data.struct_val_field.expr;
- IrInstruction *expr_value = ir_gen_node(irb, expr_node, scope);
+ IrInstruction *expr_value = ir_gen_node(irb, expr_node, scope, LValNone, field_result_loc);
if (expr_value == irb->codegen->invalid_instruction)
return expr_value;
fields[i].name = name;
- fields[i].value = expr_value;
+ fields[i].result_loc = field_result_loc;
fields[i].source_node = entry_node;
}
- return ir_build_container_init_fields(irb, scope, node, container_type, field_count, fields);
+ ir_build_container_init_fields(irb, scope, node, container_type, field_count, fields, new_result_loc);
+ return ir_gen_result(irb, scope, node, lval, old_result_loc, LValNone, ensured_result_loc);
} else if (kind == ContainerInitKindArray) {
- size_t item_count = container_init_expr->entries.length;
- IrInstruction **values = allocate(item_count);
- for (size_t i = 0; i < item_count; i += 1) {
+ size_t elem_count = container_init_expr->entries.length;
+ IrInstruction *array_type = ir_build_infer_array_type(irb, scope, node, container_type, elem_count);
+ IrInstruction *new_result_loc = ir_build_result_cast(irb, scope, node, array_type, ensured_result_loc);
+
+ IrInstruction **result_locs = allocate(elem_count);
+ for (size_t i = 0; i < elem_count; i += 1) {
AstNode *expr_node = container_init_expr->entries.at(i);
- IrInstruction *expr_value = ir_gen_node(irb, expr_node, scope);
+ IrInstruction *index_value = ir_build_const_usize(irb, scope, expr_node, i);
+ IrInstruction *elem_result_loc = ir_mark_gen(ir_build_elem_ptr(irb, scope, expr_node, new_result_loc,
+ index_value, true, PtrLenSingle));
+ IrInstruction *expr_value = ir_gen_node(irb, expr_node, scope, LValNone, elem_result_loc);
if (expr_value == irb->codegen->invalid_instruction)
return expr_value;
- values[i] = expr_value;
+ result_locs[i] = elem_result_loc;
}
- return ir_build_container_init_list(irb, scope, node, container_type, item_count, values);
+ ir_build_container_init_list(irb, scope, node, array_type, elem_count, result_locs, new_result_loc);
+ return ir_gen_result(irb, scope, node, lval, old_result_loc, LValNone, ensured_result_loc);
} else {
zig_unreachable();
}
@@ -5038,7 +5898,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
IrInstruction *type_instruction;
if (variable_declaration->type != nullptr) {
- type_instruction = ir_gen_node(irb, variable_declaration->type, scope);
+ type_instruction = ir_gen_node(irb, variable_declaration->type, scope, LValNone, nullptr);
if (type_instruction == irb->codegen->invalid_instruction)
return type_instruction;
} else {
@@ -5053,18 +5913,18 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
ir_should_inline(irb->exec, scope) || variable_declaration->is_comptime);
ZigVar *var = ir_create_var(irb, node, scope, variable_declaration->symbol,
is_const, is_const, is_shadowable, is_comptime);
- // we detect IrInstructionIdDeclVar in gen_block to make sure the next node
+ // we detect IrInstructionIdDeclVarSrc in gen_block to make sure the next node
// is inside var->child_scope
if (!is_extern && !variable_declaration->expr) {
- var->value->type = irb->codegen->builtin_types.entry_invalid;
+ var->var_type = irb->codegen->builtin_types.entry_invalid;
add_node_error(irb->codegen, node, buf_sprintf("variables must be initialized"));
return irb->codegen->invalid_instruction;
}
IrInstruction *align_value = nullptr;
if (variable_declaration->align_expr != nullptr) {
- align_value = ir_gen_node(irb, variable_declaration->align_expr, scope);
+ align_value = ir_gen_node(irb, variable_declaration->align_expr, scope, LValNone, nullptr);
if (align_value == irb->codegen->invalid_instruction)
return align_value;
}
@@ -5074,20 +5934,39 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod
buf_sprintf("cannot set section of local variable '%s'", buf_ptr(variable_declaration->symbol)));
}
+ IrInstruction *alloca = ir_build_alloca_src(irb, scope, node, nullptr, align_value,
+ buf_ptr(variable_declaration->symbol), is_comptime);
+
+ IrInstruction *cast_result_loc = nullptr;
+ if (type_instruction != nullptr) {
+ cast_result_loc = ir_build_first_arg_result_loc(irb, scope, node, alloca, type_instruction);
+ } else {
+ cast_result_loc = alloca;
+ }
+
// Temporarily set the name of the IrExecutable to the VariableDeclaration
// so that the struct or enum from the init expression inherits the name.
Buf *old_exec_name = irb->exec->name;
irb->exec->name = variable_declaration->symbol;
- IrInstruction *init_value = ir_gen_node(irb, variable_declaration->expr, scope);
+ IrInstruction *init_value = ir_gen_node(irb, variable_declaration->expr, scope, LValNone, cast_result_loc);
irb->exec->name = old_exec_name;
if (init_value == irb->codegen->invalid_instruction)
return init_value;
- return ir_build_var_decl(irb, scope, node, var, type_instruction, align_value, init_value);
+ if (type_instruction != nullptr) {
+ IrInstruction **args = allocate(1);
+ args[0] = ir_gen_result(irb, scope, node, LValNone, alloca, LValNone, cast_result_loc);
+ ir_build_call(irb, scope, node, nullptr, type_instruction, 1, args, false,
+ FnInlineAuto, false, nullptr, nullptr, alloca, cast_result_loc, LValNone);
+ }
+
+ return ir_build_var_decl_src(irb, scope, node, var, nullptr, align_value, alloca);
}
-static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
+static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeWhileExpr);
AstNode *continue_expr_node = node->data.while_expr.continue_expr;
@@ -5122,25 +6001,32 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
} else {
payload_scope = subexpr_scope;
}
- IrInstruction *err_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope, LValPtr);
- if (err_val_ptr == irb->codegen->invalid_instruction)
- return err_val_ptr;
- IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr);
- IrInstruction *is_err = ir_build_test_err(irb, scope, node->data.while_expr.condition, err_val);
+ IrInstruction *err_union_ptr = ir_gen_node(irb, node->data.while_expr.condition, subexpr_scope,
+ LValPtr, nullptr);
+ if (err_union_ptr == irb->codegen->invalid_instruction)
+ return err_union_ptr;
+
+ IrInstruction *ptr_opt_err_code = ir_build_error_union_field_error_set(irb, scope,
+ node->data.while_expr.condition, err_union_ptr, false);
+ IrInstruction *opt_err_code = ir_build_load_ptr(irb, scope, node->data.while_expr.condition,
+ ptr_opt_err_code, nullptr);
+ IrInstruction *is_err = ir_build_test_nonnull(irb, scope, node->data.while_expr.condition, opt_err_code);
IrBasicBlock *after_cond_block = irb->current_basic_block;
- IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
+ assert(else_node != nullptr);
+ IrInstruction *void_else_result = ir_mark_gen(ir_build_const_void(irb, scope, node));
+
if (!instr_is_unreachable(is_err)) {
ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_err,
- else_block, body_block, is_comptime));
+ else_block, body_block, is_comptime, result_loc));
}
ir_set_cursor_at_end_and_append_block(irb, body_block);
if (var_symbol) {
- IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, payload_scope, symbol_node,
- err_val_ptr, false);
- IrInstruction *var_value = node->data.while_expr.var_is_ptr ?
- var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value);
- ir_build_var_decl(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
+ IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, payload_scope, symbol_node,
+ err_union_ptr, nullptr, false);
+ IrInstruction *var_ptr = node->data.while_expr.var_is_ptr ?
+ ir_build_ref(irb, payload_scope, symbol_node, payload_ptr, true, false, nullptr) : payload_ptr;
+ ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_ptr);
}
ZigList incoming_values = {0};
@@ -5150,10 +6036,12 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
loop_scope->break_block = end_block;
loop_scope->continue_block = continue_block;
loop_scope->is_comptime = is_comptime;
+ loop_scope->result_loc = result_loc;
loop_scope->incoming_blocks = &incoming_blocks;
loop_scope->incoming_values = &incoming_values;
- IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base);
+ IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base,
+ lval, result_loc);
if (body_result == irb->codegen->invalid_instruction)
return body_result;
@@ -5164,7 +6052,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
if (continue_expr_node) {
ir_set_cursor_at_end_and_append_block(irb, continue_block);
- IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, payload_scope);
+ IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, payload_scope, LValNone, nullptr);
if (expr_result == irb->codegen->invalid_instruction)
return expr_result;
if (!instr_is_unreachable(expr_result))
@@ -5172,21 +6060,22 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
}
ir_set_cursor_at_end_and_append_block(irb, else_block);
- assert(else_node != nullptr);
// TODO make it an error to write to error variable
AstNode *err_symbol_node = else_node; // TODO make more accurate
ZigVar *err_var = ir_create_var(irb, err_symbol_node, scope, err_symbol,
- true, false, false, is_comptime);
+ true, true, false, is_comptime);
Scope *err_scope = err_var->child_scope;
- IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr);
- ir_build_var_decl(irb, err_scope, symbol_node, err_var, nullptr, nullptr, err_var_value);
+ IrInstruction *unwrapped_err_code_ptr = ir_build_optional_unwrap_ptr(irb, err_scope, err_symbol_node,
+ ptr_opt_err_code, false);
+ ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, nullptr, unwrapped_err_code_ptr);
- IrInstruction *else_result = ir_gen_node(irb, else_node, err_scope);
+ IrInstruction *else_result = ir_gen_node(irb, else_node, err_scope, lval, result_loc);
if (else_result == irb->codegen->invalid_instruction)
return else_result;
if (!instr_is_unreachable(else_result))
ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
+
IrBasicBlock *after_else_block = irb->current_basic_block;
ir_set_cursor_at_end_and_append_block(irb, end_block);
if (else_result) {
@@ -5207,23 +6096,24 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
ZigVar *payload_var = ir_create_var(irb, symbol_node, subexpr_scope, var_symbol,
true, false, false, is_comptime);
Scope *child_scope = payload_var->child_scope;
- IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope, LValPtr);
+ IrInstruction *maybe_val_ptr = ir_gen_node(irb, node->data.while_expr.condition, subexpr_scope,
+ LValPtr, nullptr);
if (maybe_val_ptr == irb->codegen->invalid_instruction)
return maybe_val_ptr;
- IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr);
+ IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr, nullptr);
IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node->data.while_expr.condition, maybe_val);
IrBasicBlock *after_cond_block = irb->current_basic_block;
IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
if (!instr_is_unreachable(is_non_null)) {
ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_non_null,
- body_block, else_block, is_comptime));
+ body_block, else_block, is_comptime, result_loc));
}
ir_set_cursor_at_end_and_append_block(irb, body_block);
- IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, child_scope, symbol_node, maybe_val_ptr, false);
- IrInstruction *var_value = node->data.while_expr.var_is_ptr ?
- var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value);
- ir_build_var_decl(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_value);
+ IrInstruction *payload_ptr = ir_build_optional_unwrap_ptr(irb, child_scope, symbol_node, maybe_val_ptr, false);
+ IrInstruction *var_ptr = node->data.while_expr.var_is_ptr ?
+ ir_build_ref(irb, child_scope, symbol_node, payload_ptr, true, false, nullptr) : payload_ptr;
+ ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_ptr);
ZigList incoming_values = {0};
ZigList incoming_blocks = {0};
@@ -5232,10 +6122,12 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
loop_scope->break_block = end_block;
loop_scope->continue_block = continue_block;
loop_scope->is_comptime = is_comptime;
+ loop_scope->result_loc = result_loc;
loop_scope->incoming_blocks = &incoming_blocks;
loop_scope->incoming_values = &incoming_values;
- IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base);
+ IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base,
+ lval, result_loc);
if (body_result == irb->codegen->invalid_instruction)
return body_result;
@@ -5246,7 +6138,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
if (continue_expr_node) {
ir_set_cursor_at_end_and_append_block(irb, continue_block);
- IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, child_scope);
+ IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, child_scope, LValNone, nullptr);
if (expr_result == irb->codegen->invalid_instruction)
return expr_result;
if (!instr_is_unreachable(expr_result))
@@ -5257,13 +6149,14 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
if (else_node) {
ir_set_cursor_at_end_and_append_block(irb, else_block);
- else_result = ir_gen_node(irb, else_node, scope);
+ else_result = ir_gen_node(irb, else_node, scope, lval, result_loc);
if (else_result == irb->codegen->invalid_instruction)
return else_result;
if (!instr_is_unreachable(else_result))
ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
}
IrBasicBlock *after_else_block = irb->current_basic_block;
+
ir_set_cursor_at_end_and_append_block(irb, end_block);
if (else_result) {
incoming_blocks.append(after_else_block);
@@ -5276,14 +6169,14 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
} else {
ir_set_cursor_at_end_and_append_block(irb, cond_block);
- IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope);
+ IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope, LValNone, nullptr);
if (cond_val == irb->codegen->invalid_instruction)
return cond_val;
IrBasicBlock *after_cond_block = irb->current_basic_block;
IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node));
if (!instr_is_unreachable(cond_val)) {
ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val,
- body_block, else_block, is_comptime));
+ body_block, else_block, is_comptime, result_loc));
}
ir_set_cursor_at_end_and_append_block(irb, body_block);
@@ -5297,10 +6190,12 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
loop_scope->break_block = end_block;
loop_scope->continue_block = continue_block;
loop_scope->is_comptime = is_comptime;
+ loop_scope->result_loc = result_loc;
loop_scope->incoming_blocks = &incoming_blocks;
loop_scope->incoming_values = &incoming_values;
- IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base);
+ IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base,
+ lval, result_loc);
if (body_result == irb->codegen->invalid_instruction)
return body_result;
@@ -5311,7 +6206,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
if (continue_expr_node) {
ir_set_cursor_at_end_and_append_block(irb, continue_block);
- IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, subexpr_scope);
+ IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, subexpr_scope, LValNone, nullptr);
if (expr_result == irb->codegen->invalid_instruction)
return expr_result;
if (!instr_is_unreachable(expr_result))
@@ -5322,13 +6217,14 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
if (else_node) {
ir_set_cursor_at_end_and_append_block(irb, else_block);
- else_result = ir_gen_node(irb, else_node, subexpr_scope);
+ else_result = ir_gen_node(irb, else_node, subexpr_scope, lval, result_loc);
if (else_result == irb->codegen->invalid_instruction)
return else_result;
if (!instr_is_unreachable(else_result))
ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime));
}
IrBasicBlock *after_else_block = irb->current_basic_block;
+
ir_set_cursor_at_end_and_append_block(irb, end_block);
if (else_result) {
incoming_blocks.append(after_else_block);
@@ -5337,12 +6233,13 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
incoming_blocks.append(after_cond_block);
incoming_values.append(void_else_result);
}
-
return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
}
}
-static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
+static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeForExpr);
AstNode *array_node = node->data.for_expr.array_expr;
@@ -5357,11 +6254,11 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
}
assert(elem_node->type == NodeTypeSymbol);
- IrInstruction *array_val_ptr = ir_gen_node_extra(irb, array_node, parent_scope, LValPtr);
+ IrInstruction *array_val_ptr = ir_gen_node(irb, array_node, parent_scope, LValPtr, nullptr);
if (array_val_ptr == irb->codegen->invalid_instruction)
return array_val_ptr;
- IrInstruction *array_val = ir_build_load_ptr(irb, parent_scope, array_node, array_val_ptr);
+ IrInstruction *array_val = ir_build_load_ptr(irb, parent_scope, array_node, array_val_ptr, nullptr);
IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_val);
IrInstruction *elem_var_type;
@@ -5379,10 +6276,6 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
ZigVar *elem_var = ir_create_var(irb, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime);
Scope *child_scope = elem_var->child_scope;
- IrInstruction *undefined_value = ir_build_const_undefined(irb, child_scope, elem_node);
- ir_build_var_decl(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, undefined_value);
- IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var);
-
AstNode *index_var_source_node;
ZigVar *index_var;
if (index_node) {
@@ -5396,10 +6289,12 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
child_scope = index_var->child_scope;
IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize);
+ IrInstruction *index_alloca = ir_build_alloca_src(irb, child_scope, node, usize, nullptr, "for_index",
+ is_comptime);
IrInstruction *zero = ir_build_const_usize(irb, child_scope, node, 0);
IrInstruction *one = ir_build_const_usize(irb, child_scope, node, 1);
- ir_build_var_decl(irb, child_scope, index_var_source_node, index_var, usize, nullptr, zero);
- IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var);
+ ir_build_store_ptr(irb, child_scope, index_var_source_node, index_alloca, zero);
+ ir_build_var_decl_src(irb, child_scope, index_var_source_node, index_var, usize, nullptr, index_alloca);
IrBasicBlock *cond_block = ir_create_basic_block(irb, child_scope, "ForCond");
@@ -5409,26 +6304,23 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
IrBasicBlock *continue_block = ir_create_basic_block(irb, child_scope, "ForContinue");
Buf *len_field_name = buf_create_from_str("len");
- IrInstruction *len_ref = ir_build_field_ptr(irb, child_scope, node, array_val_ptr, len_field_name);
- IrInstruction *len_val = ir_build_load_ptr(irb, child_scope, node, len_ref);
+ IrInstruction *len_ref = ir_build_field_ptr(irb, child_scope, node, array_val_ptr, nullptr,
+ len_field_name, false);
+ IrInstruction *len_val = ir_build_load_ptr(irb, child_scope, node, len_ref, nullptr);
ir_build_br(irb, child_scope, node, cond_block, is_comptime);
ir_set_cursor_at_end_and_append_block(irb, cond_block);
- IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_ptr);
+ IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_alloca, nullptr);
IrInstruction *cond = ir_build_bin_op(irb, child_scope, node, IrBinOpCmpLessThan, index_val, len_val, false);
IrBasicBlock *after_cond_block = irb->current_basic_block;
IrInstruction *void_else_value = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
- ir_mark_gen(ir_build_cond_br(irb, child_scope, node, cond, body_block, else_block, is_comptime));
+ ir_mark_gen(ir_build_cond_br(irb, child_scope, node, cond, body_block, else_block, is_comptime, result_loc));
ir_set_cursor_at_end_and_append_block(irb, body_block);
IrInstruction *elem_ptr = ir_build_elem_ptr(irb, child_scope, node, array_val_ptr, index_val, false, PtrLenSingle);
- IrInstruction *elem_val;
- if (node->data.for_expr.elem_is_ptr) {
- elem_val = elem_ptr;
- } else {
- elem_val = ir_build_load_ptr(irb, child_scope, node, elem_ptr);
- }
- ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, elem_var_ptr, elem_val));
+ IrInstruction *elem_var_ptr = node->data.for_expr.elem_is_ptr ?
+ ir_build_ref(irb, child_scope, elem_node, elem_ptr, true, false, nullptr) : elem_ptr;
+ ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, elem_var_ptr);
ZigList incoming_values = {0};
ZigList incoming_blocks = {0};
@@ -5436,24 +6328,25 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
loop_scope->break_block = end_block;
loop_scope->continue_block = continue_block;
loop_scope->is_comptime = is_comptime;
+ loop_scope->result_loc = result_loc;
loop_scope->incoming_blocks = &incoming_blocks;
loop_scope->incoming_values = &incoming_values;
- IrInstruction *body_result = ir_gen_node(irb, body_node, &loop_scope->base);
+ IrInstruction *body_result = ir_gen_node(irb, body_node, &loop_scope->base, lval, result_loc);
if (!instr_is_unreachable(body_result))
ir_mark_gen(ir_build_br(irb, child_scope, node, continue_block, is_comptime));
ir_set_cursor_at_end_and_append_block(irb, continue_block);
IrInstruction *new_index_val = ir_build_bin_op(irb, child_scope, node, IrBinOpAdd, index_val, one, false);
- ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, index_ptr, new_index_val));
+ ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, index_alloca, new_index_val));
ir_build_br(irb, child_scope, node, cond_block, is_comptime);
IrInstruction *else_result = nullptr;
if (else_node) {
ir_set_cursor_at_end_and_append_block(irb, else_block);
- else_result = ir_gen_node(irb, else_node, parent_scope);
+ else_result = ir_gen_node(irb, else_node, parent_scope, lval, result_loc);
if (else_result == irb->codegen->invalid_instruction)
return else_result;
if (!instr_is_unreachable(else_result))
@@ -5469,7 +6362,6 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
incoming_blocks.append(after_cond_block);
incoming_values.append(void_else_value);
}
-
return ir_build_phi(irb, parent_scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
}
@@ -5512,11 +6404,11 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
return irb->codegen->invalid_instruction;
}
- IrInstruction *size_value = ir_gen_node(irb, size_node, comptime_scope);
+ IrInstruction *size_value = ir_gen_node(irb, size_node, comptime_scope, LValNone, nullptr);
if (size_value == irb->codegen->invalid_instruction)
return size_value;
- IrInstruction *child_type = ir_gen_node(irb, child_type_node, comptime_scope);
+ IrInstruction *child_type = ir_gen_node(irb, child_type_node, comptime_scope, LValNone, nullptr);
if (child_type == irb->codegen->invalid_instruction)
return child_type;
@@ -5524,14 +6416,14 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
} else {
IrInstruction *align_value;
if (align_expr != nullptr) {
- align_value = ir_gen_node(irb, align_expr, comptime_scope);
+ align_value = ir_gen_node(irb, align_expr, comptime_scope, LValNone, nullptr);
if (align_value == irb->codegen->invalid_instruction)
return align_value;
} else {
align_value = nullptr;
}
- IrInstruction *child_type = ir_gen_node(irb, child_type_node, comptime_scope);
+ IrInstruction *child_type = ir_gen_node(irb, child_type_node, comptime_scope, LValNone, nullptr);
if (child_type == irb->codegen->invalid_instruction)
return child_type;
@@ -5546,7 +6438,7 @@ static IrInstruction *ir_gen_promise_type(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *payload_type_value = nullptr;
if (payload_type_node != nullptr) {
- payload_type_value = ir_gen_node(irb, payload_type_node, scope);
+ payload_type_value = ir_gen_node(irb, payload_type_node, scope, LValNone, nullptr);
if (payload_type_value == irb->codegen->invalid_instruction)
return payload_type_value;
@@ -5578,7 +6470,7 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod
if (asm_output->return_type) {
return_count += 1;
- IrInstruction *return_type = ir_gen_node(irb, asm_output->return_type, scope);
+ IrInstruction *return_type = ir_gen_node(irb, asm_output->return_type, scope, LValNone, nullptr);
if (return_type == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
if (return_count > 1) {
@@ -5612,7 +6504,7 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod
}
for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1) {
AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
- IrInstruction *input_value = ir_gen_node(irb, asm_input->expr, scope);
+ IrInstruction *input_value = ir_gen_node(irb, asm_input->expr, scope, LValNone, nullptr);
if (input_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -5622,8 +6514,10 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod
return ir_build_asm(irb, scope, node, input_list, output_types, output_vars, return_count, is_volatile);
}
-static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
- assert(node->type == NodeTypeTestExpr);
+static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
+ assert(node->type == NodeTypeIfOptional);
Buf *var_symbol = node->data.test_expr.var_symbol;
AstNode *expr_node = node->data.test_expr.target_node;
@@ -5631,11 +6525,11 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no
AstNode *else_node = node->data.test_expr.else_node;
bool var_is_ptr = node->data.test_expr.var_is_ptr;
- IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr);
+ IrInstruction *maybe_val_ptr = ir_gen_node(irb, expr_node, scope, LValPtr, nullptr);
if (maybe_val_ptr == irb->codegen->invalid_instruction)
return maybe_val_ptr;
- IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr);
+ IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr, nullptr);
IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, maybe_val);
IrBasicBlock *then_block = ir_create_basic_block(irb, scope, "OptionalThen");
@@ -5648,7 +6542,7 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no
} else {
is_comptime = ir_build_test_comptime(irb, scope, node, is_non_null);
}
- ir_build_cond_br(irb, scope, node, is_non_null, then_block, else_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, is_non_null, then_block, else_block, is_comptime, result_loc);
ir_set_cursor_at_end_and_append_block(irb, then_block);
@@ -5661,14 +6555,15 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no
ZigVar *var = ir_create_var(irb, node, subexpr_scope,
var_symbol, is_const, is_const, is_shadowable, is_comptime);
- IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, subexpr_scope, node, maybe_val_ptr, false);
- IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value);
- ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
+ IrInstruction *payload_ptr = ir_build_optional_unwrap_ptr(irb, subexpr_scope, node, maybe_val_ptr, false);
+ IrInstruction *var_ptr = var_is_ptr ?
+ ir_build_ref(irb, subexpr_scope, node, payload_ptr, true, false, nullptr) : payload_ptr;
+ ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_ptr);
var_scope = var->child_scope;
} else {
var_scope = subexpr_scope;
}
- IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var_scope);
+ IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var_scope, lval, result_loc);
if (then_expr_result == irb->codegen->invalid_instruction)
return then_expr_result;
IrBasicBlock *after_then_block = irb->current_basic_block;
@@ -5678,7 +6573,7 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no
ir_set_cursor_at_end_and_append_block(irb, else_block);
IrInstruction *else_expr_result;
if (else_node) {
- else_expr_result = ir_gen_node(irb, else_node, subexpr_scope);
+ else_expr_result = ir_gen_node(irb, else_node, subexpr_scope, lval, result_loc);
if (else_expr_result == irb->codegen->invalid_instruction)
return else_expr_result;
} else {
@@ -5699,7 +6594,9 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no
return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
}
-static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
+static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeIfErrorExpr);
AstNode *target_node = node->data.if_err_expr.target_node;
@@ -5710,40 +6607,47 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
Buf *var_symbol = node->data.if_err_expr.var_symbol;
Buf *err_symbol = node->data.if_err_expr.err_symbol;
- IrInstruction *err_val_ptr = ir_gen_node_extra(irb, target_node, scope, LValPtr);
- if (err_val_ptr == irb->codegen->invalid_instruction)
- return err_val_ptr;
+ IrInstruction *err_union_ptr = ir_gen_node(irb, target_node, scope, LValPtr, nullptr);
+ if (err_union_ptr == irb->codegen->invalid_instruction)
+ return err_union_ptr;
- IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr);
- IrInstruction *is_err = ir_build_test_err(irb, scope, node, err_val);
+ IrInstruction *ptr_opt_err_code = ir_build_error_union_field_error_set(irb, scope, node, err_union_ptr, false);
+ IrInstruction *opt_err_code = ir_build_load_ptr(irb, scope, node, ptr_opt_err_code, nullptr);
+ IrInstruction *is_err = ir_build_test_nonnull(irb, scope, node, opt_err_code);
- IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "TryOk");
- IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "TryElse");
- IrBasicBlock *endif_block = ir_create_basic_block(irb, scope, "TryEnd");
+ IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "IfErrThen");
+ IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "IfErrElse");
+ IrBasicBlock *endif_block = ir_create_basic_block(irb, scope, "IfErrEnd");
bool force_comptime = ir_should_inline(irb->exec, scope);
- IrInstruction *is_comptime = force_comptime ? ir_build_const_bool(irb, scope, node, true) : ir_build_test_comptime(irb, scope, node, is_err);
- ir_build_cond_br(irb, scope, node, is_err, else_block, ok_block, is_comptime);
+ IrInstruction *is_comptime = force_comptime ?
+ ir_build_const_bool(irb, scope, node, true) : ir_build_test_comptime(irb, scope, node, is_err);
+ ir_build_cond_br(irb, scope, node, is_err, else_block, ok_block, is_comptime, result_loc);
ir_set_cursor_at_end_and_append_block(irb, ok_block);
Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime);
Scope *var_scope;
if (var_symbol) {
+ IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_union_ptr,
+ nullptr, false);
+
IrInstruction *var_type = nullptr;
bool is_shadowable = false;
- IrInstruction *var_is_comptime = force_comptime ? ir_build_const_bool(irb, subexpr_scope, node, true) : ir_build_test_comptime(irb, subexpr_scope, node, err_val);
+ IrInstruction *var_is_comptime = force_comptime ?
+ ir_build_const_bool(irb, subexpr_scope, node, true) :
+ ir_build_test_comptime(irb, subexpr_scope, node, payload_ptr);
ZigVar *var = ir_create_var(irb, node, subexpr_scope,
var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime);
- IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_val_ptr, false);
- IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value);
- ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
+ IrInstruction *var_ptr = var_is_ptr ?
+ ir_build_ref(irb, subexpr_scope, node, payload_ptr, true, false, nullptr) : payload_ptr;
+ ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_ptr);
var_scope = var->child_scope;
} else {
var_scope = subexpr_scope;
}
- IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var_scope);
+ IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var_scope, lval, result_loc);
if (then_expr_result == irb->codegen->invalid_instruction)
return then_expr_result;
IrBasicBlock *after_then_block = irb->current_basic_block;
@@ -5756,19 +6660,19 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
if (else_node) {
Scope *err_var_scope;
if (err_symbol) {
- IrInstruction *var_type = nullptr;
bool is_shadowable = false;
bool is_const = true;
ZigVar *var = ir_create_var(irb, node, subexpr_scope,
err_symbol, is_const, is_const, is_shadowable, is_comptime);
- IrInstruction *var_value = ir_build_unwrap_err_code(irb, subexpr_scope, node, err_val_ptr);
- ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
+ IrInstruction *unwrapped_err_code_ptr = ir_build_optional_unwrap_ptr(irb, subexpr_scope, node,
+ ptr_opt_err_code, false);
+ ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, nullptr, unwrapped_err_code_ptr);
err_var_scope = var->child_scope;
} else {
err_var_scope = subexpr_scope;
}
- else_expr_result = ir_gen_node(irb, else_node, err_var_scope);
+ else_expr_result = ir_gen_node(irb, else_node, err_var_scope, lval, result_loc);
if (else_expr_result == irb->codegen->invalid_instruction)
return else_expr_result;
} else {
@@ -5792,7 +6696,8 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *switch_node, AstNode *prong_node,
IrBasicBlock *end_block, IrInstruction *is_comptime, IrInstruction *var_is_comptime,
IrInstruction *target_value_ptr, IrInstruction *prong_value,
- ZigList *incoming_blocks, ZigList *incoming_values)
+ ZigList *incoming_blocks, ZigList *incoming_values,
+ LVal lval, IrInstruction *result_loc)
{
assert(switch_node->type == NodeTypeSwitchExpr);
assert(prong_node->type == NodeTypeSwitchProng);
@@ -5805,25 +6710,23 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit
Buf *var_name = var_symbol_node->data.symbol_expr.symbol;
bool var_is_ptr = prong_node->data.switch_prong.var_is_ptr;
+ IrInstruction *var_type = nullptr; // infer the type
bool is_shadowable = false;
bool is_const = true;
ZigVar *var = ir_create_var(irb, var_symbol_node, scope,
var_name, is_const, is_const, is_shadowable, var_is_comptime);
+
+ IrInstruction *payload_ptr = (prong_value == nullptr) ? target_value_ptr :
+ ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, prong_value);
+ IrInstruction *var_ptr = var_is_ptr ?
+ ir_build_ref(irb, scope, var_symbol_node, payload_ptr, true, false, nullptr) : payload_ptr;
+ ir_build_var_decl_src(irb, scope, var_symbol_node, var, var_type, nullptr, var_ptr);
child_scope = var->child_scope;
- IrInstruction *var_value;
- if (prong_value) {
- IrInstruction *var_ptr_value = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, prong_value);
- var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, var_symbol_node, var_ptr_value);
- } else {
- var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr);
- }
- IrInstruction *var_type = nullptr; // infer the type
- ir_build_var_decl(irb, scope, var_symbol_node, var, var_type, nullptr, var_value);
} else {
child_scope = scope;
}
- IrInstruction *expr_result = ir_gen_node(irb, expr_node, child_scope);
+ IrInstruction *expr_result = ir_gen_node(irb, expr_node, child_scope, lval, result_loc);
if (expr_result == irb->codegen->invalid_instruction)
return false;
if (!instr_is_unreachable(expr_result))
@@ -5833,11 +6736,13 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit
return true;
}
-static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
+static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *result_loc)
+{
assert(node->type == NodeTypeSwitchExpr);
AstNode *target_node = node->data.switch_expr.expr;
- IrInstruction *target_value_ptr = ir_gen_node_extra(irb, target_node, scope, LValPtr);
+ IrInstruction *target_value_ptr = ir_gen_node(irb, target_node, scope, LValPtr, nullptr);
if (target_value_ptr == irb->codegen->invalid_instruction)
return target_value_ptr;
IrInstruction *target_value = ir_build_switch_target(irb, scope, node, target_value_ptr);
@@ -5882,7 +6787,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
IrBasicBlock *prev_block = irb->current_basic_block;
ir_set_cursor_at_end_and_append_block(irb, else_block);
if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
- is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values))
+ is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values,
+ lval, result_loc))
{
return irb->codegen->invalid_instruction;
}
@@ -5897,11 +6803,11 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
AstNode *start_node = item_node->data.switch_range.start;
AstNode *end_node = item_node->data.switch_range.end;
- IrInstruction *start_value = ir_gen_node(irb, start_node, comptime_scope);
+ IrInstruction *start_value = ir_gen_node(irb, start_node, comptime_scope, LValNone, nullptr);
if (start_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *end_value = ir_gen_node(irb, end_node, comptime_scope);
+ IrInstruction *end_value = ir_gen_node(irb, end_node, comptime_scope, LValNone, nullptr);
if (end_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -5921,7 +6827,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
ok_bit = both_ok;
}
} else {
- IrInstruction *item_value = ir_gen_node(irb, item_node, comptime_scope);
+ IrInstruction *item_value = ir_gen_node(irb, item_node, comptime_scope, LValNone, nullptr);
if (item_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -5945,11 +6851,12 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
assert(ok_bit);
assert(last_item_node);
ir_mark_gen(ir_build_cond_br(irb, scope, last_item_node, ok_bit, range_block_yes,
- range_block_no, is_comptime));
+ range_block_no, is_comptime, result_loc));
ir_set_cursor_at_end_and_append_block(irb, range_block_yes);
if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
- is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values))
+ is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values,
+ lval, result_loc))
{
return irb->codegen->invalid_instruction;
}
@@ -5974,7 +6881,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);
assert(item_node->type != NodeTypeSwitchRange);
- IrInstruction *item_value = ir_gen_node(irb, item_node, comptime_scope);
+ IrInstruction *item_value = ir_gen_node(irb, item_node, comptime_scope, LValNone, nullptr);
if (item_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -5993,7 +6900,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
IrBasicBlock *prev_block = irb->current_basic_block;
ir_set_cursor_at_end_and_append_block(irb, prong_block);
if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
- is_comptime, var_is_comptime, target_value_ptr, only_item_value, &incoming_blocks, &incoming_values))
+ is_comptime, var_is_comptime, target_value_ptr, only_item_value, &incoming_blocks, &incoming_values,
+ lval, result_loc))
{
return irb->codegen->invalid_instruction;
}
@@ -6002,13 +6910,14 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
}
- IrInstruction *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value, check_ranges.items, check_ranges.length,
- else_prong != nullptr);
+ IrInstruction *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value,
+ check_ranges.items, check_ranges.length, else_prong != nullptr);
if (cases.length == 0) {
ir_build_br(irb, scope, node, else_block, is_comptime);
} else {
- ir_build_switch_br(irb, scope, node, target_value, else_block, cases.length, cases.items, is_comptime, switch_prongs_void);
+ ir_build_switch_br(irb, scope, node, target_value, else_block, cases.length, cases.items,
+ is_comptime, switch_prongs_void, result_loc);
}
if (!else_prong) {
@@ -6025,14 +6934,18 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
}
}
-static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval) {
+static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNode *node,
+ LVal lval, IrInstruction *result_loc)
+{
assert(node->type == NodeTypeCompTime);
Scope *child_scope = create_comptime_scope(irb->codegen, node, parent_scope);
- return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval);
+ return ir_gen_node(irb, node->data.comptime_expr.expr, child_scope, lval, result_loc);
}
-static IrInstruction *ir_gen_return_from_block(IrBuilder *irb, Scope *break_scope, AstNode *node, ScopeBlock *block_scope) {
+static IrInstruction *ir_gen_return_from_block(IrBuilder *irb, Scope *break_scope, AstNode *node,
+ ScopeBlock *block_scope)
+{
IrInstruction *is_comptime;
if (ir_should_inline(irb->exec, break_scope)) {
is_comptime = ir_build_const_bool(irb, break_scope, node, true);
@@ -6042,7 +6955,7 @@ static IrInstruction *ir_gen_return_from_block(IrBuilder *irb, Scope *break_scop
IrInstruction *result_value;
if (node->data.break_expr.expr) {
- result_value = ir_gen_node(irb, node->data.break_expr.expr, break_scope);
+ result_value = ir_gen_node(irb, node->data.break_expr.expr, break_scope, block_scope->lval, block_scope->result_loc);
if (result_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
} else {
@@ -6112,7 +7025,7 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode *
IrInstruction *result_value;
if (node->data.break_expr.expr) {
- result_value = ir_gen_node(irb, node->data.break_expr.expr, break_scope);
+ result_value = ir_gen_node(irb, node->data.break_expr.expr, break_scope, LValNone, loop_scope->result_loc);
if (result_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
} else {
@@ -6200,35 +7113,44 @@ static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode
return ir_build_const_void(irb, parent_scope, node);
}
-static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node) {
+static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
+ IrInstruction *old_result_loc)
+{
assert(node->type == NodeTypeSliceExpr);
+ IrInstruction *new_result_loc = ensure_result_loc(irb, scope, node, lval, old_result_loc);
+ if (new_result_loc == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+
AstNodeSliceExpr *slice_expr = &node->data.slice_expr;
AstNode *array_node = slice_expr->array_ref_expr;
AstNode *start_node = slice_expr->start;
AstNode *end_node = slice_expr->end;
- IrInstruction *ptr_value = ir_gen_node_extra(irb, array_node, scope, LValPtr);
+ IrInstruction *ptr_value = ir_gen_node(irb, array_node, scope, LValPtr, nullptr);
if (ptr_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *start_value = ir_gen_node(irb, start_node, scope);
+ IrInstruction *start_value = ir_gen_node(irb, start_node, scope, LValNone, nullptr);
if (start_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
IrInstruction *end_value;
if (end_node) {
- end_value = ir_gen_node(irb, end_node, scope);
+ end_value = ir_gen_node(irb, end_node, scope, LValNone, nullptr);
if (end_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
} else {
end_value = nullptr;
}
- return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, true);
+ ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, true, new_result_loc);
+ return ir_gen_result(irb, scope, node, lval, old_result_loc, LValNone, new_result_loc);
}
-static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
+static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval,
+ IrInstruction *old_result_loc)
+{
assert(node->type == NodeTypeUnwrapErrorExpr);
AstNode *op1_node = node->data.unwrap_err_expr.op1;
@@ -6242,16 +7164,31 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN
add_node_error(irb->codegen, var_node, buf_sprintf("unused variable: '%s'", buf_ptr(var_name)));
return irb->codegen->invalid_instruction;
}
- return ir_gen_err_assert_ok(irb, parent_scope, node, op1_node, LValNone);
+ return ir_gen_catch_unreachable(irb, parent_scope, node, op1_node, lval, old_result_loc);
}
+ IrInstruction *new_result_loc;
+ IrInstruction *ptr_opt_err_code;
+ IrInstruction *opt_err_code;
+ if (var_node) {
+ new_result_loc = ensure_result_loc(irb, parent_scope, node, lval, old_result_loc);
+ if (new_result_loc == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
- IrInstruction *err_union_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPtr);
- if (err_union_ptr == irb->codegen->invalid_instruction)
- return irb->codegen->invalid_instruction;
+ ptr_opt_err_code = ir_gen_node(irb, op1_node, parent_scope, LValErrorUnionPtr, new_result_loc);
+ if (ptr_opt_err_code == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+ opt_err_code = ir_build_load_ptr(irb, parent_scope, node, ptr_opt_err_code, nullptr);
+ } else {
+ new_result_loc = ensure_result_loc(irb, parent_scope, node, lval, old_result_loc);
+ if (new_result_loc == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
- IrInstruction *err_union_val = ir_build_load_ptr(irb, parent_scope, node, err_union_ptr);
- IrInstruction *is_err = ir_build_test_err(irb, parent_scope, node, err_union_val);
+ opt_err_code = ir_gen_node(irb, op1_node, parent_scope, LValErrorUnionVal, new_result_loc);
+ if (opt_err_code == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+ }
+ IrInstruction *is_err = ir_build_test_nonnull(irb, parent_scope, node, opt_err_code);
IrInstruction *is_comptime;
if (ir_should_inline(irb->exec, parent_scope)) {
@@ -6260,10 +7197,9 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN
is_comptime = ir_build_test_comptime(irb, parent_scope, node, is_err);
}
- IrBasicBlock *ok_block = ir_create_basic_block(irb, parent_scope, "UnwrapErrOk");
- IrBasicBlock *err_block = ir_create_basic_block(irb, parent_scope, "UnwrapErrError");
- IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "UnwrapErrEnd");
- ir_build_cond_br(irb, parent_scope, node, is_err, err_block, ok_block, is_comptime);
+ IrBasicBlock *err_block = ir_create_basic_block(irb, parent_scope, "CatchError");
+ IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "CatchEnd");
+ ir_build_cond_br(irb, parent_scope, node, is_err, err_block, end_block, is_comptime, new_result_loc);
ir_set_cursor_at_end_and_append_block(irb, err_block);
Scope *err_scope;
@@ -6275,32 +7211,20 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN
ZigVar *var = ir_create_var(irb, node, parent_scope, var_name,
is_const, is_const, is_shadowable, is_comptime);
err_scope = var->child_scope;
- IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr);
- ir_build_var_decl(irb, err_scope, var_node, var, nullptr, nullptr, err_val);
+ IrInstruction *unwrapped_err_code_ptr = ir_build_optional_unwrap_ptr(irb, err_scope, var_node,
+ ptr_opt_err_code, false);
+ ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, nullptr, unwrapped_err_code_ptr);
} else {
err_scope = parent_scope;
}
- IrInstruction *err_result = ir_gen_node(irb, op2_node, err_scope);
+ IrInstruction *err_result = ir_gen_node(irb, op2_node, err_scope, LValNone, new_result_loc);
if (err_result == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrBasicBlock *after_err_block = irb->current_basic_block;
if (!instr_is_unreachable(err_result))
ir_mark_gen(ir_build_br(irb, err_scope, node, end_block, is_comptime));
- ir_set_cursor_at_end_and_append_block(irb, ok_block);
- IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, parent_scope, node, err_union_ptr, false);
- IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr);
- IrBasicBlock *after_ok_block = irb->current_basic_block;
- ir_build_br(irb, parent_scope, node, end_block, is_comptime);
-
ir_set_cursor_at_end_and_append_block(irb, end_block);
- IrInstruction **incoming_values = allocate(2);
- incoming_values[0] = err_result;
- incoming_values[1] = unwrapped_payload;
- IrBasicBlock **incoming_blocks = allocate(2);
- incoming_blocks[0] = after_err_block;
- incoming_blocks[1] = after_ok_block;
- return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values);
+ return ir_gen_result(irb, parent_scope, node, lval, old_result_loc, LValErrorUnionVal, new_result_loc);
}
static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *outer_scope, Scope *inner_scope) {
@@ -6312,7 +7236,8 @@ static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *o
ScopeVarDecl *var_scope = (ScopeVarDecl *)inner_scope;
if (need_comma)
buf_append_char(name, ',');
- render_const_value(codegen, name, var_scope->var->value);
+ // TODO: const ptr reinterpret here to make the var type agree with the value?
+ render_const_value(codegen, name, var_scope->var->const_value);
return true;
}
@@ -6498,7 +7423,7 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
}
if (param_node->data.param_decl.var_token == nullptr) {
AstNode *type_node = param_node->data.param_decl.type;
- IrInstruction *type_value = ir_gen_node(irb, type_node, parent_scope);
+ IrInstruction *type_value = ir_gen_node(irb, type_node, parent_scope, LValNone, nullptr);
if (type_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
param_types[i] = type_value;
@@ -6509,7 +7434,7 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
IrInstruction *align_value = nullptr;
if (node->data.fn_proto.align_expr != nullptr) {
- align_value = ir_gen_node(irb, node->data.fn_proto.align_expr, parent_scope);
+ align_value = ir_gen_node(irb, node->data.fn_proto.align_expr, parent_scope, LValNone, nullptr);
if (align_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
}
@@ -6519,7 +7444,7 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
if (node->data.fn_proto.return_type == nullptr) {
return_type = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_void);
} else {
- return_type = ir_gen_node(irb, node->data.fn_proto.return_type, parent_scope);
+ return_type = ir_gen_node(irb, node->data.fn_proto.return_type, parent_scope, LValNone, nullptr);
if (return_type == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
}
@@ -6532,7 +7457,8 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
IrInstruction *async_allocator_type_value = nullptr;
if (node->data.fn_proto.async_allocator_type != nullptr) {
- async_allocator_type_value = ir_gen_node(irb, node->data.fn_proto.async_allocator_type, parent_scope);
+ async_allocator_type_value = ir_gen_node(irb, node->data.fn_proto.async_allocator_type, parent_scope,
+ LValNone, nullptr);
if (async_allocator_type_value == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
}
@@ -6562,11 +7488,11 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *is_suspended_mask = ir_build_const_usize(irb, scope, node, 0x2); // 0b010
// TODO relies on Zig not re-ordering fields
- IrInstruction *casted_target_inst = ir_build_ptr_cast(irb, scope, node, promise_T_type_val, target_inst);
+ IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst);
IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst);
Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
- IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
- atomic_state_field_name);
+ IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, nullptr,
+ atomic_state_field_name, false);
// set the is_canceled bit
IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
@@ -6575,12 +7501,12 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
- ir_build_cond_br(irb, scope, node, is_canceled_bool, done_block, not_canceled_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, is_canceled_bool, done_block, not_canceled_block, is_comptime, nullptr);
ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
IrInstruction *awaiter_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
IrInstruction *is_returned_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpEq, awaiter_addr, ptr_mask, false);
- ir_build_cond_br(irb, scope, node, is_returned_bool, post_return_block, pre_return_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, is_returned_bool, post_return_block, pre_return_block, is_comptime, nullptr);
ir_set_cursor_at_end_and_append_block(irb, post_return_block);
if (cancel_awaited) {
@@ -6588,7 +7514,7 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode
} else {
IrInstruction *is_awaited_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, await_mask, false);
IrInstruction *is_awaited_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_awaited_value, zero, false);
- ir_build_cond_br(irb, scope, node, is_awaited_bool, done_block, do_cancel_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, is_awaited_bool, done_block, do_cancel_block, is_comptime, nullptr);
}
ir_set_cursor_at_end_and_append_block(irb, pre_return_block);
@@ -6598,7 +7524,7 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode
} else {
IrInstruction *is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
IrInstruction *is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
- ir_build_cond_br(irb, scope, node, is_suspended_bool, do_cancel_block, done_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, is_suspended_bool, do_cancel_block, done_block, is_comptime, nullptr);
}
} else {
ir_build_br(irb, scope, node, done_block, is_comptime);
@@ -6615,7 +7541,7 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode
static IrInstruction *ir_gen_cancel(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypeCancel);
- IrInstruction *target_inst = ir_gen_node(irb, node->data.cancel_expr.expr, scope);
+ IrInstruction *target_inst = ir_gen_node(irb, node->data.cancel_expr.expr, scope, LValNone, nullptr);
if (target_inst == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -6640,11 +7566,11 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode
get_promise_type(irb->codegen, irb->codegen->builtin_types.entry_void));
// TODO relies on Zig not re-ordering fields
- IrInstruction *casted_target_inst = ir_build_ptr_cast(irb, scope, node, promise_T_type_val, target_inst);
+ IrInstruction *casted_target_inst = ir_build_ptr_cast_src(irb, scope, node, promise_T_type_val, target_inst);
IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst);
Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
- IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
- atomic_state_field_name);
+ IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, nullptr,
+ atomic_state_field_name, false);
// clear the is_suspended bit
IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node,
@@ -6653,12 +7579,12 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode
IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
- ir_build_cond_br(irb, scope, node, is_canceled_bool, done_block, not_canceled_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, is_canceled_bool, done_block, not_canceled_block, is_comptime, nullptr);
ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
IrInstruction *is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
IrInstruction *is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
- ir_build_cond_br(irb, scope, node, is_suspended_bool, suspended_block, not_suspended_block, is_comptime);
+ ir_build_cond_br(irb, scope, node, is_suspended_bool, suspended_block, not_suspended_block, is_comptime, nullptr);
ir_set_cursor_at_end_and_append_block(irb, not_suspended_block);
ir_build_unreachable(irb, scope, node);
@@ -6674,7 +7600,7 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode
static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypeResume);
- IrInstruction *target_inst = ir_gen_node(irb, node->data.resume_expr.expr, scope);
+ IrInstruction *target_inst = ir_gen_node(irb, node->data.resume_expr.expr, scope, LValNone, nullptr);
if (target_inst == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -6684,7 +7610,7 @@ static IrInstruction *ir_gen_resume(IrBuilder *irb, Scope *scope, AstNode *node)
static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
assert(node->type == NodeTypeAwaitExpr);
- IrInstruction *target_inst = ir_gen_node(irb, node->data.await_expr.expr, scope);
+ IrInstruction *target_inst = ir_gen_node(irb, node->data.await_expr.expr, scope, LValNone, nullptr);
if (target_inst == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
@@ -6711,12 +7637,14 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, target_inst);
Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
- IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name);
+ IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, nullptr,
+ result_ptr_field_name, false);
if (irb->codegen->have_err_ret_tracing) {
IrInstruction *err_ret_trace_ptr = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::NonNull);
Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
- IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name);
+ IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
+ nullptr, err_ret_trace_ptr_field_name, false);
ir_build_store_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr, err_ret_trace_ptr);
}
@@ -6738,11 +7666,10 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
- atomic_state_field_name);
+ nullptr, atomic_state_field_name, false);
IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_promise);
IrInstruction *const_bool_false = ir_build_const_bool(irb, scope, node, false);
- IrInstruction *undefined_value = ir_build_const_undefined(irb, scope, node);
IrInstruction *usize_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize);
IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, scope, node, 0x7); // 0b111
@@ -6756,9 +7683,10 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst);
IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type);
ir_build_await_bookkeeping(irb, scope, node, promise_result_type);
- ir_build_var_decl(irb, scope, node, result_var, promise_result_type, nullptr, undefined_value);
- IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var);
- ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr);
+ IrInstruction *result_var_alloca = ir_build_alloca_src(irb, scope, node, promise_result_type, nullptr, "",
+ nullptr);
+ ir_build_var_decl_src(irb, scope, node, result_var, promise_result_type, nullptr, result_var_alloca);
+ ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, result_var_alloca);
IrInstruction *save_token = ir_build_coro_save(irb, scope, node, irb->exec->coro_handle);
IrInstruction *coro_handle_addr = ir_build_ptr_to_int(irb, scope, node, irb->exec->coro_handle);
@@ -6769,7 +7697,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *is_awaited_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, await_mask, false);
IrInstruction *is_awaited_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_awaited_value, zero, false);
- ir_build_cond_br(irb, scope, node, is_awaited_bool, already_awaited_block, not_awaited_block, const_bool_false);
+ ir_build_cond_br(irb, scope, node, is_awaited_bool, already_awaited_block, not_awaited_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, already_awaited_block);
ir_build_unreachable(irb, scope, node);
@@ -6779,10 +7707,10 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *is_non_null = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false);
IrInstruction *is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
IrInstruction *is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
- ir_build_cond_br(irb, scope, node, is_canceled_bool, cancel_target_block, not_canceled_block, const_bool_false);
+ ir_build_cond_br(irb, scope, node, is_canceled_bool, cancel_target_block, not_canceled_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
- ir_build_cond_br(irb, scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false);
+ ir_build_cond_br(irb, scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, cancel_target_block);
ir_build_cancel(irb, scope, node, target_inst);
@@ -6791,16 +7719,18 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_set_cursor_at_end_and_append_block(irb, no_suspend_block);
if (irb->codegen->have_err_ret_tracing) {
Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
- IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name);
+ IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
+ nullptr, err_ret_trace_field_name, false);
IrInstruction *dest_err_ret_trace_ptr = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::NonNull);
ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr);
}
Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
- IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name);
+ IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, nullptr,
+ result_field_name, false);
// If the type of the result handle_is_ptr then this does not actually perform a load. But we need it to,
// because we're about to destroy the memory. So we store it into our result variable.
- IrInstruction *no_suspend_result = ir_build_load_ptr(irb, scope, node, promise_result_ptr);
- ir_build_store_ptr(irb, scope, node, my_result_var_ptr, no_suspend_result);
+ IrInstruction *no_suspend_result = ir_build_load_ptr(irb, scope, node, promise_result_ptr, nullptr);
+ ir_build_store_ptr(irb, scope, node, result_var_alloca, no_suspend_result);
ir_build_cancel(irb, scope, node, target_inst);
ir_build_br(irb, scope, node, merge_block, const_bool_false);
@@ -6811,7 +7741,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
AtomicRmwOp_or, AtomicOrderSeqCst);
IrInstruction *my_is_suspended_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, my_prev_atomic_value, is_suspended_mask, false);
IrInstruction *my_is_suspended_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, my_is_suspended_value, zero, false);
- ir_build_cond_br(irb, scope, node, my_is_suspended_bool, my_suspended_block, my_not_suspended_block, const_bool_false);
+ ir_build_cond_br(irb, scope, node, my_is_suspended_bool, my_suspended_block, my_not_suspended_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, my_suspended_block);
ir_build_unreachable(irb, scope, node);
@@ -6819,7 +7749,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_set_cursor_at_end_and_append_block(irb, my_not_suspended_block);
IrInstruction *my_is_canceled_value = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, my_prev_atomic_value, is_canceled_mask, false);
IrInstruction *my_is_canceled_bool = ir_build_bin_op(irb, scope, node, IrBinOpCmpNotEq, my_is_canceled_value, zero, false);
- ir_build_cond_br(irb, scope, node, my_is_canceled_bool, cleanup_block, do_suspend_block, const_bool_false);
+ ir_build_cond_br(irb, scope, node, my_is_canceled_bool, cleanup_block, do_suspend_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, do_suspend_block);
IrInstruction *suspend_code = ir_build_coro_suspend(irb, scope, node, save_token, const_bool_false);
@@ -6830,7 +7760,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
cases[1].value = ir_build_const_u8(irb, scope, node, 1);
cases[1].block = destroy_block;
ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block,
- 2, cases, const_bool_false, nullptr);
+ 2, cases, const_bool_false, nullptr, nullptr);
ir_set_cursor_at_end_and_append_block(irb, destroy_block);
ir_gen_cancel_target(irb, scope, node, target_inst, false, true);
@@ -6844,7 +7774,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
IrInstruction *my_await_handle_addr = ir_build_bin_op(irb, scope, node, IrBinOpBinAnd, b_my_prev_atomic_value, ptr_mask, false);
IrInstruction *dont_have_my_await_handle = ir_build_bin_op(irb, scope, node, IrBinOpCmpEq, my_await_handle_addr, zero, false);
IrInstruction *dont_destroy_ourselves = ir_build_bin_op(irb, scope, node, IrBinOpBoolAnd, dont_have_my_await_handle, is_canceled_bool, false);
- ir_build_cond_br(irb, scope, node, dont_have_my_await_handle, do_defers_block, do_cancel_block, const_bool_false);
+ ir_build_cond_br(irb, scope, node, dont_have_my_await_handle, do_defers_block, do_cancel_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, do_cancel_block);
IrInstruction *my_await_handle = ir_build_int_to_ptr(irb, scope, node, promise_type_val, my_await_handle_addr);
@@ -6853,13 +7783,13 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n
ir_set_cursor_at_end_and_append_block(irb, do_defers_block);
ir_gen_defers_for_block(irb, scope, outer_scope, true);
- ir_mark_gen(ir_build_cond_br(irb, scope, node, dont_destroy_ourselves, irb->exec->coro_early_final, irb->exec->coro_final_cleanup_block, const_bool_false));
+ ir_mark_gen(ir_build_cond_br(irb, scope, node, dont_destroy_ourselves, irb->exec->coro_early_final, irb->exec->coro_final_cleanup_block, const_bool_false, nullptr));
ir_set_cursor_at_end_and_append_block(irb, resume_block);
ir_build_br(irb, scope, node, merge_block, const_bool_false);
ir_set_cursor_at_end_and_append_block(irb, merge_block);
- return ir_build_load_ptr(irb, scope, node, my_result_var_ptr);
+ return ir_build_load_ptr(irb, scope, node, result_var_alloca, nullptr);
}
static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
@@ -6920,13 +7850,13 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
IrInstruction *is_canceled_value = ir_build_bin_op(irb, parent_scope, node, IrBinOpBinAnd, prev_atomic_value, is_canceled_mask, false);
IrInstruction *is_canceled_bool = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpNotEq, is_canceled_value, zero, false);
- ir_build_cond_br(irb, parent_scope, node, is_canceled_bool, canceled_block, not_canceled_block, const_bool_false);
+ ir_build_cond_br(irb, parent_scope, node, is_canceled_bool, canceled_block, not_canceled_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, canceled_block);
IrInstruction *await_handle_addr = ir_build_bin_op(irb, parent_scope, node, IrBinOpBinAnd, prev_atomic_value, ptr_mask, false);
IrInstruction *have_await_handle = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpNotEq, await_handle_addr, zero, false);
IrBasicBlock *post_canceled_block = irb->current_basic_block;
- ir_build_cond_br(irb, parent_scope, node, have_await_handle, cancel_awaiter_block, cleanup_block, const_bool_false);
+ ir_build_cond_br(irb, parent_scope, node, have_await_handle, cancel_awaiter_block, cleanup_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, cancel_awaiter_block);
IrInstruction *await_handle = ir_build_int_to_ptr(irb, parent_scope, node, promise_type_val, await_handle_addr);
@@ -6937,7 +7867,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
ir_set_cursor_at_end_and_append_block(irb, not_canceled_block);
IrInstruction *is_suspended_value = ir_build_bin_op(irb, parent_scope, node, IrBinOpBinAnd, prev_atomic_value, is_suspended_mask, false);
IrInstruction *is_suspended_bool = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpNotEq, is_suspended_value, zero, false);
- ir_build_cond_br(irb, parent_scope, node, is_suspended_bool, suspended_block, not_suspended_block, const_bool_false);
+ ir_build_cond_br(irb, parent_scope, node, is_suspended_bool, suspended_block, not_suspended_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, suspended_block);
ir_build_unreachable(irb, parent_scope, node);
@@ -6952,7 +7882,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
suspend_scope->resume_block = resume_block;
child_scope = &suspend_scope->base;
IrInstruction *save_token = ir_build_coro_save(irb, child_scope, node, irb->exec->coro_handle);
- ir_gen_node(irb, node->data.suspend.block, child_scope);
+ ir_gen_node(irb, node->data.suspend.block, child_scope, LValNone, nullptr);
suspend_code = ir_mark_gen(ir_build_coro_suspend(irb, parent_scope, node, save_token, const_bool_false));
}
@@ -6962,7 +7892,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
cases[1].value = ir_mark_gen(ir_build_const_u8(irb, parent_scope, node, 1));
cases[1].block = canceled_block;
ir_mark_gen(ir_build_switch_br(irb, parent_scope, node, suspend_code, irb->exec->coro_suspend_block,
- 2, cases, const_bool_false, nullptr));
+ 2, cases, const_bool_false, nullptr, nullptr));
ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
IrBasicBlock **incoming_blocks = allocate(2);
@@ -6973,14 +7903,14 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
incoming_values[1] = const_bool_false;
IrInstruction *destroy_ourselves = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values);
ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);
- ir_mark_gen(ir_build_cond_br(irb, parent_scope, node, destroy_ourselves, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, const_bool_false));
+ ir_mark_gen(ir_build_cond_br(irb, parent_scope, node, destroy_ourselves, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, const_bool_false, nullptr));
ir_set_cursor_at_end_and_append_block(irb, resume_block);
return ir_mark_gen(ir_build_const_void(irb, parent_scope, node));
}
-static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,
- LVal lval)
+static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval,
+ IrInstruction *result_loc)
{
assert(scope);
switch (node->type) {
@@ -6994,134 +7924,155 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeTestDecl:
zig_unreachable();
case NodeTypeBlock:
- return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node), lval);
+ return ir_gen_block(irb, scope, node, lval, result_loc);
case NodeTypeGroupedExpr:
- return ir_gen_node_raw(irb, node->data.grouped_expr, scope, lval);
+ return ir_gen_node_raw(irb, node->data.grouped_expr, scope, lval, result_loc);
case NodeTypeBinOpExpr:
- return ir_lval_wrap(irb, scope, ir_gen_bin_op(irb, scope, node), lval);
+ return ir_gen_bin_op(irb, scope, node, lval, result_loc);
case NodeTypeIntLiteral:
- return ir_lval_wrap(irb, scope, ir_gen_int_lit(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_int_lit(irb, scope, node));
case NodeTypeFloatLiteral:
- return ir_lval_wrap(irb, scope, ir_gen_float_lit(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_float_lit(irb, scope, node));
case NodeTypeCharLiteral:
- return ir_lval_wrap(irb, scope, ir_gen_char_lit(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_char_lit(irb, scope, node));
case NodeTypeSymbol:
- return ir_gen_symbol(irb, scope, node, lval);
+ return ir_gen_symbol(irb, scope, node, lval, result_loc);
case NodeTypeFnCallExpr:
- return ir_gen_fn_call(irb, scope, node, lval);
+ return ir_gen_fn_call(irb, scope, node, lval, result_loc);
case NodeTypeIfBoolExpr:
- return ir_lval_wrap(irb, scope, ir_gen_if_bool_expr(irb, scope, node), lval);
+ return ir_gen_if_bool_expr(irb, scope, node, lval, result_loc);
case NodeTypePrefixOpExpr:
- return ir_gen_prefix_op_expr(irb, scope, node, lval);
+ return ir_gen_prefix_op_expr(irb, scope, node, lval, result_loc);
case NodeTypeContainerInitExpr:
- return ir_lval_wrap(irb, scope, ir_gen_container_init_expr(irb, scope, node), lval);
+ return ir_gen_container_init_expr(irb, scope, node, lval, result_loc);
case NodeTypeVariableDeclaration:
- return ir_lval_wrap(irb, scope, ir_gen_var_decl(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_var_decl(irb, scope, node));
case NodeTypeWhileExpr:
- return ir_lval_wrap(irb, scope, ir_gen_while_expr(irb, scope, node), lval);
+ return ir_gen_while_expr(irb, scope, node, lval, result_loc);
case NodeTypeForExpr:
- return ir_lval_wrap(irb, scope, ir_gen_for_expr(irb, scope, node), lval);
+ return ir_gen_for_expr(irb, scope, node, lval, result_loc);
case NodeTypeArrayAccessExpr:
- return ir_gen_array_access(irb, scope, node, lval);
+ return ir_gen_array_access(irb, scope, node, lval, result_loc);
case NodeTypeReturnExpr:
- return ir_gen_return(irb, scope, node, lval);
+ return ir_gen_return(irb, scope, node, lval, result_loc);
case NodeTypeFieldAccessExpr:
- {
- IrInstruction *ptr_instruction = ir_gen_field_access(irb, scope, node);
- if (ptr_instruction == irb->codegen->invalid_instruction)
- return ptr_instruction;
- if (lval == LValPtr)
- return ptr_instruction;
-
- return ir_build_load_ptr(irb, scope, node, ptr_instruction);
- }
+ return ir_gen_field_access(irb, scope, node, lval, result_loc);
case NodeTypePtrDeref: {
AstNode *expr_node = node->data.ptr_deref_expr.target;
- IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, lval);
- if (value == irb->codegen->invalid_instruction)
- return value;
-
- return ir_build_un_op(irb, scope, node, IrUnOpDereference, value);
+ IrInstruction *ptr_inst = ir_gen_node(irb, expr_node, scope, LValNone, nullptr);
+ if (ptr_inst == irb->codegen->invalid_instruction)
+ return ptr_inst;
+ return ir_gen_ptr(irb, scope, node, lval, result_loc, ptr_inst);
}
case NodeTypeUnwrapOptional: {
AstNode *expr_node = node->data.unwrap_optional.expr;
+ if (lval == LValPtr) {
+ IrInstruction *maybe_ptr = ir_gen_node(irb, expr_node, scope, LValPtr, nullptr);
+ if (maybe_ptr == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+
+ IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, scope, expr_node, maybe_ptr, true);
+ if (result_loc == nullptr)
+ return unwrapped_ptr;
+ ir_build_store_ptr(irb, scope, node, result_loc, unwrapped_ptr);
+ return result_loc;
+ }
- IrInstruction *maybe_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr);
- if (maybe_ptr == irb->codegen->invalid_instruction)
+ IrInstruction *ensured_result_loc = ensure_result_loc(irb, scope, node, lval, result_loc);
+ if (ensured_result_loc == irb->codegen->invalid_instruction)
return irb->codegen->invalid_instruction;
- IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_ptr, true);
- if (lval == LValPtr)
- return unwrapped_ptr;
- return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
+ IrInstruction *is_non_null = ir_gen_node(irb, expr_node, scope, LValOptional, ensured_result_loc);
+ if (is_non_null == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+
+ ir_build_assert_non_null(irb, scope, expr_node, is_non_null);
+ return ir_gen_result(irb, scope, node, lval, result_loc, LValOptional, ensured_result_loc);
}
case NodeTypeBoolLiteral:
- return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_bool_literal(irb, scope, node));
case NodeTypeArrayType:
- return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_array_type(irb, scope, node));
case NodeTypePointerType:
- return ir_lval_wrap(irb, scope, ir_gen_pointer_type(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_pointer_type(irb, scope, node));
case NodeTypePromiseType:
- return ir_lval_wrap(irb, scope, ir_gen_promise_type(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_promise_type(irb, scope, node));
case NodeTypeStringLiteral:
- return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_string_literal(irb, scope, node));
case NodeTypeUndefinedLiteral:
- return ir_lval_wrap(irb, scope, ir_gen_undefined_literal(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_undefined_literal(irb, scope, node));
case NodeTypeAsmExpr:
- return ir_lval_wrap(irb, scope, ir_gen_asm_expr(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_asm_expr(irb, scope, node));
case NodeTypeNullLiteral:
- return ir_lval_wrap(irb, scope, ir_gen_null_literal(irb, scope, node), lval);
+ return ir_gen_null_literal(irb, scope, node, lval, result_loc);
case NodeTypeIfErrorExpr:
- return ir_lval_wrap(irb, scope, ir_gen_if_err_expr(irb, scope, node), lval);
- case NodeTypeTestExpr:
- return ir_lval_wrap(irb, scope, ir_gen_test_expr(irb, scope, node), lval);
+ return ir_gen_if_err_expr(irb, scope, node, lval, result_loc);
+ case NodeTypeIfOptional:
+ return ir_gen_if_optional_expr(irb, scope, node, lval, result_loc);
case NodeTypeSwitchExpr:
- return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval);
+ return ir_gen_switch_expr(irb, scope, node, lval, result_loc);
case NodeTypeCompTime:
- return ir_gen_comptime(irb, scope, node, lval);
+ return ir_gen_comptime(irb, scope, node, lval, result_loc);
case NodeTypeErrorType:
- return ir_lval_wrap(irb, scope, ir_gen_error_type(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_error_type(irb, scope, node));
case NodeTypeBreak:
- return ir_lval_wrap(irb, scope, ir_gen_break(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_break(irb, scope, node));
case NodeTypeContinue:
- return ir_lval_wrap(irb, scope, ir_gen_continue(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_continue(irb, scope, node));
case NodeTypeUnreachable:
- return ir_lval_wrap(irb, scope, ir_build_unreachable(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_build_unreachable(irb, scope, node));
case NodeTypeDefer:
- return ir_lval_wrap(irb, scope, ir_gen_defer(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_defer(irb, scope, node));
case NodeTypeSliceExpr:
- return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval);
+ return ir_gen_slice(irb, scope, node, lval, result_loc);
case NodeTypeUnwrapErrorExpr:
- return ir_lval_wrap(irb, scope, ir_gen_err_ok_or(irb, scope, node), lval);
+ return ir_gen_catch(irb, scope, node, lval, result_loc);
case NodeTypeContainerDecl:
- return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_container_decl(irb, scope, node));
case NodeTypeFnProto:
- return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_fn_proto(irb, scope, node));
case NodeTypeErrorSetDecl:
- return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_err_set_decl(irb, scope, node));
case NodeTypeCancel:
- return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_cancel(irb, scope, node));
case NodeTypeResume:
- return ir_lval_wrap(irb, scope, ir_gen_resume(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_resume(irb, scope, node));
case NodeTypeAwaitExpr:
- return ir_lval_wrap(irb, scope, ir_gen_await_expr(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_await_expr(irb, scope, node));
case NodeTypeSuspend:
- return ir_lval_wrap(irb, scope, ir_gen_suspend(irb, scope, node), lval);
+ return ir_gen_value(irb, scope, node, lval, result_loc, ir_gen_suspend(irb, scope, node));
+ case NodeTypeErrorLiteral: {
+ IrInstruction *err_code = ir_build_error_literal(irb, scope, node, node->data.error_literal.name);
+ switch (lval) {
+ case LValErrorUnionVal:
+ if (result_loc != nullptr) {
+ IrInstruction *undef = ir_build_const_undefined(irb, scope, node);
+ ir_build_store_ptr(irb, scope, node, result_loc, undef);
+ }
+ return err_code;
+ case LValErrorUnionPtr:
+ if (result_loc != nullptr) {
+ IrInstruction *undef = ir_build_const_undefined(irb, scope, node);
+ ir_build_store_ptr(irb, scope, node, result_loc, undef);
+ }
+ return ir_build_ref(irb, scope, node, err_code, true, false, nullptr);
+ default:
+ return ir_gen_value(irb, scope, node, lval, result_loc, err_code);
+ }
+ }
}
zig_unreachable();
}
-static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval) {
- IrInstruction *result = ir_gen_node_raw(irb, node, scope, lval);
+static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval,
+ IrInstruction *result_loc)
+{
+ IrInstruction *result = ir_gen_node_raw(irb, node, scope, lval, result_loc);
irb->exec->invalid = irb->exec->invalid || (result == irb->codegen->invalid_instruction);
return result;
}
-static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope) {
- return ir_gen_node_extra(irb, node, scope, LValNone);
-}
-
static void invalidate_exec(IrExecutable *exec) {
if (exec->invalid)
return;
@@ -7152,6 +8103,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
ir_ref_bb(irb->current_basic_block);
ZigFn *fn_entry = exec_fn_entry(irb->exec);
+
bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
IrInstruction *coro_id;
IrInstruction *u8_ptr_type;
@@ -7172,73 +8124,88 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type);
IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type);
// TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa
- ir_build_var_decl(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef);
- coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var);
+ coro_promise_ptr = ir_build_alloca_src(irb, coro_scope, node, coro_frame_type_value, nullptr, "", nullptr);
+ ir_build_var_decl_src(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, coro_promise_ptr);
ZigVar *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);
IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node,
get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
- ir_build_var_decl(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value);
- irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var);
+ irb->exec->await_handle_var_ptr = ir_build_alloca_src(irb, coro_scope, node, await_handle_type_val, nullptr, "", nullptr);
+ ir_build_store_ptr(irb, coro_scope, node, irb->exec->await_handle_var_ptr, null_value);
+ ir_build_var_decl_src(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr,
+ irb->exec->await_handle_var_ptr);
u8_ptr_type = ir_build_const_type(irb, coro_scope, node,
get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false));
- IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr);
+ IrInstruction *promise_as_u8_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, coro_promise_ptr);
coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr);
coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node);
- ir_build_var_decl(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size);
+ IrInstruction *coro_size_var_alloca = ir_build_alloca_src(irb, coro_scope, node, nullptr, nullptr, "", nullptr);
+ ir_build_store_ptr(irb, coro_scope, node, coro_size_var_alloca, coro_size);
+ ir_build_var_decl_src(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size_var_alloca);
IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node,
ImplicitAllocatorIdArg);
irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false);
- ir_build_var_decl(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr);
+ IrInstruction *coro_allocator_var_alloca = ir_build_alloca_src(irb, coro_scope, node, nullptr, nullptr, "", nullptr);
+ ir_build_store_ptr(irb, coro_scope, node, coro_allocator_var_alloca, implicit_allocator_ptr);
+ ir_build_var_decl_src(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr,
+ coro_allocator_var_alloca);
Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME);
- IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, alloc_field_name);
- IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr);
+ IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr,
+ nullptr, alloc_field_name, false);
+ IrInstruction *alloc_fn = ir_build_load_ptr(irb, coro_scope, node, alloc_fn_ptr, nullptr);
IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, coro_scope, node, alloc_fn, coro_size);
IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr);
IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, coro_scope, "AllocError");
IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, coro_scope, "AllocOk");
- ir_build_cond_br(irb, coro_scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false);
+ ir_build_cond_br(irb, coro_scope, node, alloc_result_is_ok, alloc_ok_block, alloc_err_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);
// we can return undefined here, because the caller passes a pointer to the error struct field
// in the error union result, and we populate it in case of allocation failure.
- ir_build_return(irb, coro_scope, node, undef);
+ ir_build_return(irb, coro_scope, node, undef, nullptr);
ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);
- IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr);
+ IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, coro_scope, node, u8_ptr_type, maybe_coro_mem_ptr);
irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr);
Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME);
irb->exec->atomic_state_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
- atomic_state_field_name);
+ nullptr, atomic_state_field_name, false);
IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
ir_build_store_ptr(irb, scope, node, irb->exec->atomic_state_field_ptr, zero);
Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
- irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name);
+ irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
+ nullptr, result_field_name, false);
result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
- irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name);
+ irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
+ nullptr, result_ptr_field_name, false);
ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr);
if (irb->codegen->have_err_ret_tracing) {
// initialize the error return trace
Buf *return_addresses_field_name = buf_create_from_str(RETURN_ADDRESSES_FIELD_NAME);
- IrInstruction *return_addresses_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, return_addresses_field_name);
+ IrInstruction *return_addresses_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
+ nullptr, return_addresses_field_name, false);
Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
- err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name);
+ err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, nullptr,
+ err_ret_trace_field_name, false);
ir_build_mark_err_ret_trace_ptr(irb, scope, node, err_ret_trace_ptr);
// coordinate with builtin.zig
Buf *index_name = buf_create_from_str("index");
- IrInstruction *index_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, index_name);
+ IrInstruction *index_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, nullptr,
+ index_name, false);
ir_build_store_ptr(irb, scope, node, index_ptr, zero);
Buf *instruction_addresses_name = buf_create_from_str("instruction_addresses");
- IrInstruction *addrs_slice_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, instruction_addresses_name);
+ IrInstruction *addrs_slice_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, nullptr,
+ instruction_addresses_name, false);
- IrInstruction *slice_value = ir_build_slice(irb, scope, node, return_addresses_ptr, zero, nullptr, false);
+ IrInstruction *slice_value = ir_build_slice(irb, scope, node, return_addresses_ptr, zero,
+ nullptr, false, addrs_slice_ptr);
ir_build_store_ptr(irb, scope, node, addrs_slice_ptr, slice_value);
}
@@ -7249,14 +8216,22 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
irb->exec->coro_final_cleanup_block = ir_create_basic_block(irb, scope, "FinalCleanup");
}
- IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValNone);
+ IrInstruction *result = ir_gen_node(irb, node, scope, LValNone, nullptr);
assert(result);
if (irb->exec->invalid)
return false;
if (!instr_is_unreachable(result)) {
// no need for save_err_ret_addr because this cannot return error
- ir_gen_async_return(irb, scope, result->source_node, result, true);
+ IrInstruction *implicit_return_result = result;
+ if (fn_entry != nullptr) {
+ ZigType *return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;
+ // return_type can be null when this function is being executed at comptime
+ if (return_type != nullptr && return_type->id == ZigTypeIdErrorUnion) {
+ implicit_return_result = ir_build_const_null(irb, scope, result->source_node);
+ }
+ }
+ ir_gen_async_return(irb, scope, result->source_node, implicit_return_result, true, nullptr);
}
if (is_async) {
@@ -7271,11 +8246,11 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
cases[0].block = invalid_resume_block;
cases[1].value = ir_build_const_u8(irb, scope, node, 1);
cases[1].block = irb->exec->coro_final_cleanup_block;
- ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block, 2, cases, const_bool_false, nullptr);
+ ir_build_switch_br(irb, scope, node, suspend_code, irb->exec->coro_suspend_block, 2, cases, const_bool_false, nullptr, nullptr);
ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_suspend_block);
ir_build_coro_end(irb, scope, node);
- ir_build_return(irb, scope, node, irb->exec->coro_handle);
+ ir_build_return(irb, scope, node, irb->exec->coro_handle, nullptr);
ir_set_cursor_at_end_and_append_block(irb, invalid_resume_block);
ir_build_unreachable(irb, scope, node);
@@ -7285,9 +8260,9 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
false, false, PtrLenUnknown, 0, 0, 0));
- IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);
- IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, result_ptr);
- IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len,
+ IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, nullptr);
+ IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, result_ptr);
+ IrInstruction *return_value_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len,
irb->exec->coro_result_field_ptr);
IrInstruction *return_type_inst = ir_build_const_type(irb, scope, node,
fn_entry->type_entry->data.fn.fn_type_id.return_type);
@@ -7296,16 +8271,17 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
}
if (irb->codegen->have_err_ret_tracing) {
Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
- IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name);
- IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr);
+ IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
+ nullptr, err_ret_trace_ptr_field_name, false);
+ IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr, nullptr);
ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr);
}
// Before we destroy the coroutine frame, we need to load the target promise into
// a register or local variable which does not get spilled into the frame,
// otherwise llvm tries to access memory inside the destroyed frame.
- IrInstruction *unwrapped_await_handle_ptr = ir_build_unwrap_maybe(irb, scope, node,
+ IrInstruction *unwrapped_await_handle_ptr = ir_build_optional_unwrap_ptr(irb, scope, node,
irb->exec->await_handle_var_ptr, false);
- IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr);
+ IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr, nullptr);
ir_build_br(irb, scope, node, check_free_block, const_bool_false);
ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);
@@ -7331,26 +8307,30 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
Buf *free_field_name = buf_create_from_str(ASYNC_FREE_FIELD_NAME);
IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node,
ImplicitAllocatorIdLocalVar);
- IrInstruction *free_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, free_field_name);
- IrInstruction *free_fn = ir_build_load_ptr(irb, scope, node, free_fn_ptr);
+ IrInstruction *free_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, nullptr,
+ free_field_name, false);
+ IrInstruction *free_fn = ir_build_load_ptr(irb, scope, node, free_fn_ptr, nullptr);
IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
IrInstruction *coro_mem_ptr_maybe = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle);
IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
false, false, PtrLenUnknown, 0, 0, 0));
- IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe);
- IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
+ IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe);
+ IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false, nullptr);
IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);
- IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr);
- IrInstruction *mem_slice = ir_build_slice(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false);
+ IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr, nullptr);
+ IrInstruction *mem_slice_alloca = ir_build_alloca_src(irb, scope, node, nullptr, nullptr, "", nullptr);
+ IrInstruction *mem_slice = ir_build_slice(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false,
+ mem_slice_alloca);
size_t arg_count = 2;
IrInstruction **args = allocate(arg_count);
args[0] = implicit_allocator_ptr; // self
args[1] = mem_slice; // old_mem
- ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false, nullptr, nullptr);
+ ir_build_call(irb, scope, node, nullptr, free_fn, arg_count, args, false, FnInlineAuto, false,
+ nullptr, nullptr, nullptr, nullptr, LValNone);
IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume");
- ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false);
+ ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false, nullptr);
ir_set_cursor_at_end_and_append_block(irb, resume_block);
ir_gen_resume_target(irb, scope, node, awaiter_handle);
@@ -7435,7 +8415,7 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal
return val;
}
-static IrInstruction *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) {
+static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec) {
IrBasicBlock *bb = exec->basic_block_list.at(0);
for (size_t i = 0; i < bb->instruction_list.length; i += 1) {
IrInstruction *instruction = bb->instruction_list.at(i);
@@ -7445,16 +8425,16 @@ static IrInstruction *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec)
if (value->value.special == ConstValSpecialRuntime) {
exec_add_error_node(codegen, exec, value->source_node,
buf_sprintf("unable to evaluate constant expression"));
- return codegen->invalid_instruction;
+ return &codegen->invalid_instruction->value;
}
- return value;
+ return &value->value;
} else if (ir_has_side_effects(instruction)) {
exec_add_error_node(codegen, exec, instruction->source_node,
buf_sprintf("unable to evaluate constant expression"));
- return codegen->invalid_instruction;
+ return &codegen->invalid_instruction->value;
}
}
- return codegen->invalid_instruction;
+ return &codegen->invalid_instruction->value;
}
static bool ir_emit_global_runtime_side_effect(IrAnalyze *ira, IrInstruction *source_instruction) {
@@ -8768,13 +9748,13 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
size_t errors_count = 0;
ZigType *err_set_type = nullptr;
if (prev_inst->value.type->id == ZigTypeIdErrorSet) {
+ if (!resolve_inferred_error_set(ira->codegen, prev_inst->value.type, prev_inst->source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
if (type_is_global_error_set(prev_inst->value.type)) {
err_set_type = ira->codegen->builtin_types.entry_global_error_set;
} else {
err_set_type = prev_inst->value.type;
- if (!resolve_inferred_error_set(ira->codegen, err_set_type, prev_inst->source_node)) {
- return ira->codegen->builtin_types.entry_invalid;
- }
update_errors_helper(ira->codegen, &errors, &errors_count);
for (uint32_t i = 0; i < err_set_type->data.error_set.err_count; i += 1) {
@@ -8807,7 +9787,13 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
if (prev_type->id == ZigTypeIdErrorSet) {
assert(err_set_type != nullptr);
- if (cur_type->id == ZigTypeIdErrorSet) {
+ if (cur_type->id == ZigTypeIdErrorSet ||
+ (cur_type->id == ZigTypeIdOptional && cur_type->data.maybe.child_type->id == ZigTypeIdErrorSet))
+ {
+ if (cur_type->id == ZigTypeIdOptional) {
+ cur_type = cur_type->data.maybe.child_type;
+ any_are_null = true;
+ }
if (type_is_global_error_set(err_set_type)) {
continue;
}
@@ -8933,6 +9919,9 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
if (prev_type->id == ZigTypeIdArray) {
convert_to_const_slice = true;
}
+ if (!resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) {
+ return ira->codegen->builtin_types.entry_invalid;
+ }
if (type_is_global_error_set(cur_type)) {
err_set_type = ira->codegen->builtin_types.entry_global_error_set;
continue;
@@ -8940,9 +9929,6 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
if (err_set_type != nullptr && type_is_global_error_set(err_set_type)) {
continue;
}
- if (!resolve_inferred_error_set(ira->codegen, cur_type, cur_inst->source_node)) {
- return ira->codegen->builtin_types.entry_invalid;
- }
update_errors_helper(ira->codegen, &errors, &errors_count);
@@ -9264,8 +10250,15 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
return slice_type;
}
} else if (err_set_type != nullptr) {
- if (prev_inst->value.type->id == ZigTypeIdErrorSet) {
- return err_set_type;
+ if (prev_inst->value.type->id == ZigTypeIdErrorSet ||
+ (prev_inst->value.type->id == ZigTypeIdOptional &&
+ prev_inst->value.type->data.maybe.child_type->id == ZigTypeIdErrorSet))
+ {
+ if (any_are_null) {
+ return get_optional_type(ira->codegen, err_set_type);
+ } else {
+ return err_set_type;
+ }
} else if (prev_inst->value.type->id == ZigTypeIdErrorUnion) {
ZigType *payload_type = prev_inst->value.type->data.error_union.payload_type;
if ((err = type_resolve(ira->codegen, payload_type, ResolveStatusSizeKnown)))
@@ -9284,9 +10277,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
buf_sprintf("unable to make error union out of number literal"));
return ira->codegen->builtin_types.entry_invalid;
} else if (prev_inst->value.type->id == ZigTypeIdNull) {
- ir_add_error_node(ira, source_node,
- buf_sprintf("unable to make error union out of null literal"));
- return ira->codegen->builtin_types.entry_invalid;
+ return get_optional_type(ira->codegen, err_set_type);
} else {
if ((err = type_resolve(ira->codegen, prev_inst->value.type, ResolveStatusSizeKnown)))
return ira->codegen->builtin_types.entry_invalid;
@@ -9310,19 +10301,10 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
}
}
-static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, ZigType *type_entry) {
- if (type_has_bits(type_entry) && handle_is_ptr(type_entry)) {
- ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
- if (fn_entry != nullptr) {
- fn_entry->alloca_list.append(instruction);
- }
- }
-}
-
static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs) {
ConstGlobalRefs *global_refs = dest->global_refs;
*dest = *src;
- if (!same_global_refs) {
+ if (!same_global_refs && src->special != ConstValSpecialUndef) {
dest->global_refs = global_refs;
if (dest->type->id == ZigTypeIdStruct) {
dest->data.x_struct.fields = allocate_nonzero(dest->type->data.structure.src_field_count);
@@ -9344,7 +10326,6 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_
zig_unreachable();
case CastOpErrSet:
case CastOpBitCast:
- case CastOpPtrOfArrayToSlice:
zig_panic("TODO");
case CastOpNoop:
{
@@ -9379,9 +10360,6 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_
}
const_val->type = new_type;
break;
- case CastOpResizeSlice:
- // can't do it
- zig_unreachable();
case CastOpIntToFloat:
{
assert(new_type->id == ZigTypeIdFloat);
@@ -9432,14 +10410,27 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_
}
return true;
}
+
+static IrInstruction *ir_const(IrAnalyze *ira, IrInstruction *old_instruction, ZigType *ty) {
+ IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb,
+ old_instruction->scope, old_instruction->source_node);
+ IrInstruction *new_instruction = &const_instruction->base;
+ new_instruction->value.type = ty;
+ new_instruction->value.special = ConstValSpecialStatic;
+ return new_instruction;
+}
+
+static IrInstruction *ir_const_undef(IrAnalyze *ira, IrInstruction *source_instr) {
+ IrInstruction *undef = ir_const(ira, source_instr, ira->codegen->builtin_types.entry_undef);
+ undef->value.special = ConstValSpecialUndef;
+ return undef;
+}
+
static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
ZigType *wanted_type, CastOp cast_op, bool need_alloca)
{
- if ((instr_is_comptime(value) || !type_has_bits(wanted_type)) &&
- cast_op != CastOpResizeSlice)
- {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ if (instr_is_comptime(value) || !type_has_bits(wanted_type)) {
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
if (!eval_const_expr_implicit_cast(ira, source_instr, cast_op, &value->value, value->value.type,
&result->value, wanted_type))
{
@@ -9449,9 +10440,6 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst
} else {
IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, value, cast_op);
result->value.type = wanted_type;
- if (need_alloca) {
- ir_add_alloca(ira, result, wanted_type);
- }
return result;
}
}
@@ -9471,14 +10459,16 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira,
wanted_type = adjust_ptr_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, value->value.type));
+ IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node,
+ wanted_type, value, CastOpBitCast);
+ result->value.type = wanted_type;
+
if (instr_is_comptime(value)) {
ConstExprValue *pointee = const_ptr_pointee(ira, ira->codegen, &value->value, source_instr->source_node);
if (pointee == nullptr)
return ira->codegen->invalid_instruction;
if (pointee->special != ConstValSpecialRuntime) {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
- result->value.type = wanted_type;
+ result->value.special = ConstValSpecialStatic;
result->value.data.x_ptr.special = ConstPtrSpecialBaseArray;
result->value.data.x_ptr.mut = value->value.data.x_ptr.mut;
result->value.data.x_ptr.data.base_array.array_val = pointee;
@@ -9488,9 +10478,6 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira,
}
}
- IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node,
- wanted_type, value, CastOpBitCast);
- result->value.type = wanted_type;
return result;
}
@@ -9517,8 +10504,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc
assert(is_slice(wanted_type));
bool is_const = wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
init_const_slice(ira->codegen, &result->value, pointee, 0, array_type->data.array.len, is_const);
result->value.data.x_struct.fields[slice_ptr_index].data.x_ptr.mut =
value->value.data.x_ptr.mut;
@@ -9527,10 +10513,11 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc
}
}
- IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node,
- wanted_type, value, CastOpPtrOfArrayToSlice);
+ IrInstruction *result_loc = ir_analyze_alloca(ira, source_instr, wanted_type, 0, "slice", false);
+ result_loc->value.special = ConstValSpecialRuntime;
+ IrInstruction *result = ir_build_ptr_of_array_to_slice(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, value, result_loc);
result->value.type = wanted_type;
- ir_add_alloca(ira, result, wanted_type);
return result;
}
@@ -9653,15 +10640,6 @@ static IrInstruction *ir_finish_anal(IrAnalyze *ira, IrInstruction *instruction)
return instruction;
}
-static IrInstruction *ir_const(IrAnalyze *ira, IrInstruction *old_instruction, ZigType *ty) {
- IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb,
- old_instruction->scope, old_instruction->source_node);
- IrInstruction *new_instruction = &const_instruction->base;
- new_instruction->value.type = ty;
- new_instruction->value.special = ConstValSpecialStatic;
- return new_instruction;
-}
-
static IrInstruction *ir_const_type(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *ty) {
IrInstruction *result = ir_const(ira, source_instruction, ira->codegen->builtin_types.entry_type);
result->value.data.x_type = ty;
@@ -9719,13 +10697,13 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un
zig_unreachable();
}
-IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
+ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota,
ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name,
IrExecutable *parent_exec)
{
if (expected_type != nullptr && type_is_invalid(expected_type))
- return codegen->invalid_instruction;
+ return &codegen->invalid_instruction->value;
IrExecutable *ir_executable = allocate(1);
ir_executable->source_node = source_node;
@@ -9738,13 +10716,13 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node
ir_gen(codegen, node, scope, ir_executable);
if (ir_executable->invalid)
- return codegen->invalid_instruction;
+ return &codegen->invalid_instruction->value;
if (codegen->verbose_ir) {
fprintf(stderr, "\nSource: ");
ast_render(codegen, stderr, node, 4);
fprintf(stderr, "\n{ // (IR)\n");
- ir_print(codegen, stderr, ir_executable, 4);
+ ir_print(codegen, stderr, ir_executable, 2);
fprintf(stderr, "}\n");
}
IrExecutable *analyzed_executable = allocate(1);
@@ -9758,17 +10736,20 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node
analyzed_executable->backward_branch_count = backward_branch_count;
analyzed_executable->backward_branch_quota = backward_branch_quota;
analyzed_executable->begin_scope = scope;
- ZigType *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, node);
- if (type_is_invalid(result_type))
- return codegen->invalid_instruction;
+
+ ConstExprValue *payload_result = create_const_vals(1);
+ ConstExprValue *analyze_result = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, node,
+ payload_result);
+ if (type_is_invalid(analyze_result->type))
+ return &codegen->invalid_instruction->value;
if (codegen->verbose_ir) {
fprintf(stderr, "{ // (analyzed)\n");
- ir_print(codegen, stderr, analyzed_executable, 4);
+ ir_print(codegen, stderr, analyzed_executable, 2);
fprintf(stderr, "}\n");
}
- return ir_exec_const_result(codegen, analyzed_executable);
+ return analyze_result;
}
static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) {
@@ -9810,11 +10791,324 @@ static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {
return const_val->data.x_ptr.data.fn.fn_entry;
}
-static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *wanted_type) {
+static IrInstruction *ir_analyze_result_optional_payload(IrAnalyze *ira, IrInstruction *result_loc,
+ ZigType *needed_child_type, bool make_non_null)
+{
+ ZigType *opt_type = get_optional_type(ira->codegen, needed_child_type);
+ result_loc = resolve_possible_alloca_inference(ira, result_loc, opt_type);
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ ZigType *old_ptr_type = result_loc->value.type;
+ assert(old_ptr_type->id == ZigTypeIdPointer);
+ ZigType *new_ptr_type = get_pointer_to_type_extra(ira->codegen, needed_child_type,
+ false, old_ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
+
+ if (instr_is_comptime(result_loc)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, result_loc, UndefBad);
+ if (ptr_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr &&
+ ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ ConstExprValue *optional_val = const_ptr_pointee(ira, ira->codegen, ptr_val, result_loc->source_node);
+ assert(optional_val->type->id == ZigTypeIdOptional);
+ bool same_comptime_repr = types_have_same_zig_comptime_repr(optional_val->type,
+ optional_val->type->data.maybe.child_type);
+ if (optional_val->special == ConstValSpecialUndef) {
+ switch (type_has_one_possible_value(ira->codegen, needed_child_type)) {
+ case OnePossibleValueInvalid:
+ return ira->codegen->invalid_instruction;
+ case OnePossibleValueNo:
+ if (!same_comptime_repr) {
+ ConstExprValue *payload_val = create_const_vals(1);
+ payload_val->type = needed_child_type;
+ payload_val->special = ConstValSpecialUndef;
+ payload_val->parent.id = ConstParentIdOptionalPayload;
+ payload_val->parent.data.p_optional_payload.optional_val = optional_val;
+
+ optional_val->data.x_optional = payload_val;
+ optional_val->special = ConstValSpecialStatic;
+ }
+ break;
+ case OnePossibleValueYes: {
+ ConstExprValue *pointee = create_const_vals(1);
+ pointee->special = ConstValSpecialStatic;
+ pointee->type = needed_child_type;
+
+ optional_val->special = ConstValSpecialStatic;
+ optional_val->data.x_optional = pointee;
+ break;
+ }
+ }
+ }
+
+ IrInstruction *result;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_result_optional_payload(&ira->new_irb, result_loc->scope,
+ result_loc->source_node, result_loc, nullptr, make_non_null);
+ result->value.type = new_ptr_type;
+ result->value.special = ConstValSpecialStatic;
+ } else {
+ result = ir_const(ira, result_loc, new_ptr_type);
+ }
+ ConstExprValue *result_val = &result->value;
+ result_val->data.x_ptr.special = ConstPtrSpecialRef;
+ result_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut;
+ switch (type_has_one_possible_value(ira->codegen, needed_child_type)) {
+ case OnePossibleValueInvalid:
+ return ira->codegen->invalid_instruction;
+ case OnePossibleValueNo:
+ if (same_comptime_repr) {
+ result_val->data.x_ptr.data.ref.pointee = optional_val;
+ } else {
+ assert(optional_val->data.x_optional != nullptr);
+ result_val->data.x_ptr.data.ref.pointee = optional_val->data.x_optional;
+ }
+ break;
+ case OnePossibleValueYes:
+ assert(optional_val->data.x_optional != nullptr);
+ result_val->data.x_ptr.data.ref.pointee = optional_val->data.x_optional;
+ break;
+ }
+
+ return result;
+ }
+ }
+
+ IrInstruction *result = ir_build_result_optional_payload(&ira->new_irb, result_loc->scope,
+ result_loc->source_node, result_loc, nullptr, make_non_null);
+ result->value.type = new_ptr_type;
+ return result;
+}
+
+static IrInstruction *ir_analyze_instruction_result_optional_payload(IrAnalyze *ira,
+ IrInstructionResultOptionalPayload *instruction)
+{
+ IrInstruction *prev_result_loc = instruction->prev_result_loc->child;
+ if (type_is_invalid(prev_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ ZigType *payload_type = ir_resolve_type(ira, instruction->payload_type->child);
+ if (type_is_invalid(payload_type))
+ return ira->codegen->invalid_instruction;
+ return ir_analyze_result_optional_payload(ira, prev_result_loc, payload_type, instruction->make_non_null);
+}
+
+static IrInstruction *ir_analyze_result_slice_ptr(IrAnalyze *ira, IrInstruction *result_loc, uint64_t len,
+ bool init_array)
+{
+ ZigType *slice_type = result_loc->value.type->data.pointer.child_type;
+ assert(is_slice(slice_type));
+ ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index].type_entry;
+ assert(slice_ptr_type->id == ZigTypeIdPointer);
+ ZigType *new_ptr_type = get_pointer_to_type_extra(ira->codegen, slice_ptr_type,
+ false, result_loc->value.type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
+ if (instr_is_comptime(result_loc)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, result_loc, UndefBad);
+ if (ptr_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr &&
+ ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ ConstExprValue *slice_val = const_ptr_pointee(ira, ira->codegen, ptr_val, result_loc->source_node);
+ assert(is_slice(slice_val->type));
+ if (slice_val->special == ConstValSpecialUndef) {
+ slice_val->data.x_struct.fields = create_const_vals(2);
+ ConstExprValue *slice_ptr_val = &slice_val->data.x_struct.fields[slice_ptr_index];
+ ConstExprValue *slice_len_val = &slice_val->data.x_struct.fields[slice_len_index];
+
+ slice_ptr_val->type = slice_ptr_type;
+ slice_ptr_val->special = ConstValSpecialUndef;
+ slice_ptr_val->parent.id = ConstParentIdStruct;
+ slice_ptr_val->parent.data.p_struct.struct_val = slice_val;
+ slice_ptr_val->parent.data.p_struct.field_index = slice_ptr_index;
+
+ slice_len_val->type = ira->codegen->builtin_types.entry_usize;
+ slice_len_val->special = ConstValSpecialUndef;
+ slice_len_val->parent.id = ConstParentIdStruct;
+ slice_len_val->parent.data.p_struct.struct_val = slice_val;
+ slice_len_val->parent.data.p_struct.field_index = slice_len_index;
+
+ slice_val->special = ConstValSpecialStatic;
+ }
+ assert(slice_val->data.x_struct.fields != nullptr);
+ ConstExprValue *slice_len_val = &slice_val->data.x_struct.fields[slice_len_index];
+ if (slice_len_val->special == ConstValSpecialUndef) {
+ slice_len_val->special = ConstValSpecialStatic;
+ bigint_init_unsigned(&slice_len_val->data.x_bigint, len);
+ }
+ IrInstruction *array_loc = nullptr;
+ if (init_array) {
+ ConstExprValue *slice_ptr_val = &slice_val->data.x_struct.fields[slice_ptr_index];
+ if (slice_ptr_val->special == ConstValSpecialUndef) {
+ ZigType *array_type = get_array_type(ira->codegen, slice_ptr_type->data.pointer.child_type, len);
+ array_loc = ir_analyze_alloca(ira, result_loc, array_type, 0, "", false);
+ assert(array_loc->value.data.x_ptr.special == ConstPtrSpecialRef);
+ ConstExprValue *array_val = array_loc->value.data.x_ptr.data.ref.pointee;
+ array_val->special = ConstValSpecialStatic;
+ array_val->data.x_array.special = ConstArraySpecialUndef;
+
+ slice_ptr_val->special = ConstValSpecialStatic;
+ slice_ptr_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut;
+ slice_ptr_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
+ slice_ptr_val->data.x_ptr.data.base_array.array_val = array_val;
+ }
+ }
+
+ IrInstruction *result;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_result_slice_ptr(&ira->new_irb, result_loc->scope, result_loc->source_node,
+ result_loc, len, array_loc);
+ result->value.type = new_ptr_type;
+ result->value.special = ConstValSpecialStatic;
+ } else {
+ result = ir_const(ira, result_loc, new_ptr_type);
+ }
+ ConstExprValue *result_val = &result->value;
+ result_val->data.x_ptr.special = ConstPtrSpecialBaseStruct;
+ result_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut;
+ result_val->data.x_ptr.data.base_struct.struct_val = slice_val;
+ result_val->data.x_ptr.data.base_struct.field_index = slice_ptr_index;
+ return result;
+ }
+ }
+ IrInstruction *array_loc = nullptr;
+ if (init_array) {
+ ZigType *array_type = get_array_type(ira->codegen, slice_ptr_type->data.pointer.child_type, len);
+ array_loc = ir_analyze_alloca(ira, result_loc, array_type, 0, "", false);
+ array_loc->value.special = ConstValSpecialRuntime;
+ }
+ IrInstruction *result = ir_build_result_slice_ptr(&ira->new_irb, result_loc->scope, result_loc->source_node,
+ result_loc, len, array_loc);
+ result->value.type = new_ptr_type;
+ return result;
+}
+
+static void init_if_undef_err_union(IrAnalyze *ira, ConstExprValue *error_union_val) {
+ if (error_union_val->special != ConstValSpecialUndef)
+ return;
+
+ ConstExprValue *vals = create_const_vals(2);
+ ConstExprValue *err_set_val = &vals[0];
+ ConstExprValue *payload_val = &vals[1];
+
+ err_set_val->type = get_optional_type(ira->codegen,
+ error_union_val->type->data.error_union.err_set_type);
+ err_set_val->special = ConstValSpecialUndef;
+ err_set_val->parent.id = ConstParentIdErrUnionCode;
+ err_set_val->parent.data.p_err_union_code.err_union_val = error_union_val;
+
+ payload_val->type = error_union_val->type->data.error_union.payload_type;
+ payload_val->special = ConstValSpecialUndef;
+ payload_val->parent.id = ConstParentIdErrUnionPayload;
+ payload_val->parent.data.p_err_union_payload.err_union_val = error_union_val;
+
+ error_union_val->data.x_err_union.error_set = err_set_val;
+ error_union_val->data.x_err_union.payload = payload_val;
+ error_union_val->special = ConstValSpecialStatic;
+}
+
+static IrInstruction *ir_analyze_result_error_union_payload(IrAnalyze *ira, IrInstruction *result_loc,
+ ZigType *needed_child_type)
+{
+ ZigType *old_ptr_type = result_loc->value.type;
+ assert(old_ptr_type->id == ZigTypeIdPointer);
+ ZigType *new_ptr_type = get_pointer_to_type_extra(ira->codegen, needed_child_type,
+ false, old_ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
+
+ if (instr_is_comptime(result_loc)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, result_loc, UndefBad);
+ if (ptr_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr &&
+ ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ ConstExprValue *error_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, result_loc->source_node);
+ assert(error_union_val->type->id == ZigTypeIdErrorUnion);
+
+ init_if_undef_err_union(ira, error_union_val);
+ assert(error_union_val->data.x_err_union.payload != nullptr);
+
+ // Make the error set null
+ error_union_val->data.x_err_union.error_set->special = ConstValSpecialStatic;
+ error_union_val->data.x_err_union.error_set->data.x_err_set = nullptr;
+
+ IrInstruction *result;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_result_error_union_payload(&ira->new_irb, result_loc->scope,
+ result_loc->source_node, result_loc);
+ result->value.type = new_ptr_type;
+ result->value.special = ConstValSpecialStatic;
+ } else {
+ result = ir_const(ira, result_loc, new_ptr_type);
+ }
+ ConstExprValue *result_val = &result->value;
+ result_val->data.x_ptr.special = ConstPtrSpecialRef;
+ result_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut;
+ result_val->data.x_ptr.data.ref.pointee = error_union_val->data.x_err_union.payload;
+
+ return result;
+ }
+ }
+
+ IrInstruction *result = ir_build_result_error_union_payload(&ira->new_irb, result_loc->scope,
+ result_loc->source_node, result_loc);
+ result->value.type = new_ptr_type;
+ return result;
+}
+
+static IrInstruction *ir_analyze_result_error_union_code(IrAnalyze *ira, IrInstruction *result_loc,
+ ZigType *needed_child_type)
+{
+ ZigType *old_ptr_type = result_loc->value.type;
+ assert(old_ptr_type->id == ZigTypeIdPointer);
+ ZigType *new_ptr_type = get_pointer_to_type_extra(ira->codegen, needed_child_type,
+ false, old_ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
+
+ if (instr_is_comptime(result_loc)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, result_loc, UndefBad);
+ if (ptr_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr &&
+ ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ ConstExprValue *error_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, result_loc->source_node);
+ assert(error_union_val->type->id == ZigTypeIdErrorUnion);
+
+ init_if_undef_err_union(ira, error_union_val);
+ assert(error_union_val->data.x_err_union.error_set != nullptr);
+
+ IrInstruction *result;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_result_error_union_code(&ira->new_irb, result_loc->scope,
+ result_loc->source_node, result_loc);
+ result->value.type = new_ptr_type;
+ result->value.special = ConstValSpecialStatic;
+ } else {
+ result = ir_const(ira, result_loc, new_ptr_type);
+ }
+ ConstExprValue *result_val = &result->value;
+ result_val->data.x_ptr.special = ConstPtrSpecialRef;
+ result_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut;
+ result_val->data.x_ptr.data.ref.pointee = error_union_val->data.x_err_union.error_set;
+
+ return result;
+ }
+ }
+
+ IrInstruction *result = ir_build_result_error_union_code(&ira->new_irb, result_loc->scope,
+ result_loc->source_node, result_loc);
+ result->value.type = new_ptr_type;
+ return result;
+}
+
+static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
+ ZigType *wanted_type)
+{
assert(wanted_type->id == ZigTypeIdOptional);
+ ZigType *payload_type = wanted_type->data.maybe.child_type;
if (instr_is_comptime(value)) {
- ZigType *payload_type = wanted_type->data.maybe.child_type;
IrInstruction *casted_payload = ir_implicit_cast(ira, value, payload_type);
if (type_is_invalid(casted_payload->value.type))
return ira->codegen->invalid_instruction;
@@ -9826,7 +11120,7 @@ static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *sourc
IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb,
source_instr->scope, source_instr->source_node);
const_instruction->base.value.special = ConstValSpecialStatic;
- if (get_codegen_ptr_type(wanted_type) != nullptr) {
+ if (types_have_same_zig_comptime_repr(wanted_type, payload_type)) {
copy_const_val(&const_instruction->base.value, val, val->data.x_ptr.mut == ConstPtrMutComptimeConst);
} else {
const_instruction->base.value.data.x_optional = val;
@@ -9835,10 +11129,16 @@ static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *sourc
return &const_instruction->base;
}
- IrInstruction *result = ir_build_maybe_wrap(&ira->new_irb, source_instr->scope, source_instr->source_node, value);
+ IrInstruction *result_loc = nullptr;
+ if (type_has_bits(payload_type) && handle_is_ptr(wanted_type)) {
+ result_loc = ir_analyze_alloca(ira, source_instr, wanted_type, 0, "", false);
+ result_loc->value.special = ConstValSpecialRuntime;
+ }
+
+ IrInstruction *result = ir_build_maybe_wrap(&ira->new_irb, source_instr->scope, source_instr->source_node,
+ value, result_loc);
result->value.type = wanted_type;
result->value.data.rh_maybe = RuntimeHintOptionalNonNull;
- ir_add_alloca(ira, result, wanted_type);
return result;
}
@@ -9857,11 +11157,16 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction
if (!val)
return ira->codegen->invalid_instruction;
+ ConstExprValue *err_set_val = create_const_vals(1);
+ err_set_val->type = wanted_type->data.error_union.err_set_type;
+ err_set_val->special = ConstValSpecialStatic;
+ err_set_val->data.x_err_set = nullptr;
+
IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb,
source_instr->scope, source_instr->source_node);
const_instruction->base.value.type = wanted_type;
const_instruction->base.value.special = ConstValSpecialStatic;
- const_instruction->base.value.data.x_err_union.err = nullptr;
+ const_instruction->base.value.data.x_err_union.error_set = err_set_val;
const_instruction->base.value.data.x_err_union.payload = val;
return &const_instruction->base;
}
@@ -9869,7 +11174,6 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction
IrInstruction *result = ir_build_err_wrap_payload(&ira->new_irb, source_instr->scope, source_instr->source_node, value);
result->value.type = wanted_type;
result->value.data.rh_error_union = RuntimeHintErrorUnionNonError;
- ir_add_alloca(ira, result, wanted_type);
return result;
}
@@ -9926,11 +11230,16 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so
if (!val)
return ira->codegen->invalid_instruction;
+ ConstExprValue *err_set_val = create_const_vals(1);
+ err_set_val->special = ConstValSpecialStatic;
+ err_set_val->type = wanted_type->data.error_union.err_set_type;
+ err_set_val->data.x_err_set = val->data.x_err_set;
+
IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb,
source_instr->scope, source_instr->source_node);
const_instruction->base.value.type = wanted_type;
const_instruction->base.value.special = ConstValSpecialStatic;
- const_instruction->base.value.data.x_err_union.err = val->data.x_err_set;
+ const_instruction->base.value.data.x_err_union.error_set = err_set_val;
const_instruction->base.value.data.x_err_union.payload = nullptr;
return &const_instruction->base;
}
@@ -9938,7 +11247,6 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so
IrInstruction *result = ir_build_err_wrap_code(&ira->new_irb, source_instr->scope, source_instr->source_node, value);
result->value.type = wanted_type;
result->value.data.rh_error_union = RuntimeHintErrorUnionError;
- ir_add_alloca(ira, result, wanted_type);
return result;
}
@@ -9952,8 +11260,9 @@ static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *so
IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, source_instr->scope, source_instr->source_node);
const_instruction->base.value.special = ConstValSpecialStatic;
if (get_codegen_ptr_type(wanted_type) != nullptr) {
- const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
- const_instruction->base.value.data.x_ptr.data.hard_coded_addr.addr = 0;
+ const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialNull;
+ } else if (is_opt_err_set(wanted_type)) {
+ const_instruction->base.value.data.x_err_set = nullptr;
} else {
const_instruction->base.value.data.x_optional = nullptr;
}
@@ -9962,7 +11271,7 @@ static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *so
}
static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *value,
- bool is_const, bool is_volatile)
+ bool is_const, bool is_volatile, IrInstruction *result_loc)
{
Error err;
@@ -9980,17 +11289,16 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
ConstPtrMutComptimeConst, is_const, is_volatile, 0);
}
+ if (result_loc == nullptr) {
+ result_loc = ir_analyze_alloca(ira, source_instruction, value->value.type, 0, "", false);
+ result_loc->value.special = ConstValSpecialRuntime;
+ }
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type,
is_const, is_volatile, PtrLenSingle, 0, 0, 0);
IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instruction->scope,
- source_instruction->source_node, value, is_const, is_volatile);
+ source_instruction->source_node, value, is_const, is_volatile, result_loc);
new_instruction->value.type = ptr_type;
new_instruction->value.data.rh_ptr = RuntimeHintPtrStack;
- if (type_has_bits(ptr_type)) {
- ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
- assert(fn_entry);
- fn_entry->alloca_list.append(new_instruction);
- }
return new_instruction;
}
@@ -10001,43 +11309,27 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
// In this function we honor the const-ness of wanted_type, because
// we may be casting [0]T to []const T which is perfectly valid.
- IrInstruction *array_ptr = nullptr;
IrInstruction *array;
if (array_arg->value.type->id == ZigTypeIdPointer) {
array = ir_get_deref(ira, source_instr, array_arg);
- array_ptr = array_arg;
} else {
array = array_arg;
}
ZigType *array_type = array->value.type;
assert(array_type->id == ZigTypeIdArray);
- if (instr_is_comptime(array)) {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ if (instr_is_comptime(array) || array_type->data.array.len == 0) {
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
init_const_slice(ira->codegen, &result->value, &array->value, 0, array_type->data.array.len, true);
result->value.type = wanted_type;
return result;
}
- IrInstruction *start = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, ira->codegen->builtin_types.entry_usize);
- init_const_usize(ira->codegen, &start->value, 0);
-
- IrInstruction *end = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, ira->codegen->builtin_types.entry_usize);
- init_const_usize(ira->codegen, &end->value, array_type->data.array.len);
-
- if (!array_ptr) array_ptr = ir_get_ref(ira, source_instr, array, true, false);
-
- IrInstruction *result = ir_build_slice(&ira->new_irb, source_instr->scope,
- source_instr->source_node, array_ptr, start, end, false);
- result->value.type = wanted_type;
- result->value.data.rh_slice.id = RuntimeHintSliceIdLen;
- result->value.data.rh_slice.len = array_type->data.array.len;
- ir_add_alloca(ira, result, result->value.type);
-
- return result;
+ // TODO once https://github.com/ziglang/zig/issues/265
+ // lands this entire function will be deleted.
+ IrInstruction *slice_alloca = ir_analyze_alloca(ira, source_instr, wanted_type, 0, "", false);
+ slice_alloca->value.special = ConstValSpecialRuntime;
+ return ir_build_array_to_slice(ira, source_instr, wanted_type, array, slice_alloca);
}
static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *source_instr,
@@ -10064,8 +11356,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag);
return result;
}
@@ -10075,8 +11366,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
actual_type->data.enumeration.src_field_count == 1)
{
assert(wanted_type== ira->codegen->builtin_types.entry_num_lit_int);
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
init_const_bigint(&result->value, wanted_type,
&actual_type->data.enumeration.fields[0].value);
return result;
@@ -10099,8 +11389,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou
ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
result->value.special = ConstValSpecialStatic;
result->value.type = wanted_type;
bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_union.tag);
@@ -10111,8 +11400,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou
if (wanted_type->data.enumeration.layout == ContainerLayoutAuto &&
wanted_type->data.enumeration.src_field_count == 1)
{
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
result->value.special = ConstValSpecialStatic;
result->value.type = wanted_type;
TypeEnumField *enum_field = target->value.type->data.unionation.fields[0].enum_field;
@@ -10129,8 +11417,7 @@ static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *sou
static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *target, ZigType *wanted_type)
{
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
init_const_undefined(ira->codegen, &result->value);
return result;
}
@@ -10162,8 +11449,7 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so
buf_sprintf("field '%s' declared here", buf_ptr(union_field->name)));
return ira->codegen->invalid_instruction;
}
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
result->value.special = ConstValSpecialStatic;
result->value.type = wanted_type;
bigint_init_bigint(&result->value.data.x_union.tag, &val->data.x_enum_tag);
@@ -10218,8 +11504,7 @@ static IrInstruction *ir_analyze_widen_or_shorten(IrAnalyze *ira, IrInstruction
return ira->codegen->invalid_instruction;
}
}
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
result->value.type = wanted_type;
if (wanted_type->id == ZigTypeIdInt) {
bigint_init_bigint(&result->value.data.x_bigint, &val->data.x_bigint);
@@ -10273,8 +11558,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
return ira->codegen->invalid_instruction;
}
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_bigint);
return result;
}
@@ -10292,8 +11576,7 @@ static IrInstruction *ir_analyze_number_to_literal(IrAnalyze *ira, IrInstruction
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
if (wanted_type->id == ZigTypeIdComptimeFloat) {
float_init_float(&result->value, val);
} else if (wanted_type->id == ZigTypeIdComptimeInt) {
@@ -10316,8 +11599,7 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
if (!resolve_inferred_error_set(ira->codegen, wanted_type, source_instr->source_node)) {
return ira->codegen->invalid_instruction;
@@ -10381,12 +11663,11 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
ErrorTableEntry *err;
if (err_type->id == ZigTypeIdErrorUnion) {
- err = val->data.x_err_union.err;
+ err = val->data.x_err_union.error_set->data.x_err_set;
} else if (err_type->id == ZigTypeIdErrorSet) {
err = val->data.x_err_set;
} else {
@@ -10421,14 +11702,12 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
return ira->codegen->invalid_instruction;
}
if (err_set_type->data.error_set.err_count == 0) {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
result->value.type = wanted_type;
bigint_init_unsigned(&result->value.data.x_bigint, 0);
return result;
} else if (err_set_type->data.error_set.err_count == 1) {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
- source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
result->value.type = wanted_type;
ErrorTableEntry *err = err_set_type->data.error_set.errors[0];
bigint_init_unsigned(&result->value.data.x_bigint, err->value);
@@ -10476,8 +11755,8 @@ static IrInstruction *ir_analyze_ptr_to_array(IrAnalyze *ira, IrInstruction *sou
array_val->type = array_type;
array_val->data.x_array.special = ConstArraySpecialNone;
array_val->data.x_array.data.s_none.elements = pointee;
- array_val->data.x_array.data.s_none.parent.id = ConstParentIdScalar;
- array_val->data.x_array.data.s_none.parent.data.p_scalar.scalar_val = pointee;
+ array_val->parent.id = ConstParentIdScalar;
+ array_val->parent.data.p_scalar.scalar_val = pointee;
IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb,
source_instr->scope, source_instr->source_node);
@@ -10625,12 +11904,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node,
false).id == ConstCastResultIdOk)
{
- return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
+ return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type);
} else if (actual_type->id == ZigTypeIdComptimeInt ||
actual_type->id == ZigTypeIdComptimeFloat)
{
if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) {
- return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
+ return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type);
} else {
return ira->codegen->invalid_instruction;
}
@@ -10654,7 +11933,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
wanted_child_type);
if (type_is_invalid(cast1->value.type))
return ira->codegen->invalid_instruction;
- return ir_analyze_maybe_wrap(ira, source_instr, cast1, wanted_type);
+ return ir_analyze_optional_wrap(ira, source_instr, cast1, wanted_type);
}
}
}
@@ -10707,6 +11986,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
(wanted_type->id == ZigTypeIdInt || wanted_type->id == ZigTypeIdComptimeInt ||
wanted_type->id == ZigTypeIdFloat || wanted_type->id == ZigTypeIdComptimeFloat))
{
+ if (value->value.special == ConstValSpecialUndef) {
+ IrInstruction *result = ir_const(ira, source_instr, wanted_type);
+ result->value.special = ConstValSpecialUndef;
+ return result;
+ }
if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) {
if (wanted_type->id == ZigTypeIdComptimeInt || wanted_type->id == ZigTypeIdInt) {
IrInstruction *result = ir_const(ira, source_instr, wanted_type);
@@ -10760,6 +12044,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
// cast from [N]T to []const T
+ // TODO: once https://github.com/ziglang/zig/issues/265 lands, remove this
+ // only the comptime branch here is used
if (is_slice(wanted_type) && actual_type->id == ZigTypeIdArray) {
ZigType *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
assert(ptr_type->id == ZigTypeIdPointer);
@@ -10771,7 +12057,23 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
}
}
+ // cast from [N]T to [*]const T
+ // TODO: once https://github.com/ziglang/zig/issues/265 lands, remove this
+ // []const T in this situation gets turned into [*]const T with the result location cast
+ if (actual_type->id == ZigTypeIdArray && wanted_type->id == ZigTypeIdPointer &&
+ wanted_type->data.pointer.ptr_len == PtrLenUnknown)
+ {
+ if ((wanted_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
+ types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
+ actual_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk)
+ {
+ IrInstruction *array_ref = ir_get_ref(ira, source_instr, value, true, false, nullptr);
+ return ir_analyze_cast(ira, source_instr, wanted_type, array_ref);
+ }
+ }
+
// cast from [N]T to ?[]const T
+ // TODO: once https://github.com/ziglang/zig/issues/265 lands, remove this
if (wanted_type->id == ZigTypeIdOptional &&
is_slice(wanted_type->data.maybe.child_type) &&
actual_type->id == ZigTypeIdArray)
@@ -10866,7 +12168,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
}
}
- // cast from error set to error union type
+ // cast from E to E!T
if (wanted_type->id == ZigTypeIdErrorUnion &&
actual_type->id == ZigTypeIdErrorSet)
{
@@ -10966,49 +12268,298 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
}
}
- // cast from T to *T where T is zero bits
- if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
- types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
- actual_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
+ // cast from T to *T where T is zero bits
+ if (wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
+ types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
+ actual_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
+ {
+ if ((err = type_resolve(ira->codegen, actual_type, ResolveStatusZeroBitsKnown))) {
+ return ira->codegen->invalid_instruction;
+ }
+ if (!type_has_bits(actual_type)) {
+ return ir_get_ref(ira, source_instr, value, false, false, nullptr);
+ }
+ }
+
+
+ // cast from undefined to anything
+ if (actual_type->id == ZigTypeIdUndefined) {
+ return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type);
+ }
+
+ ErrorMsg *parent_msg = ir_add_error_node(ira, source_instr->source_node,
+ buf_sprintf("expected type '%s', found '%s'",
+ buf_ptr(&wanted_type->name),
+ buf_ptr(&actual_type->name)));
+ report_recursive_error(ira, source_instr->source_node, &const_cast_result, parent_msg);
+ return ira->codegen->invalid_instruction;
+}
+
+static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, ZigType *expected_type) {
+ assert(value);
+ assert(value != ira->codegen->invalid_instruction);
+ assert(!expected_type || !type_is_invalid(expected_type));
+ assert(value->value.type);
+ assert(!type_is_invalid(value->value.type));
+ if (expected_type == nullptr)
+ return value; // anything will do
+ if (expected_type == value->value.type)
+ return value; // match
+ if (value->value.type->id == ZigTypeIdUnreachable)
+ return value;
+
+ return ir_analyze_cast(ira, value, expected_type, value);
+}
+
+static Error resolve_alloca_inference(IrAnalyze *ira, IrInstructionAllocaGen *alloca,
+ ZigType *child_type)
+{
+ Error err;
+ if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown)))
+ return err;
+ assert(alloca->base.value.data.x_ptr.special != ConstPtrSpecialInvalid);
+ alloca->base.value.data.x_ptr.data.ref.pointee->type = child_type;
+ alloca->base.value.type = get_pointer_to_type_extra(ira->codegen, child_type, false, false,
+ PtrLenSingle, alloca->align, 0, 0);
+ return ErrorNone;
+}
+
+static IrInstruction *resolve_possible_alloca_inference(IrAnalyze *ira, IrInstruction *base, ZigType *child_type) {
+ Error err;
+ assert(base->value.type->id == ZigTypeIdPointer);
+ ZigType *infer_child = base->value.type->data.pointer.child_type;
+ if (base->id == IrInstructionIdResultSliceToBytesPlaceholder) {
+ IrInstructionResultSliceToBytesPlaceholder *res_slice_to_bytes =
+ reinterpret_cast(base);
+ // When the instruction was made it didn't have enough information to do analysis,
+ // so it emitted a placeholder. Now we have the information, so we do
+ // the analysis, and rely on the ref_count being 0 so that it is not emitted.
+ assert(res_slice_to_bytes->base.ref_count == 0);
+ assert(res_slice_to_bytes->pass1_parent != nullptr);
+ IrInstruction *new_res_slice_to_bytes = ir_analyze_result_slice_to_bytes(ira, base,
+ res_slice_to_bytes->prev_result_loc, res_slice_to_bytes->elem_type, child_type);
+ res_slice_to_bytes->pass1_parent->child = new_res_slice_to_bytes;
+ return new_res_slice_to_bytes;
+ }
+ if (infer_child == ira->codegen->builtin_types.entry_infer) {
+ if (base->id == IrInstructionIdAllocaGen) {
+ if ((err = resolve_alloca_inference(ira, reinterpret_cast(base), child_type)))
+ return ira->codegen->invalid_instruction;
+ } else if (base->id == IrInstructionIdPtrCastGen) {
+ IrInstructionPtrCastGen *ptr_cast = reinterpret_cast(base);
+ // When the ptr cast instruction was made it didn't have the destination type, so
+ // we had to set it to "infer". Now we have the destination type, so we re-do
+ // analysis, and rely on the ref_count being 0 so that it is not emitted.
+ assert(ptr_cast->base.ref_count == 0);
+ ZigType *prev_ptr_type = ptr_cast->ptr->value.type;
+ // TODO should this be adjust_ptr_child?
+ ZigType *new_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type, false, false,
+ PtrLenSingle, prev_ptr_type->data.pointer.explicit_alignment, 0, 0);
+ IrInstruction *new_ptr_cast = ir_analyze_ptr_cast(ira, base, ptr_cast->ptr, new_ptr_type, base);
+ ptr_cast->pass1_parent->child = new_ptr_cast;
+ return new_ptr_cast;
+ }
+ } else if (is_slice(infer_child)) {
+ ZigType *slice_ptr_type = infer_child->data.structure.fields[slice_ptr_index].type_entry;
+ assert(slice_ptr_type->id == ZigTypeIdPointer);
+ if (slice_ptr_type->data.pointer.child_type == ira->codegen->builtin_types.entry_infer) {
+ assert(base->id == IrInstructionIdPtrCastGen);
+ IrInstructionPtrCastGen *ptr_cast = reinterpret_cast(base);
+ // See above comment
+ assert(ptr_cast->base.ref_count == 0);
+ assert(ptr_cast->ptr->ref_count == 1); // The ref is this PtrCast instruction
+ ZigType *prev_ptr_type = ptr_cast->ptr->value.type;
+ assert(is_slice(child_type));
+ ZigType *good_slice_ptr_type = child_type->data.structure.fields[slice_ptr_index].type_entry;
+ ZigType *good_u8_ptr_type = adjust_ptr_child(ira->codegen, good_slice_ptr_type,
+ ira->codegen->builtin_types.entry_u8);
+ ZigType *good_u8_slice_type = get_slice_type(ira->codegen, good_u8_ptr_type);
+ ptr_cast->ptr->value.type = adjust_ptr_child(ira->codegen, prev_ptr_type, good_u8_slice_type);
+ ZigType *new_ptr_type = adjust_ptr_child(ira->codegen, prev_ptr_type, child_type);
+ ptr_cast->base.value.type = new_ptr_type;
+ }
+ }
+ return base;
+}
+
+static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align) {
+ if (ptr_type->id == ZigTypeIdPointer) {
+ return get_pointer_to_type_extra(g,
+ ptr_type->data.pointer.child_type,
+ ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
+ ptr_type->data.pointer.ptr_len,
+ new_align,
+ ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes);
+ } else if (ptr_type->id == ZigTypeIdOptional) {
+ ZigType *actual_ptr_type = ptr_type->data.pointer.child_type;
+ return get_optional_type(g, adjust_ptr_align(g, actual_ptr_type, new_align));
+ }
+ zig_unreachable();
+}
+
+// TODO: audit callsites. The purpose of this function is to change the element type of the pointer
+// while leaving the other properties the same. But if the original pointer has ABI alignment and
+// the original element type has different ABI alignment than the new element type, the resulting
+// pointer type will have different alignment, which is probably incorrect. Probably this function
+// will have to be removed and the logic in the callsites reworked.
+static ZigType *adjust_ptr_child(CodeGen *g, ZigType *ptr_type, ZigType *new_child) {
+ assert(ptr_type->id == ZigTypeIdPointer);
+ return get_pointer_to_type_extra(g,
+ new_child,
+ ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
+ ptr_type->data.pointer.ptr_len,
+ ptr_type->data.pointer.explicit_alignment,
+ ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes);
+}
+
+static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align) {
+ assert(is_slice(slice_type));
+ ZigType *ptr_type = adjust_ptr_align(g, slice_type->data.structure.fields[slice_ptr_index].type_entry,
+ new_align);
+ return get_slice_type(g, ptr_type);
+}
+
+static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) {
+ assert(ptr_type->id == ZigTypeIdPointer);
+ return get_pointer_to_type_extra(g,
+ ptr_type->data.pointer.child_type,
+ ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
+ ptr_len,
+ ptr_type->data.pointer.explicit_alignment,
+ ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes);
+}
+
+static IrInstruction *ir_implicit_cast_result(IrAnalyze *ira, AstNode *source_node,
+ IrInstruction *unresolved_result_loc, ZigType *needed_child_type, bool allow_failure)
+{
+ if (type_is_invalid(unresolved_result_loc->value.type) || type_is_invalid(needed_child_type))
+ return ira->codegen->invalid_instruction;
+
+ assert(unresolved_result_loc->value.type->id == ZigTypeIdPointer);
+ if (unresolved_result_loc->value.special == ConstValSpecialStatic &&
+ unresolved_result_loc->value.data.x_ptr.special == ConstPtrSpecialDiscard)
+ {
+ return unresolved_result_loc;
+ }
+
+ IrInstruction *result_loc = resolve_possible_alloca_inference(ira, unresolved_result_loc, needed_child_type);
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ if (needed_child_type == nullptr)
+ return result_loc;
+
+ assert(result_loc->value.type->id == ZigTypeIdPointer);
+ ZigType *have_child_type = result_loc->value.type->data.pointer.child_type;
+ if (have_child_type == needed_child_type)
+ return result_loc;
+
+ // perfect match or non-const to const
+ ConstCastOnly const_cast_result = types_match_const_cast_only(ira, have_child_type, needed_child_type,
+ source_node, false);
+ if (const_cast_result.id == ConstCastResultIdInvalid)
+ return ira->codegen->invalid_instruction;
+ if (const_cast_result.id == ConstCastResultIdOk) {
+ ZigType *new_ptr_type = adjust_ptr_child(ira->codegen, result_loc->value.type, needed_child_type);
+ return ir_analyze_ptr_cast(ira, result_loc, result_loc, new_ptr_type, result_loc);
+ }
+
+ // cast from *[N]T to []T
+ if (is_slice(have_child_type) &&
+ needed_child_type->id == ZigTypeIdPointer &&
+ needed_child_type->data.pointer.ptr_len == PtrLenSingle &&
+ needed_child_type->data.pointer.child_type->id == ZigTypeIdArray)
+ {
+ ZigType *slice_ptr_type = have_child_type->data.structure.fields[slice_ptr_index].type_entry;
+ assert(slice_ptr_type->id == ZigTypeIdPointer);
+ ZigType *array_type = needed_child_type->data.pointer.child_type;
+ bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0
+ || !needed_child_type->data.pointer.is_const);
+ if (const_ok && types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
+ array_type->data.array.child_type, source_node,
+ !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk)
+ {
+ return ir_analyze_result_slice_ptr(ira, result_loc, array_type->data.array.len, false);
+ }
+ }
+
+ // cast from [N]T to []const T
+ if (is_slice(have_child_type) && needed_child_type->id == ZigTypeIdArray) {
+ ZigType *ptr_type = have_child_type->data.structure.fields[slice_ptr_index].type_entry;
+ assert(ptr_type->id == ZigTypeIdPointer);
+ if ((ptr_type->data.pointer.is_const || needed_child_type->data.array.len == 0) &&
+ types_match_const_cast_only(ira, ptr_type->data.pointer.child_type,
+ needed_child_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk)
+ {
+ return ir_analyze_result_slice_ptr(ira, result_loc, needed_child_type->data.array.len, true);
+ }
+ }
+
+ // cast from T to ?T
+ if (have_child_type->id == ZigTypeIdOptional) {
+ if (types_match_const_cast_only(ira, have_child_type->data.maybe.child_type, needed_child_type, source_node,
+ false).id == ConstCastResultIdOk)
+ {
+ return ir_analyze_result_optional_payload(ira, result_loc, needed_child_type, true);
+ }
+ }
+
+ // cast from T to E!T
+ if (have_child_type->id == ZigTypeIdErrorUnion) {
+ if (types_match_const_cast_only(ira, have_child_type->data.error_union.payload_type, needed_child_type,
+ source_node, false).id == ConstCastResultIdOk)
+ {
+ return ir_analyze_result_error_union_payload(ira, result_loc, needed_child_type);
+ }
+ }
+
+ // cast from E to E!T
+ if (have_child_type->id == ZigTypeIdErrorUnion &&
+ needed_child_type->id == ZigTypeIdErrorSet)
{
- if ((err = type_resolve(ira->codegen, actual_type, ResolveStatusZeroBitsKnown))) {
- return ira->codegen->invalid_instruction;
- }
- if (!type_has_bits(actual_type)) {
- return ir_get_ref(ira, source_instr, value, false, false);
- }
+ return ir_analyze_result_error_union_code(ira, result_loc, needed_child_type);
}
+ // cast from T to E!?T
+ if (have_child_type->id == ZigTypeIdErrorUnion &&
+ have_child_type->data.error_union.payload_type->id == ZigTypeIdOptional &&
+ needed_child_type->id != ZigTypeIdOptional)
+ {
+ ZigType *wanted_child_type = have_child_type->data.error_union.payload_type->data.maybe.child_type;
+ if (types_match_const_cast_only(ira, wanted_child_type, needed_child_type, source_node,
+ false).id == ConstCastResultIdOk ||
+ needed_child_type->id == ZigTypeIdNull ||
+ needed_child_type->id == ZigTypeIdComptimeInt ||
+ needed_child_type->id == ZigTypeIdComptimeFloat)
+ {
+ IrInstruction *cast1 = ir_implicit_cast_result(ira, source_node, result_loc,
+ have_child_type->data.error_union.payload_type, allow_failure);
+ if (cast1 == nullptr)
+ return nullptr;
+ if (type_is_invalid(cast1->value.type))
+ return ira->codegen->invalid_instruction;
+
+ return ir_implicit_cast_result(ira, source_node, cast1, needed_child_type, allow_failure);
+ }
+ }
// cast from undefined to anything
- if (actual_type->id == ZigTypeIdUndefined) {
- return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type);
+ if (needed_child_type->id == ZigTypeIdUndefined) {
+ return result_loc;
}
- ErrorMsg *parent_msg = ir_add_error_node(ira, source_instr->source_node,
+ if (allow_failure) {
+ return nullptr;
+ }
+
+ ErrorMsg *parent_msg = ir_add_error_node(ira, source_node,
buf_sprintf("expected type '%s', found '%s'",
- buf_ptr(&wanted_type->name),
- buf_ptr(&actual_type->name)));
- report_recursive_error(ira, source_instr->source_node, &const_cast_result, parent_msg);
+ buf_ptr(&have_child_type->name),
+ buf_ptr(&needed_child_type->name)));
+ report_recursive_error(ira, source_node, &const_cast_result, parent_msg);
return ira->codegen->invalid_instruction;
}
-static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, ZigType *expected_type) {
- assert(value);
- assert(value != ira->codegen->invalid_instruction);
- assert(!expected_type || !type_is_invalid(expected_type));
- assert(value->value.type);
- assert(!type_is_invalid(value->value.type));
- if (expected_type == nullptr)
- return value; // anything will do
- if (expected_type == value->value.type)
- return value; // match
- if (value->value.type->id == ZigTypeIdUnreachable)
- return value;
-
- return ir_analyze_cast(ira, value, expected_type, value);
-}
-
static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) {
Error err;
ZigType *type_entry = ptr->value.type;
@@ -11018,23 +12569,23 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
ZigType *child_type = type_entry->data.pointer.child_type;
// dereferencing a *u0 is comptime known to be 0
if (child_type->id == ZigTypeIdInt && child_type->data.integral.bit_count == 0) {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope,
- source_instruction->source_node, child_type);
+ IrInstruction *result = ir_const(ira, source_instruction, child_type);
init_const_unsigned_negative(&result->value, child_type, 0, false);
return result;
}
+ // if it's infer, that means it's void
+ if (child_type == ira->codegen->builtin_types.entry_infer) {
+ return ir_const_void(ira, source_instruction);
+ }
if (instr_is_comptime(ptr)) {
if (ptr->value.special == ConstValSpecialUndef) {
ir_add_error(ira, ptr, buf_sprintf("attempt to dereference undefined value"));
return ira->codegen->invalid_instruction;
}
- if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst ||
- ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar)
- {
+ if (ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) {
ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
if (pointee->special != ConstValSpecialRuntime) {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope,
- source_instruction->source_node, child_type);
+ IrInstruction *result = ir_const(ira, source_instruction, child_type);
if ((err = ir_read_const_ptr(ira, ira->codegen, source_instruction->source_node, &result->value,
&ptr->value)))
@@ -11046,9 +12597,13 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
}
}
}
- // TODO if the instruction is a const ref instruction we can skip it
+ // if the instruction is a const ref instruction we can skip it
+ if (ptr->id == IrInstructionIdRef) {
+ IrInstructionRef *ref_inst = reinterpret_cast(ptr);
+ return ref_inst->value;
+ }
IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope,
- source_instruction->source_node, ptr);
+ source_instruction->source_node, ptr, nullptr);
load_ptr_instruction->value.type = child_type;
return load_ptr_instruction;
} else {
@@ -11270,7 +12825,14 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio
if (type_is_invalid(value->value.type))
return ir_unreach_error(ira);
- IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type);
+ IrInstruction *result_loc = nullptr;
+ if (instruction->result_loc != nullptr) {
+ result_loc = instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ir_unreach_error(ira);
+ }
+
+ IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->scalar_return_type);
if (type_is_invalid(casted_value->value.type) && ira->explicit_return_type_source_node != nullptr) {
ErrorMsg *msg = ira->codegen->errors.last();
add_error_note(ira->codegen, msg, ira->explicit_return_type_source_node,
@@ -11285,16 +12847,24 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio
ir_add_error(ira, casted_value, buf_sprintf("function returns address of local variable"));
return ir_unreach_error(ira);
}
+
+ if (result_loc != nullptr && instr_is_comptime(result_loc) &&
+ !ir_should_inline(ira->new_irb.exec, instruction->base.scope))
+ {
+ IrInstruction *loaded = ir_get_deref(ira, &instruction->base, result_loc);
+ result_loc->value.special = ConstValSpecialRuntime;
+ ir_analyze_store_ptr(ira, &instruction->base, result_loc, loaded);
+ }
+
IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope,
- instruction->base.source_node, casted_value);
+ instruction->base.source_node, casted_value, nullptr);
result->value.type = ira->codegen->builtin_types.entry_unreachable;
return ir_finish_anal(ira, result);
}
static IrInstruction *ir_analyze_instruction_const(IrAnalyze *ira, IrInstructionConst *instruction) {
IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
- // TODO determine if we need to use copy_const_val here
- result->value = instruction->base.value;
+ copy_const_val(&result->value, &instruction->base.value, true);
return result;
}
@@ -11369,6 +12939,8 @@ static bool optional_value_is_null(ConstExprValue *val) {
if (get_codegen_ptr_type(val->type) != nullptr) {
return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr &&
val->data.x_ptr.data.hard_coded_addr.addr == 0;
+ } else if (is_opt_err_set(val->type)) {
+ return val->data.x_err_set == nullptr;
} else {
return val->data.x_optional == nullptr;
}
@@ -11568,19 +13140,18 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *
if (casted_op2 == ira->codegen->invalid_instruction)
return ira->codegen->invalid_instruction;
- bool requires_comptime;
- switch (type_requires_comptime(ira->codegen, resolved_type)) {
- case ReqCompTimeYes:
- requires_comptime = true;
+ bool one_possible_value;
+ switch (type_has_one_possible_value(ira->codegen, resolved_type)) {
+ case OnePossibleValueInvalid:
+ return ira->codegen->invalid_instruction;
+ case OnePossibleValueYes:
+ one_possible_value = true;
break;
- case ReqCompTimeNo:
- requires_comptime = false;
+ case OnePossibleValueNo:
+ one_possible_value = false;
break;
- case ReqCompTimeInvalid:
- return ira->codegen->invalid_instruction;
}
- bool one_possible_value = !requires_comptime && !type_has_bits(resolved_type);
if (one_possible_value || (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2))) {
ConstExprValue *op1_val = one_possible_value ? &casted_op1->value : ir_resolve_const(ira, casted_op1, UndefBad);
if (op1_val == nullptr)
@@ -12481,16 +14052,12 @@ static IrInstruction *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructio
zig_unreachable();
}
-static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstructionDeclVar *decl_var_instruction) {
+static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
+ IrInstructionDeclVarSrc *decl_var_instruction)
+{
Error err;
ZigVar *var = decl_var_instruction->var;
- IrInstruction *init_value = decl_var_instruction->init_value->child;
- if (type_is_invalid(init_value->value.type)) {
- var->value->type = ira->codegen->builtin_types.entry_invalid;
- return ira->codegen->invalid_instruction;
- }
-
ZigType *explicit_type = nullptr;
IrInstruction *var_type = nullptr;
if (decl_var_instruction->var_type != nullptr) {
@@ -12498,32 +14065,51 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
ZigType *proposed_type = ir_resolve_type(ira, var_type);
explicit_type = validate_var_type(ira->codegen, var_type->source_node, proposed_type);
if (type_is_invalid(explicit_type)) {
- var->value->type = ira->codegen->builtin_types.entry_invalid;
+ var->var_type = ira->codegen->builtin_types.entry_invalid;
return ira->codegen->invalid_instruction;
}
}
AstNode *source_node = decl_var_instruction->base.source_node;
- IrInstruction *casted_init_value = ir_implicit_cast(ira, init_value, explicit_type);
bool is_comptime_var = ir_get_var_is_comptime(var);
bool var_class_requires_const = false;
- ZigType *result_type = casted_init_value->value.type;
+ IrInstruction *var_ptr = decl_var_instruction->ptr->child;
+ if (type_is_invalid(var_ptr->value.type)) {
+ var->var_type = ira->codegen->builtin_types.entry_invalid;
+ return ira->codegen->invalid_instruction;
+ }
+
+ assert(var_ptr->value.type->id == ZigTypeIdPointer);
+
+ ZigType *result_type = var_ptr->value.type->data.pointer.child_type;
if (type_is_invalid(result_type)) {
result_type = ira->codegen->builtin_types.entry_invalid;
} else if (result_type->id == ZigTypeIdUnreachable || result_type->id == ZigTypeIdOpaque) {
ir_add_error_node(ira, source_node,
buf_sprintf("variable of type '%s' not allowed", buf_ptr(&result_type->name)));
result_type = ira->codegen->builtin_types.entry_invalid;
+ } else {
+ if ((err = type_resolve(ira->codegen, result_type, ResolveStatusZeroBitsKnown))) {
+ result_type = ira->codegen->builtin_types.entry_invalid;
+ }
+ }
+
+ ConstExprValue *init_val = nullptr;
+ if (instr_is_comptime(var_ptr) && var_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) {
+ init_val = const_ptr_pointee(ira, ira->codegen, &var_ptr->value, decl_var_instruction->base.source_node);
+ if (is_comptime_var) {
+ var->const_value = init_val;
+ }
}
switch (type_requires_comptime(ira->codegen, result_type)) {
case ReqCompTimeInvalid:
result_type = ira->codegen->builtin_types.entry_invalid;
break;
- case ReqCompTimeYes: {
+ case ReqCompTimeYes:
var_class_requires_const = true;
if (!var->gen_is_const && !is_comptime_var) {
ir_add_error_node(ira, source_node,
@@ -12532,26 +14118,27 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
result_type = ira->codegen->builtin_types.entry_invalid;
}
break;
- }
case ReqCompTimeNo:
- if (casted_init_value->value.special == ConstValSpecialStatic &&
- casted_init_value->value.type->id == ZigTypeIdFn &&
- casted_init_value->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr &&
- casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways)
- {
- var_class_requires_const = true;
- if (!var->src_is_const && !is_comptime_var) {
- ErrorMsg *msg = ir_add_error_node(ira, source_node,
- buf_sprintf("functions marked inline must be stored in const or comptime var"));
- AstNode *proto_node = casted_init_value->value.data.x_ptr.data.fn.fn_entry->proto_node;
- add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here"));
- result_type = ira->codegen->builtin_types.entry_invalid;
+ if (init_val != nullptr) {
+ if (init_val->special == ConstValSpecialStatic &&
+ init_val->type->id == ZigTypeIdFn &&
+ init_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr &&
+ init_val->data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways)
+ {
+ var_class_requires_const = true;
+ if (!var->src_is_const && !is_comptime_var) {
+ ErrorMsg *msg = ir_add_error_node(ira, source_node,
+ buf_sprintf("functions marked inline must be stored in const or comptime var"));
+ AstNode *proto_node = init_val->data.x_ptr.data.fn.fn_entry->proto_node;
+ add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here"));
+ result_type = ira->codegen->builtin_types.entry_invalid;
+ }
}
}
break;
}
- if (var->value->type != nullptr && !is_comptime_var) {
+ if (var->var_type != nullptr && !is_comptime_var) {
// This is at least the second time we've seen this variable declaration during analysis.
// This means that this is actually a different variable due to, e.g. an inline while loop.
// We make a new variable so that it can hold a different type, and so the debug info can
@@ -12573,8 +14160,8 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
// This must be done after possibly creating a new variable above
var->ref_count = 0;
- var->value->type = result_type;
- assert(var->value->type);
+ var->var_type = result_type;
+ assert(var->var_type);
if (type_is_invalid(result_type)) {
return ir_const_void(ira, &decl_var_instruction->base);
@@ -12582,22 +14169,38 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
if (decl_var_instruction->align_value == nullptr) {
if ((err = type_resolve(ira->codegen, result_type, ResolveStatusAlignmentKnown))) {
- var->value->type = ira->codegen->builtin_types.entry_invalid;
+ var->var_type = ira->codegen->builtin_types.entry_invalid;
return ir_const_void(ira, &decl_var_instruction->base);
}
var->align_bytes = get_abi_alignment(ira->codegen, result_type);
} else {
if (!ir_resolve_align(ira, decl_var_instruction->align_value->child, &var->align_bytes)) {
- var->value->type = ira->codegen->builtin_types.entry_invalid;
+ var->var_type = ira->codegen->builtin_types.entry_invalid;
}
}
- if (casted_init_value->value.special != ConstValSpecialRuntime) {
- if (var->mem_slot_index != SIZE_MAX) {
+ if (init_val != nullptr && init_val->special != ConstValSpecialRuntime) {
+ // Resolve ConstPtrMutInfer
+ if (var->gen_is_const) {
+ var_ptr->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
+ } else if (is_comptime_var) {
+ var_ptr->value.data.x_ptr.mut = ConstPtrMutComptimeVar;
+ } else {
+ // we need a runtime ptr but we have a comptime val.
+ // since it's a comptime val there are no instructions for it.
+ // we memcpy the init value here
+ IrInstruction *deref = ir_get_deref(ira, var_ptr, var_ptr);
+ // If this assertion trips, something is wrong with the IR instructions, because
+ // we expected the above deref to return a constant value, but it created a runtime
+ // instruction.
+ assert(deref->value.special != ConstValSpecialRuntime);
+ var_ptr->value.special = ConstValSpecialRuntime;
+ ir_analyze_store_ptr(ira, var_ptr, var_ptr, deref);
+ }
+ if (var_ptr->value.special == ConstValSpecialStatic && var->mem_slot_index != SIZE_MAX) {
assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length);
ConstExprValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index);
- copy_const_val(mem_slot, &casted_init_value->value, !is_comptime_var || var->gen_is_const);
-
+ copy_const_val(mem_slot, init_val, !is_comptime_var || var->gen_is_const);
if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {
return ir_const_void(ira, &decl_var_instruction->base);
}
@@ -12605,7 +14208,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
} else if (is_comptime_var) {
ir_add_error(ira, &decl_var_instruction->base,
buf_sprintf("cannot store runtime value in compile time variable"));
- var->value->type = ira->codegen->builtin_types.entry_invalid;
+ var->var_type = ira->codegen->builtin_types.entry_invalid;
return ira->codegen->invalid_instruction;
}
@@ -12613,9 +14216,8 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruct
if (fn_entry)
fn_entry->variable_list.append(var);
- IrInstruction *result = ir_build_var_decl(&ira->new_irb,
- decl_var_instruction->base.scope, decl_var_instruction->base.source_node,
- var, var_type, nullptr, casted_init_value);
+ IrInstruction *result = ir_build_var_decl_gen(&ira->new_irb, decl_var_instruction->base.scope,
+ decl_var_instruction->base.source_node, var, var_ptr);
result->value.type = ira->codegen->builtin_types.entry_void;
return result;
}
@@ -12882,15 +14484,16 @@ IrInstruction *ir_get_implicit_allocator(IrAnalyze *ira, IrInstruction *source_i
zig_unreachable();
}
-static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *call_instruction, ZigFn *fn_entry, ZigType *fn_type,
- IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, IrInstruction *async_allocator_inst)
+static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *call_instruction, ZigFn *fn_entry,
+ ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count,
+ IrInstruction *async_allocator_inst)
{
Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME);
//Buf *free_field_name = buf_create_from_str("freeFn");
assert(async_allocator_inst->value.type->id == ZigTypeIdPointer);
ZigType *container_type = async_allocator_inst->value.type->data.pointer.child_type;
IrInstruction *field_ptr_inst = ir_analyze_container_field_ptr(ira, alloc_field_name, &call_instruction->base,
- async_allocator_inst, container_type);
+ async_allocator_inst, container_type, false);
if (type_is_invalid(field_ptr_inst->value.type)) {
return ira->codegen->invalid_instruction;
}
@@ -12915,10 +14518,59 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *c
ZigType *promise_type = get_promise_type(ira->codegen, return_type);
ZigType *async_return_type = get_error_union_type(ira->codegen, alloc_fn_error_set_type, promise_type);
- IrInstruction *result = ir_build_call(&ira->new_irb, call_instruction->base.scope, call_instruction->base.source_node,
- fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true, async_allocator_inst, nullptr);
- result->value.type = async_return_type;
- return result;
+ IrInstruction *tmp_stack_space = ir_analyze_alloca(ira, &call_instruction->base, async_return_type,
+ 0, "", false);
+ tmp_stack_space->value.special = ConstValSpecialRuntime;
+ if (type_is_invalid(tmp_stack_space->value.type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *new_call_inst = ir_build_call(&ira->new_irb, call_instruction->base.scope,
+ call_instruction->base.source_node, fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true,
+ async_allocator_inst, nullptr, tmp_stack_space, nullptr, LValNone);
+ new_call_inst->value.type = async_return_type;
+
+ IrInstruction *result_loc = nullptr;
+ if (call_instruction->result_loc != nullptr && call_instruction->result_loc->child != nullptr) {
+ result_loc = call_instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ }
+
+ switch (call_instruction->lval) {
+ case LValNone:
+ return new_call_inst;
+ case LValPtr:
+ return ir_get_ref(ira, &call_instruction->base, new_call_inst, true, false, nullptr);
+ case LValErrorUnionVal: {
+ IrInstruction *call_inst_ref = ir_get_ref(ira, &call_instruction->base, new_call_inst,
+ true, false, nullptr);
+ IrInstruction *payload_ptr = ir_analyze_unwrap_err_payload(ira, &call_instruction->base,
+ call_inst_ref, nullptr, false);
+ IrInstruction *payload_deref = ir_get_deref(ira, &call_instruction->base, payload_ptr);
+ ir_analyze_store_ptr(ira, &call_instruction->base, result_loc, payload_deref);
+ IrInstruction *result = ir_build_unwrap_err_code(&ira->new_irb, call_instruction->base.scope,
+ call_instruction->base.source_node, new_call_inst);
+ result->value.type = get_optional_type(ira->codegen, alloc_fn_error_set_type);
+ return result;
+ }
+ case LValErrorUnionPtr: {
+ IrInstruction *call_inst_ref = ir_get_ref(ira, &call_instruction->base, new_call_inst,
+ true, false, nullptr);
+ IrInstruction *payload_ptr = ir_analyze_unwrap_err_payload(ira, &call_instruction->base,
+ call_inst_ref, nullptr, false);
+ IrInstruction *payload_deref = ir_get_deref(ira, &call_instruction->base, payload_ptr);
+ ir_analyze_store_ptr(ira, &call_instruction->base, result_loc, payload_deref);
+
+ IrInstruction *result = ir_build_error_union_field_error_set(&ira->new_irb,
+ call_instruction->base.scope, call_instruction->base.source_node, new_call_inst, false);
+ result->value.type = get_pointer_to_type(ira->codegen,
+ get_optional_type(ira->codegen, alloc_fn_error_set_type), true);
+ return result;
+ }
+ case LValOptional:
+ zig_panic("TODO");
+ }
+ zig_unreachable();
}
static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node,
@@ -12947,7 +14599,7 @@ static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node
Buf *param_name = param_decl_node->data.param_decl.name;
ZigVar *var = add_variable(ira->codegen, param_decl_node,
- *exec_scope, param_name, true, arg_val, nullptr);
+ *exec_scope, param_name, true, arg_val, nullptr, arg_val->type);
*exec_scope = var->child_scope;
*next_proto_i += 1;
@@ -13005,7 +14657,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
if (!param_name) return false;
if (!is_var_args) {
ZigVar *var = add_variable(ira->codegen, param_decl_node,
- *child_scope, param_name, true, arg_val, nullptr);
+ *child_scope, param_name, true, arg_val, nullptr, arg_val->type);
*child_scope = var->child_scope;
var->shadowable = !comptime_arg;
@@ -13059,9 +14711,7 @@ static ZigVar *get_fn_var_by_index(ZigFn *fn_entry, size_t index) {
return fn_entry->variable_list.at(next_var_i);
}
-static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
- ZigVar *var)
-{
+static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var) {
while (var->next_var != nullptr) {
var = var->next_var;
}
@@ -13070,14 +14720,14 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
assert(ira->codegen->errors.length != 0);
return ira->codegen->invalid_instruction;
}
- if (var->value->type == nullptr || type_is_invalid(var->value->type))
+ if (var->var_type == nullptr || type_is_invalid(var->var_type))
return ira->codegen->invalid_instruction;
bool comptime_var_mem = ir_get_var_is_comptime(var);
ConstExprValue *mem_slot = nullptr;
- if (var->value->special == ConstValSpecialStatic) {
- mem_slot = var->value;
+ if (var->const_value->special == ConstValSpecialStatic) {
+ mem_slot = var->const_value;
} else {
if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const)) {
// find the relevant exec_context
@@ -13103,27 +14753,509 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
} else if (var->gen_is_const) {
ptr_mut = ConstPtrMutComptimeConst;
} else {
- assert(!comptime_var_mem);
- ptr_mut = ConstPtrMutRuntimeVar;
+ assert(!comptime_var_mem);
+ ptr_mut = ConstPtrMutRuntimeVar;
+ }
+ return ir_get_const_ptr(ira, instruction, mem_slot, var->var_type,
+ ptr_mut, is_const, is_volatile, var->align_bytes);
+ }
+ }
+ zig_unreachable();
+ }
+
+no_mem_slot:
+
+ IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb,
+ instruction->scope, instruction->source_node, var);
+ var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->var_type,
+ var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0);
+
+ bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr);
+ var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack;
+
+ return var_ptr_instruction;
+}
+
+static void make_const_ptr_runtime(IrAnalyze *ira, IrInstruction *ptr) {
+ assert(ptr->id != IrInstructionIdConst);
+ bool is_static = (ptr->value.special != ConstValSpecialRuntime);
+ ptr->value.special = ConstValSpecialRuntime;
+ if (!is_static) return;
+ ConstExprValue *val;
+ switch (ptr->value.data.x_ptr.special) {
+ case ConstPtrSpecialInvalid:
+ zig_unreachable();
+ case ConstPtrSpecialHardCodedAddr:
+ case ConstPtrSpecialDiscard:
+ case ConstPtrSpecialFunction:
+ case ConstPtrSpecialNull:
+ return;
+ case ConstPtrSpecialRef:
+ val = ptr->value.data.x_ptr.data.ref.pointee;
+ break;
+ case ConstPtrSpecialBaseArray:
+ val = ptr->value.data.x_ptr.data.base_array.array_val;
+ break;
+ case ConstPtrSpecialBaseStruct:
+ val = ptr->value.data.x_ptr.data.base_struct.struct_val;
+ break;
+ case ConstPtrSpecialBaseErrorUnionCode:
+ val = ptr->value.data.x_ptr.data.base_err_union_code.err_union_val;
+ break;
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ val = ptr->value.data.x_ptr.data.base_err_union_payload.err_union_val;
+ break;
+ case ConstPtrSpecialBaseOptionalPayload:
+ val = ptr->value.data.x_ptr.data.base_optional_payload.optional_val;
+ break;
+ }
+
+ for (;;) {
+ is_static = (val->special != ConstValSpecialRuntime);
+ val->special = ConstValSpecialRuntime;
+ if (!is_static) return;
+
+ switch (val->parent.id) {
+ case ConstParentIdNone:
+ return;
+ case ConstParentIdStruct:
+ val = val->parent.data.p_struct.struct_val;
+ continue;
+ case ConstParentIdErrUnionCode:
+ val = val->parent.data.p_err_union_code.err_union_val;
+ continue;
+ case ConstParentIdErrUnionPayload:
+ val = val->parent.data.p_err_union_payload.err_union_val;
+ continue;
+ case ConstParentIdOptionalPayload:
+ val = val->parent.data.p_optional_payload.optional_val;
+ continue;
+ case ConstParentIdArray:
+ val = val->parent.data.p_array.array_val;
+ continue;
+ case ConstParentIdUnion:
+ val = val->parent.data.p_union.union_val;
+ continue;
+ case ConstParentIdScalar:
+ val = val->parent.data.p_scalar.scalar_val;
+ continue;
+ }
+ zig_unreachable();
+ }
+}
+
+static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *uncasted_ptr, IrInstruction *uncasted_value)
+{
+ Error err;
+ if (uncasted_ptr->value.type->id != ZigTypeIdPointer) {
+ ir_add_error(ira, uncasted_ptr,
+ buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&uncasted_ptr->value.type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ if (uncasted_ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) {
+ return ir_const_void(ira, source_instr);
+ }
+
+ if (uncasted_ptr->value.type->data.pointer.is_const && !source_instr->is_gen && !uncasted_ptr->is_gen) {
+ ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
+ return ira->codegen->invalid_instruction;
+ }
+
+ IrInstruction *ptr = ir_implicit_cast_result(ira, source_instr->source_node,
+ uncasted_ptr, uncasted_value->value.type, true);
+ if (ptr == nullptr) {
+ ptr = uncasted_ptr;
+ }
+ if (type_is_invalid(ptr->value.type))
+ return ira->codegen->invalid_instruction;
+
+ ZigType *child_type = ptr->value.type->data.pointer.child_type;
+ IrInstruction *value = ir_implicit_cast(ira, uncasted_value, child_type);
+ if (type_is_invalid(value->value.type))
+ return ira->codegen->invalid_instruction;
+
+ if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
+ if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst) {
+ ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant"));
+ return ira->codegen->invalid_instruction;
+ }
+ if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar ||
+ ptr->value.data.x_ptr.mut == ConstPtrMutInfer)
+ {
+ if (instr_is_comptime(value)) {
+ ConstExprValue *dest_val = const_ptr_pointee(ira, ira->codegen, &ptr->value, source_instr->source_node);
+ if (dest_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ if (dest_val->special != ConstValSpecialRuntime) {
+ // TODO this allows a value stored to have the original value modified and then
+ // have that affect what should be a copy. We need some kind of advanced copy-on-write
+ // system to make these two tests pass at the same time:
+ // * "string literal used as comptime slice is memoized"
+ // * "comptime modification of const struct field" - except modified to avoid
+ // ConstPtrMutComptimeVar, thus defeating the logic below.
+ bool same_global_refs = ptr->value.data.x_ptr.mut != ConstPtrMutComptimeVar;
+ copy_const_val(dest_val, &value->value, same_global_refs);
+ if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) {
+ switch (type_has_one_possible_value(ira->codegen, child_type)) {
+ case OnePossibleValueInvalid:
+ return ira->codegen->invalid_instruction;
+ case OnePossibleValueNo:
+ ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr;
+ break;
+ case OnePossibleValueYes:
+ break;
+ }
+ }
+ return ir_const_void(ira, source_instr);
+ }
+ }
+ if (ptr->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ make_const_ptr_runtime(ira, ptr);
+ make_const_ptr_runtime(ira, uncasted_ptr);
+ if (get_codegen_ptr_type(value->value.type) != nullptr && ptr->id == IrInstructionIdAllocaGen) {
+ uint32_t child_ptr_alignment;
+ if ((err = resolve_ptr_align(ira, value->value.type, &child_ptr_alignment)))
+ return ira->codegen->invalid_instruction;
+ uint32_t parent_ptr_alignment;
+ if ((err = resolve_ptr_align(ira, ptr->value.type->data.pointer.child_type, &parent_ptr_alignment)))
+ return ira->codegen->invalid_instruction;
+ if (child_ptr_alignment > parent_ptr_alignment) {
+ ptr->value.type = adjust_ptr_child(ira->codegen, ptr->value.type,
+ adjust_ptr_align(ira->codegen, ptr->value.type->data.pointer.child_type, child_ptr_alignment));
+ }
+ }
+ } else {
+ ir_add_error(ira, source_instr,
+ buf_sprintf("cannot store runtime value in compile time variable"));
+ ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
+ dest_val->type = ira->codegen->builtin_types.entry_invalid;
+
+ return ira->codegen->invalid_instruction;
+ }
+ }
+ }
+
+ switch (type_requires_comptime(ira->codegen, child_type)) {
+ case ReqCompTimeInvalid:
+ return ira->codegen->invalid_instruction;
+ case ReqCompTimeYes:
+ switch (type_has_one_possible_value(ira->codegen, ptr->value.type)) {
+ case OnePossibleValueInvalid:
+ return ira->codegen->invalid_instruction;
+ case OnePossibleValueNo:
+ ir_add_error(ira, source_instr,
+ buf_sprintf("cannot store runtime value in type '%s'", buf_ptr(&child_type->name)));
+ return ira->codegen->invalid_instruction;
+ case OnePossibleValueYes:
+ return ir_const_void(ira, source_instr);
+ }
+ zig_unreachable();
+ case ReqCompTimeNo:
+ break;
+ }
+
+ IrInstruction *result = ir_build_store_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node,
+ ptr, value);
+ result->value.type = ira->codegen->builtin_types.entry_void;
+ return result;
+}
+
+// Note this is semantically different from what gets run with ir_build_set_nonnull_bit
+static IrInstruction *ir_analyze_set_non_null_bit(IrAnalyze *ira,
+ IrInstruction *source_instr, IrInstruction *base_ptr, IrInstruction *non_null_bit)
+{
+ ZigType *ptr_type = base_ptr->value.type;
+ assert(ptr_type->id == ZigTypeIdPointer);
+
+ ZigType *opt_type = ptr_type->data.pointer.child_type;
+ if (type_is_invalid(opt_type))
+ return ira->codegen->invalid_instruction;
+
+ if (opt_type->id != ZigTypeIdOptional) {
+ ir_add_error(ira, base_ptr,
+ buf_sprintf("expected optional type, found '%s'", buf_ptr(&opt_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ if (instr_is_comptime(base_ptr)) {
+ zig_panic("TODO comptime set non null bit");
+ }
+
+ assert(handle_is_ptr(opt_type));
+
+ return ir_build_set_nonnull_bit(&ira->new_irb,
+ source_instr->scope, source_instr->source_node, base_ptr, non_null_bit, nullptr);
+}
+
+static IrInstruction *analyze_runtime_call(IrAnalyze *ira, FnTypeId *fn_type_id,
+ IrInstructionCall *call_instruction, ZigFn *fn_entry, IrInstruction *fn_ref, size_t call_param_count,
+ IrInstruction **casted_args, FnInline fn_inline, IrInstruction *casted_new_stack)
+{
+ ZigType *return_type = fn_type_id->return_type;
+
+ // For an optional or error union, this result location is a pointer to the payload field.
+ // For other types this is a base pointer to the value.
+ IrInstruction *payload_result_loc = nullptr;
+ // For an optional or error union, this is a base pointer.
+ // For other types this is the same as payload_result_loc.
+ IrInstruction *base_result_loc = nullptr;
+
+ bool convert_to_value;
+ ZigType *scalar_result_type; // of the call instruction
+ ZigType *payload_result_type; // of the call instruction
+ if (return_type->id == ZigTypeIdErrorUnion) {
+ scalar_result_type = get_optional_type(ira->codegen, return_type->data.error_union.err_set_type);
+ payload_result_type = return_type->data.error_union.payload_type;
+ convert_to_value = call_instruction->lval != LValErrorUnionVal && call_instruction->lval != LValErrorUnionPtr;
+ } else if (return_type->id == ZigTypeIdErrorSet) {
+ scalar_result_type = return_type;
+ payload_result_type = ira->codegen->builtin_types.entry_void;
+ convert_to_value = call_instruction->lval != LValErrorUnionVal && call_instruction->lval != LValErrorUnionPtr;
+ } else if (return_type->id == ZigTypeIdOptional && handle_is_ptr(return_type)) {
+ scalar_result_type = ira->codegen->builtin_types.entry_bool;
+ payload_result_type = return_type->data.maybe.child_type;
+ convert_to_value = call_instruction->lval != LValOptional;
+ } else {
+ payload_result_type = return_type;
+ scalar_result_type = return_type;
+ convert_to_value = false;
+ }
+
+ bool need_store_ptr = !convert_to_value &&
+ (return_type == payload_result_type) && !handle_is_ptr(return_type);
+
+ bool need_unwrap_optional = call_instruction->lval == LValOptional && need_store_ptr &&
+ payload_result_type->id == ZigTypeIdOptional;
+
+ IrInstruction *prev_result_loc = nullptr;
+ if (call_instruction->result_loc != nullptr && call_instruction->result_loc->child != nullptr) {
+ prev_result_loc = call_instruction->result_loc->child;
+ if (prev_result_loc->value.special == ConstValSpecialStatic &&
+ prev_result_loc->value.data.x_ptr.special == ConstPtrSpecialDiscard)
+ {
+ need_store_ptr = false;
+ convert_to_value = false;
+ prev_result_loc = nullptr;
+ }
+ } else {
+ need_store_ptr = false;
+ }
+ if (prev_result_loc == nullptr) {
+ if (return_type->id == ZigTypeIdErrorUnion ||
+ (type_has_bits(return_type) && want_first_arg_sret(ira->codegen, fn_type_id)))
+ {
+ prev_result_loc = ir_analyze_alloca(ira, &call_instruction->base, nullptr, 0, "", false);
+ if (type_is_invalid(prev_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ }
+ }
+
+ bool need_copy = false;
+
+ if (prev_result_loc != nullptr) {
+ if (type_is_invalid(prev_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ if (instr_is_comptime(prev_result_loc)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, prev_result_loc, UndefBad);
+ if (!ptr_val)
+ return ira->codegen->invalid_instruction;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ ptr_val->special = ConstValSpecialRuntime;
+ }
+ }
+
+ if (convert_to_value) {
+ base_result_loc = ir_implicit_cast_result(ira, call_instruction->base.source_node,
+ prev_result_loc, return_type, false);
+ if (type_is_invalid(base_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ if (return_type->id == ZigTypeIdErrorUnion) {
+ payload_result_loc = ir_analyze_unwrap_err_payload(ira, &call_instruction->base,
+ base_result_loc, nullptr, false);
+ if (type_is_invalid(payload_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ } else if (return_type->id == ZigTypeIdErrorSet) {
+ payload_result_loc = nullptr;
+ } else if (return_type->id == ZigTypeIdOptional) {
+ payload_result_loc = ir_analyze_unwrap_optional_payload(ira, &call_instruction->base,
+ base_result_loc, false);
+ if (type_is_invalid(payload_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ } else {
+ zig_unreachable();
+ }
+ } else if (return_type->id != ZigTypeIdErrorSet) {
+ if (need_unwrap_optional) {
+ payload_result_type = payload_result_type->data.maybe.child_type;
+ }
+ payload_result_loc = ir_implicit_cast_result(ira, call_instruction->base.source_node,
+ prev_result_loc, payload_result_type, true);
+ if (payload_result_loc == nullptr) {
+ if (need_store_ptr) {
+ payload_result_loc = prev_result_loc;
+ } else {
+ payload_result_loc = ir_analyze_alloca(ira, &call_instruction->base, payload_result_type,
+ 0, "", false);
+ if (type_is_invalid(payload_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ payload_result_loc->value.special = ConstValSpecialRuntime;
+ need_copy = true;
}
- return ir_get_const_ptr(ira, instruction, mem_slot, var->value->type,
- ptr_mut, is_const, is_volatile, var->align_bytes);
}
+ base_result_loc = payload_result_loc;
+ if (type_is_invalid(payload_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
}
- zig_unreachable();
}
-no_mem_slot:
+ // This instruction, in the case of optional and error union, is always the error code / bool value.
+ // So if the LVal does not match this, we have to emit more instructions to adhere to the expected
+ // types.
+ IrInstruction *new_call_instruction = ir_build_call(&ira->new_irb,
+ call_instruction->base.scope, call_instruction->base.source_node,
+ fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr,
+ casted_new_stack, payload_result_loc, nullptr, LValNone);
+ new_call_instruction->value.type = scalar_result_type;
+ if (scalar_result_type->id == ZigTypeIdUnreachable)
+ return ir_finish_anal(ira, new_call_instruction);
- IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb,
- instruction->scope, instruction->source_node, var);
- var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->value->type,
- var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0);
+ if (need_copy) {
+ IrInstruction *loaded = ir_get_deref(ira, &call_instruction->base, payload_result_loc);
+ if (type_is_invalid(loaded->value.type))
+ return ira->codegen->invalid_instruction;
+ IrInstruction *store_inst = ir_analyze_store_ptr(ira, &call_instruction->base, prev_result_loc, loaded);
+ if (type_is_invalid(store_inst->value.type))
+ return ira->codegen->invalid_instruction;
+ }
- bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr);
- var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack;
+ if (need_store_ptr) {
+ switch (call_instruction->lval) {
+ case LValNone:
+ ir_analyze_store_ptr(ira, &call_instruction->base, payload_result_loc, new_call_instruction);
+ return new_call_instruction;
+ case LValPtr:
+ ir_analyze_store_ptr(ira, &call_instruction->base, payload_result_loc, new_call_instruction);
+ return payload_result_loc;
+ case LValErrorUnionVal: {
+ ir_analyze_store_ptr(ira, &call_instruction->base, payload_result_loc, new_call_instruction);
+ IrInstruction *err_code_ptr = ir_analyze_error_union_field_error_set(ira, &call_instruction->base,
+ payload_result_loc, false);
+ return ir_get_deref(ira, &call_instruction->base, err_code_ptr);
+ }
+ case LValErrorUnionPtr: {
+ ir_analyze_store_ptr(ira, &call_instruction->base, payload_result_loc, new_call_instruction);
+ return ir_analyze_error_union_field_error_set(ira, &call_instruction->base,
+ payload_result_loc, false);
+ }
+ case LValOptional: {
+ IrInstruction *ref = ir_get_ref(ira, &call_instruction->base, new_call_instruction, true, false, nullptr);
+ IrInstruction *payload_ptr = ir_analyze_unwrap_optional_payload(ira, &call_instruction->base, ref, false);
+ IrInstruction *payload = ir_get_deref(ira, &call_instruction->base, payload_ptr);
+ ir_analyze_store_ptr(ira, &call_instruction->base, payload_result_loc, payload);
+ return ir_analyze_test_non_null(ira, &call_instruction->base, new_call_instruction);
+ }
+ }
+ zig_unreachable();
+ }
+ if (!convert_to_value) {
+ switch (call_instruction->lval) {
+ case LValNone:
+ return new_call_instruction;
+ case LValPtr:
+ if (payload_result_loc != nullptr)
+ return payload_result_loc;
+ return ir_get_ref(ira, &call_instruction->base, new_call_instruction, true, false, nullptr);
+ case LValErrorUnionVal: {
+ if (return_type->id == ZigTypeIdErrorUnion || return_type->id == ZigTypeIdErrorSet) {
+ return new_call_instruction;
+ } else {
+ return ir_const(ira, &call_instruction->base, ira->codegen->builtin_types.entry_null);
+ }
+ }
+ case LValErrorUnionPtr: {
+ if (return_type->id == ZigTypeIdErrorUnion || return_type->id == ZigTypeIdErrorSet) {
+ ZigType *err_type;
+ if (return_type->id == ZigTypeIdErrorUnion) {
+ err_type = return_type->data.error_union.err_set_type;
+ } else {
+ assert(return_type->id == ZigTypeIdErrorSet);
+ err_type = return_type;
+ }
+ ZigType *opt_err_type = get_optional_type(ira->codegen, err_type);
+ IrInstruction *err_code_alloca = ir_analyze_alloca(ira, &call_instruction->base,
+ opt_err_type, 0, "err", false);
+ ir_analyze_store_ptr(ira, &call_instruction->base, err_code_alloca, new_call_instruction);
+ return err_code_alloca;
+ } else {
+ IrInstruction *null = ir_const(ira, &call_instruction->base,
+ ira->codegen->builtin_types.entry_null);
+ return ir_get_ref(ira, &call_instruction->base, null, true, false, nullptr);
+ }
+ }
+ case LValOptional:
+ if (return_type->id == ZigTypeIdOptional) {
+ return new_call_instruction;
+ } else {
+ return ir_const_bool(ira, &call_instruction->base, false);
+ }
+ }
+ zig_unreachable();
+ }
- return var_ptr_instruction;
+ if (return_type->id == ZigTypeIdErrorUnion) {
+ IrInstruction *err_code_ptr = ir_analyze_error_union_field_error_set(ira,
+ &call_instruction->base, base_result_loc, false);
+ if (type_is_invalid(err_code_ptr->value.type))
+ return ira->codegen->invalid_instruction;
+ ir_analyze_store_ptr(ira, &call_instruction->base, err_code_ptr, new_call_instruction);
+ switch (call_instruction->lval) {
+ case LValNone:
+ return ir_get_deref(ira, &call_instruction->base, base_result_loc);
+ case LValPtr:
+ return base_result_loc;
+ case LValErrorUnionVal:
+ case LValErrorUnionPtr:
+ zig_unreachable();
+ case LValOptional:
+ // This means incorrectly used optional syntax for error union.
+ zig_panic("TODO");
+ }
+ zig_unreachable();
+ } else if (return_type->id == ZigTypeIdErrorSet) {
+ ir_analyze_store_ptr(ira, &call_instruction->base, base_result_loc, new_call_instruction);
+ switch (call_instruction->lval) {
+ case LValNone:
+ return new_call_instruction;
+ case LValPtr:
+ return base_result_loc;
+ case LValErrorUnionVal:
+ case LValErrorUnionPtr:
+ zig_unreachable();
+ case LValOptional:
+ // This means incorrectly used optional syntax for error union.
+ zig_panic("TODO");
+ }
+ zig_unreachable();
+ } else if (return_type->id == ZigTypeIdOptional) {
+ ir_analyze_set_non_null_bit(ira, &call_instruction->base, base_result_loc, new_call_instruction);
+ switch (call_instruction->lval) {
+ case LValNone:
+ return ir_get_deref(ira, &call_instruction->base, base_result_loc);
+ case LValPtr:
+ return base_result_loc;
+ case LValOptional:
+ zig_unreachable();
+ case LValErrorUnionVal:
+ case LValErrorUnionPtr:
+ // This means incorrectly used error union for optional.
+ zig_panic("TODO");
+ }
+ zig_unreachable();
+ } else {
+ zig_unreachable();
+ }
}
static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
@@ -13270,7 +15402,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
}
bool cacheable = fn_eval_cacheable(exec_scope, return_type);
- IrInstruction *result = nullptr;
+ ConstExprValue *result = nullptr;
if (cacheable) {
auto entry = ira->codegen->memoized_fn_eval_table.maybe_get(exec_scope);
if (entry)
@@ -13286,18 +15418,19 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
if (inferred_err_set_type != nullptr) {
inferred_err_set_type->data.error_set.infer_fn = nullptr;
- if (result->value.type->id == ZigTypeIdErrorUnion) {
- if (result->value.data.x_err_union.err != nullptr) {
+ if (result->type->id == ZigTypeIdErrorUnion) {
+ ErrorTableEntry *err = result->data.x_err_union.error_set->data.x_err_set;
+ if (err != nullptr) {
inferred_err_set_type->data.error_set.err_count = 1;
inferred_err_set_type->data.error_set.errors = allocate(1);
- inferred_err_set_type->data.error_set.errors[0] = result->value.data.x_err_union.err;
+ inferred_err_set_type->data.error_set.errors[0] = err;
}
- ZigType *fn_inferred_err_set_type = result->value.type->data.error_union.err_set_type;
+ ZigType *fn_inferred_err_set_type = result->type->data.error_union.err_set_type;
inferred_err_set_type->data.error_set.err_count = fn_inferred_err_set_type->data.error_set.err_count;
inferred_err_set_type->data.error_set.errors = fn_inferred_err_set_type->data.error_set.errors;
- } else if (result->value.type->id == ZigTypeIdErrorSet) {
- inferred_err_set_type->data.error_set.err_count = result->value.type->data.error_set.err_count;
- inferred_err_set_type->data.error_set.errors = result->value.type->data.error_set.errors;
+ } else if (result->type->id == ZigTypeIdErrorSet) {
+ inferred_err_set_type->data.error_set.err_count = result->type->data.error_set.err_count;
+ inferred_err_set_type->data.error_set.errors = result->type->data.error_set.errors;
}
}
@@ -13305,15 +15438,116 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
ira->codegen->memoized_fn_eval_table.put(exec_scope, result);
}
- if (type_is_invalid(result->value.type))
+ if (type_is_invalid(result->type))
+ return ira->codegen->invalid_instruction;
+ }
+
+ IrInstruction *new_instruction = ir_const(ira, &call_instruction->base, result->type);
+ copy_const_val(&new_instruction->value, result, true);
+
+ if (call_instruction->result_loc != nullptr && call_instruction->result_loc->child != nullptr) {
+ IrInstruction *prev_result_loc = call_instruction->result_loc->child;
+ if (type_is_invalid(prev_result_loc->value.type))
return ira->codegen->invalid_instruction;
+ if (instr_is_comptime(prev_result_loc)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, prev_result_loc, UndefBad);
+ if (!ptr_val)
+ return ira->codegen->invalid_instruction;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ ptr_val->special = ConstValSpecialStatic;
+ }
+ }
+
+ switch (call_instruction->lval) {
+ case LValNone: {
+ IrInstruction *store_inst = ir_analyze_store_ptr(ira, &call_instruction->base,
+ prev_result_loc, new_instruction);
+ if (type_is_invalid(store_inst->value.type))
+ return ira->codegen->invalid_instruction;
+ return ir_finish_anal(ira, ir_const_void(ira, &call_instruction->base));
+ }
+ case LValErrorUnionVal:
+ case LValErrorUnionPtr: {
+ IrInstruction *ref_inst = ir_get_ref(ira, &call_instruction->base, new_instruction,
+ true, false, nullptr);
+ if (type_is_invalid(ref_inst->value.type))
+ return ira->codegen->invalid_instruction;
+ if (new_instruction->value.type->id == ZigTypeIdErrorSet) {
+ IrInstruction *undef = ir_const(ira, &call_instruction->base,
+ ira->codegen->builtin_types.entry_undef);
+ ir_analyze_store_ptr(ira, &call_instruction->base, prev_result_loc, undef);
+ return ir_finish_anal(ira, ref_inst);
+ }
+ IrInstruction *payload_ptr = ir_analyze_unwrap_err_payload(ira,
+ &call_instruction->base, ref_inst, nullptr, false);
+ if (type_is_invalid(payload_ptr->value.type))
+ return ira->codegen->invalid_instruction;
+ IrInstruction *payload = ir_get_deref(ira, &call_instruction->base, payload_ptr);
+ if (type_is_invalid(payload->value.type))
+ return ira->codegen->invalid_instruction;
+ IrInstruction *store_inst = ir_analyze_store_ptr(ira, &call_instruction->base,
+ prev_result_loc, payload);
+ if (type_is_invalid(store_inst->value.type))
+ return ira->codegen->invalid_instruction;
+ assert(new_instruction->value.type->id == ZigTypeIdErrorUnion);
+ ZigType *err_set_type = new_instruction->value.type->data.error_union.err_set_type;
+ ZigType *opt_err_set_type = get_optional_type(ira->codegen, err_set_type);
+ IrInstruction *err_code_ptr = ir_analyze_result_error_union_code(ira, ref_inst,
+ opt_err_set_type);
+ if (type_is_invalid(err_code_ptr->value.type))
+ return ira->codegen->invalid_instruction;
+ if (call_instruction->lval == LValErrorUnionPtr)
+ return ir_finish_anal(ira, err_code_ptr);
+ IrInstruction *err_code = ir_get_deref(ira, &call_instruction->base, err_code_ptr);
+ if (type_is_invalid(err_code->value.type))
+ return ira->codegen->invalid_instruction;
+ return ir_finish_anal(ira, err_code);
+ }
+ case LValOptional: {
+ IrInstruction *ref_inst = ir_get_ref(ira, &call_instruction->base, new_instruction,
+ true, false, nullptr);
+ if (type_is_invalid(ref_inst->value.type))
+ return ira->codegen->invalid_instruction;
+ IrInstruction *payload_ptr = ir_analyze_unwrap_optional_payload(ira,
+ &call_instruction->base, ref_inst, false);
+ if (type_is_invalid(payload_ptr->value.type))
+ return ira->codegen->invalid_instruction;
+ IrInstruction *payload = ir_get_deref(ira, &call_instruction->base, payload_ptr);
+ if (type_is_invalid(payload->value.type))
+ return ira->codegen->invalid_instruction;
+ IrInstruction *store_inst = ir_analyze_store_ptr(ira, &call_instruction->base,
+ prev_result_loc, payload);
+ if (type_is_invalid(store_inst->value.type))
+ return ira->codegen->invalid_instruction;
+ assert(new_instruction->value.type->id == ZigTypeIdOptional);
+ IrInstruction *is_non_null = ir_analyze_test_non_null(ira, &call_instruction->base,
+ new_instruction);
+ if (type_is_invalid(is_non_null->value.type))
+ return ira->codegen->invalid_instruction;
+ return ir_finish_anal(ira, is_non_null);
+ }
+ case LValPtr:
+ zig_panic("TODO");
+ }
+ zig_unreachable();
}
- IrInstruction *new_instruction = ir_const(ira, &call_instruction->base, result->value.type);
- // TODO should we use copy_const_val?
- new_instruction->value = result->value;
- new_instruction->value.type = return_type;
- return ir_finish_anal(ira, new_instruction);
+ switch (call_instruction->lval) {
+ case LValNone:
+ return ir_finish_anal(ira, new_instruction);
+ case LValPtr: {
+ IrInstruction *ref_inst = ir_get_ref(ira, &call_instruction->base, new_instruction,
+ true, false, nullptr);
+ return ir_finish_anal(ira, ref_inst);
+ }
+ case LValErrorUnionPtr:
+ zig_unreachable();
+ case LValErrorUnionVal:
+ zig_unreachable();
+ case LValOptional:
+ zig_unreachable();
+ }
+ zig_unreachable();
}
IrInstruction *casted_new_stack = nullptr;
@@ -13470,18 +15704,21 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
ConstExprValue *var_args_val = create_const_arg_tuple(ira->codegen,
first_var_arg, inst_fn_type_id.param_count);
ZigVar *var = add_variable(ira->codegen, param_decl_node,
- impl_fn->child_scope, param_name, true, var_args_val, nullptr);
+ impl_fn->child_scope, param_name, true, var_args_val, nullptr, var_args_val->type);
impl_fn->child_scope = var->child_scope;
}
if (fn_proto_node->data.fn_proto.align_expr != nullptr) {
- IrInstruction *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope,
+ ConstExprValue *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope,
fn_proto_node->data.fn_proto.align_expr, get_align_amt_type(ira->codegen),
ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota,
nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec);
+ IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb,
+ impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr);
+ const_instruction->base.value = *align_result;
uint32_t align_bytes = 0;
- ir_resolve_align(ira, align_result, &align_bytes);
+ ir_resolve_align(ira, &const_instruction->base, &align_bytes);
impl_fn->align_bytes = align_bytes;
inst_fn_type_id.alignment = align_bytes;
}
@@ -13559,29 +15796,20 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
ira->codegen->fn_defs.append(impl_fn);
}
- ZigType *return_type = impl_fn->type_entry->data.fn.fn_type_id.return_type;
- if (fn_type_can_fail(&impl_fn->type_entry->data.fn.fn_type_id)) {
+ FnTypeId *impl_fn_type_id = &impl_fn->type_entry->data.fn.fn_type_id;
+ if (fn_type_can_fail(impl_fn_type_id)) {
parent_fn_entry->calls_or_awaits_errorable_fn = true;
}
- size_t impl_param_count = impl_fn->type_entry->data.fn.fn_type_id.param_count;
+ size_t impl_param_count = impl_fn_type_id->param_count;
if (call_instruction->is_async) {
IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry,
fn_ref, casted_args, impl_param_count, async_allocator_inst);
- ir_add_alloca(ira, result, result->value.type);
return ir_finish_anal(ira, result);
}
- assert(async_allocator_inst == nullptr);
- IrInstruction *new_call_instruction = ir_build_call(&ira->new_irb,
- call_instruction->base.scope, call_instruction->base.source_node,
- impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline,
- call_instruction->is_async, nullptr, casted_new_stack);
- new_call_instruction->value.type = return_type;
-
- ir_add_alloca(ira, new_call_instruction, return_type);
-
- return ir_finish_anal(ira, new_call_instruction);
+ return analyze_runtime_call(ira, impl_fn_type_id, call_instruction, impl_fn,
+ nullptr, impl_param_count, casted_args, fn_inline, casted_new_stack);
}
ZigFn *parent_fn_entry = exec_fn_entry(ira->new_irb.exec);
@@ -13664,7 +15892,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref,
casted_args, call_param_count, async_allocator_inst);
- ir_add_alloca(ira, result, result->value.type);
return ir_finish_anal(ira, result);
}
@@ -13674,12 +15901,8 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
return ira->codegen->invalid_instruction;
}
- IrInstruction *new_call_instruction = ir_build_call(&ira->new_irb,
- call_instruction->base.scope, call_instruction->base.source_node,
- fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr, casted_new_stack);
- new_call_instruction->value.type = return_type;
- ir_add_alloca(ira, new_call_instruction, return_type);
- return ir_finish_anal(ira, new_call_instruction);
+ return analyze_runtime_call(ira, fn_type_id, call_instruction, fn_entry, fn_ref,
+ call_param_count, casted_args, fn_inline, casted_new_stack);
}
static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCall *call_instruction) {
@@ -13704,12 +15927,100 @@ static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionC
return ira->codegen->invalid_instruction;
}
- IrInstruction *arg = call_instruction->args[0]->child;
+ IrInstruction *first_arg_result_loc = (call_instruction->first_arg_result_loc == nullptr) ?
+ nullptr : call_instruction->first_arg_result_loc->child;
+ if (first_arg_result_loc != nullptr) {
+ IrInstruction *result_loc = call_instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ result_loc = resolve_possible_alloca_inference(ira, result_loc, dest_type);
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ if (is_slice(dest_type)) {
+ if (type_is_invalid(first_arg_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ // If this is a slice cast, this is the equivalent of a container init fields instruction.
+ // Deal with ConstPtrMutInfer.
+ if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ if (instr_is_comptime(first_arg_result_loc)) {
+ result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
+ } else {
+ result_loc->value.special = ConstValSpecialRuntime;
+ }
+ }
+ return ir_const_void(ira, &call_instruction->base);
+ }
+
+ switch (call_instruction->lval) {
+ case LValPtr:
+ zig_unreachable();
+ case LValNone: {
+ IrInstruction *deref = ir_get_deref(ira, &call_instruction->base, result_loc);
+ if (type_is_invalid(deref->value.type))
+ return ira->codegen->invalid_instruction;
+ return ir_finish_anal(ira, deref);
+ }
+ case LValErrorUnionVal: {
+ assert(result_loc != nullptr);
+ IrInstruction *only_arg = call_instruction->args[0]->child;
+ if (type_is_invalid(only_arg->value.type))
+ return ira->codegen->invalid_instruction;
+ if (only_arg->value.type->id == ZigTypeIdErrorSet) {
+ IrInstruction *undef = ir_const(ira, &call_instruction->base,
+ ira->codegen->builtin_types.entry_undef);
+ ir_analyze_store_ptr(ira, &call_instruction->base, result_loc, undef);
+ return ir_finish_anal(ira, only_arg);
+ } else if (only_arg->value.type->id == ZigTypeIdErrorUnion) {
+ zig_panic("TODO");
+ } else {
+ IrInstruction *null = ir_const(ira, &call_instruction->base,
+ ira->codegen->builtin_types.entry_null);
+ return ir_finish_anal(ira, null);
+ }
+ }
+ case LValOptional: {
+ assert(result_loc != nullptr);
+ IrInstruction *only_arg = call_instruction->args[0]->child;
+ if (type_is_invalid(only_arg->value.type))
+ return ira->codegen->invalid_instruction;
+ IrInstruction *true_value = ir_const_bool(ira, &call_instruction->base, true);
+ return ir_finish_anal(ira, true_value);
+ }
+ case LValErrorUnionPtr:
+ zig_panic("TODO");
+ }
+ }
+ IrInstruction *arg_value = call_instruction->args[0]->child;
+ if (type_is_invalid(arg_value->value.type))
+ return ira->codegen->invalid_instruction;
+ IrInstruction *result = ir_implicit_cast(ira, arg_value, dest_type);
+
+ if (call_instruction->result_loc == nullptr || call_instruction->result_loc->child == nullptr) {
+ switch (call_instruction->lval) {
+ case LValNone:
+ return ir_finish_anal(ira, result);
+ case LValPtr: {
+ IrInstruction *ptr_to_result = ir_get_ref(ira, &call_instruction->base, result,
+ true, false, nullptr);
+ return ir_finish_anal(ira, ptr_to_result);
+ }
+ case LValErrorUnionVal:
+ case LValErrorUnionPtr:
+ case LValOptional:
+ zig_unreachable();
+ }
+ }
- IrInstruction *cast_instruction = ir_analyze_cast(ira, &call_instruction->base, dest_type, arg);
- if (type_is_invalid(cast_instruction->value.type))
+ // we must store into the result loc
+ IrInstruction *result_loc = call_instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
return ira->codegen->invalid_instruction;
- return ir_finish_anal(ira, cast_instruction);
+ result_loc = resolve_possible_alloca_inference(ira, result_loc, dest_type);
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ ir_analyze_store_ptr(ira, &call_instruction->base, result_loc, result);
+ return result;
} else if (fn_ref->value.type->id == ZigTypeIdFn) {
ZigFn *fn_table_entry = ir_resolve_fn(ira, fn_ref);
if (fn_table_entry == nullptr)
@@ -13774,6 +16085,13 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
switch (ptr_val->data.x_ptr.special) {
case ConstPtrSpecialInvalid:
zig_unreachable();
+ case ConstPtrSpecialNull:
+ if (dst_size == 0)
+ return ErrorNone;
+ opt_ir_add_error_node(ira, codegen, source_node,
+ buf_sprintf("attempt to read %zu bytes from null pointer",
+ dst_size));
+ return ErrorSemanticAnalyzeFail;
case ConstPtrSpecialRef: {
opt_ir_add_error_node(ira, codegen, source_node,
buf_sprintf("attempt to read %zu bytes from pointer to %s which is %zu bytes",
@@ -13806,6 +16124,9 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
return ErrorNone;
}
case ConstPtrSpecialBaseStruct:
+ case ConstPtrSpecialBaseErrorUnionCode:
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ case ConstPtrSpecialBaseOptionalPayload:
case ConstPtrSpecialDiscard:
case ConstPtrSpecialHardCodedAddr:
case ConstPtrSpecialFunction:
@@ -14001,9 +16322,14 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi
if (!ir_resolve_comptime(ira, cond_br_instruction->is_comptime->child, &is_comptime))
return ir_unreach_error(ira);
- if (is_comptime || instr_is_comptime(condition)) {
+ ZigType *bool_type = ira->codegen->builtin_types.entry_bool;
+ IrInstruction *casted_condition = ir_implicit_cast(ira, condition, bool_type);
+ if (casted_condition == ira->codegen->invalid_instruction)
+ return ir_unreach_error(ira);
+
+ if (is_comptime || instr_is_comptime(casted_condition)) {
bool cond_is_true;
- if (!ir_resolve_bool(ira, condition, &cond_is_true))
+ if (!ir_resolve_bool(ira, casted_condition, &cond_is_true))
return ir_unreach_error(ira);
IrBasicBlock *old_dest_block = cond_is_true ?
@@ -14022,10 +16348,22 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi
return ir_finish_anal(ira, result);
}
- ZigType *bool_type = ira->codegen->builtin_types.entry_bool;
- IrInstruction *casted_condition = ir_implicit_cast(ira, condition, bool_type);
- if (casted_condition == ira->codegen->invalid_instruction)
- return ir_unreach_error(ira);
+ // The if condition is not comptime known. This means we must mark the result location
+ // as runtime known, in case it is ConstPtrMutInfer.
+ if (cond_br_instruction->result_loc != nullptr) {
+ IrInstruction *result_loc = cond_br_instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ir_unreach_error(ira);
+ if (instr_is_comptime(result_loc)) {
+ ConstExprValue *result_ptr = ir_resolve_const(ira, result_loc, UndefBad);
+ if (result_ptr == nullptr)
+ return ir_unreach_error(ira);
+ assert(result_ptr->type->id == ZigTypeIdPointer);
+ if (result_ptr->data.x_ptr.mut == ConstPtrMutInfer) {
+ result_ptr->special = ConstValSpecialRuntime;
+ }
+ }
+ }
assert(cond_br_instruction->then_block != cond_br_instruction->else_block);
IrBasicBlock *new_then_block = ir_get_new_bb_runtime(ira, cond_br_instruction->then_block, &cond_br_instruction->base);
@@ -14038,7 +16376,7 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi
IrInstruction *result = ir_build_cond_br(&ira->new_irb,
cond_br_instruction->base.scope, cond_br_instruction->base.source_node,
- casted_condition, new_then_block, new_else_block, nullptr);
+ casted_condition, new_then_block, new_else_block, nullptr, nullptr);
result->value.type = ira->codegen->builtin_types.entry_unreachable;
return ir_finish_anal(ira, result);
}
@@ -14065,8 +16403,7 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh
if (value->value.special != ConstValSpecialRuntime) {
IrInstruction *result = ir_const(ira, &phi_instruction->base, nullptr);
- // TODO use copy_const_val?
- result->value = value->value;
+ copy_const_val(&result->value, &value->value, true);
return result;
} else {
return value;
@@ -14115,14 +16452,24 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh
if (type_is_invalid(resolved_type))
return ira->codegen->invalid_instruction;
- if (resolved_type->id == ZigTypeIdComptimeFloat ||
- resolved_type->id == ZigTypeIdComptimeInt ||
- resolved_type->id == ZigTypeIdNull ||
- resolved_type->id == ZigTypeIdUndefined)
- {
+ switch (type_has_one_possible_value(ira->codegen, resolved_type)) {
+ case OnePossibleValueInvalid:
+ return ira->codegen->invalid_instruction;
+ case OnePossibleValueYes:
+ return ir_const(ira, &phi_instruction->base, resolved_type);
+ case OnePossibleValueNo:
+ break;
+ }
+
+ switch (type_requires_comptime(ira->codegen, resolved_type)) {
+ case ReqCompTimeInvalid:
+ return ira->codegen->invalid_instruction;
+ case ReqCompTimeYes:
ir_add_error_node(ira, phi_instruction->base.source_node,
- buf_sprintf("unable to infer expression type"));
+ buf_sprintf("values of type '%s' must be comptime known", buf_ptr(&resolved_type->name)));
return ira->codegen->invalid_instruction;
+ case ReqCompTimeNo:
+ break;
}
bool all_stack_ptrs = (resolved_type->id == ZigTypeIdPointer);
@@ -14179,33 +16526,6 @@ static IrInstruction *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstructi
return result;
}
-static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align) {
- assert(ptr_type->id == ZigTypeIdPointer);
- return get_pointer_to_type_extra(g,
- ptr_type->data.pointer.child_type,
- ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
- ptr_type->data.pointer.ptr_len,
- new_align,
- ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes);
-}
-
-static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align) {
- assert(is_slice(slice_type));
- ZigType *ptr_type = adjust_ptr_align(g, slice_type->data.structure.fields[slice_ptr_index].type_entry,
- new_align);
- return get_slice_type(g, ptr_type);
-}
-
-static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) {
- assert(ptr_type->id == ZigTypeIdPointer);
- return get_pointer_to_type_extra(g,
- ptr_type->data.pointer.child_type,
- ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
- ptr_len,
- ptr_type->data.pointer.explicit_alignment,
- ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes);
-}
-
static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionElemPtr *elem_ptr_instruction) {
Error err;
IrInstruction *array_ptr = elem_ptr_instruction->array_ptr->child;
@@ -14369,13 +16689,32 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
if (array_ptr_val == nullptr)
return ira->codegen->invalid_instruction;
+ if (array_ptr_val->special == ConstValSpecialUndef && array_type->id == ZigTypeIdArray) {
+ array_ptr_val->data.x_array.special = ConstArraySpecialNone;
+ array_ptr_val->data.x_array.data.s_none.elements = create_const_vals(array_type->data.array.len);
+ array_ptr_val->special = ConstValSpecialStatic;
+ for (size_t i = 0; i != array_type->data.array.len; i += 1) {
+ ConstExprValue *elem_val = &array_ptr_val->data.x_array.data.s_none.elements[i];
+ elem_val->special = ConstValSpecialUndef;
+ elem_val->type = array_type->data.array.child_type;
+ elem_val->parent.id = ConstParentIdArray;
+ elem_val->parent.data.p_array.array_val = array_ptr_val;
+ elem_val->parent.data.p_array.elem_index = i;
+ }
+ }
+
if (array_ptr_val->special != ConstValSpecialRuntime &&
(array_type->id != ZigTypeIdPointer ||
array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr))
{
if (array_type->id == ZigTypeIdPointer) {
- IrInstruction *result = ir_const(ira, &elem_ptr_instruction->base, return_type);
+ IrInstruction *result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope,
+ elem_ptr_instruction->base.source_node, array_ptr, casted_elem_index, safety_check_on,
+ elem_ptr_instruction->ptr_len);
+ result->is_gen = array_ptr->is_gen;
+ result->value.type = return_type;
ConstExprValue *out_val = &result->value;
+ out_val->special = ConstValSpecialStatic;
out_val->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut;
size_t new_index;
size_t mem_size;
@@ -14412,10 +16751,18 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
}
case ConstPtrSpecialBaseStruct:
zig_panic("TODO elem ptr on a const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO elem ptr on a const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO elem ptr on a const inner error union payload");
+ case ConstPtrSpecialBaseOptionalPayload:
+ zig_panic("TODO elem ptr on a const inner optional payload");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
zig_panic("TODO element ptr of a function casted to a ptr");
+ case ConstPtrSpecialNull:
+ zig_panic("TODO elem ptr on a null pointer");
}
if (new_index >= mem_size) {
ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
@@ -14428,11 +16775,13 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
if (ptr_field->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
IrInstruction *result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope, elem_ptr_instruction->base.source_node,
array_ptr, casted_elem_index, false, elem_ptr_instruction->ptr_len);
+ result->is_gen = array_ptr->is_gen;
result->value.type = return_type;
return result;
}
ConstExprValue *len_field = &array_ptr_val->data.x_struct.fields[slice_len_index];
IrInstruction *result = ir_const(ira, &elem_ptr_instruction->base, return_type);
+ result->is_gen = array_ptr->is_gen;
ConstExprValue *out_val = &result->value;
uint64_t slice_len = bigint_as_unsigned(&len_field->data.x_bigint);
if (index >= slice_len) {
@@ -14465,14 +16814,32 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
}
case ConstPtrSpecialBaseStruct:
zig_panic("TODO elem ptr on a slice backed by const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO elem ptr on a slice backed by const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO elem ptr on a slice backed by const inner error union payload");
+ case ConstPtrSpecialBaseOptionalPayload:
+ zig_panic("TODO elem ptr on a slice backed by const optional payload");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
zig_panic("TODO elem ptr on a slice that was ptrcast from a function");
+ case ConstPtrSpecialNull:
+ zig_panic("TODO elem ptr on a slice has a null pointer");
}
return result;
} else if (array_type->id == ZigTypeIdArray) {
- IrInstruction *result = ir_const(ira, &elem_ptr_instruction->base, return_type);
+ IrInstruction *result;
+ if (orig_array_ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope,
+ elem_ptr_instruction->base.source_node, array_ptr, casted_elem_index,
+ false, elem_ptr_instruction->ptr_len);
+ result->value.type = return_type;
+ result->value.special = ConstValSpecialStatic;
+ } else {
+ result = ir_const(ira, &elem_ptr_instruction->base, return_type);
+ }
+ result->is_gen = array_ptr->is_gen;
ConstExprValue *out_val = &result->value;
out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
out_val->data.x_ptr.mut = orig_array_ptr_val->data.x_ptr.mut;
@@ -14512,6 +16879,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
IrInstruction *result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope, elem_ptr_instruction->base.source_node,
array_ptr, casted_elem_index, safety_check_on, elem_ptr_instruction->ptr_len);
+ result->is_gen = array_ptr->is_gen;
result->value.type = return_type;
return result;
}
@@ -14536,7 +16904,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
IrInstruction *bound_fn_value = ir_build_const_bound_fn(&ira->new_irb, source_instr->scope,
source_instr->source_node, fn_entry, container_ptr);
- return ir_get_ref(ira, source_instr, bound_fn_value, true, false);
+ return ir_get_ref(ira, source_instr, bound_fn_value, true, false, nullptr);
}
}
const char *prefix_name;
@@ -14557,7 +16925,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
}
static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name,
- IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type)
+ IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type, bool initialize)
{
Error err;
@@ -14588,14 +16956,39 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
return ira->codegen->invalid_instruction;
if (type_is_invalid(struct_val->type))
return ira->codegen->invalid_instruction;
+
+ if (struct_val->special == ConstValSpecialUndef) {
+ struct_val->data.x_struct.fields = create_const_vals(bare_type->data.structure.src_field_count);
+ struct_val->special = ConstValSpecialStatic;
+ for (size_t i = 0; i < bare_type->data.structure.src_field_count; i += 1) {
+ ConstExprValue *field_val = &struct_val->data.x_struct.fields[i];
+ field_val->special = ConstValSpecialUndef;
+ field_val->type = bare_type->data.structure.fields[i].type_entry;
+ ConstParent *parent = get_const_val_parent(ira->codegen, field_val);
+ if (parent != nullptr) {
+ parent->id = ConstParentIdStruct;
+ parent->data.p_struct.struct_val = struct_val;
+ parent->data.p_struct.field_index = i;
+ }
+ }
+ }
+ assert(struct_val->special != ConstValSpecialUndef);
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry,
is_const, is_volatile, PtrLenSingle, align_bytes,
(uint32_t)(ptr_bit_offset + field->bit_offset_in_host),
(uint32_t)host_int_bytes_for_result_type);
- IrInstruction *result = ir_const(ira, source_instr, ptr_type);
+ IrInstruction *result;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_struct_field_ptr(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, container_ptr, field);
+ result->value.type = ptr_type;
+ result->value.special = ConstValSpecialStatic;
+ } else {
+ result = ir_const(ira, source_instr, ptr_type);
+ }
ConstExprValue *const_val = &result->value;
const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct;
- const_val->data.x_ptr.mut = container_ptr->value.data.x_ptr.mut;
+ const_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut;
const_val->data.x_ptr.data.base_struct.struct_val = struct_val;
const_val->data.x_ptr.data.base_struct.field_index = field->src_index;
return result;
@@ -14631,22 +17024,35 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
if (type_is_invalid(union_val->type))
return ira->codegen->invalid_instruction;
- TypeUnionField *actual_field = find_union_field_by_tag(bare_type, &union_val->data.x_union.tag);
- if (actual_field == nullptr)
- zig_unreachable();
+ if (union_val->special == ConstValSpecialUndef || initialize) {
+ ConstExprValue *payload_val = create_const_vals(1);
+ payload_val->special = ConstValSpecialUndef;
+ payload_val->type = field->type_entry;
+ ConstParent *parent = get_const_val_parent(ira->codegen, payload_val);
+ if (parent != nullptr) {
+ parent->id = ConstParentIdUnion;
+ parent->data.p_union.union_val = union_val;
+ }
- if (field != actual_field) {
- ir_add_error_node(ira, source_instr->source_node,
- buf_sprintf("accessing union field '%s' while field '%s' is set", buf_ptr(field_name),
- buf_ptr(actual_field->name)));
- return ira->codegen->invalid_instruction;
- }
+ union_val->special = ConstValSpecialStatic;
+ bigint_init_bigint(&union_val->data.x_union.tag, &field->enum_field->value);
+ union_val->data.x_union.payload = payload_val;
+ } else {
+ TypeUnionField *actual_field = find_union_field_by_tag(bare_type, &union_val->data.x_union.tag);
+ if (actual_field == nullptr)
+ zig_unreachable();
+ if (field != actual_field) {
+ ir_add_error_node(ira, source_instr->source_node,
+ buf_sprintf("accessing union field '%s' while field '%s' is set", buf_ptr(field_name),
+ buf_ptr(actual_field->name)));
+ return ira->codegen->invalid_instruction;
+ }
+ }
ConstExprValue *payload_val = union_val->data.x_union.payload;
ZigType *field_type = field->type_entry;
- if (field_type->id == ZigTypeIdVoid) {
- assert(payload_val == nullptr);
+ if (field_type->id == ZigTypeIdVoid && payload_val == nullptr) {
payload_val = create_const_vals(1);
payload_val->special = ConstValSpecialStatic;
payload_val->type = field_type;
@@ -14655,16 +17061,27 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type,
is_const, is_volatile, PtrLenSingle, 0, 0, 0);
- IrInstruction *result = ir_const(ira, source_instr, ptr_type);
+ IrInstruction *result;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, container_ptr, field,
+ IrInstructionUnionFieldPtrIdResultPtr);
+ result->value.type = ptr_type;
+ result->value.special = ConstValSpecialStatic;
+ } else {
+ result = ir_const(ira, source_instr, ptr_type);
+ }
ConstExprValue *const_val = &result->value;
const_val->data.x_ptr.special = ConstPtrSpecialRef;
- const_val->data.x_ptr.mut = container_ptr->value.data.x_ptr.mut;
+ const_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut;
const_val->data.x_ptr.data.ref.pointee = payload_val;
return result;
}
}
- IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, container_ptr, field);
+ IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, container_ptr, field,
+ initialize ? IrInstructionUnionFieldPtrIdResultPtr : IrInstructionUnionFieldPtrIdRef);
result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
PtrLenSingle, 0, 0, 0);
return result;
@@ -14758,7 +17175,37 @@ static ErrorTableEntry *find_err_table_entry(ZigType *err_set_type, Buf *field_n
return nullptr;
}
-static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstructionFieldPtr *field_ptr_instruction) {
+static IrInstruction *ir_analyze_error_literal(IrAnalyze *ira, IrInstruction *source_instr, Buf *name) {
+ ErrorTableEntry *err_entry;
+ auto existing_entry = ira->codegen->error_table.maybe_get(name);
+ if (existing_entry) {
+ err_entry = existing_entry->value;
+ } else {
+ err_entry = allocate(1);
+ err_entry->decl_node = source_instr->source_node;
+ buf_init_from_buf(&err_entry->name, name);
+ size_t error_value_count = ira->codegen->errors_by_index.length;
+ assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)ira->codegen->err_tag_type->data.integral.bit_count));
+ err_entry->value = error_value_count;
+ ira->codegen->errors_by_index.append(err_entry);
+ ira->codegen->err_enumerators.append(ZigLLVMCreateDebugEnumerator(ira->codegen->dbuilder,
+ buf_ptr(name), error_value_count));
+ ira->codegen->error_table.put(name, err_entry);
+ }
+ if (err_entry->set_with_only_this_in_it == nullptr) {
+ err_entry->set_with_only_this_in_it = make_err_set_with_one_item(ira->codegen,
+ source_instr->scope, source_instr->source_node, err_entry);
+ }
+ ZigType *err_set_type = err_entry->set_with_only_this_in_it;
+
+ IrInstruction *result = ir_const(ira, source_instr, err_set_type);
+ result->value.data.x_err_set = err_entry;
+ return result;
+}
+
+static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira,
+ IrInstructionFieldPtr *field_ptr_instruction)
+{
Error err;
IrInstruction *container_ptr = field_ptr_instruction->container_ptr->child;
if (type_is_invalid(container_ptr->value.type))
@@ -14770,6 +17217,16 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
buf_ptr(&container_ptr->value.type->name)));
return ira->codegen->invalid_instruction;
}
+
+ if (field_ptr_instruction->container_type != nullptr) {
+ ZigType *container_type = ir_resolve_type(ira, field_ptr_instruction->container_type->child);
+ if (type_is_invalid(container_type))
+ return ira->codegen->invalid_instruction;
+ container_ptr = resolve_possible_alloca_inference(ira, container_ptr, container_type);
+ if (type_is_invalid(container_ptr->value.type))
+ return ira->codegen->invalid_instruction;
+ }
+
ZigType *container_type = container_ptr->value.type->data.pointer.child_type;
Buf *field_name = field_ptr_instruction->field_name_buffer;
@@ -14790,10 +17247,12 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
if (container_type->id == ZigTypeIdPointer) {
ZigType *bare_type = container_ref_type(container_type);
IrInstruction *container_child = ir_get_deref(ira, &field_ptr_instruction->base, container_ptr);
- IrInstruction *result = ir_analyze_container_field_ptr(ira, field_name, &field_ptr_instruction->base, container_child, bare_type);
+ IrInstruction *result = ir_analyze_container_field_ptr(ira, field_name, &field_ptr_instruction->base,
+ container_child, bare_type, field_ptr_instruction->initialize);
return result;
} else {
- IrInstruction *result = ir_analyze_container_field_ptr(ira, field_name, &field_ptr_instruction->base, container_ptr, container_type);
+ IrInstruction *result = ir_analyze_container_field_ptr(ira, field_name, &field_ptr_instruction->base,
+ container_ptr, container_type, field_ptr_instruction->initialize);
return result;
}
} else if (is_array_ref(container_type)) {
@@ -14909,49 +17368,28 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
buf_ptr(&child_type->name), buf_ptr(field_name)));
return ira->codegen->invalid_instruction;
} else if (child_type->id == ZigTypeIdErrorSet) {
- ErrorTableEntry *err_entry;
- ZigType *err_set_type;
+ bool ptr_is_const = true;
+ bool ptr_is_volatile = false;
if (type_is_global_error_set(child_type)) {
- auto existing_entry = ira->codegen->error_table.maybe_get(field_name);
- if (existing_entry) {
- err_entry = existing_entry->value;
- } else {
- err_entry = allocate(1);
- err_entry->decl_node = field_ptr_instruction->base.source_node;
- buf_init_from_buf(&err_entry->name, field_name);
- size_t error_value_count = ira->codegen->errors_by_index.length;
- assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)ira->codegen->err_tag_type->data.integral.bit_count));
- err_entry->value = error_value_count;
- ira->codegen->errors_by_index.append(err_entry);
- ira->codegen->err_enumerators.append(ZigLLVMCreateDebugEnumerator(ira->codegen->dbuilder,
- buf_ptr(field_name), error_value_count));
- ira->codegen->error_table.put(field_name, err_entry);
- }
- if (err_entry->set_with_only_this_in_it == nullptr) {
- err_entry->set_with_only_this_in_it = make_err_set_with_one_item(ira->codegen,
- field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node,
- err_entry);
- }
- err_set_type = err_entry->set_with_only_this_in_it;
- } else {
- if (!resolve_inferred_error_set(ira->codegen, child_type, field_ptr_instruction->base.source_node)) {
- return ira->codegen->invalid_instruction;
- }
- err_entry = find_err_table_entry(child_type, field_name);
- if (err_entry == nullptr) {
- ir_add_error(ira, &field_ptr_instruction->base,
- buf_sprintf("no error named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&child_type->name)));
- return ira->codegen->invalid_instruction;
- }
- err_set_type = child_type;
+ IrInstruction *value = ir_analyze_error_literal(ira, &field_ptr_instruction->base, field_name);
+ return ir_get_ref(ira, &field_ptr_instruction->base, value,
+ ptr_is_const, ptr_is_volatile, nullptr);
+ }
+ if (!resolve_inferred_error_set(ira->codegen, child_type, field_ptr_instruction->base.source_node)) {
+ return ira->codegen->invalid_instruction;
+ }
+ ErrorTableEntry *err_entry = find_err_table_entry(child_type, field_name);
+ if (err_entry == nullptr) {
+ ir_add_error(ira, &field_ptr_instruction->base,
+ buf_sprintf("no error named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&child_type->name)));
+ return ira->codegen->invalid_instruction;
}
+ ZigType *err_set_type = child_type;
ConstExprValue *const_val = create_const_vals(1);
const_val->special = ConstValSpecialStatic;
const_val->type = err_set_type;
const_val->data.x_err_set = err_entry;
- bool ptr_is_const = true;
- bool ptr_is_volatile = false;
return ir_get_const_ptr(ira, &field_ptr_instruction->base, const_val,
err_set_type, ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0);
} else if (child_type->id == ZigTypeIdInt) {
@@ -15155,74 +17593,36 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc
}
}
-static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *load_ptr_instruction) {
- IrInstruction *ptr = load_ptr_instruction->ptr->child;
- if (type_is_invalid(ptr->value.type))
- return ira->codegen->invalid_instruction;
- return ir_get_deref(ira, &load_ptr_instruction->base, ptr);
-}
-
-static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *store_ptr_instruction) {
- IrInstruction *ptr = store_ptr_instruction->ptr->child;
+static IrInstruction *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *instruction) {
+ IrInstruction *ptr = instruction->ptr->child;
+ if (ptr == nullptr)
+ return ir_const_void(ira, &instruction->base);
if (type_is_invalid(ptr->value.type))
return ira->codegen->invalid_instruction;
- IrInstruction *value = store_ptr_instruction->value->child;
+ IrInstruction *value = instruction->value->child;
if (type_is_invalid(value->value.type))
return ira->codegen->invalid_instruction;
- if (ptr->value.type->id != ZigTypeIdPointer) {
- ir_add_error(ira, ptr,
- buf_sprintf("attempt to dereference non pointer type '%s'", buf_ptr(&ptr->value.type->name)));
- return ira->codegen->invalid_instruction;
- }
-
- if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) {
- return ir_const_void(ira, &store_ptr_instruction->base);
- }
-
- if (ptr->value.type->data.pointer.is_const && !store_ptr_instruction->base.is_gen) {
- ir_add_error(ira, &store_ptr_instruction->base, buf_sprintf("cannot assign to constant"));
- return ira->codegen->invalid_instruction;
- }
-
- ZigType *child_type = ptr->value.type->data.pointer.child_type;
- IrInstruction *casted_value = ir_implicit_cast(ira, value, child_type);
- if (casted_value == ira->codegen->invalid_instruction)
- return ira->codegen->invalid_instruction;
+ return ir_analyze_store_ptr(ira, &instruction->base, ptr, value);
+}
- if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
- if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst) {
- ir_add_error(ira, &store_ptr_instruction->base, buf_sprintf("cannot assign to constant"));
- return ira->codegen->invalid_instruction;
- }
- if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) {
- if (instr_is_comptime(casted_value)) {
- ConstExprValue *dest_val = const_ptr_pointee(ira, ira->codegen, &ptr->value, store_ptr_instruction->base.source_node);
- if (dest_val == nullptr)
- return ira->codegen->invalid_instruction;
- if (dest_val->special != ConstValSpecialRuntime) {
- *dest_val = casted_value->value;
- if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) {
- ira->new_irb.current_basic_block->must_be_comptime_source_instr = &store_ptr_instruction->base;
- }
- return ir_const_void(ira, &store_ptr_instruction->base);
- }
- }
- ir_add_error(ira, &store_ptr_instruction->base,
- buf_sprintf("cannot store runtime value in compile time variable"));
- ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value);
- dest_val->type = ira->codegen->builtin_types.entry_invalid;
+static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *instruction) {
+ IrInstruction *ptr = instruction->ptr->child;
+ if (type_is_invalid(ptr->value.type))
+ return ira->codegen->invalid_instruction;
- return ira->codegen->invalid_instruction;
- }
- }
+ IrInstruction *deref = ir_get_deref(ira, &instruction->base, ptr);
+ if (instruction->result_loc == nullptr || instruction->result_loc->child == nullptr)
+ return deref;
- IrInstruction *result = ir_build_store_ptr(&ira->new_irb,
- store_ptr_instruction->base.scope, store_ptr_instruction->base.source_node,
- ptr, casted_value);
- result->value.type = ira->codegen->builtin_types.entry_void;
- return result;
+ IrInstruction *result_loc = instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ ir_analyze_store_ptr(ira, &instruction->base, result_loc, deref);
+
+ return deref;
}
static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeOf *typeof_instruction) {
@@ -15693,11 +18093,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira,
zig_unreachable();
}
-static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrInstructionTestNonNull *instruction) {
- IrInstruction *value = instruction->value->child;
- if (type_is_invalid(value->value.type))
- return ira->codegen->invalid_instruction;
-
+static IrInstruction *ir_analyze_test_non_null(IrAnalyze *ira, IrInstruction *source_inst, IrInstruction *value) {
ZigType *type_entry = value->value.type;
if (type_entry->id == ZigTypeIdOptional) {
@@ -15706,60 +18102,73 @@ static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIns
if (!maybe_val)
return ira->codegen->invalid_instruction;
- return ir_const_bool(ira, &instruction->base, !optional_value_is_null(maybe_val));
+ return ir_const_bool(ira, source_inst, !optional_value_is_null(maybe_val));
}
IrInstruction *result = ir_build_test_nonnull(&ira->new_irb,
- instruction->base.scope, instruction->base.source_node, value);
+ source_inst->scope, source_inst->source_node, value);
result->value.type = ira->codegen->builtin_types.entry_bool;
return result;
} else if (type_entry->id == ZigTypeIdNull) {
- return ir_const_bool(ira, &instruction->base, false);
+ return ir_const_bool(ira, source_inst, false);
} else {
- return ir_const_bool(ira, &instruction->base, true);
+ return ir_const_bool(ira, source_inst, true);
}
}
-static IrInstruction *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
- IrInstructionUnwrapOptional *unwrap_maybe_instruction)
-{
- IrInstruction *value = unwrap_maybe_instruction->value->child;
+static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrInstructionTestNonNull *instruction) {
+ IrInstruction *value = instruction->value->child;
if (type_is_invalid(value->value.type))
return ira->codegen->invalid_instruction;
- ZigType *ptr_type = value->value.type;
+ return ir_analyze_test_non_null(ira, &instruction->base, value);
+}
+
+static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *base_ptr, bool safety_check_on)
+{
+ ZigType *ptr_type = base_ptr->value.type;
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *type_entry = ptr_type->data.pointer.child_type;
- if (type_is_invalid(type_entry)) {
+ if (type_is_invalid(type_entry))
return ira->codegen->invalid_instruction;
- } else if (type_entry->id != ZigTypeIdOptional) {
- ir_add_error_node(ira, unwrap_maybe_instruction->value->source_node,
+
+ if (type_entry->id != ZigTypeIdOptional) {
+ if (!safety_check_on)
+ return base_ptr;
+ ir_add_error_node(ira, base_ptr->source_node,
buf_sprintf("expected optional type, found '%s'", buf_ptr(&type_entry->name)));
return ira->codegen->invalid_instruction;
}
+
ZigType *child_type = type_entry->data.maybe.child_type;
ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
- if (instr_is_comptime(value)) {
- ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
+ if (instr_is_comptime(base_ptr)) {
+ ConstExprValue *val = ir_resolve_const(ira, base_ptr, UndefBad);
if (!val)
return ira->codegen->invalid_instruction;
- ConstExprValue *maybe_val = const_ptr_pointee(ira, ira->codegen, val, unwrap_maybe_instruction->base.source_node);
+ ConstExprValue *maybe_val = const_ptr_pointee(ira, ira->codegen, val, source_instr->source_node);
if (maybe_val == nullptr)
return ira->codegen->invalid_instruction;
if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) {
if (optional_value_is_null(maybe_val)) {
- ir_add_error(ira, &unwrap_maybe_instruction->base, buf_sprintf("unable to unwrap null"));
+ if (!safety_check_on) {
+ IrInstruction *undef = ir_const_undef(ira, source_instr);
+ IrInstruction *casted_undef = ir_implicit_cast(ira, undef, child_type);
+ return ir_get_ref(ira, source_instr, casted_undef, true, false, nullptr);
+ }
+ ir_add_error(ira, source_instr, buf_sprintf("unable to unwrap null"));
return ira->codegen->invalid_instruction;
}
- IrInstruction *result = ir_const(ira, &unwrap_maybe_instruction->base, result_type);
+ IrInstruction *result = ir_const(ira, source_instr, result_type);
ConstExprValue *out_val = &result->value;
out_val->data.x_ptr.special = ConstPtrSpecialRef;
out_val->data.x_ptr.mut = val->data.x_ptr.mut;
- if (type_is_codegen_pointer(child_type)) {
+ if (types_have_same_zig_comptime_repr(type_entry, child_type)) {
out_val->data.x_ptr.data.ref.pointee = maybe_val;
} else {
out_val->data.x_ptr.data.ref.pointee = maybe_val->data.x_optional;
@@ -15768,13 +18177,61 @@ static IrInstruction *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
}
}
- IrInstruction *result = ir_build_unwrap_maybe(&ira->new_irb,
- unwrap_maybe_instruction->base.scope, unwrap_maybe_instruction->base.source_node,
- value, unwrap_maybe_instruction->safety_check_on);
+ IrInstruction *result = ir_build_optional_unwrap_ptr(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, base_ptr, safety_check_on);
result->value.type = result_type;
return result;
}
+static IrInstruction *ir_analyze_instruction_optional_unwrap_ptr(IrAnalyze *ira,
+ IrInstructionOptionalUnwrapPtr *instruction)
+{
+ IrInstruction *base_ptr = instruction->base_ptr->child;
+ if (type_is_invalid(base_ptr->value.type))
+ return ira->codegen->invalid_instruction;
+
+ return ir_analyze_unwrap_optional_payload(ira, &instruction->base, base_ptr, instruction->safety_check_on);
+}
+
+static IrInstruction *ir_analyze_instruction_optional_unwrap_val(IrAnalyze *ira,
+ IrInstructionOptionalUnwrapVal *instruction)
+{
+ IrInstruction *opt = instruction->opt->child;
+ if (type_is_invalid(opt->value.type))
+ return ira->codegen->invalid_instruction;
+
+ ZigType *opt_type = opt->value.type;
+ if (opt_type->id != ZigTypeIdOptional) {
+ ir_add_error_node(ira, opt->source_node,
+ buf_sprintf("expected optional type, found '%s'", buf_ptr(&opt_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ ZigType *child_type = opt_type->data.maybe.child_type;
+ if (instr_is_comptime(opt)) {
+ ConstExprValue *opt_val = ir_resolve_const(ira, opt, UndefBad);
+ if (!opt_val)
+ return ira->codegen->invalid_instruction;
+ if (optional_value_is_null(opt_val)) {
+ ir_add_error(ira, &instruction->base, buf_sprintf("unable to unwrap null"));
+ return ira->codegen->invalid_instruction;
+ }
+ IrInstruction *result = ir_const(ira, &instruction->base, child_type);
+ if (types_have_same_zig_comptime_repr(opt_val->type, child_type)) {
+ copy_const_val(&result->value, opt_val, false);
+ } else {
+ copy_const_val(&result->value, opt_val->data.x_optional, false);
+ }
+ result->value.type = child_type;
+ return result;
+ }
+
+ IrInstruction *result = ir_build_optional_unwrap_val(&ira->new_irb, instruction->base.scope,
+ instruction->base.source_node, opt, instruction->safety_check_on);
+ result->value.type = child_type;
+ return result;
+}
+
static IrInstruction *ir_analyze_instruction_ctz(IrAnalyze *ira, IrInstructionCtz *ctz_instruction) {
IrInstruction *value = ctz_instruction->value->child;
if (type_is_invalid(value->value.type)) {
@@ -16012,10 +18469,27 @@ static IrInstruction *ir_analyze_instruction_switch_br(IrAnalyze *ira,
new_case->block->ref_instruction = &switch_br_instruction->base;
}
+ // The switch target is not comptime known. This means we must mark the result location
+ // as runtime known, in case it is ConstPtrMutInfer.
+ if (switch_br_instruction->result_loc != nullptr) {
+ IrInstruction *result_loc = switch_br_instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ir_unreach_error(ira);
+ if (instr_is_comptime(result_loc)) {
+ ConstExprValue *result_ptr = ir_resolve_const(ira, result_loc, UndefBad);
+ if (result_ptr == nullptr)
+ return ir_unreach_error(ira);
+ assert(result_ptr->type->id == ZigTypeIdPointer);
+ if (result_ptr->data.x_ptr.mut == ConstPtrMutInfer) {
+ result_ptr->special = ConstValSpecialRuntime;
+ }
+ }
+ }
+
IrBasicBlock *new_else_block = ir_get_new_bb(ira, switch_br_instruction->else_block, &switch_br_instruction->base);
IrInstruction *result = ir_build_switch_br(&ira->new_irb,
switch_br_instruction->base.scope, switch_br_instruction->base.source_node,
- target_value, new_else_block, case_count, cases, nullptr, nullptr);
+ target_value, new_else_block, case_count, cases, nullptr, nullptr, nullptr);
result->value.type = ira->codegen->builtin_types.entry_unreachable;
return ir_finish_anal(ira, result);
}
@@ -16075,9 +18549,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
return result;
}
- IrInstruction *result = ir_build_load_ptr(&ira->new_irb,
- switch_target_instruction->base.scope, switch_target_instruction->base.source_node,
- target_value_ptr);
+ IrInstruction *result = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr);
result->value.type = target_type;
return result;
}
@@ -16107,8 +18579,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
return result;
}
- IrInstruction *union_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
- switch_target_instruction->base.source_node, target_value_ptr);
+ IrInstruction *union_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr);
union_value->value.type = target_type;
IrInstruction *union_tag_inst = ir_build_union_tag(&ira->new_irb, switch_target_instruction->base.scope,
@@ -16132,8 +18603,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira,
return result;
}
- IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
- switch_target_instruction->base.source_node, target_value_ptr);
+ IrInstruction *enum_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr);
enum_value->value.type = target_type;
return enum_value;
}
@@ -16193,7 +18663,8 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru
}
IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb,
- instruction->base.scope, instruction->base.source_node, target_value_ptr, field);
+ instruction->base.scope, instruction->base.source_node, target_value_ptr, field,
+ IrInstructionUnionFieldPtrIdSwitch);
result->value.type = get_pointer_to_type(ira->codegen, field->type_entry,
target_value_ptr->value.type->data.pointer.is_const);
return result;
@@ -16281,16 +18752,24 @@ static IrInstruction *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionRe
IrInstruction *value = ref_instruction->value->child;
if (type_is_invalid(value->value.type))
return ira->codegen->invalid_instruction;
- return ir_get_ref(ira, &ref_instruction->base, value, ref_instruction->is_const, ref_instruction->is_volatile);
+ IrInstruction *result_loc = nullptr;
+ if (ref_instruction->result_loc != nullptr) {
+ result_loc = ref_instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ }
+ return ir_get_ref(ira, &ref_instruction->base, value, ref_instruction->is_const, ref_instruction->is_volatile,
+ result_loc);
}
static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrInstruction *instruction,
- ZigType *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields)
+ ZigType *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields,
+ IrInstruction *result_loc)
{
Error err;
assert(container_type->id == ZigTypeIdUnion);
- if ((err = ensure_complete_type(ira->codegen, container_type)))
+ if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown)))
return ira->codegen->invalid_instruction;
if (instr_field_count != 1) {
@@ -16300,8 +18779,8 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI
}
IrInstructionContainerInitFieldsField *field = &fields[0];
- IrInstruction *field_value = field->value->child;
- if (type_is_invalid(field_value->value.type))
+ IrInstruction *field_result_loc = field->result_loc->child;
+ if (type_is_invalid(field_result_loc->value.type))
return ira->codegen->invalid_instruction;
TypeUnionField *type_field = find_union_type_field(container_type, field->name);
@@ -16315,49 +18794,25 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI
if (type_is_invalid(type_field->type_entry))
return ira->codegen->invalid_instruction;
- IrInstruction *casted_field_value = ir_implicit_cast(ira, field_value, type_field->type_entry);
- if (casted_field_value == ira->codegen->invalid_instruction)
- return ira->codegen->invalid_instruction;
-
- if ((err = type_resolve(ira->codegen, casted_field_value->value.type, ResolveStatusZeroBitsKnown)))
- return ira->codegen->invalid_instruction;
-
- bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope);
- if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime ||
- !type_has_bits(casted_field_value->value.type))
- {
- ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk);
- if (!field_val)
- return ira->codegen->invalid_instruction;
-
- IrInstruction *result = ir_const(ira, instruction, container_type);
- ConstExprValue *out_val = &result->value;
- out_val->data.x_union.payload = field_val;
- out_val->data.x_union.tag = type_field->enum_field->value;
-
- ConstParent *parent = get_const_val_parent(ira->codegen, field_val);
- if (parent != nullptr) {
- parent->id = ConstParentIdUnion;
- parent->data.p_union.union_val = out_val;
+ if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ if (instr_is_comptime(field_result_loc) &&
+ field_result_loc->value.data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
+ } else {
+ result_loc->value.special = ConstValSpecialRuntime;
}
-
- return result;
}
-
- IrInstruction *new_instruction = ir_build_union_init(&ira->new_irb,
- instruction->scope, instruction->source_node,
- container_type, type_field, casted_field_value);
- new_instruction->value.type = container_type;
- ir_add_alloca(ira, new_instruction, container_type);
- return new_instruction;
+ return ir_const_void(ira, instruction);
}
static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction,
- ZigType *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields)
+ ZigType *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields,
+ IrInstruction *result_loc)
{
- Error err;
if (container_type->id == ZigTypeIdUnion) {
- return ir_analyze_container_init_fields_union(ira, instruction, container_type, instr_field_count, fields);
+ return ir_analyze_container_init_fields_union(ira, instruction, container_type, instr_field_count,
+ fields, result_loc);
}
if (container_type->id != ZigTypeIdStruct || is_slice(container_type)) {
ir_add_error(ira, instruction,
@@ -16366,28 +18821,26 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
return ira->codegen->invalid_instruction;
}
- if ((err = ensure_complete_type(ira->codegen, container_type)))
- return ira->codegen->invalid_instruction;
-
size_t actual_field_count = container_type->data.structure.src_field_count;
-
- IrInstruction *first_non_const_instruction = nullptr;
-
AstNode **field_assign_nodes = allocate(actual_field_count);
+ ZigList const_ptrs = {};
+
+ // Here we iterate over the fields that have been initialized, and emit
+ // compile errors for missing fields and duplicate fields.
+ // It is only now that we find out whether the struct initialization can be a comptime
+ // value, but we have already emitted runtime instructions for the fields that
+ // were initialized with runtime values, and have omitted instructions that would have
+ // initialized fields with comptime values.
+ // So now we must clean up this situation. If it turns out the struct initialization can
+ // be a comptime value, overwrite ConstPtrMutInfer with ConstPtrMutComptimeConst.
+ // Otherwise, we must emit instructions to runtime-initialize the fields that have
+ // comptime-known values.
- IrInstructionStructInitField *new_fields = allocate(actual_field_count);
-
- bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope);
-
- ConstExprValue const_val = {};
- const_val.special = ConstValSpecialStatic;
- const_val.type = container_type;
- const_val.data.x_struct.fields = create_const_vals(actual_field_count);
for (size_t i = 0; i < instr_field_count; i += 1) {
IrInstructionContainerInitFieldsField *field = &fields[i];
- IrInstruction *field_value = field->value->child;
- if (type_is_invalid(field_value->value.type))
+ IrInstruction *field_result_loc = field->result_loc->child;
+ if (type_is_invalid(field_result_loc->value.type))
return ira->codegen->invalid_instruction;
TypeStructField *type_field = find_struct_type_field(container_type, field->name);
@@ -16401,10 +18854,6 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
if (type_is_invalid(type_field->type_entry))
return ira->codegen->invalid_instruction;
- IrInstruction *casted_field_value = ir_implicit_cast(ira, field_value, type_field->type_entry);
- if (casted_field_value == ira->codegen->invalid_instruction)
- return ira->codegen->invalid_instruction;
-
size_t field_index = type_field->src_index;
AstNode *existing_assign_node = field_assign_nodes[field_index];
if (existing_assign_node) {
@@ -16414,20 +18863,10 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
}
field_assign_nodes[field_index] = field->source_node;
- new_fields[field_index].value = casted_field_value;
- new_fields[field_index].type_struct_field = type_field;
-
- if (const_val.special == ConstValSpecialStatic) {
- if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime) {
- ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk);
- if (!field_val)
- return ira->codegen->invalid_instruction;
-
- copy_const_val(&const_val.data.x_struct.fields[field_index], field_val, true);
- } else {
- first_non_const_instruction = casted_field_value;
- const_val.special = ConstValSpecialRuntime;
- }
+ if (instr_is_comptime(field_result_loc) &&
+ field_result_loc->value.data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ const_ptrs.append(field_result_loc);
}
}
@@ -16442,171 +18881,127 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc
if (any_missing)
return ira->codegen->invalid_instruction;
- if (const_val.special == ConstValSpecialStatic) {
- IrInstruction *result = ir_const(ira, instruction, nullptr);
- ConstExprValue *out_val = &result->value;
- // TODO copy_const_val?
- *out_val = const_val;
- result->value.type = container_type;
-
- for (size_t i = 0; i < instr_field_count; i += 1) {
- ConstExprValue *field_val = &out_val->data.x_struct.fields[i];
- ConstParent *parent = get_const_val_parent(ira->codegen, field_val);
- if (parent != nullptr) {
- parent->id = ConstParentIdStruct;
- parent->data.p_struct.field_index = i;
- parent->data.p_struct.struct_val = out_val;
+ if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ if (const_ptrs.length == actual_field_count) {
+ result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
+ } else {
+ result_loc->value.special = ConstValSpecialRuntime;
+ for (size_t i = 0; i < const_ptrs.length; i += 1) {
+ IrInstruction *field_result_loc = const_ptrs.at(i);
+ IrInstruction *deref = ir_get_deref(ira, field_result_loc, field_result_loc);
+ field_result_loc->value.special = ConstValSpecialRuntime;
+ ir_analyze_store_ptr(ira, field_result_loc, field_result_loc, deref);
}
}
-
- return result;
- }
-
- if (is_comptime) {
- ir_add_error_node(ira, first_non_const_instruction->source_node,
- buf_sprintf("unable to evaluate constant expression"));
- return ira->codegen->invalid_instruction;
}
- IrInstruction *new_instruction = ir_build_struct_init(&ira->new_irb,
- instruction->scope, instruction->source_node,
- container_type, actual_field_count, new_fields);
- new_instruction->value.type = container_type;
- ir_add_alloca(ira, new_instruction, container_type);
- return new_instruction;
+ return ir_const_void(ira, instruction);
}
static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira,
IrInstructionContainerInitList *instruction)
{
- IrInstruction *container_type_value = instruction->container_type->child;
- if (type_is_invalid(container_type_value->value.type))
+ ZigType *container_type = ir_resolve_type(ira, instruction->container_type->child);
+ if (type_is_invalid(container_type))
return ira->codegen->invalid_instruction;
- size_t elem_count = instruction->item_count;
- if (container_type_value->value.type->id == ZigTypeIdMetaType) {
- ZigType *container_type = ir_resolve_type(ira, container_type_value);
- if (type_is_invalid(container_type))
- return ira->codegen->invalid_instruction;
-
- if (container_type->id == ZigTypeIdStruct && !is_slice(container_type) && elem_count == 0) {
- return ir_analyze_container_init_fields(ira, &instruction->base, container_type,
- 0, nullptr);
- } else if (is_slice(container_type) || container_type->id == ZigTypeIdArray) {
- // array is same as slice init but we make a compile error if the length is wrong
- ZigType *child_type;
- if (container_type->id == ZigTypeIdArray) {
- child_type = container_type->data.array.child_type;
- if (container_type->data.array.len != elem_count) {
- ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count);
-
- ir_add_error(ira, &instruction->base,
- buf_sprintf("expected %s literal, found %s literal",
- buf_ptr(&container_type->name), buf_ptr(&literal_type->name)));
- return ira->codegen->invalid_instruction;
- }
- } else {
- ZigType *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry;
- assert(pointer_type->id == ZigTypeIdPointer);
- child_type = pointer_type->data.pointer.child_type;
- }
-
- ZigType *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count);
+ // handled by IrInstructionInferArrayType
+ assert(!is_slice(container_type));
- ConstExprValue const_val = {};
- const_val.special = ConstValSpecialStatic;
- const_val.type = fixed_size_array_type;
- const_val.data.x_array.data.s_none.elements = create_const_vals(elem_count);
+ IrInstruction *result_loc = instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
- bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope);
+ size_t elem_count = instruction->elem_count;
- IrInstruction **new_items = allocate(elem_count);
+ if (container_type->id == ZigTypeIdStruct && elem_count == 0)
+ return ir_analyze_container_init_fields(ira, &instruction->base, container_type, 0, nullptr, result_loc);
- IrInstruction *first_non_const_instruction = nullptr;
+ if (container_type->id == ZigTypeIdVoid) {
+ if (elem_count != 0) {
+ ir_add_error_node(ira, instruction->base.source_node,
+ buf_sprintf("void expression expects no arguments"));
+ return ira->codegen->invalid_instruction;
+ }
+ return ir_const_void(ira, &instruction->base);
+ }
- for (size_t i = 0; i < elem_count; i += 1) {
- IrInstruction *arg_value = instruction->items[i]->child;
- if (type_is_invalid(arg_value->value.type))
- return ira->codegen->invalid_instruction;
+ if (container_type->id != ZigTypeIdArray) {
+ ir_add_error_node(ira, instruction->base.source_node,
+ buf_sprintf("type '%s' does not support array initialization",
+ buf_ptr(&container_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
- IrInstruction *casted_arg = ir_implicit_cast(ira, arg_value, child_type);
- if (casted_arg == ira->codegen->invalid_instruction)
- return ira->codegen->invalid_instruction;
+ // array is same as slice init but we make a compile error if the length is wrong
+ ZigType *child_type = container_type->data.array.child_type;
+ if (container_type->data.array.len != elem_count) {
+ ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count);
- new_items[i] = casted_arg;
+ ir_add_error(ira, &instruction->base,
+ buf_sprintf("expected %s literal, found %s literal",
+ buf_ptr(&container_type->name), buf_ptr(&literal_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
- if (const_val.special == ConstValSpecialStatic) {
- if (is_comptime || casted_arg->value.special != ConstValSpecialRuntime) {
- ConstExprValue *elem_val = ir_resolve_const(ira, casted_arg, UndefBad);
- if (!elem_val)
- return ira->codegen->invalid_instruction;
+ // The Result Location Mechanism has already emitted runtime instructions to
+ // initialize runtime elements and has omitted instructions for the comptime
+ // elements. However it is only now that we find out whether the array initialization
+ // can be a comptime value. So we must clean up the situation. If it turns out
+ // array initialization can be a comptime value, overwrite ConstPtrMutInfer with
+ // ConstPtrMutComptimeConst. Otherwise, emit instructions to runtime-initialize the
+ // elements that have comptime-known values.
+ ZigList const_ptrs = {};
- copy_const_val(&const_val.data.x_array.data.s_none.elements[i], elem_val, true);
- } else {
- first_non_const_instruction = casted_arg;
- const_val.special = ConstValSpecialRuntime;
- }
- }
- }
+ for (size_t i = 0; i < elem_count; i += 1) {
+ IrInstruction *elem_result_loc = instruction->elem_result_loc_list[i]->child;
+ if (type_is_invalid(elem_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
- if (const_val.special == ConstValSpecialStatic) {
- IrInstruction *result = ir_const(ira, &instruction->base, nullptr);
- ConstExprValue *out_val = &result->value;
- // TODO copy_const_val?
- *out_val = const_val;
- result->value.type = fixed_size_array_type;
- for (size_t i = 0; i < elem_count; i += 1) {
- ConstExprValue *elem_val = &out_val->data.x_array.data.s_none.elements[i];
- ConstParent *parent = get_const_val_parent(ira->codegen, elem_val);
- if (parent != nullptr) {
- parent->id = ConstParentIdArray;
- parent->data.p_array.array_val = out_val;
- parent->data.p_array.elem_index = i;
- }
- }
- return result;
- }
+ assert(elem_result_loc->value.type->id == ZigTypeIdPointer);
- if (is_comptime) {
- ir_add_error_node(ira, first_non_const_instruction->source_node,
- buf_sprintf("unable to evaluate constant expression"));
- return ira->codegen->invalid_instruction;
+ if (instr_is_comptime(elem_result_loc) &&
+ elem_result_loc->value.data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ ConstExprValue *elem_val = const_ptr_pointee_unchecked(ira->codegen, &elem_result_loc->value);
+ if (value_is_comptime(elem_val)) {
+ const_ptrs.append(elem_result_loc);
}
+ }
+ }
- IrInstruction *new_instruction = ir_build_container_init_list(&ira->new_irb,
- instruction->base.scope, instruction->base.source_node,
- container_type_value, elem_count, new_items);
- new_instruction->value.type = fixed_size_array_type;
- ir_add_alloca(ira, new_instruction, fixed_size_array_type);
- return new_instruction;
- } else if (container_type->id == ZigTypeIdVoid) {
- if (elem_count != 0) {
- ir_add_error_node(ira, instruction->base.source_node,
- buf_sprintf("void expression expects no arguments"));
- return ira->codegen->invalid_instruction;
- }
- return ir_const_void(ira, &instruction->base);
+ if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ if (const_ptrs.length == elem_count) {
+ result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
} else {
- ir_add_error_node(ira, instruction->base.source_node,
- buf_sprintf("type '%s' does not support array initialization",
- buf_ptr(&container_type->name)));
- return ira->codegen->invalid_instruction;
+ make_const_ptr_runtime(ira, result_loc);
+ for (size_t i = 0; i < const_ptrs.length; i += 1) {
+ IrInstruction *elem_result_loc = const_ptrs.at(i);
+ assert(elem_result_loc->value.special == ConstValSpecialStatic);
+ IrInstruction *deref = ir_get_deref(ira, elem_result_loc, elem_result_loc);
+ make_const_ptr_runtime(ira, elem_result_loc);
+ ir_analyze_store_ptr(ira, elem_result_loc, elem_result_loc, deref);
+ }
}
- } else {
- ir_add_error(ira, container_type_value,
- buf_sprintf("expected type, found '%s' value", buf_ptr(&container_type_value->value.type->name)));
- return ira->codegen->invalid_instruction;
}
+
+ return ir_const_void(ira, &instruction->base);
}
-static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, IrInstructionContainerInitFields *instruction) {
+static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira,
+ IrInstructionContainerInitFields *instruction)
+{
IrInstruction *container_type_value = instruction->container_type->child;
ZigType *container_type = ir_resolve_type(ira, container_type_value);
if (type_is_invalid(container_type))
return ira->codegen->invalid_instruction;
+ IrInstruction *result_loc = instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
return ir_analyze_container_init_fields(ira, &instruction->base, container_type,
- instruction->field_count, instruction->fields);
+ instruction->field_count, instruction->fields, result_loc);
}
static IrInstruction *ir_analyze_instruction_compile_err(IrAnalyze *ira,
@@ -16659,7 +19054,7 @@ static IrInstruction *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruct
if (type_is_invalid(value->value.type))
return ira->codegen->invalid_instruction;
- IrInstruction *casted_value = ir_implicit_cast(ira, value, value->value.type);
+ IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->codegen->builtin_types.entry_global_error_set);
if (type_is_invalid(casted_value->value.type))
return ira->codegen->invalid_instruction;
@@ -16920,10 +19315,11 @@ static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, Zig
ZigVar *var = tld->var;
- if ((err = ensure_complete_type(ira->codegen, var->value->type)))
+ if ((err = ensure_complete_type(ira->codegen, var->const_value->type)))
return ira->codegen->builtin_types.entry_invalid;
- assert(var->value->type->id == ZigTypeIdMetaType);
- return var->value->data.x_type;
+
+ assert(var->const_value->type->id == ZigTypeIdMetaType);
+ return var->const_value->data.x_type;
}
static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, ScopeDecls *decls_scope) {
@@ -16978,7 +19374,6 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco
definition_array->special = ConstValSpecialStatic;
definition_array->type = get_array_type(ira->codegen, type_info_definition_type, definition_count);
definition_array->data.x_array.special = ConstArraySpecialNone;
- definition_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
definition_array->data.x_array.data.s_none.elements = create_const_vals(definition_count);
init_const_slice(ira->codegen, out_val, definition_array, 0, definition_count, false);
@@ -17009,33 +19404,30 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco
inner_fields[1].data.x_bool = curr_entry->value->visib_mod == VisibModPub;
inner_fields[2].special = ConstValSpecialStatic;
inner_fields[2].type = type_info_definition_data_type;
- inner_fields[2].data.x_union.parent.id = ConstParentIdStruct;
- inner_fields[2].data.x_union.parent.data.p_struct.struct_val = definition_val;
- inner_fields[2].data.x_union.parent.data.p_struct.field_index = 1;
+ inner_fields[2].parent.id = ConstParentIdStruct;
+ inner_fields[2].parent.data.p_struct.struct_val = definition_val;
+ inner_fields[2].parent.data.p_struct.field_index = 1;
switch (curr_entry->value->id) {
case TldIdVar:
{
ZigVar *var = ((TldVar *)curr_entry->value)->var;
- if ((err = ensure_complete_type(ira->codegen, var->value->type)))
+ if ((err = ensure_complete_type(ira->codegen, var->const_value->type)))
return ErrorSemanticAnalyzeFail;
- if (var->value->type->id == ZigTypeIdMetaType)
- {
+ if (var->const_value->type->id == ZigTypeIdMetaType) {
// We have a variable of type 'type', so it's actually a type definition.
// 0: Data.Type: type
bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 0);
- inner_fields[2].data.x_union.payload = var->value;
- }
- else
- {
+ inner_fields[2].data.x_union.payload = var->const_value;
+ } else {
// We have a variable of another type, so we store the type of the variable.
// 1: Data.Var: type
bigint_init_unsigned(&inner_fields[2].data.x_union.tag, 1);
ConstExprValue *payload = create_const_vals(1);
payload->type = ira->codegen->builtin_types.entry_type;
- payload->data.x_type = var->value->type;
+ payload->data.x_type = var->const_value->type;
inner_fields[2].data.x_union.payload = payload;
}
@@ -17055,8 +19447,8 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco
ConstExprValue *fn_def_val = create_const_vals(1);
fn_def_val->special = ConstValSpecialStatic;
fn_def_val->type = type_info_fn_def_type;
- fn_def_val->data.x_struct.parent.id = ConstParentIdUnion;
- fn_def_val->data.x_struct.parent.data.p_union.union_val = &inner_fields[2];
+ fn_def_val->parent.id = ConstParentIdUnion;
+ fn_def_val->parent.data.p_union.union_val = &inner_fields[2];
ConstExprValue *fn_def_fields = create_const_vals(9);
fn_def_val->data.x_struct.fields = fn_def_fields;
@@ -17120,7 +19512,6 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco
fn_arg_name_array->type = get_array_type(ira->codegen,
get_slice_type(ira->codegen, u8_ptr), fn_arg_count);
fn_arg_name_array->data.x_array.special = ConstArraySpecialNone;
- fn_arg_name_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
fn_arg_name_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count);
init_const_slice(ira->codegen, &fn_def_fields[8], fn_arg_name_array, 0, fn_arg_count, false);
@@ -17131,9 +19522,9 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Sco
ConstExprValue *fn_arg_name_val = &fn_arg_name_array->data.x_array.data.s_none.elements[fn_arg_index];
ConstExprValue *arg_name = create_const_str_lit(ira->codegen, &arg_var->name);
init_const_slice(ira->codegen, fn_arg_name_val, arg_name, 0, buf_len(&arg_var->name), true);
- fn_arg_name_val->data.x_struct.parent.id = ConstParentIdArray;
- fn_arg_name_val->data.x_struct.parent.data.p_array.array_val = fn_arg_name_array;
- fn_arg_name_val->data.x_struct.parent.data.p_array.elem_index = fn_arg_index;
+ fn_arg_name_val->parent.id = ConstParentIdArray;
+ fn_arg_name_val->parent.data.p_array.array_val = fn_arg_name_array;
+ fn_arg_name_val->parent.data.p_array.elem_index = fn_arg_index;
}
inner_fields[2].data.x_union.payload = fn_def_val;
@@ -17426,7 +19817,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
enum_field_array->special = ConstValSpecialStatic;
enum_field_array->type = get_array_type(ira->codegen, type_info_enum_field_type, enum_field_count);
enum_field_array->data.x_array.special = ConstArraySpecialNone;
- enum_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
enum_field_array->data.x_array.data.s_none.elements = create_const_vals(enum_field_count);
init_const_slice(ira->codegen, &fields[2], enum_field_array, 0, enum_field_count, false);
@@ -17436,9 +19826,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
TypeEnumField *enum_field = &type_entry->data.enumeration.fields[enum_field_index];
ConstExprValue *enum_field_val = &enum_field_array->data.x_array.data.s_none.elements[enum_field_index];
make_enum_field_val(ira, enum_field_val, enum_field, type_info_enum_field_type);
- enum_field_val->data.x_struct.parent.id = ConstParentIdArray;
- enum_field_val->data.x_struct.parent.data.p_array.array_val = enum_field_array;
- enum_field_val->data.x_struct.parent.data.p_array.elem_index = enum_field_index;
+ enum_field_val->parent.id = ConstParentIdArray;
+ enum_field_val->parent.data.p_array.array_val = enum_field_array;
+ enum_field_val->parent.data.p_array.elem_index = enum_field_index;
}
// defs: []TypeInfo.Definition
ensure_field_index(result->type, "defs", 3);
@@ -17465,7 +19855,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
error_array->special = ConstValSpecialStatic;
error_array->type = get_array_type(ira->codegen, type_info_error_type, error_count);
error_array->data.x_array.special = ConstArraySpecialNone;
- error_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
error_array->data.x_array.data.s_none.elements = create_const_vals(error_count);
init_const_slice(ira->codegen, &fields[0], error_array, 0, error_count, false);
@@ -17489,9 +19878,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
bigint_init_unsigned(&inner_fields[1].data.x_bigint, error->value);
error_val->data.x_struct.fields = inner_fields;
- error_val->data.x_struct.parent.id = ConstParentIdArray;
- error_val->data.x_struct.parent.data.p_array.array_val = error_array;
- error_val->data.x_struct.parent.data.p_array.elem_index = error_index;
+ error_val->parent.id = ConstParentIdArray;
+ error_val->parent.data.p_array.array_val = error_array;
+ error_val->parent.data.p_array.elem_index = error_index;
}
break;
@@ -17560,7 +19949,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
union_field_array->special = ConstValSpecialStatic;
union_field_array->type = get_array_type(ira->codegen, type_info_union_field_type, union_field_count);
union_field_array->data.x_array.special = ConstArraySpecialNone;
- union_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
union_field_array->data.x_array.data.s_none.elements = create_const_vals(union_field_count);
init_const_slice(ira->codegen, &fields[2], union_field_array, 0, union_field_count, false);
@@ -17593,9 +19981,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(union_field->name), true);
union_field_val->data.x_struct.fields = inner_fields;
- union_field_val->data.x_struct.parent.id = ConstParentIdArray;
- union_field_val->data.x_struct.parent.data.p_array.array_val = union_field_array;
- union_field_val->data.x_struct.parent.data.p_array.elem_index = union_field_index;
+ union_field_val->parent.id = ConstParentIdArray;
+ union_field_val->parent.data.p_array.array_val = union_field_array;
+ union_field_val->parent.data.p_array.elem_index = union_field_index;
}
// defs: []TypeInfo.Definition
ensure_field_index(result->type, "defs", 3);
@@ -17635,7 +20023,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
struct_field_array->special = ConstValSpecialStatic;
struct_field_array->type = get_array_type(ira->codegen, type_info_struct_field_type, struct_field_count);
struct_field_array->data.x_array.special = ConstArraySpecialNone;
- struct_field_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
struct_field_array->data.x_array.data.s_none.elements = create_const_vals(struct_field_count);
init_const_slice(ira->codegen, &fields[1], struct_field_array, 0, struct_field_count, false);
@@ -17669,9 +20056,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
init_const_slice(ira->codegen, &inner_fields[0], name, 0, buf_len(struct_field->name), true);
struct_field_val->data.x_struct.fields = inner_fields;
- struct_field_val->data.x_struct.parent.id = ConstParentIdArray;
- struct_field_val->data.x_struct.parent.data.p_array.array_val = struct_field_array;
- struct_field_val->data.x_struct.parent.data.p_array.elem_index = struct_field_index;
+ struct_field_val->parent.id = ConstParentIdArray;
+ struct_field_val->parent.data.p_array.array_val = struct_field_array;
+ struct_field_val->parent.data.p_array.elem_index = struct_field_index;
}
// defs: []TypeInfo.Definition
ensure_field_index(result->type, "defs", 2);
@@ -17741,7 +20128,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
fn_arg_array->special = ConstValSpecialStatic;
fn_arg_array->type = get_array_type(ira->codegen, type_info_fn_arg_type, fn_arg_count);
fn_arg_array->data.x_array.special = ConstArraySpecialNone;
- fn_arg_array->data.x_array.data.s_none.parent.id = ConstParentIdNone;
fn_arg_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count);
init_const_slice(ira->codegen, &fields[5], fn_arg_array, 0, fn_arg_count, false);
@@ -17778,9 +20164,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, ZigType *type_entry, ConstE
}
fn_arg_val->data.x_struct.fields = inner_fields;
- fn_arg_val->data.x_struct.parent.id = ConstParentIdArray;
- fn_arg_val->data.x_struct.parent.data.p_array.array_val = fn_arg_array;
- fn_arg_val->data.x_struct.parent.data.p_array.elem_index = fn_arg_index;
+ fn_arg_val->parent.id = ConstParentIdArray;
+ fn_arg_val->parent.data.p_array.array_val = fn_arg_array;
+ fn_arg_val->parent.data.p_array.elem_index = fn_arg_index;
}
break;
@@ -17824,8 +20210,8 @@ static IrInstruction *ir_analyze_instruction_type_info(IrAnalyze *ira,
if (payload != nullptr) {
assert(payload->type->id == ZigTypeIdStruct);
- payload->data.x_struct.parent.id = ConstParentIdUnion;
- payload->data.x_struct.parent.data.p_union.union_val = out_val;
+ payload->parent.id = ConstParentIdUnion;
+ payload->parent.data.p_union.union_val = out_val;
}
return result;
@@ -17897,10 +20283,10 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct
// Execute the C import block like an inline function
ZigType *void_type = ira->codegen->builtin_types.entry_void;
- IrInstruction *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type,
+ ConstExprValue *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type,
ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr,
&cimport_scope->buf, block_node, nullptr, nullptr);
- if (type_is_invalid(cimport_result->value.type))
+ if (type_is_invalid(cimport_result->type))
return ira->codegen->invalid_instruction;
find_libc_include_path(ira->codegen);
@@ -18050,7 +20436,7 @@ static IrInstruction *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstru
return result;
}
-static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchg *instruction) {
+static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchgSrc *instruction) {
ZigType *operand_type = ir_resolve_atomic_operand_type(ira, instruction->type_value->child);
if (type_is_invalid(operand_type))
return ira->codegen->invalid_instruction;
@@ -18059,6 +20445,13 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi
if (type_is_invalid(ptr->value.type))
return ira->codegen->invalid_instruction;
+ IrInstruction *result_loc = instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ result_loc = resolve_possible_alloca_inference(ira, result_loc, operand_type);
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
// TODO let this be volatile
ZigType *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false);
IrInstruction *casted_ptr = ir_implicit_cast(ira, ptr, ptr_type);
@@ -18122,11 +20515,15 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi
zig_panic("TODO compile-time execution of cmpxchg");
}
- IrInstruction *result = ir_build_cmpxchg(&ira->new_irb, instruction->base.scope, instruction->base.source_node,
- nullptr, casted_ptr, casted_cmp_value, casted_new_value, nullptr, nullptr, instruction->is_weak,
- operand_type, success_order, failure_order);
- result->value.type = get_optional_type(ira->codegen, operand_type);
- ir_add_alloca(ira, result, result->value.type);
+ if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ result_loc->value.special = ConstValSpecialRuntime;
+ }
+
+ IrInstruction *result = ir_build_cmpxchg_gen(&ira->new_irb, instruction->base.scope,
+ instruction->base.source_node,
+ operand_type, casted_ptr, casted_cmp_value, casted_new_value,
+ success_order, failure_order, result_loc, instruction->is_weak);
+ result->value.type = ira->codegen->builtin_types.entry_bool;
return result;
}
@@ -18263,167 +20660,51 @@ static IrInstruction *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstru
}
}
- if (target->value.type->id != ZigTypeIdFloat) {
- ir_add_error(ira, instruction->target, buf_sprintf("expected float type, found '%s'",
- buf_ptr(&target->value.type->name)));
- return ira->codegen->invalid_instruction;
- }
-
- return ir_analyze_widen_or_shorten(ira, &instruction->base, target, dest_type);
-}
-
-static IrInstruction *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstructionErrSetCast *instruction) {
- ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child);
- if (type_is_invalid(dest_type))
- return ira->codegen->invalid_instruction;
-
- if (dest_type->id != ZigTypeIdErrorSet) {
- ir_add_error(ira, instruction->dest_type,
- buf_sprintf("expected error set type, found '%s'", buf_ptr(&dest_type->name)));
- return ira->codegen->invalid_instruction;
- }
-
- IrInstruction *target = instruction->target->child;
- if (type_is_invalid(target->value.type))
- return ira->codegen->invalid_instruction;
-
- if (target->value.type->id != ZigTypeIdErrorSet) {
- ir_add_error(ira, instruction->target,
- buf_sprintf("expected error set type, found '%s'", buf_ptr(&target->value.type->name)));
- return ira->codegen->invalid_instruction;
- }
-
- return ir_analyze_err_set_cast(ira, &instruction->base, target, dest_type);
-}
-
-static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) {
- Error err;
-
- if (ty->id == ZigTypeIdPointer) {
- if ((err = type_resolve(ira->codegen, ty->data.pointer.child_type, ResolveStatusAlignmentKnown)))
- return err;
- }
-
- *result_align = get_ptr_align(ira->codegen, ty);
- return ErrorNone;
-}
-
-static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionFromBytes *instruction) {
- Error err;
-
- ZigType *dest_child_type = ir_resolve_type(ira, instruction->dest_child_type->child);
- if (type_is_invalid(dest_child_type))
- return ira->codegen->invalid_instruction;
-
- IrInstruction *target = instruction->target->child;
- if (type_is_invalid(target->value.type))
- return ira->codegen->invalid_instruction;
-
- bool src_ptr_const;
- bool src_ptr_volatile;
- uint32_t src_ptr_align;
- if (target->value.type->id == ZigTypeIdPointer) {
- src_ptr_const = target->value.type->data.pointer.is_const;
- src_ptr_volatile = target->value.type->data.pointer.is_volatile;
-
- if ((err = resolve_ptr_align(ira, target->value.type, &src_ptr_align)))
- return ira->codegen->invalid_instruction;
- } else if (is_slice(target->value.type)) {
- ZigType *src_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry;
- src_ptr_const = src_ptr_type->data.pointer.is_const;
- src_ptr_volatile = src_ptr_type->data.pointer.is_volatile;
-
- if ((err = resolve_ptr_align(ira, src_ptr_type, &src_ptr_align)))
- return ira->codegen->invalid_instruction;
- } else {
- src_ptr_const = true;
- src_ptr_volatile = false;
-
- if ((err = type_resolve(ira->codegen, target->value.type, ResolveStatusAlignmentKnown)))
- return ira->codegen->invalid_instruction;
-
- src_ptr_align = get_abi_alignment(ira->codegen, target->value.type);
- }
-
- if ((err = type_resolve(ira->codegen, dest_child_type, ResolveStatusSizeKnown)))
- return ira->codegen->invalid_instruction;
-
- ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_child_type,
- src_ptr_const, src_ptr_volatile, PtrLenUnknown,
- src_ptr_align, 0, 0);
- ZigType *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type);
-
- ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
- src_ptr_const, src_ptr_volatile, PtrLenUnknown,
- src_ptr_align, 0, 0);
- ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr);
-
- IrInstruction *casted_value = ir_implicit_cast(ira, target, u8_slice);
- if (type_is_invalid(casted_value->value.type))
- return ira->codegen->invalid_instruction;
-
- bool have_known_len = false;
- uint64_t known_len;
-
- if (instr_is_comptime(casted_value)) {
- ConstExprValue *val = ir_resolve_const(ira, casted_value, UndefBad);
- if (!val)
- return ira->codegen->invalid_instruction;
-
- ConstExprValue *len_val = &val->data.x_struct.fields[slice_len_index];
- if (value_is_comptime(len_val)) {
- known_len = bigint_as_unsigned(&len_val->data.x_bigint);
- have_known_len = true;
- }
- }
-
- if (casted_value->value.data.rh_slice.id == RuntimeHintSliceIdLen) {
- known_len = casted_value->value.data.rh_slice.len;
- have_known_len = true;
- }
-
- if (have_known_len) {
- uint64_t child_type_size = type_size(ira->codegen, dest_child_type);
- uint64_t remainder = known_len % child_type_size;
- if (remainder != 0) {
- ErrorMsg *msg = ir_add_error(ira, &instruction->base,
- buf_sprintf("unable to convert [%" ZIG_PRI_u64 "]u8 to %s: size mismatch",
- known_len, buf_ptr(&dest_slice_type->name)));
- add_error_note(ira->codegen, msg, instruction->dest_child_type->source_node,
- buf_sprintf("%s has size %" ZIG_PRI_u64 "; remaining bytes: %" ZIG_PRI_u64,
- buf_ptr(&dest_child_type->name), child_type_size, remainder));
- return ira->codegen->invalid_instruction;
- }
- }
-
- return ir_resolve_cast(ira, &instruction->base, casted_value, dest_slice_type, CastOpResizeSlice, true);
+ if (target->value.type->id != ZigTypeIdFloat) {
+ ir_add_error(ira, instruction->target, buf_sprintf("expected float type, found '%s'",
+ buf_ptr(&target->value.type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ return ir_analyze_widen_or_shorten(ira, &instruction->base, target, dest_type);
}
-static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstructionToBytes *instruction) {
- Error err;
+static IrInstruction *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstructionErrSetCast *instruction) {
+ ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child);
+ if (type_is_invalid(dest_type))
+ return ira->codegen->invalid_instruction;
+
+ if (dest_type->id != ZigTypeIdErrorSet) {
+ ir_add_error(ira, instruction->dest_type,
+ buf_sprintf("expected error set type, found '%s'", buf_ptr(&dest_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
IrInstruction *target = instruction->target->child;
if (type_is_invalid(target->value.type))
return ira->codegen->invalid_instruction;
- if (!is_slice(target->value.type)) {
+ if (target->value.type->id != ZigTypeIdErrorSet) {
ir_add_error(ira, instruction->target,
- buf_sprintf("expected slice, found '%s'", buf_ptr(&target->value.type->name)));
+ buf_sprintf("expected error set type, found '%s'", buf_ptr(&target->value.type->name)));
return ira->codegen->invalid_instruction;
}
- ZigType *src_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry;
+ return ir_analyze_err_set_cast(ira, &instruction->base, target, dest_type);
+}
- uint32_t alignment;
- if ((err = resolve_ptr_align(ira, src_ptr_type, &alignment)))
- return ira->codegen->invalid_instruction;
+static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) {
+ Error err;
- ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
- src_ptr_type->data.pointer.is_const, src_ptr_type->data.pointer.is_volatile, PtrLenUnknown,
- alignment, 0, 0);
- ZigType *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type);
+ ZigType *ptr_type = get_src_ptr_type(ty);
+ assert(ptr_type != nullptr);
+ if (ptr_type->id == ZigTypeIdPointer) {
+ if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
+ return err;
+ }
- return ir_resolve_cast(ira, &instruction->base, target, dest_slice_type, CastOpResizeSlice, true);
+ *result_align = get_ptr_align(ira->codegen, ty);
+ return ErrorNone;
}
static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) {
@@ -18630,10 +20911,18 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio
}
case ConstPtrSpecialBaseStruct:
zig_panic("TODO memset on const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO memset on const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO memset on const inner error union payload");
+ case ConstPtrSpecialBaseOptionalPayload:
+ zig_panic("TODO memset on const inner optional payload");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
zig_panic("TODO memset on ptr cast from function");
+ case ConstPtrSpecialNull:
+ zig_panic("TODO memset on null ptr");
}
size_t count = bigint_as_unsigned(&casted_count->value.data.x_bigint);
@@ -18745,10 +21034,18 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio
}
case ConstPtrSpecialBaseStruct:
zig_panic("TODO memcpy on const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO memcpy on const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO memcpy on const inner error union payload");
+ case ConstPtrSpecialBaseOptionalPayload:
+ zig_panic("TODO memcpy on const inner optional payload");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
zig_panic("TODO memcpy on ptr cast from function");
+ case ConstPtrSpecialNull:
+ zig_panic("TODO memcpy on null ptr");
}
if (dest_start + count > dest_end) {
@@ -18781,10 +21078,18 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio
}
case ConstPtrSpecialBaseStruct:
zig_panic("TODO memcpy on const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO memcpy on const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO memcpy on const inner error union payload");
+ case ConstPtrSpecialBaseOptionalPayload:
+ zig_panic("TODO memcpy on const inner optional payload");
case ConstPtrSpecialHardCodedAddr:
zig_unreachable();
case ConstPtrSpecialFunction:
zig_panic("TODO memcpy on ptr cast from function");
+ case ConstPtrSpecialNull:
+ zig_panic("TODO memcpy on null ptr");
}
if (src_start + count > src_end) {
@@ -18812,9 +21117,9 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
if (type_is_invalid(ptr_ptr->value.type))
return ira->codegen->invalid_instruction;
- ZigType *ptr_type = ptr_ptr->value.type;
- assert(ptr_type->id == ZigTypeIdPointer);
- ZigType *array_type = ptr_type->data.pointer.child_type;
+ ZigType *ptr_ptr_type = ptr_ptr->value.type;
+ assert(ptr_ptr_type->id == ZigTypeIdPointer);
+ ZigType *array_type = ptr_ptr_type->data.pointer.child_type;
IrInstruction *start = instruction->start->child;
if (type_is_invalid(start->value.type))
@@ -18837,46 +21142,60 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
end = nullptr;
}
- ZigType *return_type;
+ ZigType *slice_ptr_type;
+ IrInstruction *ptr;
if (array_type->id == ZigTypeIdArray) {
bool is_comptime_const = ptr_ptr->value.special == ConstValSpecialStatic &&
ptr_ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst;
- ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.array.child_type,
- ptr_type->data.pointer.is_const || is_comptime_const,
- ptr_type->data.pointer.is_volatile,
+ slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.array.child_type,
+ ptr_ptr_type->data.pointer.is_const || is_comptime_const,
+ ptr_ptr_type->data.pointer.is_volatile,
PtrLenUnknown,
- ptr_type->data.pointer.explicit_alignment, 0, 0);
- return_type = get_slice_type(ira->codegen, slice_ptr_type);
+ ptr_ptr_type->data.pointer.explicit_alignment, 0, 0);
+ ptr = ptr_ptr;
} else if (array_type->id == ZigTypeIdPointer) {
+ ptr = ir_get_deref(ira, &instruction->base, ptr_ptr);
+ if (type_is_invalid(ptr->value.type))
+ return ira->codegen->invalid_instruction;
+
if (array_type->data.pointer.ptr_len == PtrLenSingle) {
ZigType *main_type = array_type->data.pointer.child_type;
if (main_type->id == ZigTypeIdArray) {
- ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen,
+ slice_ptr_type = get_pointer_to_type_extra(ira->codegen,
main_type->data.pointer.child_type,
array_type->data.pointer.is_const, array_type->data.pointer.is_volatile,
PtrLenUnknown,
array_type->data.pointer.explicit_alignment, 0, 0);
- return_type = get_slice_type(ira->codegen, slice_ptr_type);
} else {
ir_add_error(ira, &instruction->base, buf_sprintf("slice of single-item pointer"));
return ira->codegen->invalid_instruction;
}
} else {
- return_type = get_slice_type(ira->codegen, array_type);
+ slice_ptr_type = array_type;
if (!end) {
ir_add_error(ira, &instruction->base, buf_sprintf("slice of pointer must include end value"));
return ira->codegen->invalid_instruction;
}
}
} else if (is_slice(array_type)) {
- ZigType *ptr_type = array_type->data.structure.fields[slice_ptr_index].type_entry;
- return_type = get_slice_type(ira->codegen, ptr_type);
+ ptr = ir_get_deref(ira, &instruction->base, ptr_ptr);
+ if (type_is_invalid(ptr->value.type))
+ return ira->codegen->invalid_instruction;
+ slice_ptr_type = array_type->data.structure.fields[slice_ptr_index].type_entry;
} else {
ir_add_error(ira, &instruction->base,
buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name)));
return ira->codegen->invalid_instruction;
}
+ ZigType *return_type = get_slice_type(ira->codegen, slice_ptr_type);
+
+ IrInstruction *result_loc = instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ result_loc = resolve_possible_alloca_inference(ira, result_loc, return_type);
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
if (instr_is_comptime(ptr_ptr) &&
value_is_comptime(&casted_start->value) &&
@@ -18944,6 +21263,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
break;
case ConstPtrSpecialBaseStruct:
zig_panic("TODO slice const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO slice const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO slice const inner error union payload");
+ case ConstPtrSpecialBaseOptionalPayload:
+ zig_panic("TODO slice const inner optional payload");
case ConstPtrSpecialHardCodedAddr:
array_val = nullptr;
abs_offset = 0;
@@ -18951,6 +21276,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
break;
case ConstPtrSpecialFunction:
zig_panic("TODO slice of ptr cast from function");
+ case ConstPtrSpecialNull:
+ zig_panic("TODO slice of null ptr");
}
} else if (is_slice(array_type)) {
ConstExprValue *slice_ptr = const_ptr_pointee(ira, ira->codegen, &ptr_ptr->value, instruction->base.source_node);
@@ -18981,6 +21308,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
break;
case ConstPtrSpecialBaseStruct:
zig_panic("TODO slice const inner struct");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO slice const inner error union code");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO slice const inner error union payload");
+ case ConstPtrSpecialBaseOptionalPayload:
+ zig_panic("TODO slice const inner optional payload");
case ConstPtrSpecialHardCodedAddr:
array_val = nullptr;
abs_offset = 0;
@@ -18988,6 +21321,8 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
break;
case ConstPtrSpecialFunction:
zig_panic("TODO slice of slice cast from function");
+ case ConstPtrSpecialNull:
+ zig_panic("TODO slice of null");
}
} else {
zig_unreachable();
@@ -19053,6 +21388,12 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
zig_unreachable();
case ConstPtrSpecialBaseStruct:
zig_panic("TODO");
+ case ConstPtrSpecialBaseErrorUnionCode:
+ zig_panic("TODO");
+ case ConstPtrSpecialBaseErrorUnionPayload:
+ zig_panic("TODO");
+ case ConstPtrSpecialBaseOptionalPayload:
+ zig_panic("TODO");
case ConstPtrSpecialHardCodedAddr:
init_const_ptr_hard_coded_addr(ira->codegen, ptr_val,
parent_ptr->type->data.pointer.child_type,
@@ -19061,19 +21402,34 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
break;
case ConstPtrSpecialFunction:
zig_panic("TODO");
+ case ConstPtrSpecialNull:
+ zig_panic("TODO");
}
ConstExprValue *len_val = &out_val->data.x_struct.fields[slice_len_index];
init_const_usize(ira->codegen, len_val, end_scalar - start_scalar);
+ if (result_loc->value.special != ConstValSpecialRuntime) {
+ return ir_analyze_store_ptr(ira, &instruction->base, result_loc, result);
+ }
+
return result;
}
+ if (instr_is_comptime(result_loc)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, result_loc, UndefBad);
+ if (!ptr_val)
+ return ira->codegen->invalid_instruction;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ ptr_val->special = ConstValSpecialRuntime;
+ }
+ }
+
IrInstruction *new_instruction = ir_build_slice(&ira->new_irb,
instruction->base.scope, instruction->base.source_node,
- ptr_ptr, casted_start, end, instruction->safety_check_on);
+ ptr, casted_start, end, instruction->safety_check_on,
+ result_loc);
new_instruction->value.type = return_type;
- ir_add_alloca(ira, new_instruction, return_type);
return new_instruction;
}
@@ -19416,7 +21772,8 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct
return ira->codegen->invalid_instruction;
if (err_union_val->special != ConstValSpecialRuntime) {
- return ir_const_bool(ira, &instruction->base, (err_union_val->data.x_err_union.err != nullptr));
+ ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set;
+ return ir_const_bool(ira, &instruction->base, (err != nullptr));
}
}
@@ -19442,105 +21799,265 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct
}
}
-static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira,
- IrInstructionUnwrapErrCode *instruction)
+static IrInstruction *ir_analyze_error_union_field_error_set(IrAnalyze *ira,
+ IrInstruction *source_instr, IrInstruction *base_ptr, bool safety_check_on)
{
- IrInstruction *value = instruction->value->child;
- if (type_is_invalid(value->value.type))
- return ira->codegen->invalid_instruction;
- ZigType *ptr_type = value->value.type;
-
- // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing.
+ ZigType *ptr_type = base_ptr->value.type;
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *type_entry = ptr_type->data.pointer.child_type;
- if (type_is_invalid(type_entry)) {
+ if (type_is_invalid(type_entry))
return ira->codegen->invalid_instruction;
- } else if (type_entry->id == ZigTypeIdErrorUnion) {
- if (instr_is_comptime(value)) {
- ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
- if (!ptr_val)
- return ira->codegen->invalid_instruction;
- ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node);
- if (err_union_val == nullptr)
- return ira->codegen->invalid_instruction;
- if (err_union_val->special != ConstValSpecialRuntime) {
- ErrorTableEntry *err = err_union_val->data.x_err_union.err;
- assert(err);
- IrInstruction *result = ir_const(ira, &instruction->base,
- type_entry->data.error_union.err_set_type);
- result->value.data.x_err_set = err;
- return result;
- }
+ if (type_entry->id == ZigTypeIdErrorSet) {
+ return base_ptr;
+ }
+ if (type_entry->id != ZigTypeIdErrorUnion) {
+ if (!safety_check_on) {
+ IrInstruction *null = ir_const(ira, source_instr, ira->codegen->builtin_types.entry_null);
+ return ir_get_ref(ira, source_instr, null, true, true, nullptr);
}
-
- IrInstruction *result = ir_build_unwrap_err_code(&ira->new_irb,
- instruction->base.scope, instruction->base.source_node, value);
- result->value.type = type_entry->data.error_union.err_set_type;
- return result;
- } else {
- ir_add_error(ira, value,
+ ir_add_error(ira, base_ptr,
buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name)));
return ira->codegen->invalid_instruction;
}
+
+ ZigType *err_set_type = type_entry->data.error_union.err_set_type;
+ ZigType *opt_err_set = get_optional_type(ira->codegen, err_set_type);
+ ZigType *result_type = get_pointer_to_type_extra(ira->codegen, opt_err_set,
+ ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle,
+ ptr_type->data.pointer.explicit_alignment, 0, 0);
+
+ if (!resolve_inferred_error_set(ira->codegen, err_set_type, source_instr->source_node))
+ return ira->codegen->invalid_instruction;
+ if (err_set_type->data.error_set.err_count == 0) {
+ IrInstruction *null = ir_const(ira, source_instr, ira->codegen->builtin_types.entry_null);
+ return ir_get_ref(ira, source_instr, null, true, true, nullptr);
+ }
+
+ if (instr_is_comptime(base_ptr)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad);
+ if (!ptr_val)
+ return ira->codegen->invalid_instruction;
+ if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
+ ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node);
+ if (err_union_val->special == ConstValSpecialUndef) {
+ ConstExprValue *vals = create_const_vals(2);
+ ConstExprValue *err_set_val = &vals[0];
+ ConstExprValue *payload_val = &vals[1];
+
+ err_set_val->special = ConstValSpecialUndef;
+ err_set_val->type = opt_err_set;
+
+ payload_val->special = ConstValSpecialUndef;
+ payload_val->type = type_entry->data.error_union.payload_type;
+
+ err_union_val->special = ConstValSpecialStatic;
+ err_union_val->data.x_err_union.error_set = err_set_val;
+ err_union_val->data.x_err_union.payload = payload_val;
+ }
+
+ IrInstruction *result;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_error_union_field_error_set(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, base_ptr, safety_check_on);
+ result->value.type = result_type;
+ result->value.special = ConstValSpecialStatic;
+ } else {
+ result = ir_const(ira, source_instr, result_type);
+ }
+ ConstExprValue *const_val = &result->value;
+ const_val->data.x_ptr.special = ConstPtrSpecialBaseErrorUnionCode;
+ const_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut;
+ const_val->data.x_ptr.data.base_err_union_code.err_union_val = err_union_val;
+ return result;
+ }
+ }
+
+ IrInstruction *result = ir_build_error_union_field_error_set(&ira->new_irb,
+ source_instr->scope, source_instr->source_node, base_ptr, safety_check_on);
+ result->value.type = result_type;
+ return result;
}
-static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
- IrInstructionUnwrapErrPayload *instruction)
+static IrInstruction *ir_analyze_instruction_error_union_field_error_set(IrAnalyze *ira,
+ IrInstructionErrorUnionFieldErrorSet *instruction)
{
- assert(instruction->value->child);
- IrInstruction *value = instruction->value->child;
- if (type_is_invalid(value->value.type))
+ IrInstruction *base_ptr = instruction->ptr->child;
+ if (type_is_invalid(base_ptr->value.type))
return ira->codegen->invalid_instruction;
- ZigType *ptr_type = value->value.type;
+ return ir_analyze_error_union_field_error_set(ira, &instruction->base, base_ptr, instruction->safety_check_on);
+}
+
+static IrInstruction *ir_analyze_unwrap_err_payload(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *base_ptr, IrInstruction *result_loc, bool safety_check_on)
+{
+ ZigType *ptr_type = base_ptr->value.type;
// This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing.
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *type_entry = ptr_type->data.pointer.child_type;
- if (type_is_invalid(type_entry)) {
+ if (type_is_invalid(type_entry))
return ira->codegen->invalid_instruction;
- } else if (type_entry->id == ZigTypeIdErrorUnion) {
- ZigType *payload_type = type_entry->data.error_union.payload_type;
- if (type_is_invalid(payload_type)) {
+ if (result_loc != nullptr && type_entry->id == ZigTypeIdErrorSet) {
+ IrInstruction *undef = ir_const_undef(ira, source_instr);
+ return ir_analyze_store_ptr(ira, source_instr, result_loc, undef);
+ }
+ if (type_entry->id != ZigTypeIdErrorUnion) {
+ if (result_loc == nullptr) {
+ ir_add_error(ira, base_ptr,
+ buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name)));
return ira->codegen->invalid_instruction;
}
- ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type,
- ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
- PtrLenSingle, 0, 0, 0);
- if (instr_is_comptime(value)) {
- ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
- if (!ptr_val)
- return ira->codegen->invalid_instruction;
- ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node);
+ IrInstruction *deref = ir_get_deref(ira, source_instr, base_ptr);
+ return ir_analyze_store_ptr(ira, source_instr, result_loc, deref);
+ }
+
+ ZigType *payload_type = type_entry->data.error_union.payload_type;
+ if (type_is_invalid(payload_type))
+ return ira->codegen->invalid_instruction;
+
+ ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type,
+ ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
+ PtrLenSingle, 0, 0, 0);
+
+ if (instr_is_comptime(base_ptr)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad);
+ if (!ptr_val)
+ return ira->codegen->invalid_instruction;
+ if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) {
+ ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node);
if (err_union_val == nullptr)
return ira->codegen->invalid_instruction;
+ if (err_union_val->special == ConstValSpecialUndef) {
+ ConstExprValue *vals = create_const_vals(2);
+ ConstExprValue *err_set_val = &vals[0];
+ ConstExprValue *payload_val = &vals[1];
+
+ ZigType *opt_err_set = get_optional_type(ira->codegen, type_entry->data.error_union.err_set_type);
+ err_set_val->special = ConstValSpecialStatic;
+ err_set_val->type = opt_err_set;
+ err_set_val->data.x_err_set = nullptr;
+
+ payload_val->special = ConstValSpecialUndef;
+ payload_val->type = payload_type;
+
+ err_union_val->special = ConstValSpecialStatic;
+ err_union_val->data.x_err_union.error_set = err_set_val;
+ err_union_val->data.x_err_union.payload = payload_val;
+ }
if (err_union_val->special != ConstValSpecialRuntime) {
- ErrorTableEntry *err = err_union_val->data.x_err_union.err;
+ ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set;
if (err != nullptr) {
- ir_add_error(ira, &instruction->base,
+ ir_add_error(ira, source_instr,
buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name)));
return ira->codegen->invalid_instruction;
}
- IrInstruction *result = ir_const(ira, &instruction->base, result_type);
+ IrInstruction *result;
+ if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_unwrap_err_payload(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, base_ptr, nullptr, safety_check_on);
+ result->value.type = result_type;
+ result->value.special = ConstValSpecialStatic;
+ } else {
+ result = ir_const(ira, source_instr, result_type);
+ }
result->value.data.x_ptr.special = ConstPtrSpecialRef;
result->value.data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload;
- return result;
+ result->value.data.x_ptr.mut = ptr_val->data.x_ptr.mut;
+ if (result_loc == nullptr) {
+ return result;
+ } else {
+ IrInstruction *deref = ir_get_deref(ira, source_instr, result);
+ return ir_analyze_store_ptr(ira, source_instr, result_loc, deref);
+ }
}
}
+ }
- IrInstruction *result = ir_build_unwrap_err_payload(&ira->new_irb,
- instruction->base.scope, instruction->base.source_node, value, instruction->safety_check_on);
- result->value.type = result_type;
+ IrInstruction *result = ir_build_unwrap_err_payload(&ira->new_irb, source_instr->scope,
+ source_instr->source_node, base_ptr, nullptr, safety_check_on);
+ result->value.type = result_type;
+ if (result_loc == nullptr) {
return result;
} else {
- ir_add_error(ira, value,
- buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name)));
+ IrInstruction *deref = ir_get_deref(ira, source_instr, result);
+ return ir_analyze_store_ptr(ira, source_instr, result_loc, deref);
+ }
+}
+
+static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
+ IrInstructionUnwrapErrPayload *instruction)
+{
+ IrInstruction *base_ptr = instruction->value->child;
+ if (type_is_invalid(base_ptr->value.type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *result_loc = nullptr;
+ if (instruction->result_loc != nullptr) {
+ result_loc = instruction->result_loc->child;
+ if (type_is_invalid(result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ }
+
+ return ir_analyze_unwrap_err_payload(ira, &instruction->base, base_ptr, result_loc, instruction->safety_check_on);
+}
+
+static IrInstruction *ir_analyze_instruction_assert_non_error(IrAnalyze *ira,
+ IrInstructionAssertNonError *instruction)
+{
+ IrInstruction *err_code = instruction->err_code->child;
+ if (type_is_invalid(err_code->value.type))
+ return ira->codegen->invalid_instruction;
+
+ assert(err_code->value.type->id == ZigTypeIdOptional);
+ assert(err_code->value.type->data.maybe.child_type->id == ZigTypeIdErrorSet);
+
+ if (instr_is_comptime(err_code)) {
+ ConstExprValue *err_val = ir_resolve_const(ira, err_code, UndefBad);
+ if (err_val == nullptr)
+ return ira->codegen->invalid_instruction;
+ // just like optional pointers are represented with the same comptime
+ // value representation as normal pointers,
+ // optional error sets are represented with the same comptime value
+ // representation as normal error sets.
+ ErrorTableEntry *err = err_val->data.x_err_set;
+ if (err == nullptr)
+ return ir_const_void(ira, &instruction->base);
+ ir_add_error(ira, &instruction->base,
+ buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ ir_build_assert_non_error(&ira->new_irb, instruction->base.scope,
+ instruction->base.source_node, err_code);
+ return ir_const_void(ira, &instruction->base);
+}
+
+static IrInstruction *ir_analyze_instruction_assert_non_null(IrAnalyze *ira,
+ IrInstructionAssertNonNull *instruction)
+{
+ IrInstruction *is_non_null = instruction->is_non_null->child;
+ if (type_is_invalid(is_non_null->value.type))
+ return ira->codegen->invalid_instruction;
+
+ assert(is_non_null->value.type->id == ZigTypeIdBool);
+
+ if (instr_is_comptime(is_non_null)) {
+ bool is_non_null_bool;
+ if (!ir_resolve_bool(ira, is_non_null, &is_non_null_bool))
+ return ira->codegen->invalid_instruction;
+ if (is_non_null_bool)
+ return ir_const_void(ira, &instruction->base);
+ ir_add_error(ira, &instruction->base, buf_sprintf("unable to unwrap null"));
return ira->codegen->invalid_instruction;
}
+ ir_build_assert_non_null(&ira->new_irb, instruction->base.scope,
+ instruction->base.source_node, is_non_null);
+ return ir_const_void(ira, &instruction->base);
}
static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnProto *instruction) {
@@ -19867,7 +22384,13 @@ static IrInstruction *ir_analyze_instruction_check_statement_is_void(IrAnalyze *
if (type_is_invalid(statement_type))
return ira->codegen->invalid_instruction;
- if (statement_type->id != ZigTypeIdVoid) {
+ // TODO this is a temporary hack because I'm about to rework coroutines anyway
+ bool is_async = exec_is_async(ira->new_irb.exec);
+ if (is_async) {
+ return ir_const_void(ira, &instruction->base);
+ }
+
+ if (statement_type->id != ZigTypeIdVoid && statement_type != ira->codegen->builtin_types.entry_infer) {
ir_add_error(ira, &instruction->base, buf_sprintf("expression value is ignored"));
}
@@ -19957,7 +22480,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3
return ira->codegen->invalid_instruction;
}
- IrInstruction *result = ir_create_const(&ira->new_irb, target->scope, target->source_node, result_type);
+ IrInstruction *result = ir_const(ira, target, result_type);
copy_const_val(&result->value, val, false);
result->value.type = result_type;
return result;
@@ -20005,8 +22528,12 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
if (!val)
return ira->codegen->invalid_instruction;
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, source_instr->source_node,
- dest_type);
+ IrInstruction *result;
+ if (val->data.x_ptr.mut == ConstPtrMutInfer) {
+ result = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr);
+ } else {
+ result = ir_const(ira, source_instr, dest_type);
+ }
copy_const_val(&result->value, val, false);
result->value.type = dest_type;
return result;
@@ -20029,9 +22556,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
return ira->codegen->invalid_instruction;
}
- IrInstruction *casted_ptr = ir_build_ptr_cast(&ira->new_irb, source_instr->scope,
- source_instr->source_node, nullptr, ptr);
- casted_ptr->value.type = dest_type;
+ IrInstruction *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr);
if (type_has_bits(dest_type) && !type_has_bits(src_type)) {
ErrorMsg *msg = ir_add_error(ira, source_instr,
@@ -20057,7 +22582,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_
return result;
}
-static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCast *instruction) {
+static IrInstruction *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstructionPtrCastSrc *instruction) {
IrInstruction *dest_type_value = instruction->dest_type->child;
ZigType *dest_type = ir_resolve_type(ira, dest_type_value);
if (type_is_invalid(dest_type))
@@ -20195,14 +22720,29 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
if ((err = buf_read_value_bytes(ira, codegen, source_node, buf + (elem_size * i), elem)))
return err;
}
- break;
+ return ErrorNone;
case ConstArraySpecialUndef:
zig_panic("TODO buf_read_value_bytes ConstArraySpecialUndef array type");
case ConstArraySpecialBuf:
zig_panic("TODO buf_read_value_bytes ConstArraySpecialBuf array type");
}
-
- return ErrorNone;
+ zig_unreachable();
+ }
+ case ZigTypeIdEnum: {
+ switch (val->type->data.enumeration.layout) {
+ case ContainerLayoutAuto:
+ zig_panic("TODO buf_read_value_bytes enum auto");
+ case ContainerLayoutPacked:
+ zig_panic("TODO buf_read_value_bytes enum packed");
+ case ContainerLayoutExtern: {
+ ZigType *tag_int_type = val->type->data.enumeration.tag_int_type;
+ assert(tag_int_type->id == ZigTypeIdInt);
+ bigint_read_twos_complement(&val->data.x_enum_tag, buf, tag_int_type->data.integral.bit_count,
+ codegen->is_big_endian, tag_int_type->data.integral.is_signed);
+ return ErrorNone;
+ }
+ }
+ zig_unreachable();
}
case ZigTypeIdStruct:
switch (val->type->data.structure.layout) {
@@ -20242,111 +22782,12 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou
zig_panic("TODO buf_read_value_bytes error union");
case ZigTypeIdErrorSet:
zig_panic("TODO buf_read_value_bytes pure error type");
- case ZigTypeIdEnum:
- zig_panic("TODO buf_read_value_bytes enum type");
case ZigTypeIdFn:
zig_panic("TODO buf_read_value_bytes fn type");
case ZigTypeIdUnion:
zig_panic("TODO buf_read_value_bytes union type");
- }
- zig_unreachable();
-}
-
-static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBitCast *instruction) {
- Error err;
- IrInstruction *dest_type_value = instruction->dest_type->child;
- ZigType *dest_type = ir_resolve_type(ira, dest_type_value);
- if (type_is_invalid(dest_type))
- return ira->codegen->invalid_instruction;
-
- IrInstruction *value = instruction->value->child;
- ZigType *src_type = value->value.type;
- if (type_is_invalid(src_type))
- return ira->codegen->invalid_instruction;
-
- if ((err = ensure_complete_type(ira->codegen, dest_type)))
- return ira->codegen->invalid_instruction;
-
- if ((err = ensure_complete_type(ira->codegen, src_type)))
- return ira->codegen->invalid_instruction;
-
- if (get_codegen_ptr_type(src_type) != nullptr) {
- ir_add_error(ira, value,
- buf_sprintf("unable to @bitCast from pointer type '%s'", buf_ptr(&src_type->name)));
- return ira->codegen->invalid_instruction;
- }
-
- switch (src_type->id) {
- case ZigTypeIdInvalid:
- case ZigTypeIdMetaType:
- case ZigTypeIdOpaque:
- case ZigTypeIdBoundFn:
- case ZigTypeIdArgTuple:
- case ZigTypeIdNamespace:
- case ZigTypeIdUnreachable:
- case ZigTypeIdComptimeFloat:
- case ZigTypeIdComptimeInt:
- case ZigTypeIdUndefined:
- case ZigTypeIdNull:
- ir_add_error(ira, dest_type_value,
- buf_sprintf("unable to @bitCast from type '%s'", buf_ptr(&src_type->name)));
- return ira->codegen->invalid_instruction;
- default:
- break;
- }
-
- if (get_codegen_ptr_type(dest_type) != nullptr) {
- ir_add_error(ira, dest_type_value,
- buf_sprintf("unable to @bitCast to pointer type '%s'", buf_ptr(&dest_type->name)));
- return ira->codegen->invalid_instruction;
- }
-
- switch (dest_type->id) {
- case ZigTypeIdInvalid:
- case ZigTypeIdMetaType:
- case ZigTypeIdOpaque:
- case ZigTypeIdBoundFn:
- case ZigTypeIdArgTuple:
- case ZigTypeIdNamespace:
- case ZigTypeIdUnreachable:
- case ZigTypeIdComptimeFloat:
- case ZigTypeIdComptimeInt:
- case ZigTypeIdUndefined:
- case ZigTypeIdNull:
- ir_add_error(ira, dest_type_value,
- buf_sprintf("unable to @bitCast to type '%s'", buf_ptr(&dest_type->name)));
- return ira->codegen->invalid_instruction;
- default:
- break;
- }
-
- uint64_t dest_size_bytes = type_size(ira->codegen, dest_type);
- uint64_t src_size_bytes = type_size(ira->codegen, src_type);
- if (dest_size_bytes != src_size_bytes) {
- ir_add_error(ira, &instruction->base,
- buf_sprintf("destination type '%s' has size %" ZIG_PRI_u64 " but source type '%s' has size %" ZIG_PRI_u64,
- buf_ptr(&dest_type->name), dest_size_bytes,
- buf_ptr(&src_type->name), src_size_bytes));
- return ira->codegen->invalid_instruction;
- }
-
- if (instr_is_comptime(value)) {
- ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
- if (!val)
- return ira->codegen->invalid_instruction;
-
- IrInstruction *result = ir_const(ira, &instruction->base, dest_type);
- uint8_t *buf = allocate_nonzero(src_size_bytes);
- buf_write_value_bytes(ira->codegen, buf, val);
- if ((err = buf_read_value_bytes(ira, ira->codegen, instruction->base.source_node, buf, &result->value)))
- return ira->codegen->invalid_instruction;
- return result;
- }
-
- IrInstruction *result = ir_build_bit_cast(&ira->new_irb, instruction->base.scope,
- instruction->base.source_node, nullptr, value);
- result->value.type = dest_type;
- return result;
+ }
+ zig_unreachable();
}
static IrInstruction *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstructionIntToPtr *instruction) {
@@ -20400,9 +22841,8 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
IrInstructionDeclRef *instruction)
{
Tld *tld = instruction->tld;
- LVal lval = instruction->lval;
- resolve_top_level_decl(ira->codegen, tld, lval == LValPtr, instruction->base.source_node);
+ resolve_top_level_decl(ira->codegen, tld, true, instruction->base.source_node);
if (tld->resolution == TldResolutionInvalid)
return ira->codegen->invalid_instruction;
@@ -20410,27 +22850,17 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
case TldIdContainer:
case TldIdCompTime:
zig_unreachable();
- case TldIdVar:
- {
+ case TldIdVar: {
TldVar *tld_var = (TldVar *)tld;
ZigVar *var = tld_var->var;
- IrInstruction *var_ptr = ir_get_var_ptr(ira, &instruction->base, var);
- if (type_is_invalid(var_ptr->value.type))
- return ira->codegen->invalid_instruction;
-
if (tld_var->extern_lib_name != nullptr) {
add_link_lib_symbol(ira, tld_var->extern_lib_name, &var->name, instruction->base.source_node);
}
- if (lval == LValPtr) {
- return var_ptr;
- } else {
- return ir_get_deref(ira, &instruction->base, var_ptr);
- }
+ return ir_get_var_ptr(ira, &instruction->base, var);
}
- case TldIdFn:
- {
+ case TldIdFn: {
TldFn *tld_fn = (TldFn *)tld;
ZigFn *fn_entry = tld_fn->fn_entry;
assert(fn_entry->type_entry);
@@ -20439,13 +22869,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
add_link_lib_symbol(ira, tld_fn->extern_lib_name, &fn_entry->symbol_name, instruction->base.source_node);
}
- IrInstruction *ref_instruction = ir_create_const_fn(&ira->new_irb, instruction->base.scope,
- instruction->base.source_node, fn_entry);
- if (lval == LValPtr) {
- return ir_get_ref(ira, &instruction->base, ref_instruction, true, false);
- } else {
- return ref_instruction;
- }
+ return ir_create_const_fn(&ira->new_irb, instruction->base.scope, instruction->base.source_node, fn_entry);
}
}
zig_unreachable();
@@ -20476,8 +22900,7 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru
if (!val)
return ira->codegen->invalid_instruction;
if (val->type->id == ZigTypeIdPointer && val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
- IrInstruction *result = ir_create_const(&ira->new_irb, instruction->base.scope,
- instruction->base.source_node, usize);
+ IrInstruction *result = ir_const(ira, &instruction->base, usize);
bigint_init_unsigned(&result->value.data.x_bigint, val->data.x_ptr.data.hard_coded_addr.addr);
result->value.type = usize;
return result;
@@ -21303,18 +23726,547 @@ static IrInstruction *ir_analyze_instruction_check_runtime_scope(IrAnalyze *ira,
return ir_const_void(ira, &instruction->base);
}
+static IrInstruction *ir_analyze_result_return(IrAnalyze *ira, IrInstruction *source_inst) {
+ // Here we create a pass2 instruction for getting the return value pointer.
+ // However we create a const value for it and mark it with ConstPtrMutInfer
+ // so that if the return expression is comptime-known, we can emit a memcpy
+ // rather than runtime instructions.
+ ZigType *result_type = get_pointer_to_type(ira->codegen, ira->payload_return_type, false);
+
+ IrInstruction *result = ir_build_result_return(&ira->new_irb, source_inst->scope, source_inst->source_node);
+ result->value.type = result_type;
+ if (ira->result_value != nullptr) {
+ result->value.special = ConstValSpecialStatic;
+ result->value.data.x_ptr.special = ConstPtrSpecialRef;
+ result->value.data.x_ptr.data.ref.pointee = ira->result_value;
+ result->value.data.x_ptr.mut = ConstPtrMutComptimeVar;
+ } else if (type_has_bits(ira->payload_return_type) && handle_is_ptr(ira->payload_return_type)) {
+ ConstExprValue *pointee = create_const_vals(1);
+ pointee->special = ConstValSpecialUndef;
+ pointee->type = ira->payload_return_type;
+
+ result->value.special = ConstValSpecialStatic;
+ result->value.data.x_ptr.special = ConstPtrSpecialRef;
+ result->value.data.x_ptr.data.ref.pointee = pointee;
+ result->value.data.x_ptr.mut = ConstPtrMutInfer;
+ } else {
+ result->value.special = ConstValSpecialRuntime;
+ }
+ return result;
+}
+
+static IrInstruction *ir_analyze_instruction_result_return(IrAnalyze *ira, IrInstructionResultReturn *instruction) {
+ ZigFn *fn = exec_fn_entry(ira->new_irb.exec);
+ if (fn == nullptr) {
+ ir_add_error(ira, &instruction->base, buf_sprintf("return outside function"));
+ return ira->codegen->invalid_instruction;
+ }
+
+ return ir_analyze_result_return(ira, &instruction->base);
+}
+
+static IrInstruction *ir_analyze_instruction_result_child(IrAnalyze *ira, IrInstructionResultChild *instruction) {
+ return instruction->prev_result_loc->child;
+}
+
+static IrInstruction *ir_analyze_instruction_result_ptr_cast(IrAnalyze *ira,
+ IrInstructionResultPtrCast *instruction)
+{
+ ZigType *elem_type = ir_resolve_type(ira, instruction->elem_type->child);
+ if (type_is_invalid(elem_type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *prev_result_loc = instruction->prev_result_loc->child;
+ if (type_is_invalid(prev_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *new_result_loc = ir_implicit_cast_result(ira, instruction->base.source_node,
+ prev_result_loc, elem_type, false);
+ if (type_is_invalid(new_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ ZigType *new_ptr_type = adjust_ptr_child(ira->codegen, new_result_loc->value.type,
+ ira->codegen->builtin_types.entry_infer);
+ IrInstruction *ptr_cast = ir_build_ptr_cast_gen(ira, &instruction->base, new_ptr_type, new_result_loc);
+ reinterpret_cast(ptr_cast)->pass1_parent = &instruction->base;
+
+ return ptr_cast;
+}
+
+static IrInstruction *ir_analyze_instruction_result_cast(IrAnalyze *ira, IrInstructionResultCast *instruction) {
+ ZigType *elem_type = ir_resolve_type(ira, instruction->elem_type->child);
+ if (type_is_invalid(elem_type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *prev_result_loc = instruction->prev_result_loc->child;
+ if (type_is_invalid(prev_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *new_result_loc = ir_implicit_cast_result(ira, instruction->base.source_node,
+ prev_result_loc, elem_type, false);
+ if (type_is_invalid(new_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ new_result_loc->is_gen = prev_result_loc->is_gen;
+ return new_result_loc;
+}
+
+static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_inst, ZigType *var_type,
+ uint32_t align, const char *name_hint, bool force_comptime)
+{
+ Error err;
+
+ ConstExprValue *pointee = create_const_vals(1);
+ pointee->special = ConstValSpecialUndef;
+
+ IrInstructionAllocaGen *result = ir_create_alloca_gen(&ira->new_irb, source_inst->scope,
+ source_inst->source_node, align, name_hint);
+ result->base.value.special = ConstValSpecialStatic;
+ result->base.value.data.x_ptr.special = ConstPtrSpecialRef;
+ result->base.value.data.x_ptr.mut = force_comptime ? ConstPtrMutComptimeVar : ConstPtrMutInfer;
+ result->base.value.data.x_ptr.data.ref.pointee = pointee;
+
+ if (var_type == nullptr) {
+ // We use a pointer to a special opaque type to signal that we want type inference.
+ result->base.value.type = get_pointer_to_type_extra(ira->codegen,
+ ira->codegen->builtin_types.entry_infer, false, false, PtrLenSingle, align, 0, 0);
+ result->base.value.data.x_ptr.data.ref.pointee->type = ira->codegen->builtin_types.entry_infer;
+ } else {
+ if ((err = resolve_alloca_inference(ira, result, var_type)))
+ return ira->codegen->invalid_instruction;
+ }
+
+ ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec);
+ if (fn_entry != nullptr) {
+ fn_entry->alloca_list.append(result);
+ }
+ result->base.is_gen = true;
+ return &result->base;
+}
+
+static IrInstruction *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructionAllocaSrc *instruction) {
+ uint32_t align = 0;
+ if (instruction->align != nullptr) {
+ if (!ir_resolve_align(ira, instruction->align->child, &align)) {
+ return ira->codegen->invalid_instruction;
+ }
+ }
+
+ bool is_comptime = false;
+ if (instruction->is_comptime != nullptr) {
+ if (!ir_resolve_bool(ira, instruction->is_comptime->child, &is_comptime))
+ return ira->codegen->invalid_instruction;
+ }
+
+ ZigType *var_type = nullptr;
+ if (instruction->child_type != nullptr) {
+ var_type = ir_resolve_type(ira, instruction->child_type->child);
+ if (type_is_invalid(var_type))
+ return ira->codegen->invalid_instruction;
+ }
+
+ return ir_analyze_alloca(ira, &instruction->base, var_type, align, instruction->name_hint, is_comptime);
+}
+
+static IrInstruction *ir_analyze_instruction_first_arg_result_loc(IrAnalyze *ira,
+ IrInstructionFirstArgResultLoc *instruction)
+{
+ IrInstruction *fn_ref = instruction->fn_ref->child;
+ if (type_is_invalid(fn_ref->value.type))
+ return ira->codegen->invalid_instruction;
+
+ if (fn_ref->value.type->id == ZigTypeIdMetaType) {
+ // Result of this instruction should be the implicitly casted result location.
+
+ ZigType *dest_type = ir_resolve_type(ira, fn_ref);
+ if (type_is_invalid(dest_type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *new_result_loc = ir_implicit_cast_result(ira, instruction->base.source_node,
+ instruction->prev_result_loc->child, dest_type, true);
+ if (new_result_loc == nullptr)
+ return nullptr;
+ if (type_is_invalid(new_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+ return new_result_loc;
+ }
+
+ bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope);
+ return ir_analyze_alloca(ira, &instruction->base, nullptr, 0, "", is_comptime);
+}
+
+static IrInstruction *ir_analyze_instruction_infer_array_type(IrAnalyze *ira,
+ IrInstructionInferArrayType *instruction)
+{
+ ZigType *src_type = ir_resolve_type(ira, instruction->src_type->child);
+ if (type_is_invalid(src_type))
+ return ira->codegen->invalid_instruction;
+
+ if (!is_slice(src_type)) {
+ return ir_const_type(ira, &instruction->base, src_type);
+ }
+
+ ZigType *child_type = src_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type;
+ ZigType *array_type = get_array_type(ira->codegen, child_type, instruction->elem_count);
+ return ir_const_type(ira, &instruction->base, array_type);
+}
+
+static IrInstruction *ir_analyze_instruction_infer_comptime(IrAnalyze *ira,
+ IrInstructionInferCompTime *instruction)
+{
+ IrInstruction *prev_result_loc = instruction->prev_result_loc->child;
+ if (type_is_invalid(prev_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *new_result_loc = instruction->new_result_loc->child;
+ if (type_is_invalid(new_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ if (prev_result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ if (instr_is_comptime(new_result_loc) &&
+ new_result_loc->value.data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ prev_result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
+ } else {
+ prev_result_loc->value.special = ConstValSpecialRuntime;
+ }
+ }
+ return ir_const_void(ira, &instruction->base);
+}
+
+static IrInstruction *ir_analyze_instruction_from_bytes_len(IrAnalyze *ira,
+ IrInstructionFromBytesLenSrc *instruction)
+{
+ Error err;
+
+ IrInstruction *prev_result_loc = instruction->prev_result_loc->child;
+ if (type_is_invalid(prev_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *new_result_loc = instruction->new_result_loc->child;
+ if (type_is_invalid(new_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ assert(prev_result_loc->value.type->id == ZigTypeIdPointer);
+ ZigType *slice_type = prev_result_loc->value.type->data.pointer.child_type;
+ assert(is_slice(slice_type));
+ ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index].type_entry;
+ assert(slice_ptr_type->id == ZigTypeIdPointer);
+ ZigType *elem_type = slice_ptr_type->data.pointer.child_type;
+
+ if (prev_result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ if (instr_is_comptime(new_result_loc) &&
+ new_result_loc->value.data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ ConstExprValue *slice_val = const_ptr_pointee(ira, ira->codegen, &new_result_loc->value,
+ instruction->base.source_node);
+ if (slice_val == nullptr)
+ return ira->codegen->invalid_instruction;
+
+ if (slice_val->special != ConstValSpecialUndef) {
+ ConstExprValue *ptr_val = &slice_val->data.x_struct.fields[slice_ptr_index];
+ ConstExprValue *len_val = &slice_val->data.x_struct.fields[slice_len_index];
+ if (ptr_val->special == ConstValSpecialStatic && len_val->special == ConstValSpecialStatic) {
+ // copy the length and divide it from the new_result_loc
+ // we need a new slice const val though, because if we modify the length it will
+ // modify the length of the new_result_loc
+ ConstExprValue *new_slice_val = create_const_vals(1);
+ copy_const_val(new_slice_val, slice_val, false);
+ prev_result_loc->value.data.x_ptr.special = ConstPtrSpecialRef;
+ prev_result_loc->value.data.x_ptr.data.ref.pointee = new_slice_val;
+
+ if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown)))
+ return ira->codegen->invalid_instruction;
+
+ size_t elem_size = type_size(ira->codegen, elem_type);
+ BigInt elem_size_bigint;
+ bigint_init_unsigned(&elem_size_bigint, elem_size);
+
+ BigInt tmp_bigint;
+ bigint_rem(&tmp_bigint, &len_val->data.x_bigint, &elem_size_bigint);
+
+ if (bigint_cmp_zero(&tmp_bigint) != CmpEQ) {
+ Buf *remaining_text = buf_alloc();
+ bigint_append_buf(remaining_text, &tmp_bigint, 10);
+ Buf *bytes_text = buf_alloc();
+ bigint_append_buf(bytes_text, &len_val->data.x_bigint, 10);
+ ir_add_error(ira, &instruction->base, buf_sprintf(
+ "converting slice of %s bytes to '%s' (element size %zu) leaves %s bytes remaining",
+ buf_ptr(bytes_text),
+ buf_ptr(&slice_type->name),
+ elem_size,
+ buf_ptr(remaining_text)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ ConstExprValue *new_len_val = &new_slice_val->data.x_struct.fields[slice_len_index];
+ new_len_val->special = ConstValSpecialStatic;
+ bigint_div_trunc(&new_len_val->data.x_bigint, &len_val->data.x_bigint, &elem_size_bigint);
+
+ prev_result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
+
+ return ir_const_void(ira, &instruction->base);
+ }
+ }
+ }
+ // comptime didn't work, mark the instructions as runtime and fall through
+ prev_result_loc->value.special = ConstValSpecialRuntime;
+ new_result_loc->value.special = ConstValSpecialRuntime;
+ }
+
+ return ir_build_from_bytes_len_gen(ira, &instruction->base, prev_result_loc, elem_type);
+}
+
+static IrInstruction *ir_analyze_instruction_to_bytes_len(IrAnalyze *ira,
+ IrInstructionToBytesLenSrc *instruction)
+{
+ Error err;
+
+ IrInstruction *prev_result_loc = instruction->prev_result_loc->child;
+ if (type_is_invalid(prev_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *new_result_loc = instruction->new_result_loc->child;
+ if (type_is_invalid(new_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ assert(new_result_loc->value.type->id == ZigTypeIdPointer);
+ ZigType *slice_type = new_result_loc->value.type->data.pointer.child_type;
+ assert(is_slice(slice_type));
+ ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index].type_entry;
+ assert(slice_ptr_type->id == ZigTypeIdPointer);
+ ZigType *elem_type = slice_ptr_type->data.pointer.child_type;
+
+ if (prev_result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ if (instr_is_comptime(new_result_loc) &&
+ new_result_loc->value.data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ ConstExprValue *slice_val = const_ptr_pointee(ira, ira->codegen, &new_result_loc->value,
+ instruction->base.source_node);
+ if (slice_val == nullptr)
+ return ira->codegen->invalid_instruction;
+
+ if (slice_val->special != ConstValSpecialUndef) {
+ ConstExprValue *ptr_val = &slice_val->data.x_struct.fields[slice_ptr_index];
+ ConstExprValue *len_val = &slice_val->data.x_struct.fields[slice_len_index];
+ if (ptr_val->special == ConstValSpecialStatic && len_val->special == ConstValSpecialStatic) {
+ // copy the length from the new_result_loc and multiply it by the element size
+ // we need a new slice const val though, because if we modify the length it will
+ // modify the length of the new_result_loc
+ ConstExprValue *new_slice_val = create_const_vals(1);
+ copy_const_val(new_slice_val, slice_val, false);
+ prev_result_loc->value.data.x_ptr.special = ConstPtrSpecialRef;
+ prev_result_loc->value.data.x_ptr.data.ref.pointee = new_slice_val;
+
+ if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown)))
+ return ira->codegen->invalid_instruction;
+
+ size_t elem_size = type_size(ira->codegen, elem_type);
+ BigInt elem_size_bigint;
+ bigint_init_unsigned(&elem_size_bigint, elem_size);
+
+ ConstExprValue *new_len_val = &new_slice_val->data.x_struct.fields[slice_len_index];
+ new_len_val->special = ConstValSpecialStatic;
+ bigint_mul(&new_len_val->data.x_bigint, &len_val->data.x_bigint, &elem_size_bigint);
+
+ prev_result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
+ return ir_const_void(ira, &instruction->base);
+ }
+ }
+ }
+ // comptime didn't work, mark the instructions as runtime and fall through
+ prev_result_loc->value.special = ConstValSpecialRuntime;
+ new_result_loc->value.special = ConstValSpecialRuntime;
+ }
+
+ return ir_build_to_bytes_len_gen(ira, &instruction->base, prev_result_loc, elem_type);
+}
+
+
+static IrInstruction *ir_analyze_instruction_set_non_null_bit(IrAnalyze *ira,
+ IrInstructionSetNonNullBit *instruction)
+{
+ IrInstruction *prev_result_loc = instruction->prev_result_loc->child;
+ if (type_is_invalid(prev_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *non_null_bit = instruction->non_null_bit->child;
+ if (type_is_invalid(non_null_bit->value.type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *new_result_loc = instruction->new_result_loc->child;
+ if (type_is_invalid(new_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ assert(prev_result_loc->value.type->id == ZigTypeIdPointer);
+ ZigType *opt_type = prev_result_loc->value.type->data.pointer.child_type;
+ assert(opt_type->id == ZigTypeIdOptional);
+
+ if (!handle_is_ptr(opt_type)) {
+ if (prev_result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) {
+ if (instr_is_comptime(new_result_loc) &&
+ new_result_loc->value.data.x_ptr.mut != ConstPtrMutRuntimeVar)
+ {
+ prev_result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst;
+ } else {
+ prev_result_loc->value.special = ConstValSpecialRuntime;
+ }
+ }
+ return ir_const_void(ira, &instruction->base);
+ }
+
+ if (instr_is_comptime(prev_result_loc) && instr_is_comptime(new_result_loc) &&
+ instr_is_comptime(non_null_bit))
+ {
+ zig_panic("TODO comptime cmpxchg");
+ }
+
+ prev_result_loc->value.special = ConstValSpecialRuntime;
+ IrInstruction *result = ir_build_set_nonnull_bit(&ira->new_irb, instruction->base.scope,
+ instruction->base.source_node, prev_result_loc, non_null_bit, nullptr);
+ result->value.type = ira->codegen->builtin_types.entry_void;
+ return result;
+}
+
+static IrInstruction *ir_analyze_instruction_error_literal(IrAnalyze *ira, IrInstructionErrorLiteral *instruction) {
+ return ir_analyze_error_literal(ira, &instruction->base, instruction->name);
+}
+
+static IrInstruction *ir_analyze_instruction_result_bytes_to_slice(IrAnalyze *ira,
+ IrInstructionResultBytesToSlice *instruction)
+{
+ // Here the pointer properties are wrong except for the child element type.
+ // This gets corrected later by resolve_alloca_inference
+ ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
+ true, false, PtrLenUnknown, 0, 0, 0);
+ ZigType *slice_of_bytes = get_slice_type(ira->codegen, slice_ptr_type);
+ IrInstruction *prev_result_loc = instruction->prev_result_loc->child;
+ IrInstruction *new_result_loc = ir_implicit_cast_result(ira, instruction->base.source_node,
+ prev_result_loc, slice_of_bytes, false);
+ if (type_is_invalid(new_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ // This pointer type is also wrong and we don't even know the child type.
+ // Also corrected later by resolve_alloca_inference
+ ZigType *new_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_infer,
+ true, false, PtrLenUnknown, 0, 0, 0);
+ ZigType *new_slice_type = get_slice_type(ira->codegen, new_ptr_type);
+ ZigType *new_result_loc_type = adjust_ptr_child(ira->codegen, prev_result_loc->value.type, new_slice_type);
+
+ IrInstruction *result = ir_build_ptr_cast_gen(ira, &instruction->base, new_result_loc_type, new_result_loc);
+ reinterpret_cast(result)->pass1_parent = &instruction->base;
+
+ // At compile time pointer casts are represented as the pointer type disagreeing
+ // with the element type, so that's easy to do here.
+ if (instr_is_comptime(new_result_loc) && new_result_loc->value.data.x_ptr.mut != ConstPtrMutInfer) {
+ ConstExprValue *val = ir_resolve_const(ira, new_result_loc, UndefOk);
+ if (!val)
+ return ira->codegen->invalid_instruction;
+
+ copy_const_val(&result->value, val, false);
+ result->value.type = new_result_loc_type;
+ return result;
+ }
+
+ return result;
+}
+
+// This function is called once we have enough information to do the analysis.
+static IrInstruction *ir_analyze_result_slice_to_bytes(IrAnalyze *ira,
+ IrInstruction *source_inst, IrInstruction *prev_result_loc, ZigType *elem_type, ZigType *bytes_slice_type)
+{
+ Error err;
+
+ if (!is_slice(bytes_slice_type)) {
+ ir_add_error(ira, source_inst,
+ buf_sprintf("expected slice, found '%s'", buf_ptr(&bytes_slice_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ ZigType *bytes_ptr_type = bytes_slice_type->data.structure.fields[slice_ptr_index].type_entry;
+ if (bytes_ptr_type->data.pointer.child_type != ira->codegen->builtin_types.entry_u8) {
+ ir_add_error(ira, source_inst,
+ buf_sprintf("expected slice of u8, found '%s'", buf_ptr(&bytes_slice_type->name)));
+ return ira->codegen->invalid_instruction;
+ }
+
+ if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusAlignmentKnown)))
+ return ira->codegen->invalid_instruction;
+
+
+ uint32_t bytes_ptr_align;
+ if ((err = resolve_ptr_align(ira, bytes_ptr_type, &bytes_ptr_align)))
+ return ira->codegen->invalid_instruction;
+
+ ZigType *elem_ptr_type = get_pointer_to_type_extra(ira->codegen, elem_type,
+ bytes_ptr_type->data.pointer.is_const, bytes_ptr_type->data.pointer.is_volatile,
+ PtrLenUnknown, bytes_ptr_align, 0, 0);
+ ZigType *slice_of_elem = get_slice_type(ira->codegen, elem_ptr_type);
+ IrInstruction *casted_prev_result_loc = ir_implicit_cast_result(ira, source_inst->source_node,
+ prev_result_loc, slice_of_elem, false);
+ if (type_is_invalid(casted_prev_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ ZigType *new_result_loc_type = adjust_ptr_child(ira->codegen, casted_prev_result_loc->value.type,
+ bytes_slice_type);
+ IrInstruction *result = ir_build_result_slice_to_bytes_gen(ira, source_inst, new_result_loc_type,
+ casted_prev_result_loc);
+
+ if (instr_is_comptime(casted_prev_result_loc)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, casted_prev_result_loc, UndefOk);
+ if (!ptr_val)
+ return ira->codegen->invalid_instruction;
+
+ copy_const_val(&result->value, ptr_val, false);
+ result->value.type = new_result_loc_type;
+ return result;
+ }
+
+ return result;
+}
+
+static IrInstruction *ir_analyze_instruction_result_slice_to_bytes(IrAnalyze *ira,
+ IrInstructionResultSliceToBytesSrc *instruction)
+{
+ ZigType *elem_type = ir_resolve_type(ira, instruction->elem_type->child);
+ if (type_is_invalid(elem_type))
+ return ira->codegen->invalid_instruction;
+
+ IrInstruction *prev_result_loc = instruction->prev_result_loc->child;
+ if (type_is_invalid(prev_result_loc->value.type))
+ return ira->codegen->invalid_instruction;
+
+ // We don't have enough type information to do anything. So we emit a placeholder instruction
+ // and then will fix things later when resolve_alloca_inference is called.
+ // This works because this is a result location instruction and so the first reference to it
+ // will be from resolve_alloca_inference.
+ return ir_build_result_slice_to_bytes_placeholder(ira, &instruction->base, prev_result_loc, elem_type);
+}
+
static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
case IrInstructionIdWidenOrShorten:
- case IrInstructionIdStructInit:
- case IrInstructionIdUnionInit:
case IrInstructionIdStructFieldPtr:
case IrInstructionIdUnionFieldPtr:
case IrInstructionIdOptionalWrap:
case IrInstructionIdErrWrapCode:
case IrInstructionIdErrWrapPayload:
case IrInstructionIdCast:
+ case IrInstructionIdPtrOfArrayToSlice:
+ case IrInstructionIdArrayToSlice:
+ case IrInstructionIdDeclVarGen:
+ case IrInstructionIdAllocaGen:
+ case IrInstructionIdResultSlicePtr:
+ case IrInstructionIdResultErrorUnionPayload:
+ case IrInstructionIdResultErrorUnionCode:
+ case IrInstructionIdPtrCastGen:
+ case IrInstructionIdCmpxchgGen:
+ case IrInstructionIdResultSliceToBytesPlaceholder:
+ case IrInstructionIdResultSliceToBytesGen:
+ case IrInstructionIdFromBytesLenGen:
+ case IrInstructionIdToBytesLenGen:
+ case IrInstructionIdUnwrapErrCode:
zig_unreachable();
case IrInstructionIdReturn:
@@ -21325,8 +24277,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_un_op(ira, (IrInstructionUnOp *)instruction);
case IrInstructionIdBinOp:
return ir_analyze_instruction_bin_op(ira, (IrInstructionBinOp *)instruction);
- case IrInstructionIdDeclVar:
- return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVar *)instruction);
+ case IrInstructionIdDeclVarSrc:
+ return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVarSrc *)instruction);
case IrInstructionIdLoadPtr:
return ir_analyze_instruction_load_ptr(ira, (IrInstructionLoadPtr *)instruction);
case IrInstructionIdStorePtr:
@@ -21371,8 +24323,10 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);
case IrInstructionIdTestNonNull:
return ir_analyze_instruction_test_non_null(ira, (IrInstructionTestNonNull *)instruction);
- case IrInstructionIdUnwrapOptional:
- return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapOptional *)instruction);
+ case IrInstructionIdOptionalUnwrapPtr:
+ return ir_analyze_instruction_optional_unwrap_ptr(ira, (IrInstructionOptionalUnwrapPtr *)instruction);
+ case IrInstructionIdOptionalUnwrapVal:
+ return ir_analyze_instruction_optional_unwrap_val(ira, (IrInstructionOptionalUnwrapVal *)instruction);
case IrInstructionIdClz:
return ir_analyze_instruction_clz(ira, (IrInstructionClz *)instruction);
case IrInstructionIdCtz:
@@ -21413,8 +24367,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_c_undef(ira, (IrInstructionCUndef *)instruction);
case IrInstructionIdEmbedFile:
return ir_analyze_instruction_embed_file(ira, (IrInstructionEmbedFile *)instruction);
- case IrInstructionIdCmpxchg:
- return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchg *)instruction);
+ case IrInstructionIdCmpxchgSrc:
+ return ir_analyze_instruction_cmpxchg(ira, (IrInstructionCmpxchgSrc *)instruction);
case IrInstructionIdFence:
return ir_analyze_instruction_fence(ira, (IrInstructionFence *)instruction);
case IrInstructionIdTruncate:
@@ -21425,10 +24379,6 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_float_cast(ira, (IrInstructionFloatCast *)instruction);
case IrInstructionIdErrSetCast:
return ir_analyze_instruction_err_set_cast(ira, (IrInstructionErrSetCast *)instruction);
- case IrInstructionIdFromBytes:
- return ir_analyze_instruction_from_bytes(ira, (IrInstructionFromBytes *)instruction);
- case IrInstructionIdToBytes:
- return ir_analyze_instruction_to_bytes(ira, (IrInstructionToBytes *)instruction);
case IrInstructionIdIntToFloat:
return ir_analyze_instruction_int_to_float(ira, (IrInstructionIntToFloat *)instruction);
case IrInstructionIdFloatToInt:
@@ -21465,10 +24415,12 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_overflow_op(ira, (IrInstructionOverflowOp *)instruction);
case IrInstructionIdTestErr:
return ir_analyze_instruction_test_err(ira, (IrInstructionTestErr *)instruction);
- case IrInstructionIdUnwrapErrCode:
- return ir_analyze_instruction_unwrap_err_code(ira, (IrInstructionUnwrapErrCode *)instruction);
case IrInstructionIdUnwrapErrPayload:
return ir_analyze_instruction_unwrap_err_payload(ira, (IrInstructionUnwrapErrPayload *)instruction);
+ case IrInstructionIdAssertNonError:
+ return ir_analyze_instruction_assert_non_error(ira, (IrInstructionAssertNonError *)instruction);
+ case IrInstructionIdAssertNonNull:
+ return ir_analyze_instruction_assert_non_null(ira, (IrInstructionAssertNonNull *)instruction);
case IrInstructionIdFnProto:
return ir_analyze_instruction_fn_proto(ira, (IrInstructionFnProto *)instruction);
case IrInstructionIdTestComptime:
@@ -21481,10 +24433,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_decl_ref(ira, (IrInstructionDeclRef *)instruction);
case IrInstructionIdPanic:
return ir_analyze_instruction_panic(ira, (IrInstructionPanic *)instruction);
- case IrInstructionIdPtrCast:
- return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCast *)instruction);
- case IrInstructionIdBitCast:
- return ir_analyze_instruction_bit_cast(ira, (IrInstructionBitCast *)instruction);
+ case IrInstructionIdPtrCastSrc:
+ return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCastSrc *)instruction);
case IrInstructionIdIntToPtr:
return ir_analyze_instruction_int_to_ptr(ira, (IrInstructionIntToPtr *)instruction);
case IrInstructionIdPtrToInt:
@@ -21581,21 +24531,53 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
return ir_analyze_instruction_enum_to_int(ira, (IrInstructionEnumToInt *)instruction);
case IrInstructionIdCheckRuntimeScope:
return ir_analyze_instruction_check_runtime_scope(ira, (IrInstructionCheckRuntimeScope *)instruction);
+ case IrInstructionIdResultReturn:
+ return ir_analyze_instruction_result_return(ira, (IrInstructionResultReturn *)instruction);
+ case IrInstructionIdResultChild:
+ return ir_analyze_instruction_result_child(ira, (IrInstructionResultChild *)instruction);
+ case IrInstructionIdResultPtrCast:
+ return ir_analyze_instruction_result_ptr_cast(ira, (IrInstructionResultPtrCast *)instruction);
+ case IrInstructionIdResultCast:
+ return ir_analyze_instruction_result_cast(ira, (IrInstructionResultCast *)instruction);
+ case IrInstructionIdAllocaSrc:
+ return ir_analyze_instruction_alloca(ira, (IrInstructionAllocaSrc *)instruction);
+ case IrInstructionIdErrorUnionFieldErrorSet:
+ return ir_analyze_instruction_error_union_field_error_set(ira, (IrInstructionErrorUnionFieldErrorSet *)instruction);
+ case IrInstructionIdFirstArgResultLoc:
+ return ir_analyze_instruction_first_arg_result_loc(ira, (IrInstructionFirstArgResultLoc *)instruction);
+ case IrInstructionIdInferArrayType:
+ return ir_analyze_instruction_infer_array_type(ira, (IrInstructionInferArrayType *)instruction);
+ case IrInstructionIdInferCompTime:
+ return ir_analyze_instruction_infer_comptime(ira, (IrInstructionInferCompTime *)instruction);
+ case IrInstructionIdFromBytesLenSrc:
+ return ir_analyze_instruction_from_bytes_len(ira, (IrInstructionFromBytesLenSrc *)instruction);
+ case IrInstructionIdToBytesLenSrc:
+ return ir_analyze_instruction_to_bytes_len(ira, (IrInstructionToBytesLenSrc *)instruction);
+ case IrInstructionIdResultOptionalPayload:
+ return ir_analyze_instruction_result_optional_payload(ira, (IrInstructionResultOptionalPayload *)instruction);
+ case IrInstructionIdSetNonNullBit:
+ return ir_analyze_instruction_set_non_null_bit(ira, (IrInstructionSetNonNullBit *)instruction);
+ case IrInstructionIdErrorLiteral:
+ return ir_analyze_instruction_error_literal(ira, (IrInstructionErrorLiteral *)instruction);
+ case IrInstructionIdResultBytesToSlice:
+ return ir_analyze_instruction_result_bytes_to_slice(ira, (IrInstructionResultBytesToSlice *)instruction);
+ case IrInstructionIdResultSliceToBytesSrc:
+ return ir_analyze_instruction_result_slice_to_bytes(ira, (IrInstructionResultSliceToBytesSrc *)instruction);
}
zig_unreachable();
}
static IrInstruction *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *old_instruction) {
IrInstruction *new_instruction = ir_analyze_instruction_nocast(ira, old_instruction);
- assert(new_instruction->value.type != nullptr);
+ assert(new_instruction == nullptr || new_instruction->value.type != nullptr);
old_instruction->child = new_instruction;
return new_instruction;
}
// This function attempts to evaluate IR code while doing type checking and other analysis.
// It emits a new IrExecutable which is partially evaluated IR code.
-ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_exec,
- ZigType *expected_type, AstNode *expected_type_source_node)
+ConstExprValue *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_exec,
+ ZigType *expected_type, AstNode *expected_type_source_node, ConstExprValue *result_value)
{
assert(!old_exec->invalid);
assert(expected_type == nullptr || !type_is_invalid(expected_type));
@@ -21603,11 +24585,40 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_
IrAnalyze *ira = allocate(1);
old_exec->analysis = ira;
ira->codegen = codegen;
+ ira->result_value = result_value;
ZigFn *fn_entry = exec_fn_entry(old_exec);
bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
ira->explicit_return_type = is_async ? get_promise_type(codegen, expected_type) : expected_type;
ira->explicit_return_type_source_node = expected_type_source_node;
+ ira->scalar_return_type = ira->explicit_return_type;
+ ira->payload_return_type = ira->explicit_return_type;
+
+ if (fn_entry != nullptr && !is_async) {
+ if (ira->explicit_return_type->id == ZigTypeIdErrorUnion) {
+ ira->scalar_return_type = get_optional_type(ira->codegen,
+ ira->explicit_return_type->data.error_union.err_set_type);
+ ira->payload_return_type = ira->explicit_return_type->data.error_union.payload_type;
+ } else if (ira->explicit_return_type->id == ZigTypeIdOptional) {
+ if (handle_is_ptr(ira->explicit_return_type)) {
+ ira->scalar_return_type = ira->codegen->builtin_types.entry_bool;
+ ira->payload_return_type = ira->explicit_return_type->data.maybe.child_type;
+ }
+ }
+ } else if (is_async) {
+ if (expected_type->id == ZigTypeIdErrorUnion) {
+ ira->payload_return_type = expected_type->data.error_union.payload_type;
+ } else if (expected_type->id == ZigTypeIdOptional) {
+ ira->payload_return_type = expected_type->data.maybe.child_type;
+ } else {
+ ira->payload_return_type = expected_type;
+ }
+ }
+
+ if (result_value != nullptr) {
+ result_value->special = ConstValSpecialUndef;
+ result_value->type = ira->payload_return_type;
+ }
ira->old_irb.codegen = codegen;
ira->old_irb.exec = old_exec;
@@ -21638,24 +24649,63 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_
}
IrInstruction *new_instruction = ir_analyze_instruction(ira, old_instruction);
- if (type_is_invalid(new_instruction->value.type) && ir_should_inline(new_exec, old_instruction->scope)) {
- return ira->codegen->builtin_types.entry_invalid;
- }
+ if (new_instruction != nullptr) {
+ if (type_is_invalid(new_instruction->value.type) && ir_should_inline(new_exec, old_instruction->scope)) {
+ return &ira->codegen->invalid_instruction->value;
+ }
- // unreachable instructions do their own control flow.
- if (new_instruction->value.type->id == ZigTypeIdUnreachable)
- continue;
+ // unreachable instructions do their own control flow.
+ if (new_instruction->value.type->id == ZigTypeIdUnreachable)
+ continue;
+ }
ira->instruction_index += 1;
}
+
if (new_exec->invalid) {
- return ira->codegen->builtin_types.entry_invalid;
+ return &ira->codegen->invalid_instruction->value;
} else if (ira->src_implicit_return_type_list.length == 0) {
- return codegen->builtin_types.entry_unreachable;
+ return &ira->codegen->unreach_instruction->value;
+ }
+ ZigType *implicit_scalar_return_type = ir_resolve_peer_types(ira, expected_type_source_node, expected_type,
+ ira->src_implicit_return_type_list.items, ira->src_implicit_return_type_list.length);
+ if (type_is_invalid(implicit_scalar_return_type))
+ return &ira->codegen->invalid_instruction->value;
+ if (result_value == nullptr) {
+ ConstExprValue *result_val = create_const_vals(1);
+ result_val->type = implicit_scalar_return_type;
+ result_val->special = ConstValSpecialRuntime;
+ return result_val;
+ }
+
+ ConstExprValue *scalar_result = ir_exec_const_result(codegen, new_exec);
+ if (type_is_invalid(scalar_result->type))
+ return &ira->codegen->invalid_instruction->value;
+
+ if (ira->scalar_return_type == ira->explicit_return_type) {
+ return scalar_result;
+ } else if (ira->scalar_return_type->id == ZigTypeIdVoid) {
+ return result_value;
+ } else if (ira->scalar_return_type->id == ZigTypeIdBool) {
+ ConstExprValue *result_val = create_const_vals(1);
+ result_val->type = ira->explicit_return_type;
+ result_val->special = ConstValSpecialStatic;
+ if (scalar_result->data.x_bool) {
+ result_val->data.x_optional = result_value;
+ } else {
+ result_val->data.x_optional = nullptr;
+ }
+ return result_val;
+ } else if (ira->scalar_return_type->id == ZigTypeIdOptional) {
+ ConstExprValue *result_val = create_const_vals(1);
+ result_val->type = ira->explicit_return_type;
+ result_val->special = ConstValSpecialStatic;
+ result_val->data.x_err_union.error_set = scalar_result;
+ result_val->data.x_err_union.payload = result_value;
+ return result_val;
} else {
- return ir_resolve_peer_types(ira, expected_type_source_node, expected_type, ira->src_implicit_return_type_list.items,
- ira->src_implicit_return_type_list.length);
+ zig_unreachable();
}
}
@@ -21666,7 +24716,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdBr:
case IrInstructionIdCondBr:
case IrInstructionIdSwitchBr:
- case IrInstructionIdDeclVar:
+ case IrInstructionIdDeclVarSrc:
+ case IrInstructionIdDeclVarGen:
case IrInstructionIdStorePtr:
case IrInstructionIdCall:
case IrInstructionIdReturn:
@@ -21681,7 +24732,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdCInclude:
case IrInstructionIdCDefine:
case IrInstructionIdCUndef:
- case IrInstructionIdCmpxchg:
case IrInstructionIdFence:
case IrInstructionIdMemset:
case IrInstructionIdMemcpy:
@@ -21709,18 +24759,27 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdMergeErrRetTraces:
case IrInstructionIdMarkErrRetTracePtr:
case IrInstructionIdAtomicRmw:
+ case IrInstructionIdAssertNonError:
+ case IrInstructionIdAssertNonNull:
+ case IrInstructionIdContainerInitFields:
+ case IrInstructionIdContainerInitList:
+ case IrInstructionIdInferCompTime:
+ case IrInstructionIdFromBytesLenSrc:
+ case IrInstructionIdFromBytesLenGen:
+ case IrInstructionIdToBytesLenSrc:
+ case IrInstructionIdToBytesLenGen:
+ case IrInstructionIdSetNonNullBit:
+ case IrInstructionIdSlice:
+ case IrInstructionIdCmpxchgGen:
+ case IrInstructionIdCmpxchgSrc:
+ case IrInstructionIdArrayToSlice:
return true;
case IrInstructionIdPhi:
case IrInstructionIdUnOp:
case IrInstructionIdBinOp:
- case IrInstructionIdLoadPtr:
case IrInstructionIdConst:
case IrInstructionIdCast:
- case IrInstructionIdContainerInitList:
- case IrInstructionIdContainerInitFields:
- case IrInstructionIdStructInit:
- case IrInstructionIdUnionInit:
case IrInstructionIdFieldPtr:
case IrInstructionIdElemPtr:
case IrInstructionIdVarPtr:
@@ -21734,7 +24793,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdSliceType:
case IrInstructionIdSizeOf:
case IrInstructionIdTestNonNull:
- case IrInstructionIdUnwrapOptional:
+ case IrInstructionIdOptionalUnwrapPtr:
+ case IrInstructionIdOptionalUnwrapVal:
case IrInstructionIdClz:
case IrInstructionIdCtz:
case IrInstructionIdPopCount:
@@ -21746,7 +24806,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdTruncate:
case IrInstructionIdIntType:
case IrInstructionIdBoolNot:
- case IrInstructionIdSlice:
case IrInstructionIdMemberCount:
case IrInstructionIdMemberType:
case IrInstructionIdMemberName:
@@ -21761,8 +24820,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdErrWrapPayload:
case IrInstructionIdFnProto:
case IrInstructionIdTestComptime:
- case IrInstructionIdPtrCast:
- case IrInstructionIdBitCast:
+ case IrInstructionIdPtrCastSrc:
+ case IrInstructionIdPtrCastGen:
case IrInstructionIdWidenOrShorten:
case IrInstructionIdPtrToInt:
case IrInstructionIdIntToPtr:
@@ -21801,11 +24860,33 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdIntToFloat:
case IrInstructionIdFloatToInt:
case IrInstructionIdBoolToInt:
- case IrInstructionIdFromBytes:
- case IrInstructionIdToBytes:
case IrInstructionIdEnumToInt:
+ case IrInstructionIdResultOptionalPayload:
+ case IrInstructionIdResultSlicePtr:
+ case IrInstructionIdResultErrorUnionPayload:
+ case IrInstructionIdResultErrorUnionCode:
+ case IrInstructionIdResultReturn:
+ case IrInstructionIdResultChild:
+ case IrInstructionIdResultPtrCast:
+ case IrInstructionIdResultCast:
+ case IrInstructionIdResultSliceToBytesSrc:
+ case IrInstructionIdResultSliceToBytesPlaceholder:
+ case IrInstructionIdResultSliceToBytesGen:
+ case IrInstructionIdResultBytesToSlice:
+ case IrInstructionIdAllocaSrc:
+ case IrInstructionIdAllocaGen:
+ case IrInstructionIdErrorUnionFieldErrorSet:
+ case IrInstructionIdFirstArgResultLoc:
+ case IrInstructionIdInferArrayType:
+ case IrInstructionIdErrorLiteral:
return false;
+ case IrInstructionIdLoadPtr:
+ return reinterpret_cast(instruction)->result_loc != nullptr;
+
+ case IrInstructionIdPtrOfArrayToSlice:
+ return reinterpret_cast(instruction)->result_loc != nullptr;
+
case IrInstructionIdAsm:
{
IrInstructionAsm *asm_instruction = (IrInstructionAsm *)instruction;
@@ -21815,7 +24896,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
{
IrInstructionUnwrapErrPayload *unwrap_err_payload_instruction =
(IrInstructionUnwrapErrPayload *)instruction;
- return unwrap_err_payload_instruction->safety_check_on;
+ return unwrap_err_payload_instruction->safety_check_on ||
+ unwrap_err_payload_instruction->result_loc != nullptr;
}
}
zig_unreachable();
diff --git a/src/ir.hpp b/src/ir.hpp
index 7af1d7f52ba8..89044c2fde66 100644
--- a/src/ir.hpp
+++ b/src/ir.hpp
@@ -13,13 +13,13 @@
bool ir_gen(CodeGen *g, AstNode *node, Scope *scope, IrExecutable *ir_executable);
bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry);
-IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
+ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
ZigType *expected_type, size_t *backward_branch_count, size_t backward_branch_quota,
ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name,
IrExecutable *parent_exec);
-ZigType *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable,
- ZigType *expected_type, AstNode *expected_type_source_node);
+ConstExprValue *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable,
+ ZigType *expected_type, AstNode *expected_type_source_node, ConstExprValue *result_value);
bool ir_has_side_effects(IrInstruction *instruction);
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index b5099db86aaf..311a8b206bad 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -70,6 +70,17 @@ static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction)
ir_print_const_value(irp, &const_instruction->base.value);
}
+static const char *lval_str(LVal lval) {
+ switch (lval) {
+ case LValNone: return "None";
+ case LValPtr: return "Ptr";
+ case LValErrorUnionVal: return "ErrorUnionVal";
+ case LValErrorUnionPtr: return "ErrorUnionPtr";
+ case LValOptional: return "Optional";
+ }
+ zig_unreachable();
+}
+
static const char *ir_bin_op_id_str(IrBinOp op_id) {
switch (op_id) {
case IrBinOpInvalid:
@@ -172,7 +183,12 @@ static void ir_print_bin_op(IrPrint *irp, IrInstructionBinOp *bin_op_instruction
}
}
-static void ir_print_decl_var(IrPrint *irp, IrInstructionDeclVar *decl_var_instruction) {
+static void ir_print_decl_var(IrPrint *irp, IrInstructionDeclVarSrc *decl_var_instruction) {
+ if (decl_var_instruction->var->is_comptime != nullptr) {
+ fprintf(irp->f, "comptime<");
+ ir_print_other_instruction(irp, decl_var_instruction->var->is_comptime);
+ fprintf(irp->f, "> ");
+ }
const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var";
const char *name = buf_ptr(&decl_var_instruction->var->name);
if (decl_var_instruction->var_type) {
@@ -188,11 +204,7 @@ static void ir_print_decl_var(IrPrint *irp, IrInstructionDeclVar *decl_var_instr
fprintf(irp->f, " ");
}
fprintf(irp->f, "= ");
- ir_print_other_instruction(irp, decl_var_instruction->init_value);
- if (decl_var_instruction->var->is_comptime != nullptr) {
- fprintf(irp->f, " // comptime = ");
- ir_print_other_instruction(irp, decl_var_instruction->var->is_comptime);
- }
+ ir_print_other_instruction(irp, decl_var_instruction->ptr);
}
static void ir_print_cast(IrPrint *irp, IrInstructionCast *cast_instruction) {
@@ -202,6 +214,7 @@ static void ir_print_cast(IrPrint *irp, IrInstructionCast *cast_instruction) {
}
static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {
+ fprintf(irp->f, "Call ");
if (call_instruction->is_async) {
fprintf(irp->f, "async");
if (call_instruction->async_allocator != nullptr) {
@@ -224,7 +237,12 @@ 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_other_instruction(irp, call_instruction->result_loc);
+ if (call_instruction->first_arg_result_loc != nullptr) {
+ fprintf(irp->f, ", first_arg_result=");
+ ir_print_other_instruction(irp, call_instruction->first_arg_result_loc);
+ }
}
static void ir_print_cond_br(IrPrint *irp, IrInstructionCondBr *cond_br_instruction) {
@@ -266,17 +284,18 @@ static void ir_print_phi(IrPrint *irp, IrInstructionPhi *phi_instruction) {
static void ir_print_container_init_list(IrPrint *irp, IrInstructionContainerInitList *instruction) {
ir_print_other_instruction(irp, instruction->container_type);
fprintf(irp->f, "{");
- if (instruction->item_count > 50) {
- fprintf(irp->f, "...(%" ZIG_PRI_usize " items)...", instruction->item_count);
+ if (instruction->elem_count > 50) {
+ fprintf(irp->f, "...(%" ZIG_PRI_usize " items)...", instruction->elem_count);
} else {
- for (size_t i = 0; i < instruction->item_count; i += 1) {
- IrInstruction *item = instruction->items[i];
+ for (size_t i = 0; i < instruction->elem_count; i += 1) {
+ IrInstruction *elem_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, elem_result_loc);
}
}
- fprintf(irp->f, "}");
+ fprintf(irp->f, "} result=");
+ ir_print_other_instruction(irp, instruction->result_loc);
}
static void ir_print_container_init_fields(IrPrint *irp, IrInstructionContainerInitFields *instruction) {
@@ -286,30 +305,10 @@ 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");
+ fprintf(irp->f, "} // result=");
+ ir_print_other_instruction(irp, instruction->result_loc);
}
static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) {
@@ -332,8 +331,11 @@ static void ir_print_var_ptr(IrPrint *irp, IrInstructionVarPtr *instruction) {
}
static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) {
- fprintf(irp->f, "*");
+ fprintf(irp->f, "LoadPtr(ptr=");
ir_print_other_instruction(irp, instruction->ptr);
+ fprintf(irp->f, ",result=");
+ ir_print_other_instruction(irp, instruction->result_loc);
+ fprintf(irp->f, ")");
}
static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) {
@@ -479,15 +481,24 @@ static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) {
fprintf(irp->f, ")");
}
-static void ir_print_test_null(IrPrint *irp, IrInstructionTestNonNull *instruction) {
- fprintf(irp->f, "*");
+static void ir_print_test_non_null(IrPrint *irp, IrInstructionTestNonNull *instruction) {
ir_print_other_instruction(irp, instruction->value);
fprintf(irp->f, " != null");
}
-static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapOptional *instruction) {
- fprintf(irp->f, "&??*");
- ir_print_other_instruction(irp, instruction->value);
+static void ir_print_optional_unwrap_ptr(IrPrint *irp, IrInstructionOptionalUnwrapPtr *instruction) {
+ fprintf(irp->f, "OptionalUnwrapPtr(");
+ ir_print_other_instruction(irp, instruction->base_ptr);
+ fprintf(irp->f, ")");
+ if (!instruction->safety_check_on) {
+ fprintf(irp->f, " // no safety");
+ }
+}
+
+static void ir_print_optional_unwrap_val(IrPrint *irp, IrInstructionOptionalUnwrapVal *instruction) {
+ fprintf(irp->f, "OptionalUnwrapVal(");
+ ir_print_other_instruction(irp, instruction->opt);
+ fprintf(irp->f, ")");
if (!instruction->safety_check_on) {
fprintf(irp->f, " // no safety");
}
@@ -558,6 +569,8 @@ static void ir_print_ref(IrPrint *irp, IrInstructionRef *instruction) {
const char *volatile_str = instruction->is_volatile ? "volatile " : "";
fprintf(irp->f, "%s%sref ", const_str, volatile_str);
ir_print_other_instruction(irp, instruction->value);
+ fprintf(irp->f, " result=");
+ ir_print_other_instruction(irp, instruction->result_loc);
}
static void ir_print_compile_err(IrPrint *irp, IrInstructionCompileErr *instruction) {
@@ -613,7 +626,7 @@ static void ir_print_embed_file(IrPrint *irp, IrInstructionEmbedFile *instructio
fprintf(irp->f, ")");
}
-static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) {
+static void ir_print_cmpxchg_src(IrPrint *irp, IrInstructionCmpxchgSrc *instruction) {
fprintf(irp->f, "@cmpxchg(");
ir_print_other_instruction(irp, instruction->ptr);
fprintf(irp->f, ", ");
@@ -627,6 +640,17 @@ static void ir_print_cmpxchg(IrPrint *irp, IrInstructionCmpxchg *instruction) {
fprintf(irp->f, ")");
}
+static void ir_print_cmpxchg_gen(IrPrint *irp, IrInstructionCmpxchgGen *instruction) {
+ fprintf(irp->f, "@cmpxchg(%s,", buf_ptr(&instruction->type->name));
+ ir_print_other_instruction(irp, instruction->ptr);
+ fprintf(irp->f, ", ");
+ ir_print_other_instruction(irp, instruction->cmp_value);
+ fprintf(irp->f, ", ");
+ ir_print_other_instruction(irp, instruction->new_value);
+ fprintf(irp->f, ") result=");
+ ir_print_other_instruction(irp, instruction->result_loc);
+}
+
static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) {
fprintf(irp->f, "@fence(");
ir_print_other_instruction(irp, instruction->order_value);
@@ -665,20 +689,6 @@ static void ir_print_err_set_cast(IrPrint *irp, IrInstructionErrSetCast *instruc
fprintf(irp->f, ")");
}
-static void ir_print_from_bytes(IrPrint *irp, IrInstructionFromBytes *instruction) {
- fprintf(irp->f, "@bytesToSlice(");
- ir_print_other_instruction(irp, instruction->dest_child_type);
- fprintf(irp->f, ", ");
- ir_print_other_instruction(irp, instruction->target);
- fprintf(irp->f, ")");
-}
-
-static void ir_print_to_bytes(IrPrint *irp, IrInstructionToBytes *instruction) {
- fprintf(irp->f, "@sliceToBytes(");
- ir_print_other_instruction(irp, instruction->target);
- fprintf(irp->f, ")");
-}
-
static void ir_print_int_to_float(IrPrint *irp, IrInstructionIntToFloat *instruction) {
fprintf(irp->f, "@intToFloat(");
ir_print_other_instruction(irp, instruction->dest_type);
@@ -741,7 +751,8 @@ static void ir_print_slice(IrPrint *irp, IrInstructionSlice *instruction) {
fprintf(irp->f, "..");
if (instruction->end)
ir_print_other_instruction(irp, instruction->end);
- fprintf(irp->f, "]");
+ fprintf(irp->f, "] result=");
+ ir_print_other_instruction(irp, instruction->result_loc);
}
static void ir_print_member_count(IrPrint *irp, IrInstructionMemberCount *instruction) {
@@ -820,15 +831,16 @@ static void ir_print_test_err(IrPrint *irp, IrInstructionTestErr *instruction) {
}
static void ir_print_unwrap_err_code(IrPrint *irp, IrInstructionUnwrapErrCode *instruction) {
- fprintf(irp->f, "@unwrapErrorCode(");
- ir_print_other_instruction(irp, instruction->value);
+ fprintf(irp->f, "UnwrapErrorCode(");
+ ir_print_other_instruction(irp, instruction->err_union);
fprintf(irp->f, ")");
}
static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayload *instruction) {
- fprintf(irp->f, "@unwrapErrorPayload(");
+ fprintf(irp->f, "ErrorUnionFieldPayload(");
ir_print_other_instruction(irp, instruction->value);
- fprintf(irp->f, ")");
+ fprintf(irp->f, ") result=");
+ ir_print_other_instruction(irp, instruction->result_loc);
if (!instruction->safety_check_on) {
fprintf(irp->f, " // no safety");
}
@@ -879,7 +891,7 @@ static void ir_print_test_comptime(IrPrint *irp, IrInstructionTestComptime *inst
fprintf(irp->f, ")");
}
-static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) {
+static void ir_print_ptr_cast_src(IrPrint *irp, IrInstructionPtrCastSrc *instruction) {
fprintf(irp->f, "@ptrCast(");
if (instruction->dest_type) {
ir_print_other_instruction(irp, instruction->dest_type);
@@ -889,18 +901,14 @@ static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) {
fprintf(irp->f, ")");
}
-static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) {
- fprintf(irp->f, "@bitCast(");
- if (instruction->dest_type) {
- ir_print_other_instruction(irp, instruction->dest_type);
- }
- fprintf(irp->f, ",");
- ir_print_other_instruction(irp, instruction->value);
+static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruction) {
+ fprintf(irp->f, "@ptrCast(");
+ ir_print_other_instruction(irp, instruction->ptr);
fprintf(irp->f, ")");
}
static void ir_print_widen_or_shorten(IrPrint *irp, IrInstructionWidenOrShorten *instruction) {
- fprintf(irp->f, "@widenOrShorten(");
+ fprintf(irp->f, "WidenOrShorten(");
ir_print_other_instruction(irp, instruction->target);
fprintf(irp->f, ")");
}
@@ -1004,8 +1012,7 @@ static void ir_print_ptr_type(IrPrint *irp, IrInstructionPtrType *instruction) {
}
static void ir_print_decl_ref(IrPrint *irp, IrInstructionDeclRef *instruction) {
- const char *ptr_str = (instruction->lval == LValPtr) ? "ptr " : "";
- fprintf(irp->f, "declref %s%s", ptr_str, buf_ptr(instruction->tld->name));
+ fprintf(irp->f, "declref %s", buf_ptr(instruction->tld->name));
}
static void ir_print_panic(IrPrint *irp, IrInstructionPanic *instruction) {
@@ -1323,6 +1330,192 @@ static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) {
fprintf(irp->f, ")");
}
+static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *instruction) {
+ fprintf(irp->f, "DeclVarGen(name=%s,ptr=", buf_ptr(&instruction->var->name));
+ ir_print_other_instruction(irp, instruction->var_ptr);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_result_optional_payload(IrPrint *irp, IrInstructionResultOptionalPayload *instruction) {
+ fprintf(irp->f, "ResultOptionalPayload(");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ",");
+ ir_print_other_instruction(irp, instruction->payload_type);
+ fprintf(irp->f, "make_non_null=%s)", instruction->make_non_null ? "yes" : "no");
+}
+
+static void ir_print_result_slice_ptr(IrPrint *irp, IrInstructionResultSlicePtr *instruction) {
+ fprintf(irp->f, "ResultSlicePtr(");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ",len=%" ZIG_PRI_u64 ")", instruction->len);
+}
+
+static void ir_print_result_error_union_payload(IrPrint *irp, IrInstructionResultErrorUnionPayload *instruction) {
+ fprintf(irp->f, "ResultErrorUnionPayload(");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_result_error_union_code(IrPrint *irp, IrInstructionResultErrorUnionCode *instruction) {
+ fprintf(irp->f, "ResultErrorUnionCode(");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_result_return(IrPrint *irp, IrInstructionResultReturn *instruction) {
+ fprintf(irp->f, "ResultReturn");
+}
+
+static void ir_print_result_child(IrPrint *irp, IrInstructionResultChild *instruction) {
+ fprintf(irp->f, "ResultChild(prev_result=");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ",lval=%s)", lval_str(instruction->lval));
+}
+
+static void ir_print_result_bytes_to_slice(IrPrint *irp, IrInstructionResultBytesToSlice *instruction) {
+ fprintf(irp->f, "ResultBytesToSlice(");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_result_slice_to_bytes_src(IrPrint *irp, IrInstructionResultSliceToBytesSrc *instruction) {
+ fprintf(irp->f, "ResultSliceToBytesSrc");
+}
+
+static void ir_print_result_slice_to_bytes_placeholder(IrPrint *irp, IrInstructionResultSliceToBytesPlaceholder *instruction) {
+ fprintf(irp->f, "ResultSliceToBytesPlaceholder");
+}
+
+static void ir_print_result_slice_to_bytes_gen(IrPrint *irp, IrInstructionResultSliceToBytesGen *instruction) {
+ fprintf(irp->f, "ResultSliceToBytesGen");
+}
+
+static void ir_print_result_ptr_cast(IrPrint *irp, IrInstructionResultPtrCast *instruction) {
+ fprintf(irp->f, "ResultPtrCast(ty=");
+ ir_print_other_instruction(irp, instruction->elem_type);
+ fprintf(irp->f, ",prev_result=");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_result_cast(IrPrint *irp, IrInstructionResultCast *instruction) {
+ fprintf(irp->f, "ResultCast(child_ty=");
+ ir_print_other_instruction(irp, instruction->elem_type);
+ fprintf(irp->f, ",prev_result=");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_alloca_src(IrPrint *irp, IrInstructionAllocaSrc *instruction) {
+ fprintf(irp->f, "AllocaSrc(ty=");
+ ir_print_other_instruction(irp, instruction->child_type);
+ fprintf(irp->f, ",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, "AllocaGen(align=%" PRIu32 ",name=%s)", instruction->align, instruction->name_hint);
+}
+
+static void ir_print_assert_non_error(IrPrint *irp, IrInstructionAssertNonError *instruction) {
+ fprintf(irp->f, "AssertNonError(");
+ ir_print_other_instruction(irp, instruction->err_code);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_assert_non_null(IrPrint *irp, IrInstructionAssertNonNull *instruction) {
+ fprintf(irp->f, "AssertNonNull(");
+ ir_print_other_instruction(irp, instruction->is_non_null);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_error_union_field_error_set(IrPrint *irp, IrInstructionErrorUnionFieldErrorSet *instruction) {
+ fprintf(irp->f, "ErrorUnionFieldErrorSet(");
+ ir_print_other_instruction(irp, instruction->ptr);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_first_arg_result_loc(IrPrint *irp, IrInstructionFirstArgResultLoc *instruction) {
+ fprintf(irp->f, "FirstArgResultLoc(prev_result=");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ",fn=");
+ ir_print_other_instruction(irp, instruction->fn_ref);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_infer_array_type(IrPrint *irp, IrInstructionInferArrayType *instruction) {
+ fprintf(irp->f, "InferArrayType(src_type=");
+ ir_print_other_instruction(irp, instruction->src_type);
+ fprintf(irp->f, ",elem_count=%zu)", instruction->elem_count);
+}
+
+static void ir_print_infer_comptime(IrPrint *irp, IrInstructionInferCompTime *instruction) {
+ fprintf(irp->f, "InferCompTime(prev_result=");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ",new_result=");
+ ir_print_other_instruction(irp, instruction->new_result_loc);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_from_bytes_len_src(IrPrint *irp, IrInstructionFromBytesLenSrc *instruction) {
+ fprintf(irp->f, "FromBytesLenSrc(prev_result=");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ",new_result=");
+ ir_print_other_instruction(irp, instruction->new_result_loc);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_from_bytes_len_gen(IrPrint *irp, IrInstructionFromBytesLenGen *instruction) {
+ fprintf(irp->f, "FromBytesLenGen(prev_result=");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ",elem_type=%s)", buf_ptr(&instruction->elem_type->name));
+}
+
+static void ir_print_to_bytes_len_src(IrPrint *irp, IrInstructionToBytesLenSrc *instruction) {
+ fprintf(irp->f, "ToBytesLenSrc(prev_result=");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ",new_result=");
+ ir_print_other_instruction(irp, instruction->new_result_loc);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_to_bytes_len_gen(IrPrint *irp, IrInstructionToBytesLenGen *instruction) {
+ fprintf(irp->f, "ToBytesLenGen(prev_result=");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ",elem_type=%s)", buf_ptr(&instruction->elem_type->name));
+}
+
+static void ir_print_set_non_null_bit(IrPrint *irp, IrInstructionSetNonNullBit *instruction) {
+ fprintf(irp->f, "SetNonNullBit(prev_result=");
+ ir_print_other_instruction(irp, instruction->prev_result_loc);
+ fprintf(irp->f, ",new_result=");
+ ir_print_other_instruction(irp, instruction->new_result_loc);
+ fprintf(irp->f, ",non_null_bit=");
+ ir_print_other_instruction(irp, instruction->non_null_bit);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_error_literal(IrPrint *irp, IrInstructionErrorLiteral *instruction) {
+ fprintf(irp->f, "error.%s", buf_ptr(instruction->name));
+}
+
+static void ir_print_ptr_of_array_to_slice(IrPrint *irp, IrInstructionPtrOfArrayToSlice *instruction) {
+ fprintf(irp->f, "PtrOfArrayToSlice(value=");
+ ir_print_other_instruction(irp, instruction->value);
+ fprintf(irp->f, ",result=");
+ ir_print_other_instruction(irp, instruction->result_loc);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_array_to_slice(IrPrint *irp, IrInstructionArrayToSlice *instruction) {
+ fprintf(irp->f, "ArrayToSlice(array=");
+ ir_print_other_instruction(irp, instruction->array);
+ fprintf(irp->f, ",result=");
+ ir_print_other_instruction(irp, instruction->result_loc);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) {
fprintf(irp->f, "@bswap(");
if (instruction->type != nullptr) {
@@ -1361,8 +1554,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdBinOp:
ir_print_bin_op(irp, (IrInstructionBinOp *)instruction);
break;
- case IrInstructionIdDeclVar:
- ir_print_decl_var(irp, (IrInstructionDeclVar *)instruction);
+ case IrInstructionIdDeclVarSrc:
+ ir_print_decl_var(irp, (IrInstructionDeclVarSrc *)instruction);
break;
case IrInstructionIdCast:
ir_print_cast(irp, (IrInstructionCast *)instruction);
@@ -1388,12 +1581,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;
@@ -1452,10 +1639,13 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_size_of(irp, (IrInstructionSizeOf *)instruction);
break;
case IrInstructionIdTestNonNull:
- ir_print_test_null(irp, (IrInstructionTestNonNull *)instruction);
+ ir_print_test_non_null(irp, (IrInstructionTestNonNull *)instruction);
break;
- case IrInstructionIdUnwrapOptional:
- ir_print_unwrap_maybe(irp, (IrInstructionUnwrapOptional *)instruction);
+ case IrInstructionIdOptionalUnwrapPtr:
+ ir_print_optional_unwrap_ptr(irp, (IrInstructionOptionalUnwrapPtr *)instruction);
+ break;
+ case IrInstructionIdOptionalUnwrapVal:
+ ir_print_optional_unwrap_val(irp, (IrInstructionOptionalUnwrapVal *)instruction);
break;
case IrInstructionIdCtz:
ir_print_ctz(irp, (IrInstructionCtz *)instruction);
@@ -1508,8 +1698,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdEmbedFile:
ir_print_embed_file(irp, (IrInstructionEmbedFile *)instruction);
break;
- case IrInstructionIdCmpxchg:
- ir_print_cmpxchg(irp, (IrInstructionCmpxchg *)instruction);
+ case IrInstructionIdCmpxchgSrc:
+ ir_print_cmpxchg_src(irp, (IrInstructionCmpxchgSrc *)instruction);
+ break;
+ case IrInstructionIdCmpxchgGen:
+ ir_print_cmpxchg_gen(irp, (IrInstructionCmpxchgGen *)instruction);
break;
case IrInstructionIdFence:
ir_print_fence(irp, (IrInstructionFence *)instruction);
@@ -1526,12 +1719,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdErrSetCast:
ir_print_err_set_cast(irp, (IrInstructionErrSetCast *)instruction);
break;
- case IrInstructionIdFromBytes:
- ir_print_from_bytes(irp, (IrInstructionFromBytes *)instruction);
- break;
- case IrInstructionIdToBytes:
- ir_print_to_bytes(irp, (IrInstructionToBytes *)instruction);
- break;
case IrInstructionIdIntToFloat:
ir_print_int_to_float(irp, (IrInstructionIntToFloat *)instruction);
break;
@@ -1607,11 +1794,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdTestComptime:
ir_print_test_comptime(irp, (IrInstructionTestComptime *)instruction);
break;
- case IrInstructionIdPtrCast:
- ir_print_ptr_cast(irp, (IrInstructionPtrCast *)instruction);
+ case IrInstructionIdPtrCastSrc:
+ ir_print_ptr_cast_src(irp, (IrInstructionPtrCastSrc *)instruction);
break;
- case IrInstructionIdBitCast:
- ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction);
+ case IrInstructionIdPtrCastGen:
+ ir_print_ptr_cast_gen(irp, (IrInstructionPtrCastGen *)instruction);
break;
case IrInstructionIdWidenOrShorten:
ir_print_widen_or_shorten(irp, (IrInstructionWidenOrShorten *)instruction);
@@ -1775,6 +1962,93 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdCheckRuntimeScope:
ir_print_check_runtime_scope(irp, (IrInstructionCheckRuntimeScope *)instruction);
break;
+ case IrInstructionIdDeclVarGen:
+ ir_print_decl_var_gen(irp, (IrInstructionDeclVarGen *)instruction);
+ break;
+ case IrInstructionIdResultOptionalPayload:
+ ir_print_result_optional_payload(irp, (IrInstructionResultOptionalPayload *)instruction);
+ break;
+ case IrInstructionIdResultSlicePtr:
+ ir_print_result_slice_ptr(irp, (IrInstructionResultSlicePtr *)instruction);
+ break;
+ case IrInstructionIdResultErrorUnionPayload:
+ ir_print_result_error_union_payload(irp, (IrInstructionResultErrorUnionPayload *)instruction);
+ break;
+ case IrInstructionIdResultErrorUnionCode:
+ ir_print_result_error_union_code(irp, (IrInstructionResultErrorUnionCode *)instruction);
+ break;
+ case IrInstructionIdResultReturn:
+ ir_print_result_return(irp, (IrInstructionResultReturn *)instruction);
+ break;
+ case IrInstructionIdResultChild:
+ ir_print_result_child(irp, (IrInstructionResultChild *)instruction);
+ break;
+ case IrInstructionIdResultBytesToSlice:
+ ir_print_result_bytes_to_slice(irp, (IrInstructionResultBytesToSlice *)instruction);
+ break;
+ case IrInstructionIdResultSliceToBytesSrc:
+ ir_print_result_slice_to_bytes_src(irp, (IrInstructionResultSliceToBytesSrc *)instruction);
+ break;
+ case IrInstructionIdResultSliceToBytesPlaceholder:
+ ir_print_result_slice_to_bytes_placeholder(irp, (IrInstructionResultSliceToBytesPlaceholder *)instruction);
+ break;
+ case IrInstructionIdResultSliceToBytesGen:
+ ir_print_result_slice_to_bytes_gen(irp, (IrInstructionResultSliceToBytesGen *)instruction);
+ break;
+ case IrInstructionIdResultPtrCast:
+ ir_print_result_ptr_cast(irp, (IrInstructionResultPtrCast *)instruction);
+ break;
+ case IrInstructionIdResultCast:
+ ir_print_result_cast(irp, (IrInstructionResultCast *)instruction);
+ break;
+ case IrInstructionIdAllocaSrc:
+ ir_print_alloca_src(irp, (IrInstructionAllocaSrc *)instruction);
+ break;
+ case IrInstructionIdAllocaGen:
+ ir_print_alloca_gen(irp, (IrInstructionAllocaGen *)instruction);
+ break;
+ case IrInstructionIdAssertNonError:
+ ir_print_assert_non_error(irp, (IrInstructionAssertNonError *)instruction);
+ break;
+ case IrInstructionIdAssertNonNull:
+ ir_print_assert_non_null(irp, (IrInstructionAssertNonNull *)instruction);
+ break;
+ case IrInstructionIdErrorUnionFieldErrorSet:
+ ir_print_error_union_field_error_set(irp, (IrInstructionErrorUnionFieldErrorSet *)instruction);
+ break;
+ case IrInstructionIdFirstArgResultLoc:
+ ir_print_first_arg_result_loc(irp, (IrInstructionFirstArgResultLoc *)instruction);
+ break;
+ case IrInstructionIdInferArrayType:
+ ir_print_infer_array_type(irp, (IrInstructionInferArrayType *)instruction);
+ break;
+ case IrInstructionIdInferCompTime:
+ ir_print_infer_comptime(irp, (IrInstructionInferCompTime *)instruction);
+ break;
+ case IrInstructionIdFromBytesLenSrc:
+ ir_print_from_bytes_len_src(irp, (IrInstructionFromBytesLenSrc *)instruction);
+ break;
+ case IrInstructionIdFromBytesLenGen:
+ ir_print_from_bytes_len_gen(irp, (IrInstructionFromBytesLenGen *)instruction);
+ break;
+ case IrInstructionIdToBytesLenSrc:
+ ir_print_to_bytes_len_src(irp, (IrInstructionToBytesLenSrc *)instruction);
+ break;
+ case IrInstructionIdToBytesLenGen:
+ ir_print_to_bytes_len_gen(irp, (IrInstructionToBytesLenGen *)instruction);
+ break;
+ case IrInstructionIdSetNonNullBit:
+ ir_print_set_non_null_bit(irp, (IrInstructionSetNonNullBit *)instruction);
+ break;
+ case IrInstructionIdErrorLiteral:
+ ir_print_error_literal(irp, (IrInstructionErrorLiteral *)instruction);
+ break;
+ case IrInstructionIdPtrOfArrayToSlice:
+ ir_print_ptr_of_array_to_slice(irp, (IrInstructionPtrOfArrayToSlice *)instruction);
+ break;
+ case IrInstructionIdArrayToSlice:
+ ir_print_array_to_slice(irp, (IrInstructionArrayToSlice *)instruction);
+ break;
}
fprintf(irp->f, "\n");
}
diff --git a/src/parser.cpp b/src/parser.cpp
index 077365995e87..d272e1077fb9 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -381,7 +381,7 @@ static AstNode *ast_parse_if_expr_helper(ParseContext *pc, AstNode *(*body_parse
else_body = ast_expect(pc, body_parser);
}
- assert(res->type == NodeTypeTestExpr);
+ assert(res->type == NodeTypeIfOptional);
if (err_payload != nullptr) {
AstNodeTestExpr old = res->data.test_expr;
res->type = NodeTypeIfErrorExpr;
@@ -990,7 +990,7 @@ static AstNode *ast_parse_if_statement(ParseContext *pc) {
if (requires_semi && else_body == nullptr)
expect_token(pc, TokenIdSemicolon);
- assert(res->type == NodeTypeTestExpr);
+ assert(res->type == NodeTypeIfOptional);
if (err_payload != nullptr) {
AstNodeTestExpr old = res->data.test_expr;
res->type = NodeTypeIfErrorExpr;
@@ -1717,10 +1717,8 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) {
if (error != nullptr) {
Token *dot = expect_token(pc, TokenIdDot);
Token *name = expect_token(pc, TokenIdSymbol);
- AstNode *left = ast_create_node(pc, NodeTypeErrorType, error);
- AstNode *res = ast_create_node(pc, NodeTypeFieldAccessExpr, dot);
- res->data.field_access_expr.struct_expr = left;
- res->data.field_access_expr.field_name = token_buf(name);
+ AstNode *res = ast_create_node(pc, NodeTypeErrorLiteral, dot);
+ res->data.error_literal.name = token_buf(name);
return res;
}
@@ -2204,7 +2202,7 @@ static AstNode *ast_parse_if_prefix(ParseContext *pc) {
Optional opt_payload = ast_parse_ptr_payload(pc);
PtrPayload payload;
- AstNode *res = ast_create_node(pc, NodeTypeTestExpr, first);
+ AstNode *res = ast_create_node(pc, NodeTypeIfOptional, first);
res->data.test_expr.target_node = condition;
if (opt_payload.unwrap(&payload)) {
res->data.test_expr.var_symbol = token_buf(payload.payload);
@@ -2999,7 +2997,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
visit_field(&node->data.if_err_expr.then_node, visit, context);
visit_field(&node->data.if_err_expr.else_node, visit, context);
break;
- case NodeTypeTestExpr:
+ case NodeTypeIfOptional:
visit_field(&node->data.test_expr.target_node, visit, context);
visit_field(&node->data.test_expr.then_node, visit, context);
visit_field(&node->data.test_expr.else_node, visit, context);
@@ -3095,5 +3093,8 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
case NodeTypeSuspend:
visit_field(&node->data.suspend.block, visit, context);
break;
+ case NodeTypeErrorLiteral:
+ // none
+ break;
}
}
diff --git a/std/debug/index.zig b/std/debug/index.zig
index 445f943594cd..5819840414a9 100644
--- a/std/debug/index.zig
+++ b/std/debug/index.zig
@@ -1953,7 +1953,8 @@ fn scanAllCompileUnits(di: *DwarfInfo) !void {
if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
- const pc_range = x: {
+ // TODO: https://github.com/ziglang/zig/pull/1682#issuecomment-451261326
+ const pc_range: ?PcRange = x: {
if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
const pc_end = switch (high_pc_value.*) {
diff --git a/std/fmt/index.zig b/std/fmt/index.zig
index b010072273b5..99885ed40862 100644
--- a/std/fmt/index.zig
+++ b/std/fmt/index.zig
@@ -710,7 +710,7 @@ fn formatIntSigned(
const minus_sign: u8 = '-';
try output(context, (*[1]u8)(&minus_sign)[0..]);
const new_value = @intCast(uint, -(value + 1)) + 1;
- const new_width = if (width == 0) 0 else (width - 1);
+ const new_width: usize = if (width == 0) 0 else (width - 1);
return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
} else if (width == 0) {
return formatIntUnsigned(@intCast(uint, value), base, uppercase, width, context, Errors, output);
@@ -718,7 +718,7 @@ fn formatIntSigned(
const plus_sign: u8 = '+';
try output(context, (*[1]u8)(&plus_sign)[0..]);
const new_value = @intCast(uint, value);
- const new_width = if (width == 0) 0 else (width - 1);
+ const new_width: usize = if (width == 0) 0 else (width - 1);
return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
}
}
@@ -760,7 +760,7 @@ fn formatIntUnsigned(
if (leftover_padding == 0) break;
}
mem.set(u8, buf[0..index], '0');
- return output(context, buf);
+ return output(context, &buf);
} else {
const padded_buf = buf[index - padding ..];
mem.set(u8, padded_buf[0..padding], '0');
diff --git a/std/heap.zig b/std/heap.zig
index 46b247fa7ead..b2210a317108 100644
--- a/std/heap.zig
+++ b/std/heap.zig
@@ -243,7 +243,8 @@ pub const ArenaAllocator = struct {
const cur_buf = cur_node.data[@sizeOf(BufNode)..];
const addr = @ptrToInt(cur_buf.ptr) + self.end_index;
const rem = @rem(addr, alignment);
- const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
+ // TODO: https://github.com/ziglang/zig/pull/1682#issuecomment-451261326
+ const march_forward_bytes: usize = if (rem == 0) 0 else (alignment - rem);
const adjusted_index = self.end_index + march_forward_bytes;
const new_end_index = adjusted_index + n;
if (new_end_index > cur_buf.len) {
@@ -290,7 +291,8 @@ pub const FixedBufferAllocator = struct {
const self = @fieldParentPtr(FixedBufferAllocator, "allocator", allocator);
const addr = @ptrToInt(self.buffer.ptr) + self.end_index;
const rem = @rem(addr, alignment);
- const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
+ // TODO: https://github.com/ziglang/zig/pull/1682#issuecomment-451303797
+ const march_forward_bytes: usize = if (rem == 0) 0 else (alignment - rem);
const adjusted_index = self.end_index + march_forward_bytes;
const new_end_index = adjusted_index + n;
if (new_end_index > self.buffer.len) {
@@ -348,7 +350,8 @@ pub const ThreadSafeFixedBufferAllocator = struct {
while (true) {
const addr = @ptrToInt(self.buffer.ptr) + end_index;
const rem = @rem(addr, alignment);
- const march_forward_bytes = if (rem == 0) 0 else (alignment - rem);
+ // TODO: https://github.com/ziglang/zig/pull/1682#issuecomment-451303797
+ const march_forward_bytes: usize = if (rem == 0) 0 else (alignment - rem);
const adjusted_index = end_index + march_forward_bytes;
const new_end_index = adjusted_index + n;
if (new_end_index > self.buffer.len) {
diff --git a/std/math/index.zig b/std/math/index.zig
index f37de2505b24..d254c50b3840 100644
--- a/std/math/index.zig
+++ b/std/math/index.zig
@@ -378,7 +378,7 @@ pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) t
return u0;
}
const is_signed = from < 0;
- const largest_positive_integer = max(if (from<0) (-from)-1 else from, to); // two's complement
+ const largest_positive_integer = max(if (from < 0) (-from) - 1 else from, to); // two's complement
const base = log2(largest_positive_integer);
const upper = (1 << base) - 1;
var magnitude_bits = if (upper >= largest_positive_integer) base else base + 1;
diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig
index 129bde913fd2..fb3649735d9c 100644
--- a/std/special/bootstrap.zig
+++ b/std/special/bootstrap.zig
@@ -22,8 +22,8 @@ nakedcc fn _start() noreturn {
switch (builtin.arch) {
builtin.Arch.x86_64 => {
argc_ptr = asm ("lea (%%rsp), %[argc]"
- : [argc] "=r" (-> [*]usize)
- );
+ : [argc] "=r" (-> [*]usize)
+ );
},
builtin.Arch.i386 => {
argc_ptr = asm ("lea (%%esp), %[argc]"
@@ -104,11 +104,12 @@ inline fn callMain() u8 {
builtin.TypeId.ErrorUnion => {
root.main() catch |err| {
std.debug.warn("error: {}\n", @errorName(err));
- if (builtin.os != builtin.Os.zen) {
- if (@errorReturnTrace()) |trace| {
- std.debug.dumpStackTrace(trace);
- }
- }
+ // TODO: restore this
+ //if (builtin.os != builtin.Os.zen) {
+ // if (@errorReturnTrace()) |trace| {
+ // std.debug.dumpStackTrace(trace);
+ // }
+ //}
return 1;
};
return 0;
diff --git a/std/special/compiler_rt/fixint.zig b/std/special/compiler_rt/fixint.zig
index fd31798cc2f9..2c85bc73d7c9 100644
--- a/std/special/compiler_rt/fixint.zig
+++ b/std/special/compiler_rt/fixint.zig
@@ -63,9 +63,17 @@ pub fn fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t) fixint_t {
// Cast to final signed result
if (negative) {
- return if (uint_result >= -math.minInt(fixint_t)) math.minInt(fixint_t) else -@intCast(fixint_t, uint_result);
+ if (uint_result >= -math.minInt(fixint_t)) {
+ return math.minInt(fixint_t);
+ } else {
+ return -@intCast(fixint_t, uint_result);
+ }
} else {
- return if (uint_result >= math.maxInt(fixint_t)) math.maxInt(fixint_t) else @intCast(fixint_t, uint_result);
+ if (uint_result >= math.maxInt(fixint_t)) {
+ return math.maxInt(fixint_t);
+ } else {
+ return @intCast(fixint_t, uint_result);
+ }
}
}
diff --git a/std/special/panic.zig b/std/special/panic.zig
index bd3ad971e0cb..88a202832b24 100644
--- a/std/special/panic.zig
+++ b/std/special/panic.zig
@@ -18,8 +18,11 @@ pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn
std.os.abort();
},
else => {
- const first_trace_addr = @ptrToInt(@returnAddress());
- std.debug.panicExtra(error_return_trace, first_trace_addr, "{}", msg);
+ // TODO put the original panic code back
+ std.debug.warn("panic: {}\n", msg);
+ std.os.abort();
+ //const first_trace_addr = @ptrToInt(@returnAddress());
+ //std.debug.panicExtra(error_return_trace, first_trace_addr, "{}", msg);
},
}
}
diff --git a/test/behavior.zig b/test/behavior.zig
deleted file mode 100644
index 10cd08dad717..000000000000
--- a/test/behavior.zig
+++ /dev/null
@@ -1,82 +0,0 @@
-const builtin = @import("builtin");
-
-comptime {
- _ = @import("cases/align.zig");
- _ = @import("cases/alignof.zig");
- _ = @import("cases/array.zig");
- _ = @import("cases/asm.zig");
- _ = @import("cases/atomics.zig");
- _ = @import("cases/bitcast.zig");
- _ = @import("cases/bool.zig");
- _ = @import("cases/bswap.zig");
- _ = @import("cases/bitreverse.zig");
- _ = @import("cases/bugs/1076.zig");
- _ = @import("cases/bugs/1111.zig");
- _ = @import("cases/bugs/1277.zig");
- _ = @import("cases/bugs/1322.zig");
- _ = @import("cases/bugs/1381.zig");
- _ = @import("cases/bugs/1421.zig");
- _ = @import("cases/bugs/1442.zig");
- _ = @import("cases/bugs/1486.zig");
- _ = @import("cases/bugs/394.zig");
- _ = @import("cases/bugs/655.zig");
- _ = @import("cases/bugs/656.zig");
- _ = @import("cases/bugs/726.zig");
- _ = @import("cases/bugs/828.zig");
- _ = @import("cases/bugs/920.zig");
- _ = @import("cases/byval_arg_var.zig");
- _ = @import("cases/cancel.zig");
- _ = @import("cases/cast.zig");
- _ = @import("cases/const_slice_child.zig");
- _ = @import("cases/coroutine_await_struct.zig");
- _ = @import("cases/coroutines.zig");
- _ = @import("cases/defer.zig");
- _ = @import("cases/enum.zig");
- _ = @import("cases/enum_with_members.zig");
- _ = @import("cases/error.zig");
- _ = @import("cases/eval.zig");
- _ = @import("cases/field_parent_ptr.zig");
- _ = @import("cases/fn.zig");
- _ = @import("cases/fn_in_struct_in_comptime.zig");
- _ = @import("cases/for.zig");
- _ = @import("cases/generics.zig");
- _ = @import("cases/if.zig");
- _ = @import("cases/import.zig");
- _ = @import("cases/incomplete_struct_param_tld.zig");
- _ = @import("cases/inttoptr.zig");
- _ = @import("cases/ir_block_deps.zig");
- _ = @import("cases/math.zig");
- _ = @import("cases/merge_error_sets.zig");
- _ = @import("cases/misc.zig");
- _ = @import("cases/namespace_depends_on_compile_var/index.zig");
- _ = @import("cases/new_stack_call.zig");
- _ = @import("cases/null.zig");
- _ = @import("cases/optional.zig");
- _ = @import("cases/pointers.zig");
- _ = @import("cases/popcount.zig");
- _ = @import("cases/ptrcast.zig");
- _ = @import("cases/pub_enum/index.zig");
- _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");
- _ = @import("cases/reflection.zig");
- _ = @import("cases/sizeof_and_typeof.zig");
- _ = @import("cases/slice.zig");
- _ = @import("cases/struct.zig");
- _ = @import("cases/struct_contains_null_ptr_itself.zig");
- _ = @import("cases/struct_contains_slice_of_itself.zig");
- _ = @import("cases/switch.zig");
- _ = @import("cases/switch_prong_err_enum.zig");
- _ = @import("cases/switch_prong_implicit_cast.zig");
- _ = @import("cases/syntax.zig");
- _ = @import("cases/this.zig");
- _ = @import("cases/truncate.zig");
- _ = @import("cases/try.zig");
- _ = @import("cases/type_info.zig");
- _ = @import("cases/undefined.zig");
- _ = @import("cases/underscore.zig");
- _ = @import("cases/union.zig");
- _ = @import("cases/var_args.zig");
- _ = @import("cases/void.zig");
- _ = @import("cases/while.zig");
- _ = @import("cases/widening.zig");
- _ = @import("cases/bit_shifting.zig");
-}
diff --git a/test/cases/array.zig b/test/cases/array.zig
deleted file mode 100644
index 7c63a649a8f3..000000000000
--- a/test/cases/array.zig
+++ /dev/null
@@ -1,173 +0,0 @@
-const assert = @import("std").debug.assert;
-const mem = @import("std").mem;
-
-test "arrays" {
- var array: [5]u32 = undefined;
-
- var i: u32 = 0;
- while (i < 5) {
- array[i] = i + 1;
- i = array[i];
- }
-
- i = 0;
- var accumulator = u32(0);
- while (i < 5) {
- accumulator += array[i];
-
- i += 1;
- }
-
- assert(accumulator == 15);
- assert(getArrayLen(array) == 5);
-}
-fn getArrayLen(a: []const u32) usize {
- return a.len;
-}
-
-test "void arrays" {
- var array: [4]void = undefined;
- array[0] = void{};
- array[1] = array[2];
- assert(@sizeOf(@typeOf(array)) == 0);
- assert(array.len == 4);
-}
-
-test "array literal" {
- const hex_mult = []u16{
- 4096,
- 256,
- 16,
- 1,
- };
-
- assert(hex_mult.len == 4);
- assert(hex_mult[1] == 256);
-}
-
-test "array dot len const expr" {
- assert(comptime x: {
- break :x some_array.len == 4;
- });
-}
-
-const ArrayDotLenConstExpr = struct {
- y: [some_array.len]u8,
-};
-const some_array = []u8{
- 0,
- 1,
- 2,
- 3,
-};
-
-test "nested arrays" {
- const array_of_strings = [][]const u8{
- "hello",
- "this",
- "is",
- "my",
- "thing",
- };
- for (array_of_strings) |s, i| {
- if (i == 0) assert(mem.eql(u8, s, "hello"));
- if (i == 1) assert(mem.eql(u8, s, "this"));
- if (i == 2) assert(mem.eql(u8, s, "is"));
- if (i == 3) assert(mem.eql(u8, s, "my"));
- if (i == 4) assert(mem.eql(u8, s, "thing"));
- }
-}
-
-var s_array: [8]Sub = undefined;
-const Sub = struct {
- b: u8,
-};
-const Str = struct {
- a: []Sub,
-};
-test "set global var array via slice embedded in struct" {
- var s = Str{ .a = s_array[0..] };
-
- s.a[0].b = 1;
- s.a[1].b = 2;
- s.a[2].b = 3;
-
- assert(s_array[0].b == 1);
- assert(s_array[1].b == 2);
- assert(s_array[2].b == 3);
-}
-
-test "array literal with specified size" {
- var array = [2]u8{
- 1,
- 2,
- };
- assert(array[0] == 1);
- assert(array[1] == 2);
-}
-
-test "array child property" {
- var x: [5]i32 = undefined;
- assert(@typeOf(x).Child == i32);
-}
-
-test "array len property" {
- var x: [5]i32 = undefined;
- assert(@typeOf(x).len == 5);
-}
-
-test "array len field" {
- var arr = [4]u8{ 0, 0, 0, 0 };
- var ptr = &arr;
- assert(arr.len == 4);
- comptime assert(arr.len == 4);
- assert(ptr.len == 4);
- comptime assert(ptr.len == 4);
-}
-
-test "single-item pointer to array indexing and slicing" {
- testSingleItemPtrArrayIndexSlice();
- comptime testSingleItemPtrArrayIndexSlice();
-}
-
-fn testSingleItemPtrArrayIndexSlice() void {
- var array = "aaaa";
- doSomeMangling(&array);
- assert(mem.eql(u8, "azya", array));
-}
-
-fn doSomeMangling(array: *[4]u8) void {
- array[1] = 'z';
- array[2..3][0] = 'y';
-}
-
-test "implicit cast single-item pointer" {
- testImplicitCastSingleItemPtr();
- comptime testImplicitCastSingleItemPtr();
-}
-
-fn testImplicitCastSingleItemPtr() void {
- var byte: u8 = 100;
- const slice = (*[1]u8)(&byte)[0..];
- slice[0] += 1;
- assert(byte == 101);
-}
-
-fn testArrayByValAtComptime(b: [2]u8) u8 {
- return b[0];
-}
-
-test "comptime evalutating function that takes array by value" {
- const arr = []u8{ 0, 1 };
- _ = comptime testArrayByValAtComptime(arr);
- _ = comptime testArrayByValAtComptime(arr);
-}
-
-test "implicit comptime in array type size" {
- var arr: [plusOne(10)]bool = undefined;
- assert(arr.len == 11);
-}
-
-fn plusOne(x: u32) u32 {
- return x + 1;
-}
diff --git a/test/cases/asm.zig b/test/cases/asm.zig
deleted file mode 100644
index 63e37c857c1d..000000000000
--- a/test/cases/asm.zig
+++ /dev/null
@@ -1,48 +0,0 @@
-const config = @import("builtin");
-const assert = @import("std").debug.assert;
-
-comptime {
- if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
- asm volatile (
- \\.globl aoeu;
- \\.type aoeu, @function;
- \\.set aoeu, derp;
- );
- }
-}
-
-test "module level assembly" {
- if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
- assert(aoeu() == 1234);
- }
-}
-
-test "output constraint modifiers" {
- // This is only testing compilation.
- var a: u32 = 3;
- asm volatile ("" : [_]"=m,r"(a) : : "");
- asm volatile ("" : [_]"=r,m"(a) : : "");
-}
-
-test "alternative constraints" {
- // Make sure we allow commas as a separator for alternative constraints.
- var a: u32 = 3;
- asm volatile ("" : [_]"=r,m"(a) : [_]"r,m"(a) : "");
-}
-
-test "sized integer/float in asm input" {
- asm volatile ("" : : [_]"m"(usize(3)) : "");
- asm volatile ("" : : [_]"m"(i15(-3)) : "");
- asm volatile ("" : : [_]"m"(u3(3)) : "");
- asm volatile ("" : : [_]"m"(i3(3)) : "");
- asm volatile ("" : : [_]"m"(u121(3)) : "");
- asm volatile ("" : : [_]"m"(i121(3)) : "");
- asm volatile ("" : : [_]"m"(f32(3.17)) : "");
- asm volatile ("" : : [_]"m"(f64(3.17)) : "");
-}
-
-extern fn aoeu() i32;
-
-export fn derp() i32 {
- return 1234;
-}
diff --git a/test/cases/bitreverse.zig b/test/cases/bitreverse.zig
deleted file mode 100644
index 3721e68a9431..000000000000
--- a/test/cases/bitreverse.zig
+++ /dev/null
@@ -1,81 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-const minInt = std.math.minInt;
-
-test "@bitreverse" {
- comptime testBitReverse();
- testBitReverse();
-}
-
-fn testBitReverse() void {
- // using comptime_ints, unsigned
- assert(@bitreverse(u0, 0) == 0);
- assert(@bitreverse(u5, 0x12) == 0x9);
- assert(@bitreverse(u8, 0x12) == 0x48);
- assert(@bitreverse(u16, 0x1234) == 0x2c48);
- assert(@bitreverse(u24, 0x123456) == 0x6a2c48);
- assert(@bitreverse(u32, 0x12345678) == 0x1e6a2c48);
- assert(@bitreverse(u40, 0x123456789a) == 0x591e6a2c48);
- assert(@bitreverse(u48, 0x123456789abc) == 0x3d591e6a2c48);
- assert(@bitreverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48);
- assert(@bitreverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48);
- assert(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48);
-
- // using runtime uints, unsigned
- var num0: u0 = 0;
- assert(@bitreverse(u0, num0) == 0);
- var num5: u5 = 0x12;
- assert(@bitreverse(u5, num5) == 0x9);
- var num8: u8 = 0x12;
- assert(@bitreverse(u8, num8) == 0x48);
- var num16: u16 = 0x1234;
- assert(@bitreverse(u16, num16) == 0x2c48);
- var num24: u24 = 0x123456;
- assert(@bitreverse(u24, num24) == 0x6a2c48);
- var num32: u32 = 0x12345678;
- assert(@bitreverse(u32, num32) == 0x1e6a2c48);
- var num40: u40 = 0x123456789a;
- assert(@bitreverse(u40, num40) == 0x591e6a2c48);
- var num48: u48 = 0x123456789abc;
- assert(@bitreverse(u48, num48) == 0x3d591e6a2c48);
- var num56: u56 = 0x123456789abcde;
- assert(@bitreverse(u56, num56) == 0x7b3d591e6a2c48);
- var num64: u64 = 0x123456789abcdef1;
- assert(@bitreverse(u64, num64) == 0x8f7b3d591e6a2c48);
- var num128: u128 = 0x123456789abcdef11121314151617181;
- assert(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48);
-
- // using comptime_ints, signed, positive
- assert(@bitreverse(i0, 0) == 0);
- assert(@bitreverse(i8, @bitCast(i8, u8(0x92))) == @bitCast(i8, u8( 0x49)));
- assert(@bitreverse(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16( 0x2c48)));
- assert(@bitreverse(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24( 0x6a2c48)));
- assert(@bitreverse(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32( 0x1e6a2c48)));
- assert(@bitreverse(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40( 0x591e6a2c48)));
- assert(@bitreverse(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48( 0x3d591e6a2c48)));
- assert(@bitreverse(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56( 0x7b3d591e6a2c48)));
- assert(@bitreverse(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64,u64(0x8f7b3d591e6a2c48)));
- assert(@bitreverse(i128, @bitCast(i128,u128(0x123456789abcdef11121314151617181))) == @bitCast(i128,u128(0x818e868a828c84888f7b3d591e6a2c48)));
-
- // using comptime_ints, signed, negative. Compare to runtime ints returned from llvm.
- var neg5: i5 = minInt(i5) + 1;
- assert(@bitreverse(i5, minInt(i5) + 1) == @bitreverse(i5, neg5));
- var neg8: i8 = -18;
- assert(@bitreverse(i8, -18) == @bitreverse(i8, neg8));
- var neg16: i16 = -32694;
- assert(@bitreverse(i16, -32694) == @bitreverse(i16, neg16));
- var neg24: i24 = -6773785;
- assert(@bitreverse(i24, -6773785) == @bitreverse(i24, neg24));
- var neg32: i32 = -16773785;
- assert(@bitreverse(i32, -16773785) == @bitreverse(i32, neg32));
- var neg40: i40 = minInt(i40) + 12345;
- assert(@bitreverse(i40, minInt(i40) + 12345) == @bitreverse(i40, neg40));
- var neg48: i48 = minInt(i48) + 12345;
- assert(@bitreverse(i48, minInt(i48) + 12345) == @bitreverse(i48, neg48));
- var neg56: i56 = minInt(i56) + 12345;
- assert(@bitreverse(i56, minInt(i56) + 12345) == @bitreverse(i56, neg56));
- var neg64: i64 = minInt(i64) + 12345;
- assert(@bitreverse(i64, minInt(i64) + 12345) == @bitreverse(i64, neg64));
- var neg128: i128 = minInt(i128) + 12345;
- assert(@bitreverse(i128, minInt(i128) + 12345) == @bitreverse(i128, neg128));
-}
diff --git a/test/cases/bswap.zig b/test/cases/bswap.zig
deleted file mode 100644
index 57993077e1a8..000000000000
--- a/test/cases/bswap.zig
+++ /dev/null
@@ -1,32 +0,0 @@
-const std = @import("std");
-const assert = std.debug.assert;
-
-test "@bswap" {
- comptime testByteSwap();
- testByteSwap();
-}
-
-fn testByteSwap() void {
- assert(@bswap(u0, 0) == 0);
- assert(@bswap(u8, 0x12) == 0x12);
- assert(@bswap(u16, 0x1234) == 0x3412);
- assert(@bswap(u24, 0x123456) == 0x563412);
- assert(@bswap(u32, 0x12345678) == 0x78563412);
- assert(@bswap(u40, 0x123456789a) == 0x9a78563412);
- assert(@bswap(u48, 0x123456789abc) == 0xbc9a78563412);
- assert(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412);
- assert(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412);
- assert(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412);
-
- assert(@bswap(i0, 0) == 0);
- assert(@bswap(i8, -50) == -50);
- assert(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412)));
- assert(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412)));
- assert(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412)));
- assert(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412)));
- assert(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412)));
- assert(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412)));
- assert(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412)));
- assert(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) ==
- @bitCast(i128, u128(0x8171615141312111f1debc9a78563412)));
-}
diff --git a/test/cases/import.zig b/test/cases/import.zig
deleted file mode 100644
index 6d6d4b020860..000000000000
--- a/test/cases/import.zig
+++ /dev/null
@@ -1,10 +0,0 @@
-const assert = @import("std").debug.assert;
-const a_namespace = @import("import/a_namespace.zig");
-
-test "call fn via namespace lookup" {
- assert(a_namespace.foo() == 1234);
-}
-
-test "importing the same thing gives the same import" {
- assert(@import("std") == @import("std"));
-}
diff --git a/test/cases/optional.zig b/test/cases/optional.zig
deleted file mode 100644
index d43682bbec3c..000000000000
--- a/test/cases/optional.zig
+++ /dev/null
@@ -1,30 +0,0 @@
-const assert = @import("std").debug.assert;
-
-pub const EmptyStruct = struct {};
-
-test "optional pointer to size zero struct" {
- var e = EmptyStruct{};
- var o: ?*EmptyStruct = &e;
- assert(o != null);
-}
-
-test "equality compare nullable pointers" {
- testNullPtrsEql();
- comptime testNullPtrsEql();
-}
-
-fn testNullPtrsEql() void {
- var number: i32 = 1234;
-
- var x: ?*i32 = null;
- var y: ?*i32 = null;
- assert(x == y);
- y = &number;
- assert(x != y);
- assert(x != &number);
- assert(&number != x);
- x = &number;
- assert(x == y);
- assert(x == &number);
- assert(&number == x);
-}
diff --git a/test/cases/popcount.zig b/test/cases/popcount.zig
deleted file mode 100644
index 7dc7f28c0e9c..000000000000
--- a/test/cases/popcount.zig
+++ /dev/null
@@ -1,24 +0,0 @@
-const assert = @import("std").debug.assert;
-
-test "@popCount" {
- comptime testPopCount();
- testPopCount();
-}
-
-fn testPopCount() void {
- {
- var x: u32 = 0xaa;
- assert(@popCount(x) == 4);
- }
- {
- var x: u32 = 0xaaaaaaaa;
- assert(@popCount(x) == 16);
- }
- {
- var x: i16 = -1;
- assert(@popCount(x) == 16);
- }
- comptime {
- assert(@popCount(0b11111111000110001100010000100001000011000011100101010001) == 24);
- }
-}
diff --git a/test/cases/reflection.zig b/test/cases/reflection.zig
deleted file mode 100644
index b9b8aff4e16a..000000000000
--- a/test/cases/reflection.zig
+++ /dev/null
@@ -1,95 +0,0 @@
-const assert = @import("std").debug.assert;
-const mem = @import("std").mem;
-const reflection = @This();
-
-test "reflection: array, pointer, optional, error union type child" {
- comptime {
- assert(([10]u8).Child == u8);
- assert((*u8).Child == u8);
- assert((anyerror!u8).Payload == u8);
- assert((?u8).Child == u8);
- }
-}
-
-test "reflection: function return type, var args, and param types" {
- comptime {
- assert(@typeOf(dummy).ReturnType == i32);
- assert(!@typeOf(dummy).is_var_args);
- assert(@typeOf(dummy_varargs).is_var_args);
- assert(@typeOf(dummy).arg_count == 3);
- assert(@ArgType(@typeOf(dummy), 0) == bool);
- assert(@ArgType(@typeOf(dummy), 1) == i32);
- assert(@ArgType(@typeOf(dummy), 2) == f32);
- }
-}
-
-fn dummy(a: bool, b: i32, c: f32) i32 {
- return 1234;
-}
-fn dummy_varargs(args: ...) void {}
-
-test "reflection: struct member types and names" {
- comptime {
- assert(@memberCount(Foo) == 3);
-
- assert(@memberType(Foo, 0) == i32);
- assert(@memberType(Foo, 1) == bool);
- assert(@memberType(Foo, 2) == void);
-
- assert(mem.eql(u8, @memberName(Foo, 0), "one"));
- assert(mem.eql(u8, @memberName(Foo, 1), "two"));
- assert(mem.eql(u8, @memberName(Foo, 2), "three"));
- }
-}
-
-test "reflection: enum member types and names" {
- comptime {
- assert(@memberCount(Bar) == 4);
-
- assert(@memberType(Bar, 0) == void);
- assert(@memberType(Bar, 1) == i32);
- assert(@memberType(Bar, 2) == bool);
- assert(@memberType(Bar, 3) == f64);
-
- assert(mem.eql(u8, @memberName(Bar, 0), "One"));
- assert(mem.eql(u8, @memberName(Bar, 1), "Two"));
- assert(mem.eql(u8, @memberName(Bar, 2), "Three"));
- assert(mem.eql(u8, @memberName(Bar, 3), "Four"));
- }
-}
-
-test "reflection: @field" {
- var f = Foo{
- .one = 42,
- .two = true,
- .three = void{},
- };
-
- assert(f.one == f.one);
- assert(@field(f, "o" ++ "ne") == f.one);
- assert(@field(f, "t" ++ "wo") == f.two);
- assert(@field(f, "th" ++ "ree") == f.three);
- assert(@field(Foo, "const" ++ "ant") == Foo.constant);
- assert(@field(Bar, "O" ++ "ne") == Bar.One);
- assert(@field(Bar, "T" ++ "wo") == Bar.Two);
- assert(@field(Bar, "Th" ++ "ree") == Bar.Three);
- assert(@field(Bar, "F" ++ "our") == Bar.Four);
- assert(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2));
- @field(f, "o" ++ "ne") = 4;
- assert(f.one == 4);
-}
-
-const Foo = struct {
- const constant = 52;
-
- one: i32,
- two: bool,
- three: void,
-};
-
-const Bar = union(enum) {
- One: void,
- Two: i32,
- Three: bool,
- Four: f64,
-};
diff --git a/test/cases/sizeof_and_typeof.zig b/test/cases/sizeof_and_typeof.zig
deleted file mode 100644
index 11c6b2f6ba36..000000000000
--- a/test/cases/sizeof_and_typeof.zig
+++ /dev/null
@@ -1,69 +0,0 @@
-const builtin = @import("builtin");
-const assert = @import("std").debug.assert;
-
-test "@sizeOf and @typeOf" {
- const y: @typeOf(x) = 120;
- assert(@sizeOf(@typeOf(y)) == 2);
-}
-const x: u16 = 13;
-const z: @typeOf(x) = 19;
-
-const A = struct {
- a: u8,
- b: u32,
- c: u8,
- d: u3,
- e: u5,
- f: u16,
- g: u16,
-};
-
-const P = packed struct {
- a: u8,
- b: u32,
- c: u8,
- d: u3,
- e: u5,
- f: u16,
- g: u16,
-};
-
-test "@byteOffsetOf" {
- // Packed structs have fixed memory layout
- assert(@byteOffsetOf(P, "a") == 0);
- assert(@byteOffsetOf(P, "b") == 1);
- assert(@byteOffsetOf(P, "c") == 5);
- assert(@byteOffsetOf(P, "d") == 6);
- assert(@byteOffsetOf(P, "e") == 6);
- assert(@byteOffsetOf(P, "f") == 7);
- assert(@byteOffsetOf(P, "g") == 9);
-
- // Normal struct fields can be moved/padded
- var a: A = undefined;
- assert(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a"));
- assert(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b"));
- assert(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c"));
- assert(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d"));
- assert(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e"));
- assert(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f"));
- assert(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g"));
-}
-
-test "@bitOffsetOf" {
- // Packed structs have fixed memory layout
- assert(@bitOffsetOf(P, "a") == 0);
- assert(@bitOffsetOf(P, "b") == 8);
- assert(@bitOffsetOf(P, "c") == 40);
- assert(@bitOffsetOf(P, "d") == 48);
- assert(@bitOffsetOf(P, "e") == 51);
- assert(@bitOffsetOf(P, "f") == 56);
- assert(@bitOffsetOf(P, "g") == 72);
-
- assert(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a"));
- assert(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b"));
- assert(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c"));
- assert(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d"));
- assert(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e"));
- assert(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f"));
- assert(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g"));
-}
diff --git a/test/cases/type_info.zig b/test/cases/type_info.zig
deleted file mode 100644
index cec532d5d304..000000000000
--- a/test/cases/type_info.zig
+++ /dev/null
@@ -1,264 +0,0 @@
-const assert = @import("std").debug.assert;
-const mem = @import("std").mem;
-const TypeInfo = @import("builtin").TypeInfo;
-const TypeId = @import("builtin").TypeId;
-
-test "type info: tag type, void info" {
- testBasic();
- comptime testBasic();
-}
-
-fn testBasic() void {
- assert(@TagType(TypeInfo) == TypeId);
- const void_info = @typeInfo(void);
- assert(TypeId(void_info) == TypeId.Void);
- assert(void_info.Void == {});
-}
-
-test "type info: integer, floating point type info" {
- testIntFloat();
- comptime testIntFloat();
-}
-
-fn testIntFloat() void {
- const u8_info = @typeInfo(u8);
- assert(TypeId(u8_info) == TypeId.Int);
- assert(!u8_info.Int.is_signed);
- assert(u8_info.Int.bits == 8);
-
- const f64_info = @typeInfo(f64);
- assert(TypeId(f64_info) == TypeId.Float);
- assert(f64_info.Float.bits == 64);
-}
-
-test "type info: pointer type info" {
- testPointer();
- comptime testPointer();
-}
-
-fn testPointer() void {
- const u32_ptr_info = @typeInfo(*u32);
- assert(TypeId(u32_ptr_info) == TypeId.Pointer);
- assert(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One);
- assert(u32_ptr_info.Pointer.is_const == false);
- assert(u32_ptr_info.Pointer.is_volatile == false);
- assert(u32_ptr_info.Pointer.alignment == @alignOf(u32));
- assert(u32_ptr_info.Pointer.child == u32);
-}
-
-test "type info: unknown length pointer type info" {
- testUnknownLenPtr();
- comptime testUnknownLenPtr();
-}
-
-fn testUnknownLenPtr() void {
- const u32_ptr_info = @typeInfo([*]const volatile f64);
- assert(TypeId(u32_ptr_info) == TypeId.Pointer);
- assert(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
- assert(u32_ptr_info.Pointer.is_const == true);
- assert(u32_ptr_info.Pointer.is_volatile == true);
- assert(u32_ptr_info.Pointer.alignment == @alignOf(f64));
- assert(u32_ptr_info.Pointer.child == f64);
-}
-
-test "type info: slice type info" {
- testSlice();
- comptime testSlice();
-}
-
-fn testSlice() void {
- const u32_slice_info = @typeInfo([]u32);
- assert(TypeId(u32_slice_info) == TypeId.Pointer);
- assert(u32_slice_info.Pointer.size == TypeInfo.Pointer.Size.Slice);
- assert(u32_slice_info.Pointer.is_const == false);
- assert(u32_slice_info.Pointer.is_volatile == false);
- assert(u32_slice_info.Pointer.alignment == 4);
- assert(u32_slice_info.Pointer.child == u32);
-}
-
-test "type info: array type info" {
- testArray();
- comptime testArray();
-}
-
-fn testArray() void {
- const arr_info = @typeInfo([42]bool);
- assert(TypeId(arr_info) == TypeId.Array);
- assert(arr_info.Array.len == 42);
- assert(arr_info.Array.child == bool);
-}
-
-test "type info: optional type info" {
- testOptional();
- comptime testOptional();
-}
-
-fn testOptional() void {
- const null_info = @typeInfo(?void);
- assert(TypeId(null_info) == TypeId.Optional);
- assert(null_info.Optional.child == void);
-}
-
-test "type info: promise info" {
- testPromise();
- comptime testPromise();
-}
-
-fn testPromise() void {
- const null_promise_info = @typeInfo(promise);
- assert(TypeId(null_promise_info) == TypeId.Promise);
- assert(null_promise_info.Promise.child == null);
-
- const promise_info = @typeInfo(promise->usize);
- assert(TypeId(promise_info) == TypeId.Promise);
- assert(promise_info.Promise.child.? == usize);
-}
-
-test "type info: error set, error union info" {
- testErrorSet();
- comptime testErrorSet();
-}
-
-fn testErrorSet() void {
- const TestErrorSet = error{
- First,
- Second,
- Third,
- };
-
- const error_set_info = @typeInfo(TestErrorSet);
- assert(TypeId(error_set_info) == TypeId.ErrorSet);
- assert(error_set_info.ErrorSet.errors.len == 3);
- assert(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First"));
- assert(error_set_info.ErrorSet.errors[2].value == @errorToInt(TestErrorSet.Third));
-
- const error_union_info = @typeInfo(TestErrorSet!usize);
- assert(TypeId(error_union_info) == TypeId.ErrorUnion);
- assert(error_union_info.ErrorUnion.error_set == TestErrorSet);
- assert(error_union_info.ErrorUnion.payload == usize);
-}
-
-test "type info: enum info" {
- testEnum();
- comptime testEnum();
-}
-
-fn testEnum() void {
- const Os = enum {
- Windows,
- Macos,
- Linux,
- FreeBSD,
- };
-
- const os_info = @typeInfo(Os);
- assert(TypeId(os_info) == TypeId.Enum);
- assert(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto);
- assert(os_info.Enum.fields.len == 4);
- assert(mem.eql(u8, os_info.Enum.fields[1].name, "Macos"));
- assert(os_info.Enum.fields[3].value == 3);
- assert(os_info.Enum.tag_type == u2);
- assert(os_info.Enum.defs.len == 0);
-}
-
-test "type info: union info" {
- testUnion();
- comptime testUnion();
-}
-
-fn testUnion() void {
- const typeinfo_info = @typeInfo(TypeInfo);
- assert(TypeId(typeinfo_info) == TypeId.Union);
- assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
- assert(typeinfo_info.Union.tag_type.? == TypeId);
- assert(typeinfo_info.Union.fields.len == 24);
- assert(typeinfo_info.Union.fields[4].enum_field != null);
- assert(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
- assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
- assert(typeinfo_info.Union.defs.len == 20);
-
- const TestNoTagUnion = union {
- Foo: void,
- Bar: u32,
- };
-
- const notag_union_info = @typeInfo(TestNoTagUnion);
- assert(TypeId(notag_union_info) == TypeId.Union);
- assert(notag_union_info.Union.tag_type == null);
- assert(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto);
- assert(notag_union_info.Union.fields.len == 2);
- assert(notag_union_info.Union.fields[0].enum_field == null);
- assert(notag_union_info.Union.fields[1].field_type == u32);
-
- const TestExternUnion = extern union {
- foo: *c_void,
- };
-
- const extern_union_info = @typeInfo(TestExternUnion);
- assert(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern);
- assert(extern_union_info.Union.tag_type == null);
- assert(extern_union_info.Union.fields[0].enum_field == null);
- assert(extern_union_info.Union.fields[0].field_type == *c_void);
-}
-
-test "type info: struct info" {
- testStruct();
- comptime testStruct();
-}
-
-fn testStruct() void {
- const struct_info = @typeInfo(TestStruct);
- assert(TypeId(struct_info) == TypeId.Struct);
- assert(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed);
- assert(struct_info.Struct.fields.len == 3);
- assert(struct_info.Struct.fields[1].offset == null);
- assert(struct_info.Struct.fields[2].field_type == *TestStruct);
- assert(struct_info.Struct.defs.len == 2);
- assert(struct_info.Struct.defs[0].is_pub);
- assert(!struct_info.Struct.defs[0].data.Fn.is_extern);
- assert(struct_info.Struct.defs[0].data.Fn.lib_name == null);
- assert(struct_info.Struct.defs[0].data.Fn.return_type == void);
- assert(struct_info.Struct.defs[0].data.Fn.fn_type == fn (*const TestStruct) void);
-}
-
-const TestStruct = packed struct {
- const Self = @This();
-
- fieldA: usize,
- fieldB: void,
- fieldC: *Self,
-
- pub fn foo(self: *const Self) void {}
-};
-
-test "type info: function type info" {
- testFunction();
- comptime testFunction();
-}
-
-fn testFunction() void {
- const fn_info = @typeInfo(@typeOf(foo));
- assert(TypeId(fn_info) == TypeId.Fn);
- assert(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified);
- assert(fn_info.Fn.is_generic);
- assert(fn_info.Fn.args.len == 2);
- assert(fn_info.Fn.is_var_args);
- assert(fn_info.Fn.return_type == null);
- assert(fn_info.Fn.async_allocator_type == null);
-
- const test_instance: TestStruct = undefined;
- const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));
- assert(TypeId(bound_fn_info) == TypeId.BoundFn);
- assert(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct);
-}
-
-fn foo(comptime a: usize, b: bool, args: ...) usize {
- return 0;
-}
-
-test "typeInfo with comptime parameter in struct fn def" {
- const S = struct {
- pub fn func(comptime x: f32) void {}
- };
- comptime var info = @typeInfo(S);
-}
diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig
new file mode 100644
index 000000000000..e545a4c4184d
--- /dev/null
+++ b/test/stage1/behavior.zig
@@ -0,0 +1,80 @@
+comptime {
+ _ = @import("behavior/align.zig");
+ _ = @import("behavior/alignof.zig");
+ _ = @import("behavior/array.zig");
+ _ = @import("behavior/asm.zig");
+ _ = @import("behavior/atomics.zig");
+ _ = @import("behavior/bit_shifting.zig");
+ _ = @import("behavior/bitcast.zig");
+ _ = @import("behavior/bitreverse.zig");
+ _ = @import("behavior/bool.zig");
+ _ = @import("behavior/bswap.zig");
+ _ = @import("behavior/bugs/1076.zig");
+ _ = @import("behavior/bugs/1111.zig");
+ _ = @import("behavior/bugs/1277.zig");
+ _ = @import("behavior/bugs/1322.zig");
+ _ = @import("behavior/bugs/1381.zig");
+ _ = @import("behavior/bugs/1421.zig");
+ _ = @import("behavior/bugs/1442.zig");
+ _ = @import("behavior/bugs/1486.zig");
+ _ = @import("behavior/bugs/394.zig");
+ _ = @import("behavior/bugs/655.zig");
+ _ = @import("behavior/bugs/656.zig");
+ _ = @import("behavior/bugs/726.zig");
+ _ = @import("behavior/bugs/828.zig");
+ _ = @import("behavior/bugs/920.zig");
+ _ = @import("behavior/byval_arg_var.zig");
+ _ = @import("behavior/cancel.zig");
+ _ = @import("behavior/cast.zig");
+ _ = @import("behavior/const_slice_child.zig");
+ _ = @import("behavior/coroutine_await_struct.zig");
+ _ = @import("behavior/coroutines.zig");
+ _ = @import("behavior/defer.zig");
+ _ = @import("behavior/enum.zig");
+ _ = @import("behavior/enum_with_members.zig");
+ _ = @import("behavior/error.zig");
+ _ = @import("behavior/eval.zig");
+ _ = @import("behavior/field_parent_ptr.zig");
+ _ = @import("behavior/fn.zig");
+ _ = @import("behavior/fn_in_struct_in_comptime.zig");
+ _ = @import("behavior/for.zig");
+ _ = @import("behavior/generics.zig");
+ _ = @import("behavior/if.zig");
+ _ = @import("behavior/import.zig");
+ _ = @import("behavior/incomplete_struct_param_tld.zig");
+ _ = @import("behavior/inttoptr.zig");
+ _ = @import("behavior/ir_block_deps.zig");
+ _ = @import("behavior/math.zig");
+ _ = @import("behavior/merge_error_sets.zig");
+ _ = @import("behavior/misc.zig");
+ _ = @import("behavior/namespace_depends_on_compile_var/index.zig");
+ _ = @import("behavior/new_stack_call.zig");
+ _ = @import("behavior/null.zig");
+ _ = @import("behavior/optional.zig");
+ _ = @import("behavior/pointers.zig");
+ _ = @import("behavior/popcount.zig");
+ _ = @import("behavior/ptrcast.zig");
+ _ = @import("behavior/pub_enum/index.zig");
+ _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
+ _ = @import("behavior/reflection.zig");
+ _ = @import("behavior/sizeof_and_typeof.zig");
+ _ = @import("behavior/slice.zig");
+ _ = @import("behavior/struct.zig");
+ _ = @import("behavior/struct_contains_null_ptr_itself.zig");
+ _ = @import("behavior/struct_contains_slice_of_itself.zig");
+ _ = @import("behavior/switch.zig");
+ _ = @import("behavior/switch_prong_err_enum.zig");
+ _ = @import("behavior/switch_prong_implicit_cast.zig");
+ _ = @import("behavior/syntax.zig");
+ _ = @import("behavior/this.zig");
+ _ = @import("behavior/truncate.zig");
+ _ = @import("behavior/try.zig");
+ _ = @import("behavior/type_info.zig");
+ _ = @import("behavior/undefined.zig");
+ _ = @import("behavior/underscore.zig");
+ _ = @import("behavior/union.zig");
+ _ = @import("behavior/var_args.zig");
+ _ = @import("behavior/void.zig");
+ _ = @import("behavior/while.zig");
+ _ = @import("behavior/widening.zig");
+}
diff --git a/test/cases/align.zig b/test/stage1/behavior/align.zig
similarity index 69%
rename from test/cases/align.zig
rename to test/stage1/behavior/align.zig
index 3dff57feb882..aa7a93ad8482 100644
--- a/test/cases/align.zig
+++ b/test/stage1/behavior/align.zig
@@ -1,13 +1,13 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
const builtin = @import("builtin");
var foo: u8 align(4) = 100;
test "global variable alignment" {
- assert(@typeOf(&foo).alignment == 4);
- assert(@typeOf(&foo) == *align(4) u8);
+ assertOrPanic(@typeOf(&foo).alignment == 4);
+ assertOrPanic(@typeOf(&foo) == *align(4) u8);
const slice = (*[1]u8)(&foo)[0..];
- assert(@typeOf(slice) == []align(4) u8);
+ assertOrPanic(@typeOf(slice) == []align(4) u8);
}
fn derp() align(@sizeOf(usize) * 2) i32 {
@@ -17,9 +17,9 @@ fn noop1() align(1) void {}
fn noop4() align(4) void {}
test "function alignment" {
- assert(derp() == 1234);
- assert(@typeOf(noop1) == fn () align(1) void);
- assert(@typeOf(noop4) == fn () align(4) void);
+ assertOrPanic(derp() == 1234);
+ assertOrPanic(@typeOf(noop1) == fn () align(1) void);
+ assertOrPanic(@typeOf(noop4) == fn () align(4) void);
noop1();
noop4();
}
@@ -30,7 +30,7 @@ var baz: packed struct {
} = undefined;
test "packed struct alignment" {
- assert(@typeOf(&baz.b) == *align(1) u32);
+ assertOrPanic(@typeOf(&baz.b) == *align(1) u32);
}
const blah: packed struct {
@@ -40,17 +40,17 @@ const blah: packed struct {
} = undefined;
test "bit field alignment" {
- assert(@typeOf(&blah.b) == *align(1:3:1) const u3);
+ assertOrPanic(@typeOf(&blah.b) == *align(1:3:1) const u3);
}
test "default alignment allows unspecified in type syntax" {
- assert(*u32 == *align(@alignOf(u32)) u32);
+ assertOrPanic(*u32 == *align(@alignOf(u32)) u32);
}
test "implicitly decreasing pointer alignment" {
const a: u32 align(4) = 3;
const b: u32 align(8) = 4;
- assert(addUnaligned(&a, &b) == 7);
+ assertOrPanic(addUnaligned(&a, &b) == 7);
}
fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 {
@@ -60,7 +60,7 @@ fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 {
test "implicitly decreasing slice alignment" {
const a: u32 align(4) = 3;
const b: u32 align(8) = 4;
- assert(addUnalignedSlice((*[1]u32)(&a)[0..], (*[1]u32)(&b)[0..]) == 7);
+ assertOrPanic(addUnalignedSlice((*[1]u32)(&a)[0..], (*[1]u32)(&b)[0..]) == 7);
}
fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {
return a[0] + b[0];
@@ -77,7 +77,7 @@ fn testBytesAlign(b: u8) void {
b,
};
const ptr = @ptrCast(*u32, &bytes[0]);
- assert(ptr.* == 0x33333333);
+ assertOrPanic(ptr.* == 0x33333333);
}
test "specifying alignment allows slice cast" {
@@ -91,13 +91,13 @@ fn testBytesAlignSlice(b: u8) void {
b,
};
const slice: []u32 = @bytesToSlice(u32, bytes[0..]);
- assert(slice[0] == 0x33333333);
+ assertOrPanic(slice[0] == 0x33333333);
}
test "@alignCast pointers" {
var x: u32 align(4) = 1;
expectsOnly1(&x);
- assert(x == 2);
+ assertOrPanic(x == 2);
}
fn expectsOnly1(x: *align(1) u32) void {
expects4(@alignCast(4, x));
@@ -113,7 +113,7 @@ test "@alignCast slices" {
};
const slice = array[0..];
sliceExpectsOnly1(slice);
- assert(slice[0] == 2);
+ assertOrPanic(slice[0] == 2);
}
fn sliceExpectsOnly1(slice: []align(1) u32) void {
sliceExpects4(@alignCast(4, slice));
@@ -128,7 +128,7 @@ test "implicitly decreasing fn alignment" {
}
fn testImplicitlyDecreaseFnAlign(ptr: fn () align(1) i32, answer: i32) void {
- assert(ptr() == answer);
+ assertOrPanic(ptr() == answer);
}
fn alignedSmall() align(8) i32 {
@@ -139,7 +139,7 @@ fn alignedBig() align(16) i32 {
}
test "@alignCast functions" {
- assert(fnExpectsOnly1(simple4) == 0x19);
+ assertOrPanic(fnExpectsOnly1(simple4) == 0x19);
}
fn fnExpectsOnly1(ptr: fn () align(1) i32) i32 {
return fnExpects4(@alignCast(4, ptr));
@@ -152,9 +152,9 @@ fn simple4() align(4) i32 {
}
test "generic function with align param" {
- assert(whyWouldYouEverDoThis(1) == 0x1);
- assert(whyWouldYouEverDoThis(4) == 0x1);
- assert(whyWouldYouEverDoThis(8) == 0x1);
+ assertOrPanic(whyWouldYouEverDoThis(1) == 0x1);
+ assertOrPanic(whyWouldYouEverDoThis(4) == 0x1);
+ assertOrPanic(whyWouldYouEverDoThis(8) == 0x1);
}
fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 {
@@ -164,28 +164,28 @@ fn whyWouldYouEverDoThis(comptime align_bytes: u8) align(align_bytes) u8 {
test "@ptrCast preserves alignment of bigger source" {
var x: u32 align(16) = 1234;
const ptr = @ptrCast(*u8, &x);
- assert(@typeOf(ptr) == *align(16) u8);
+ assertOrPanic(@typeOf(ptr) == *align(16) u8);
}
test "runtime known array index has best alignment possible" {
// take full advantage of over-alignment
var array align(4) = []u8{ 1, 2, 3, 4 };
- assert(@typeOf(&array[0]) == *align(4) u8);
- assert(@typeOf(&array[1]) == *u8);
- assert(@typeOf(&array[2]) == *align(2) u8);
- assert(@typeOf(&array[3]) == *u8);
+ assertOrPanic(@typeOf(&array[0]) == *align(4) u8);
+ assertOrPanic(@typeOf(&array[1]) == *u8);
+ assertOrPanic(@typeOf(&array[2]) == *align(2) u8);
+ assertOrPanic(@typeOf(&array[3]) == *u8);
// because align is too small but we still figure out to use 2
var bigger align(2) = []u64{ 1, 2, 3, 4 };
- assert(@typeOf(&bigger[0]) == *align(2) u64);
- assert(@typeOf(&bigger[1]) == *align(2) u64);
- assert(@typeOf(&bigger[2]) == *align(2) u64);
- assert(@typeOf(&bigger[3]) == *align(2) u64);
+ assertOrPanic(@typeOf(&bigger[0]) == *align(2) u64);
+ assertOrPanic(@typeOf(&bigger[1]) == *align(2) u64);
+ assertOrPanic(@typeOf(&bigger[2]) == *align(2) u64);
+ assertOrPanic(@typeOf(&bigger[3]) == *align(2) u64);
// because pointer is align 2 and u32 align % 2 == 0 we can assume align 2
var smaller align(2) = []u32{ 1, 2, 3, 4 };
- comptime assert(@typeOf(smaller[0..]) == []align(2) u32);
- comptime assert(@typeOf(smaller[0..].ptr) == [*]align(2) u32);
+ comptime assertOrPanic(@typeOf(smaller[0..]) == []align(2) u32);
+ comptime assertOrPanic(@typeOf(smaller[0..].ptr) == [*]align(2) u32);
testIndex(smaller[0..].ptr, 0, *align(2) u32);
testIndex(smaller[0..].ptr, 1, *align(2) u32);
testIndex(smaller[0..].ptr, 2, *align(2) u32);
@@ -198,14 +198,14 @@ test "runtime known array index has best alignment possible" {
testIndex2(array[0..].ptr, 3, *u8);
}
fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void {
- comptime assert(@typeOf(&smaller[index]) == T);
+ comptime assertOrPanic(@typeOf(&smaller[index]) == T);
}
fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) void {
- comptime assert(@typeOf(&ptr[index]) == T);
+ comptime assertOrPanic(@typeOf(&ptr[index]) == T);
}
test "alignstack" {
- assert(fnWithAlignedStack() == 1234);
+ assertOrPanic(fnWithAlignedStack() == 1234);
}
fn fnWithAlignedStack() i32 {
@@ -214,7 +214,7 @@ fn fnWithAlignedStack() i32 {
}
test "alignment of structs" {
- assert(@alignOf(struct {
+ assertOrPanic(@alignOf(struct {
a: i32,
b: *i32,
}) == @alignOf(usize));
diff --git a/test/cases/alignof.zig b/test/stage1/behavior/alignof.zig
similarity index 61%
rename from test/cases/alignof.zig
rename to test/stage1/behavior/alignof.zig
index 433e86e45edf..98c805908b72 100644
--- a/test/cases/alignof.zig
+++ b/test/stage1/behavior/alignof.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
const builtin = @import("builtin");
const maxInt = std.math.maxInt;
@@ -10,8 +10,9 @@ const Foo = struct {
};
test "@alignOf(T) before referencing T" {
- comptime assert(@alignOf(Foo) != maxInt(usize));
+ comptime assertOrPanic(@alignOf(Foo) != maxInt(usize));
if (builtin.arch == builtin.Arch.x86_64) {
- comptime assert(@alignOf(Foo) == 4);
+ comptime assertOrPanic(@alignOf(Foo) == 4);
}
}
+
diff --git a/test/stage1/behavior/array.zig b/test/stage1/behavior/array.zig
new file mode 100644
index 000000000000..118330520986
--- /dev/null
+++ b/test/stage1/behavior/array.zig
@@ -0,0 +1,270 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+const mem = @import("std").mem;
+
+test "arrays" {
+ var array: [5]u32 = undefined;
+
+ var i: u32 = 0;
+ while (i < 5) {
+ array[i] = i + 1;
+ i = array[i];
+ }
+
+ i = 0;
+ var accumulator = u32(0);
+ while (i < 5) {
+ accumulator += array[i];
+
+ i += 1;
+ }
+
+ assertOrPanic(accumulator == 15);
+ assertOrPanic(getArrayLen(array) == 5);
+}
+fn getArrayLen(a: []const u32) usize {
+ return a.len;
+}
+
+test "void arrays" {
+ var array: [4]void = undefined;
+ array[0] = void{};
+ array[1] = array[2];
+ assertOrPanic(@sizeOf(@typeOf(array)) == 0);
+ assertOrPanic(array.len == 4);
+}
+
+test "array literal" {
+ const hex_mult = []u16{
+ 4096,
+ 256,
+ 16,
+ 1,
+ };
+
+ assertOrPanic(hex_mult.len == 4);
+ assertOrPanic(hex_mult[1] == 256);
+}
+
+test "array dot len const expr" {
+ assertOrPanic(comptime x: {
+ break :x some_array.len == 4;
+ });
+}
+
+const ArrayDotLenConstExpr = struct {
+ y: [some_array.len]u8,
+};
+const some_array = []u8{
+ 0,
+ 1,
+ 2,
+ 3,
+};
+
+test "nested arrays" {
+ const array_of_strings = [][]const u8{
+ "hello",
+ "this",
+ "is",
+ "my",
+ "thing",
+ };
+ for (array_of_strings) |s, i| {
+ if (i == 0) assertOrPanic(mem.eql(u8, s, "hello"));
+ if (i == 1) assertOrPanic(mem.eql(u8, s, "this"));
+ if (i == 2) assertOrPanic(mem.eql(u8, s, "is"));
+ if (i == 3) assertOrPanic(mem.eql(u8, s, "my"));
+ if (i == 4) assertOrPanic(mem.eql(u8, s, "thing"));
+ }
+}
+
+var s_array: [8]Sub = undefined;
+const Sub = struct {
+ b: u8,
+};
+const Str = struct {
+ a: []Sub,
+};
+test "set global var array via slice embedded in struct" {
+ var s = Str{ .a = s_array[0..] };
+
+ s.a[0].b = 1;
+ s.a[1].b = 2;
+ s.a[2].b = 3;
+
+ assertOrPanic(s_array[0].b == 1);
+ assertOrPanic(s_array[1].b == 2);
+ assertOrPanic(s_array[2].b == 3);
+}
+
+test "array literal with specified size" {
+ var array = [2]u8{
+ 1,
+ 2,
+ };
+ assertOrPanic(array[0] == 1);
+ assertOrPanic(array[1] == 2);
+}
+
+test "array child property" {
+ var x: [5]i32 = undefined;
+ assertOrPanic(@typeOf(x).Child == i32);
+}
+
+test "array len property" {
+ var x: [5]i32 = undefined;
+ assertOrPanic(@typeOf(x).len == 5);
+}
+
+test "array len field" {
+ var arr = [4]u8{ 0, 0, 0, 0 };
+ var ptr = &arr;
+ assertOrPanic(arr.len == 4);
+ comptime assertOrPanic(arr.len == 4);
+ assertOrPanic(ptr.len == 4);
+ comptime assertOrPanic(ptr.len == 4);
+}
+
+test "single-item pointer to array indexing and slicing" {
+ testSingleItemPtrArrayIndexSlice();
+ comptime testSingleItemPtrArrayIndexSlice();
+}
+
+fn testSingleItemPtrArrayIndexSlice() void {
+ var array = "aaaa";
+ doSomeMangling(&array);
+ assertOrPanic(mem.eql(u8, "azya", array));
+}
+
+fn doSomeMangling(array: *[4]u8) void {
+ array[1] = 'z';
+ array[2..3][0] = 'y';
+}
+
+test "implicit cast single-item pointer" {
+ testImplicitCastSingleItemPtr();
+ comptime testImplicitCastSingleItemPtr();
+}
+
+fn testImplicitCastSingleItemPtr() void {
+ var byte: u8 = 100;
+ const slice = (*[1]u8)(&byte)[0..];
+ slice[0] += 1;
+ assertOrPanic(byte == 101);
+}
+
+fn testArrayByValAtComptime(b: [2]u8) u8 {
+ return b[0];
+}
+
+test "comptime evalutating function that takes array by value" {
+ const arr = []u8{ 0, 1 };
+ _ = comptime testArrayByValAtComptime(arr);
+ _ = comptime testArrayByValAtComptime(arr);
+}
+
+test "implicit comptime in array type size" {
+ var arr: [plusOne(10)]bool = undefined;
+ assertOrPanic(arr.len == 11);
+}
+
+fn plusOne(x: u32) u32 {
+ return x + 1;
+}
+
+test "array literal as argument to function" {
+ const S = struct {
+ fn entry(two: i32) void {
+ foo([]i32{
+ 1,
+ 2,
+ 3,
+ });
+ foo([]i32{
+ 1,
+ two,
+ 3,
+ });
+ foo2(true, []i32{
+ 1,
+ 2,
+ 3,
+ });
+ foo2(true, []i32{
+ 1,
+ two,
+ 3,
+ });
+ }
+ fn foo(x: []const i32) void {
+ assertOrPanic(x[0] == 1);
+ assertOrPanic(x[1] == 2);
+ assertOrPanic(x[2] == 3);
+ }
+ fn foo2(trash: bool, x: []const i32) void {
+ assertOrPanic(trash);
+ assertOrPanic(x[0] == 1);
+ assertOrPanic(x[1] == 2);
+ assertOrPanic(x[2] == 3);
+ }
+ };
+ S.entry(2);
+ comptime S.entry(2);
+}
+
+test "double nested array to const slice cast in array literal" {
+ const S = struct {
+ fn entry(two: i32) void {
+ const cases = [][]const []const i32{
+ [][]const i32{[]i32{1}},
+ [][]const i32{[]i32{ 2, 3 }},
+ [][]const i32{
+ []i32{4},
+ []i32{ 5, 6, 7 },
+ },
+ };
+ check(cases);
+
+ const cases2 = [][]const i32{
+ []i32{1},
+ []i32{ two, 3 },
+ };
+ assertOrPanic(cases2.len == 2);
+ assertOrPanic(cases2[0].len == 1);
+ assertOrPanic(cases2[0][0] == 1);
+ assertOrPanic(cases2[1].len == 2);
+ assertOrPanic(cases2[1][0] == 2);
+ assertOrPanic(cases2[1][1] == 3);
+
+ const cases3 = [][]const []const i32{
+ [][]const i32{[]i32{1}},
+ [][]const i32{[]i32{ two, 3 }},
+ [][]const i32{
+ []i32{4},
+ []i32{ 5, 6, 7 },
+ },
+ };
+ check(cases3);
+ }
+
+ fn check(cases: []const []const []const i32) void {
+ assertOrPanic(cases.len == 3);
+ assertOrPanic(cases[0].len == 1);
+ assertOrPanic(cases[0][0].len == 1);
+ assertOrPanic(cases[0][0][0] == 1);
+ assertOrPanic(cases[1].len == 1);
+ assertOrPanic(cases[1][0].len == 2);
+ assertOrPanic(cases[1][0][0] == 2);
+ assertOrPanic(cases[1][0][1] == 3);
+ assertOrPanic(cases[2].len == 2);
+ assertOrPanic(cases[2][0].len == 1);
+ assertOrPanic(cases[2][0][0] == 4);
+ assertOrPanic(cases[2][1].len == 3);
+ assertOrPanic(cases[2][1][0] == 5);
+ assertOrPanic(cases[2][1][1] == 6);
+ assertOrPanic(cases[2][1][2] == 7);
+ }
+ };
+ S.entry(2);
+ comptime S.entry(2);
+}
diff --git a/test/stage1/behavior/asm.zig b/test/stage1/behavior/asm.zig
new file mode 100644
index 000000000000..48701c583621
--- /dev/null
+++ b/test/stage1/behavior/asm.zig
@@ -0,0 +1,92 @@
+const config = @import("builtin");
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+comptime {
+ if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
+ asm volatile (
+ \\.globl aoeu;
+ \\.type aoeu, @function;
+ \\.set aoeu, derp;
+ );
+ }
+}
+
+test "module level assembly" {
+ if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) {
+ assertOrPanic(aoeu() == 1234);
+ }
+}
+
+test "output constraint modifiers" {
+ // This is only testing compilation.
+ var a: u32 = 3;
+ asm volatile (""
+ : [_] "=m,r" (a)
+ :
+ : ""
+ );
+ asm volatile (""
+ : [_] "=r,m" (a)
+ :
+ : ""
+ );
+}
+
+test "alternative constraints" {
+ // Make sure we allow commas as a separator for alternative constraints.
+ var a: u32 = 3;
+ asm volatile (""
+ : [_] "=r,m" (a)
+ : [_] "r,m" (a)
+ : ""
+ );
+}
+
+test "sized integer/float in asm input" {
+ asm volatile (""
+ :
+ : [_] "m" (usize(3))
+ : ""
+ );
+ asm volatile (""
+ :
+ : [_] "m" (i15(-3))
+ : ""
+ );
+ asm volatile (""
+ :
+ : [_] "m" (u3(3))
+ : ""
+ );
+ asm volatile (""
+ :
+ : [_] "m" (i3(3))
+ : ""
+ );
+ asm volatile (""
+ :
+ : [_] "m" (u121(3))
+ : ""
+ );
+ asm volatile (""
+ :
+ : [_] "m" (i121(3))
+ : ""
+ );
+ asm volatile (""
+ :
+ : [_] "m" (f32(3.17))
+ : ""
+ );
+ asm volatile (""
+ :
+ : [_] "m" (f64(3.17))
+ : ""
+ );
+}
+
+extern fn aoeu() i32;
+
+export fn derp() i32 {
+ return 1234;
+}
diff --git a/test/cases/atomics.zig b/test/stage1/behavior/atomics.zig
similarity index 65%
rename from test/cases/atomics.zig
rename to test/stage1/behavior/atomics.zig
index 67c9ab3dd117..fa3c5f29a603 100644
--- a/test/cases/atomics.zig
+++ b/test/stage1/behavior/atomics.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
const builtin = @import("builtin");
const AtomicRmwOp = builtin.AtomicRmwOp;
const AtomicOrder = builtin.AtomicOrder;
@@ -7,18 +7,18 @@ const AtomicOrder = builtin.AtomicOrder;
test "cmpxchg" {
var x: i32 = 1234;
if (@cmpxchgWeak(i32, &x, 99, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
- assert(x1 == 1234);
+ assertOrPanic(x1 == 1234);
} else {
@panic("cmpxchg should have failed");
}
while (@cmpxchgWeak(i32, &x, 1234, 5678, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
- assert(x1 == 1234);
+ assertOrPanic(x1 == 1234);
}
- assert(x == 5678);
+ assertOrPanic(x == 5678);
- assert(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
- assert(x == 42);
+ assertOrPanic(@cmpxchgStrong(i32, &x, 5678, 42, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
+ assertOrPanic(x == 42);
}
test "fence" {
@@ -30,24 +30,24 @@ test "fence" {
test "atomicrmw and atomicload" {
var data: u8 = 200;
testAtomicRmw(&data);
- assert(data == 42);
+ assertOrPanic(data == 42);
testAtomicLoad(&data);
}
fn testAtomicRmw(ptr: *u8) void {
const prev_value = @atomicRmw(u8, ptr, AtomicRmwOp.Xchg, 42, AtomicOrder.SeqCst);
- assert(prev_value == 200);
+ assertOrPanic(prev_value == 200);
comptime {
var x: i32 = 1234;
const y: i32 = 12345;
- assert(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234);
- assert(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345);
+ assertOrPanic(@atomicLoad(i32, &x, AtomicOrder.SeqCst) == 1234);
+ assertOrPanic(@atomicLoad(i32, &y, AtomicOrder.SeqCst) == 12345);
}
}
fn testAtomicLoad(ptr: *u8) void {
const x = @atomicLoad(u8, ptr, AtomicOrder.SeqCst);
- assert(x == 42);
+ assertOrPanic(x == 42);
}
test "cmpxchg with ptr" {
@@ -56,16 +56,16 @@ test "cmpxchg with ptr" {
var data3: i32 = 9101;
var x: *i32 = &data1;
if (@cmpxchgWeak(*i32, &x, &data2, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
- assert(x1 == &data1);
+ assertOrPanic(x1 == &data1);
} else {
@panic("cmpxchg should have failed");
}
while (@cmpxchgWeak(*i32, &x, &data1, &data3, AtomicOrder.SeqCst, AtomicOrder.SeqCst)) |x1| {
- assert(x1 == &data1);
+ assertOrPanic(x1 == &data1);
}
- assert(x == &data3);
+ assertOrPanic(x == &data3);
- assert(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
- assert(x == &data2);
+ assertOrPanic(@cmpxchgStrong(*i32, &x, &data3, &data2, AtomicOrder.SeqCst, AtomicOrder.SeqCst) == null);
+ assertOrPanic(x == &data2);
}
diff --git a/test/cases/bit_shifting.zig b/test/stage1/behavior/bit_shifting.zig
similarity index 90%
rename from test/cases/bit_shifting.zig
rename to test/stage1/behavior/bit_shifting.zig
index 325e765bb0a5..3290688358fe 100644
--- a/test/cases/bit_shifting.zig
+++ b/test/stage1/behavior/bit_shifting.zig
@@ -1,9 +1,9 @@
const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
fn ShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, comptime V: type) type {
- assert(Key == @IntType(false, Key.bit_count));
- assert(Key.bit_count >= mask_bit_count);
+ assertOrPanic(Key == @IntType(false, Key.bit_count));
+ assertOrPanic(Key.bit_count >= mask_bit_count);
const ShardKey = @IntType(false, mask_bit_count);
const shift_amount = Key.bit_count - ShardKey.bit_count;
return struct {
@@ -77,12 +77,12 @@ fn testShardedTable(comptime Key: type, comptime mask_bit_count: comptime_int, c
var node_buffer: [node_count]Table.Node = undefined;
for (node_buffer) |*node, i| {
const key = @intCast(Key, i);
- assert(table.get(key) == null);
+ assertOrPanic(table.get(key) == null);
node.init(key, {});
table.put(node);
}
for (node_buffer) |*node, i| {
- assert(table.get(@intCast(Key, i)) == node);
+ assertOrPanic(table.get(@intCast(Key, i)) == node);
}
}
diff --git a/test/cases/bitcast.zig b/test/stage1/behavior/bitcast.zig
similarity index 78%
rename from test/cases/bitcast.zig
rename to test/stage1/behavior/bitcast.zig
index d85a84ed225e..19030255e4f7 100644
--- a/test/cases/bitcast.zig
+++ b/test/stage1/behavior/bitcast.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
const maxInt = std.math.maxInt;
test "@bitCast i32 -> u32" {
@@ -8,8 +8,8 @@ test "@bitCast i32 -> u32" {
}
fn testBitCast_i32_u32() void {
- assert(conv(-1) == maxInt(u32));
- assert(conv2(maxInt(u32)) == -1);
+ assertOrPanic(conv(-1) == maxInt(u32));
+ assertOrPanic(conv2(maxInt(u32)) == -1);
}
fn conv(x: i32) u32 {
@@ -27,11 +27,10 @@ test "@bitCast extern enum to its integer type" {
fn testBitCastExternEnum() void {
var SOCK_DGRAM = @This().B;
var sock_dgram = @bitCast(c_int, SOCK_DGRAM);
- assert(sock_dgram == 1);
+ assertOrPanic(sock_dgram == 1);
}
};
SOCK.testBitCastExternEnum();
comptime SOCK.testBitCastExternEnum();
}
-
diff --git a/test/stage1/behavior/bitreverse.zig b/test/stage1/behavior/bitreverse.zig
new file mode 100644
index 000000000000..97787ace84f2
--- /dev/null
+++ b/test/stage1/behavior/bitreverse.zig
@@ -0,0 +1,81 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+const minInt = std.math.minInt;
+
+test "@bitreverse" {
+ comptime testBitReverse();
+ testBitReverse();
+}
+
+fn testBitReverse() void {
+ // using comptime_ints, unsigned
+ assertOrPanic(@bitreverse(u0, 0) == 0);
+ assertOrPanic(@bitreverse(u5, 0x12) == 0x9);
+ assertOrPanic(@bitreverse(u8, 0x12) == 0x48);
+ assertOrPanic(@bitreverse(u16, 0x1234) == 0x2c48);
+ assertOrPanic(@bitreverse(u24, 0x123456) == 0x6a2c48);
+ assertOrPanic(@bitreverse(u32, 0x12345678) == 0x1e6a2c48);
+ assertOrPanic(@bitreverse(u40, 0x123456789a) == 0x591e6a2c48);
+ assertOrPanic(@bitreverse(u48, 0x123456789abc) == 0x3d591e6a2c48);
+ assertOrPanic(@bitreverse(u56, 0x123456789abcde) == 0x7b3d591e6a2c48);
+ assertOrPanic(@bitreverse(u64, 0x123456789abcdef1) == 0x8f7b3d591e6a2c48);
+ assertOrPanic(@bitreverse(u128, 0x123456789abcdef11121314151617181) == 0x818e868a828c84888f7b3d591e6a2c48);
+
+ // using runtime uints, unsigned
+ var num0: u0 = 0;
+ assertOrPanic(@bitreverse(u0, num0) == 0);
+ var num5: u5 = 0x12;
+ assertOrPanic(@bitreverse(u5, num5) == 0x9);
+ var num8: u8 = 0x12;
+ assertOrPanic(@bitreverse(u8, num8) == 0x48);
+ var num16: u16 = 0x1234;
+ assertOrPanic(@bitreverse(u16, num16) == 0x2c48);
+ var num24: u24 = 0x123456;
+ assertOrPanic(@bitreverse(u24, num24) == 0x6a2c48);
+ var num32: u32 = 0x12345678;
+ assertOrPanic(@bitreverse(u32, num32) == 0x1e6a2c48);
+ var num40: u40 = 0x123456789a;
+ assertOrPanic(@bitreverse(u40, num40) == 0x591e6a2c48);
+ var num48: u48 = 0x123456789abc;
+ assertOrPanic(@bitreverse(u48, num48) == 0x3d591e6a2c48);
+ var num56: u56 = 0x123456789abcde;
+ assertOrPanic(@bitreverse(u56, num56) == 0x7b3d591e6a2c48);
+ var num64: u64 = 0x123456789abcdef1;
+ assertOrPanic(@bitreverse(u64, num64) == 0x8f7b3d591e6a2c48);
+ var num128: u128 = 0x123456789abcdef11121314151617181;
+ assertOrPanic(@bitreverse(u128, num128) == 0x818e868a828c84888f7b3d591e6a2c48);
+
+ // using comptime_ints, signed, positive
+ assertOrPanic(@bitreverse(i0, 0) == 0);
+ assertOrPanic(@bitreverse(i8, @bitCast(i8, u8(0x92))) == @bitCast(i8, u8(0x49)));
+ assertOrPanic(@bitreverse(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x2c48)));
+ assertOrPanic(@bitreverse(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x6a2c48)));
+ assertOrPanic(@bitreverse(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x1e6a2c48)));
+ assertOrPanic(@bitreverse(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x591e6a2c48)));
+ assertOrPanic(@bitreverse(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0x3d591e6a2c48)));
+ assertOrPanic(@bitreverse(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0x7b3d591e6a2c48)));
+ assertOrPanic(@bitreverse(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0x8f7b3d591e6a2c48)));
+ assertOrPanic(@bitreverse(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) == @bitCast(i128, u128(0x818e868a828c84888f7b3d591e6a2c48)));
+
+ // using comptime_ints, signed, negative. Compare to runtime ints returned from llvm.
+ var neg5: i5 = minInt(i5) + 1;
+ assertOrPanic(@bitreverse(i5, minInt(i5) + 1) == @bitreverse(i5, neg5));
+ var neg8: i8 = -18;
+ assertOrPanic(@bitreverse(i8, -18) == @bitreverse(i8, neg8));
+ var neg16: i16 = -32694;
+ assertOrPanic(@bitreverse(i16, -32694) == @bitreverse(i16, neg16));
+ var neg24: i24 = -6773785;
+ assertOrPanic(@bitreverse(i24, -6773785) == @bitreverse(i24, neg24));
+ var neg32: i32 = -16773785;
+ assertOrPanic(@bitreverse(i32, -16773785) == @bitreverse(i32, neg32));
+ var neg40: i40 = minInt(i40) + 12345;
+ assertOrPanic(@bitreverse(i40, minInt(i40) + 12345) == @bitreverse(i40, neg40));
+ var neg48: i48 = minInt(i48) + 12345;
+ assertOrPanic(@bitreverse(i48, minInt(i48) + 12345) == @bitreverse(i48, neg48));
+ var neg56: i56 = minInt(i56) + 12345;
+ assertOrPanic(@bitreverse(i56, minInt(i56) + 12345) == @bitreverse(i56, neg56));
+ var neg64: i64 = minInt(i64) + 12345;
+ assertOrPanic(@bitreverse(i64, minInt(i64) + 12345) == @bitreverse(i64, neg64));
+ var neg128: i128 = minInt(i128) + 12345;
+ assertOrPanic(@bitreverse(i128, minInt(i128) + 12345) == @bitreverse(i128, neg128));
+}
diff --git a/test/cases/bool.zig b/test/stage1/behavior/bool.zig
similarity index 50%
rename from test/cases/bool.zig
rename to test/stage1/behavior/bool.zig
index 3e4ac9c1cfe4..2d7241526f42 100644
--- a/test/cases/bool.zig
+++ b/test/stage1/behavior/bool.zig
@@ -1,25 +1,25 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
test "bool literals" {
- assert(true);
- assert(!false);
+ assertOrPanic(true);
+ assertOrPanic(!false);
}
test "cast bool to int" {
const t = true;
const f = false;
- assert(@boolToInt(t) == u32(1));
- assert(@boolToInt(f) == u32(0));
+ assertOrPanic(@boolToInt(t) == u32(1));
+ assertOrPanic(@boolToInt(f) == u32(0));
nonConstCastBoolToInt(t, f);
}
fn nonConstCastBoolToInt(t: bool, f: bool) void {
- assert(@boolToInt(t) == u32(1));
- assert(@boolToInt(f) == u32(0));
+ assertOrPanic(@boolToInt(t) == u32(1));
+ assertOrPanic(@boolToInt(f) == u32(0));
}
test "bool cmp" {
- assert(testBoolCmp(true, false) == false);
+ assertOrPanic(testBoolCmp(true, false) == false);
}
fn testBoolCmp(a: bool, b: bool) bool {
return a == b;
@@ -30,6 +30,6 @@ const global_t = true;
const not_global_f = !global_f;
const not_global_t = !global_t;
test "compile time bool not" {
- assert(not_global_f);
- assert(!not_global_t);
+ assertOrPanic(not_global_f);
+ assertOrPanic(!not_global_t);
}
diff --git a/test/stage1/behavior/bswap.zig b/test/stage1/behavior/bswap.zig
new file mode 100644
index 000000000000..8084538e03c0
--- /dev/null
+++ b/test/stage1/behavior/bswap.zig
@@ -0,0 +1,32 @@
+const std = @import("std");
+const assertOrPanic = std.debug.assertOrPanic;
+
+test "@bswap" {
+ comptime testByteSwap();
+ testByteSwap();
+}
+
+fn testByteSwap() void {
+ assertOrPanic(@bswap(u0, 0) == 0);
+ assertOrPanic(@bswap(u8, 0x12) == 0x12);
+ assertOrPanic(@bswap(u16, 0x1234) == 0x3412);
+ assertOrPanic(@bswap(u24, 0x123456) == 0x563412);
+ assertOrPanic(@bswap(u32, 0x12345678) == 0x78563412);
+ assertOrPanic(@bswap(u40, 0x123456789a) == 0x9a78563412);
+ assertOrPanic(@bswap(u48, 0x123456789abc) == 0xbc9a78563412);
+ assertOrPanic(@bswap(u56, 0x123456789abcde) == 0xdebc9a78563412);
+ assertOrPanic(@bswap(u64, 0x123456789abcdef1) == 0xf1debc9a78563412);
+ assertOrPanic(@bswap(u128, 0x123456789abcdef11121314151617181) == 0x8171615141312111f1debc9a78563412);
+
+ assertOrPanic(@bswap(i0, 0) == 0);
+ assertOrPanic(@bswap(i8, -50) == -50);
+ assertOrPanic(@bswap(i16, @bitCast(i16, u16(0x1234))) == @bitCast(i16, u16(0x3412)));
+ assertOrPanic(@bswap(i24, @bitCast(i24, u24(0x123456))) == @bitCast(i24, u24(0x563412)));
+ assertOrPanic(@bswap(i32, @bitCast(i32, u32(0x12345678))) == @bitCast(i32, u32(0x78563412)));
+ assertOrPanic(@bswap(i40, @bitCast(i40, u40(0x123456789a))) == @bitCast(i40, u40(0x9a78563412)));
+ assertOrPanic(@bswap(i48, @bitCast(i48, u48(0x123456789abc))) == @bitCast(i48, u48(0xbc9a78563412)));
+ assertOrPanic(@bswap(i56, @bitCast(i56, u56(0x123456789abcde))) == @bitCast(i56, u56(0xdebc9a78563412)));
+ assertOrPanic(@bswap(i64, @bitCast(i64, u64(0x123456789abcdef1))) == @bitCast(i64, u64(0xf1debc9a78563412)));
+ assertOrPanic(@bswap(i128, @bitCast(i128, u128(0x123456789abcdef11121314151617181))) ==
+ @bitCast(i128, u128(0x8171615141312111f1debc9a78563412)));
+}
diff --git a/test/cases/bugs/1076.zig b/test/stage1/behavior/bugs/1076.zig
similarity index 75%
rename from test/cases/bugs/1076.zig
rename to test/stage1/behavior/bugs/1076.zig
index 7b843123104e..69a7e70f7dbb 100644
--- a/test/cases/bugs/1076.zig
+++ b/test/stage1/behavior/bugs/1076.zig
@@ -1,6 +1,6 @@
const std = @import("std");
const mem = std.mem;
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
test "comptime code should not modify constant data" {
testCastPtrOfArrayToSliceAndPtr();
@@ -11,6 +11,6 @@ fn testCastPtrOfArrayToSliceAndPtr() void {
var array = "aoeu";
const x: [*]u8 = &array;
x[0] += 1;
- assert(mem.eql(u8, array[0..], "boeu"));
+ assertOrPanic(mem.eql(u8, array[0..], "boeu"));
}
diff --git a/test/cases/bugs/1111.zig b/test/stage1/behavior/bugs/1111.zig
similarity index 100%
rename from test/cases/bugs/1111.zig
rename to test/stage1/behavior/bugs/1111.zig
diff --git a/test/cases/bugs/1277.zig b/test/stage1/behavior/bugs/1277.zig
similarity index 100%
rename from test/cases/bugs/1277.zig
rename to test/stage1/behavior/bugs/1277.zig
diff --git a/test/cases/bugs/1322.zig b/test/stage1/behavior/bugs/1322.zig
similarity index 66%
rename from test/cases/bugs/1322.zig
rename to test/stage1/behavior/bugs/1322.zig
index 2de92191ec17..2e67f4473fec 100644
--- a/test/cases/bugs/1322.zig
+++ b/test/stage1/behavior/bugs/1322.zig
@@ -13,7 +13,7 @@ const C = struct {};
test "tagged union with all void fields but a meaningful tag" {
var a: A = A{ .b = B{ .c = C{} } };
- std.debug.assert(@TagType(B)(a.b) == @TagType(B).c);
+ std.debug.assertOrPanic(@TagType(B)(a.b) == @TagType(B).c);
a = A{ .b = B.None };
- std.debug.assert(@TagType(B)(a.b) == @TagType(B).None);
+ std.debug.assertOrPanic(@TagType(B)(a.b) == @TagType(B).None);
}
diff --git a/test/cases/bugs/1381.zig b/test/stage1/behavior/bugs/1381.zig
similarity index 100%
rename from test/cases/bugs/1381.zig
rename to test/stage1/behavior/bugs/1381.zig
diff --git a/test/cases/bugs/1421.zig b/test/stage1/behavior/bugs/1421.zig
similarity index 70%
rename from test/cases/bugs/1421.zig
rename to test/stage1/behavior/bugs/1421.zig
index fcbb8b70e4f8..fbc932781ab9 100644
--- a/test/cases/bugs/1421.zig
+++ b/test/stage1/behavior/bugs/1421.zig
@@ -1,6 +1,6 @@
const std = @import("std");
const builtin = @import("builtin");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
const S = struct {
fn method() builtin.TypeInfo {
@@ -10,5 +10,5 @@ const S = struct {
test "functions with return type required to be comptime are generic" {
const ti = S.method();
- assert(builtin.TypeId(ti) == builtin.TypeId.Struct);
+ assertOrPanic(builtin.TypeId(ti) == builtin.TypeId.Struct);
}
diff --git a/test/cases/bugs/1442.zig b/test/stage1/behavior/bugs/1442.zig
similarity index 100%
rename from test/cases/bugs/1442.zig
rename to test/stage1/behavior/bugs/1442.zig
diff --git a/test/cases/bugs/1486.zig b/test/stage1/behavior/bugs/1486.zig
similarity index 51%
rename from test/cases/bugs/1486.zig
rename to test/stage1/behavior/bugs/1486.zig
index 98fae36d3a0f..0483e3828cde 100644
--- a/test/cases/bugs/1486.zig
+++ b/test/stage1/behavior/bugs/1486.zig
@@ -1,11 +1,11 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
const ptr = &global;
var global: u64 = 123;
test "constant pointer to global variable causes runtime load" {
global = 1234;
- assert(&global == ptr);
- assert(ptr.* == 1234);
+ assertOrPanic(&global == ptr);
+ assertOrPanic(ptr.* == 1234);
}
diff --git a/test/cases/bugs/394.zig b/test/stage1/behavior/bugs/394.zig
similarity index 68%
rename from test/cases/bugs/394.zig
rename to test/stage1/behavior/bugs/394.zig
index b0afec23572a..766ad9e15761 100644
--- a/test/cases/bugs/394.zig
+++ b/test/stage1/behavior/bugs/394.zig
@@ -7,12 +7,12 @@ const S = struct {
y: E,
};
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
test "bug 394 fixed" {
const x = S{
.x = 3,
.y = E{ .B = 1 },
};
- assert(x.x == 3);
+ assertOrPanic(x.x == 3);
}
diff --git a/test/cases/bugs/655.zig b/test/stage1/behavior/bugs/655.zig
similarity index 67%
rename from test/cases/bugs/655.zig
rename to test/stage1/behavior/bugs/655.zig
index ebb8da0658d4..67ba6a231f33 100644
--- a/test/cases/bugs/655.zig
+++ b/test/stage1/behavior/bugs/655.zig
@@ -3,10 +3,10 @@ const other_file = @import("655_other_file.zig");
test "function with *const parameter with type dereferenced by namespace" {
const x: other_file.Integer = 1234;
- comptime std.debug.assert(@typeOf(&x) == *const other_file.Integer);
+ comptime std.debug.assertOrPanic(@typeOf(&x) == *const other_file.Integer);
foo(&x);
}
fn foo(x: *const other_file.Integer) void {
- std.debug.assert(x.* == 1234);
+ std.debug.assertOrPanic(x.* == 1234);
}
diff --git a/test/cases/bugs/655_other_file.zig b/test/stage1/behavior/bugs/655_other_file.zig
similarity index 100%
rename from test/cases/bugs/655_other_file.zig
rename to test/stage1/behavior/bugs/655_other_file.zig
diff --git a/test/cases/bugs/656.zig b/test/stage1/behavior/bugs/656.zig
similarity index 84%
rename from test/cases/bugs/656.zig
rename to test/stage1/behavior/bugs/656.zig
index f93f0ac4d51f..cb37fe67fe84 100644
--- a/test/cases/bugs/656.zig
+++ b/test/stage1/behavior/bugs/656.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
const PrefixOp = union(enum) {
Return,
@@ -22,7 +22,7 @@ fn foo(a: bool, b: bool) void {
PrefixOp.AddrOf => |addr_of_info| {
if (b) {}
if (addr_of_info.align_expr) |align_expr| {
- assert(align_expr == 1234);
+ assertOrPanic(align_expr == 1234);
}
},
PrefixOp.Return => {},
diff --git a/test/cases/bugs/726.zig b/test/stage1/behavior/bugs/726.zig
similarity index 71%
rename from test/cases/bugs/726.zig
rename to test/stage1/behavior/bugs/726.zig
index 2acc91eb26c1..ce20480c6332 100644
--- a/test/cases/bugs/726.zig
+++ b/test/stage1/behavior/bugs/726.zig
@@ -1,9 +1,9 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
test "@ptrCast from const to nullable" {
const c: u8 = 4;
var x: ?*const u8 = @ptrCast(?*const u8, &c);
- assert(x.?.* == 4);
+ assertOrPanic(x.?.* == 4);
}
test "@ptrCast from var in empty struct to nullable" {
@@ -11,6 +11,6 @@ test "@ptrCast from var in empty struct to nullable" {
var c: u8 = 4;
};
var x: ?*const u8 = @ptrCast(?*const u8, &container.c);
- assert(x.?.* == 4);
+ assertOrPanic(x.?.* == 4);
}
diff --git a/test/cases/bugs/828.zig b/test/stage1/behavior/bugs/828.zig
similarity index 100%
rename from test/cases/bugs/828.zig
rename to test/stage1/behavior/bugs/828.zig
diff --git a/test/cases/bugs/920.zig b/test/stage1/behavior/bugs/920.zig
similarity index 95%
rename from test/cases/bugs/920.zig
rename to test/stage1/behavior/bugs/920.zig
index 2903f05a29ab..e29c5c4acf5a 100644
--- a/test/cases/bugs/920.zig
+++ b/test/stage1/behavior/bugs/920.zig
@@ -60,6 +60,6 @@ test "bug 920 fixed" {
};
for (NormalDist1.f) |_, i| {
- std.debug.assert(NormalDist1.f[i] == NormalDist.f[i]);
+ std.debug.assertOrPanic(NormalDist1.f[i] == NormalDist.f[i]);
}
}
diff --git a/test/cases/byval_arg_var.zig b/test/stage1/behavior/byval_arg_var.zig
similarity index 70%
rename from test/cases/byval_arg_var.zig
rename to test/stage1/behavior/byval_arg_var.zig
index 826b9cc9e593..14ee212ce07c 100644
--- a/test/cases/byval_arg_var.zig
+++ b/test/stage1/behavior/byval_arg_var.zig
@@ -2,11 +2,11 @@ const std = @import("std");
var result: []const u8 = "wrong";
-test "aoeu" {
+test "pass string literal byvalue to a generic var param" {
start();
blowUpStack(10);
- std.debug.assert(std.mem.eql(u8, result, "string literal"));
+ std.debug.assertOrPanic(std.mem.eql(u8, result, "string literal"));
}
fn start() void {
diff --git a/test/cases/cancel.zig b/test/stage1/behavior/cancel.zig
similarity index 84%
rename from test/cases/cancel.zig
rename to test/stage1/behavior/cancel.zig
index c0f74fd34f44..863da4bdb831 100644
--- a/test/cases/cancel.zig
+++ b/test/stage1/behavior/cancel.zig
@@ -10,9 +10,9 @@ test "cancel forwards" {
const p = async<&da.allocator> f1() catch unreachable;
cancel p;
- std.debug.assert(defer_f1);
- std.debug.assert(defer_f2);
- std.debug.assert(defer_f3);
+ std.debug.assertOrPanic(defer_f1);
+ std.debug.assertOrPanic(defer_f2);
+ std.debug.assertOrPanic(defer_f3);
}
async fn f1() void {
@@ -47,10 +47,10 @@ test "cancel backwards" {
const p = async<&da.allocator> b1() catch unreachable;
cancel p;
- std.debug.assert(defer_b1);
- std.debug.assert(defer_b2);
- std.debug.assert(defer_b3);
- std.debug.assert(defer_b4);
+ std.debug.assertOrPanic(defer_b1);
+ std.debug.assertOrPanic(defer_b2);
+ std.debug.assertOrPanic(defer_b3);
+ std.debug.assertOrPanic(defer_b4);
}
async fn b1() void {
diff --git a/test/cases/cast.zig b/test/stage1/behavior/cast.zig
similarity index 66%
rename from test/cases/cast.zig
rename to test/stage1/behavior/cast.zig
index bd45bbc00f08..1a8b61454069 100644
--- a/test/cases/cast.zig
+++ b/test/stage1/behavior/cast.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
const mem = std.mem;
const maxInt = std.math.maxInt;
@@ -7,12 +7,12 @@ test "int to ptr cast" {
const x = usize(13);
const y = @intToPtr(*u8, x);
const z = @ptrToInt(y);
- assert(z == 13);
+ assertOrPanic(z == 13);
}
test "integer literal to pointer cast" {
const vga_mem = @intToPtr(*u16, 0xB8000);
- assert(@ptrToInt(vga_mem) == 0xB8000);
+ assertOrPanic(@ptrToInt(vga_mem) == 0xB8000);
}
test "pointer reinterpret const float to int" {
@@ -20,7 +20,7 @@ test "pointer reinterpret const float to int" {
const float_ptr = &float;
const int_ptr = @ptrCast(*const i32, float_ptr);
const int_val = int_ptr.*;
- assert(int_val == 858993411);
+ assertOrPanic(int_val == 858993411);
}
test "implicitly cast indirect pointer to maybe-indirect pointer" {
@@ -44,10 +44,10 @@ test "implicitly cast indirect pointer to maybe-indirect pointer" {
const p = &s;
const q = &p;
const r = &q;
- assert(42 == S.constConst(q));
- assert(42 == S.maybeConstConst(q));
- assert(42 == S.constConstConst(r));
- assert(42 == S.maybeConstConstConst(r));
+ assertOrPanic(42 == S.constConst(q));
+ assertOrPanic(42 == S.maybeConstConst(q));
+ assertOrPanic(42 == S.constConstConst(r));
+ assertOrPanic(42 == S.maybeConstConstConst(r));
}
test "explicit cast from integer to error type" {
@@ -57,14 +57,14 @@ test "explicit cast from integer to error type" {
fn testCastIntToErr(err: anyerror) void {
const x = @errorToInt(err);
const y = @intToError(x);
- assert(error.ItBroke == y);
+ assertOrPanic(error.ItBroke == y);
}
test "peer resolve arrays of different size to const slice" {
- assert(mem.eql(u8, boolToStr(true), "true"));
- assert(mem.eql(u8, boolToStr(false), "false"));
- comptime assert(mem.eql(u8, boolToStr(true), "true"));
- comptime assert(mem.eql(u8, boolToStr(false), "false"));
+ assertOrPanic(mem.eql(u8, boolToStr(true), "true"));
+ assertOrPanic(mem.eql(u8, boolToStr(false), "false"));
+ comptime assertOrPanic(mem.eql(u8, boolToStr(true), "true"));
+ comptime assertOrPanic(mem.eql(u8, boolToStr(false), "false"));
}
fn boolToStr(b: bool) []const u8 {
return if (b) "true" else "false";
@@ -75,30 +75,32 @@ test "peer resolve array and const slice" {
comptime testPeerResolveArrayConstSlice(true);
}
fn testPeerResolveArrayConstSlice(b: bool) void {
- const value1 = if (b) "aoeu" else ([]const u8)("zz");
+ // TODO: https://github.com/ziglang/zig/pull/1682#issuecomment-451303797
+ const value1: []const u8 = if (b) "aoeu" else ([]const u8)("zz");
const value2 = if (b) ([]const u8)("zz") else "aoeu";
- assert(mem.eql(u8, value1, "aoeu"));
- assert(mem.eql(u8, value2, "zz"));
+ assertOrPanic(mem.eql(u8, value1, "aoeu"));
+ assertOrPanic(mem.eql(u8, value2, "zz"));
}
test "implicitly cast from T to anyerror!?T" {
castToOptionalTypeError(1);
comptime castToOptionalTypeError(1);
}
+
const A = struct {
a: i32,
};
fn castToOptionalTypeError(z: i32) void {
const x = i32(1);
const y: anyerror!?i32 = x;
- assert((try y).? == 1);
+ assertOrPanic((try y).? == 1);
const f = z;
const g: anyerror!?i32 = f;
const a = A{ .a = z };
const b: anyerror!?A = a;
- assert((b catch unreachable).?.a == 1);
+ assertOrPanic((b catch unreachable).?.a == 1);
}
test "implicitly cast from int to anyerror!?T" {
@@ -113,7 +115,7 @@ fn implicitIntLitToOptional() void {
test "return null from fn() anyerror!?&T" {
const a = returnNullFromOptionalTypeErrorRef();
const b = returnNullLitFromOptionalTypeErrorRef();
- assert((try a) == null and (try b) == null);
+ assertOrPanic((try a) == null and (try b) == null);
}
fn returnNullFromOptionalTypeErrorRef() anyerror!?*A {
const a: ?*A = null;
@@ -124,11 +126,11 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A {
}
test "peer type resolution: ?T and T" {
- assert(peerTypeTAndOptionalT(true, false).? == 0);
- assert(peerTypeTAndOptionalT(false, false).? == 3);
+ assertOrPanic(peerTypeTAndOptionalT(true, false).? == 0);
+ assertOrPanic(peerTypeTAndOptionalT(false, false).? == 3);
comptime {
- assert(peerTypeTAndOptionalT(true, false).? == 0);
- assert(peerTypeTAndOptionalT(false, false).? == 3);
+ assertOrPanic(peerTypeTAndOptionalT(true, false).? == 0);
+ assertOrPanic(peerTypeTAndOptionalT(false, false).? == 3);
}
}
fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
@@ -140,11 +142,11 @@ fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
}
test "peer type resolution: [0]u8 and []const u8" {
- assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
- assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
+ assertOrPanic(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
+ assertOrPanic(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
comptime {
- assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
- assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
+ assertOrPanic(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
+ assertOrPanic(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
}
}
fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
@@ -156,8 +158,8 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
}
test "implicitly cast from [N]T to ?[]const T" {
- assert(mem.eql(u8, castToOptionalSlice().?, "hi"));
- comptime assert(mem.eql(u8, castToOptionalSlice().?, "hi"));
+ assertOrPanic(mem.eql(u8, castToOptionalSlice().?, "hi"));
+ comptime assertOrPanic(mem.eql(u8, castToOptionalSlice().?, "hi"));
}
fn castToOptionalSlice() ?[]const u8 {
@@ -170,7 +172,7 @@ test "implicitly cast from [0]T to anyerror![]T" {
}
fn testCastZeroArrayToErrSliceMut() void {
- assert((gimmeErrOrSlice() catch unreachable).len == 0);
+ assertOrPanic((gimmeErrOrSlice() catch unreachable).len == 0);
}
fn gimmeErrOrSlice() anyerror![]u8 {
@@ -181,14 +183,14 @@ test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" {
{
var data = "hi";
const slice = data[0..];
- assert((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
- assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
+ assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
+ assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
}
comptime {
var data = "hi";
const slice = data[0..];
- assert((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
- assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
+ assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
+ assertOrPanic((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
}
}
fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 {
@@ -206,7 +208,7 @@ test "resolve undefined with integer" {
fn testResolveUndefWithInt(b: bool, x: i32) void {
const value = if (b) x else undefined;
if (b) {
- assert(value == x);
+ assertOrPanic(value == x);
}
}
@@ -218,17 +220,17 @@ test "implicit cast from &const [N]T to []const T" {
fn testCastConstArrayRefToConstSlice() void {
const blah = "aoeu";
const const_array_ref = &blah;
- assert(@typeOf(const_array_ref) == *const [4]u8);
+ assertOrPanic(@typeOf(const_array_ref) == *const [4]u8);
const slice: []const u8 = const_array_ref;
- assert(mem.eql(u8, slice, "aoeu"));
+ assertOrPanic(mem.eql(u8, slice, "aoeu"));
}
test "peer type resolution: error and [N]T" {
// TODO: implicit error!T to error!U where T can implicitly cast to U
- //assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
- //comptime assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
- assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK"));
- comptime assert(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK"));
+ //assertOrPanic(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
+ //comptime assertOrPanic(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
+ assertOrPanic(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK"));
+ comptime assertOrPanic(mem.eql(u8, try testPeerErrorAndArray2(1), "OKK"));
}
//fn testPeerErrorAndArray(x: u8) error![]const u8 {
@@ -252,9 +254,9 @@ test "@floatToInt" {
fn testFloatToInts() void {
const x = i32(1e4);
- assert(x == 10000);
+ assertOrPanic(x == 10000);
const y = @floatToInt(i32, f32(1e4));
- assert(y == 10000);
+ assertOrPanic(y == 10000);
expectFloatToInt(f16, 255.1, u8, 255);
expectFloatToInt(f16, 127.2, i8, 127);
expectFloatToInt(f16, -128.2, i8, -128);
@@ -265,7 +267,7 @@ fn testFloatToInts() void {
}
fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) void {
- assert(@floatToInt(I, f) == i);
+ assertOrPanic(@floatToInt(I, f) == i);
}
test "cast u128 to f128 and back" {
@@ -274,7 +276,7 @@ test "cast u128 to f128 and back" {
}
fn testCast128() void {
- assert(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000);
+ assertOrPanic(cast128Int(cast128Float(0x7fff0000000000000000000000000000)) == 0x7fff0000000000000000000000000000);
}
fn cast128Int(x: f128) u128 {
@@ -294,9 +296,9 @@ test "const slice widen cast" {
};
const u32_value = @bytesToSlice(u32, bytes[0..])[0];
- assert(u32_value == 0x12121212);
+ assertOrPanic(u32_value == 0x12121212);
- assert(@bitCast(u32, bytes) == 0x12121212);
+ assertOrPanic(@bitCast(u32, bytes) == 0x12121212);
}
test "single-item pointer of array to slice and to unknown length pointer" {
@@ -308,76 +310,76 @@ fn testCastPtrOfArrayToSliceAndPtr() void {
var array = "aoeu";
const x: [*]u8 = &array;
x[0] += 1;
- assert(mem.eql(u8, array[0..], "boeu"));
+ assertOrPanic(mem.eql(u8, array[0..], "boeu"));
const y: []u8 = &array;
y[0] += 1;
- assert(mem.eql(u8, array[0..], "coeu"));
+ assertOrPanic(mem.eql(u8, array[0..], "coeu"));
}
test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
const window_name = [1][*]const u8{c"window name"};
const x: [*]const ?[*]const u8 = &window_name;
- assert(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name"));
+ assertOrPanic(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name"));
}
test "@intCast comptime_int" {
const result = @intCast(i32, 1234);
- assert(@typeOf(result) == i32);
- assert(result == 1234);
+ assertOrPanic(@typeOf(result) == i32);
+ assertOrPanic(result == 1234);
}
test "@floatCast comptime_int and comptime_float" {
{
const result = @floatCast(f16, 1234);
- assert(@typeOf(result) == f16);
- assert(result == 1234.0);
+ assertOrPanic(@typeOf(result) == f16);
+ assertOrPanic(result == 1234.0);
}
{
const result = @floatCast(f16, 1234.0);
- assert(@typeOf(result) == f16);
- assert(result == 1234.0);
+ assertOrPanic(@typeOf(result) == f16);
+ assertOrPanic(result == 1234.0);
}
{
const result = @floatCast(f32, 1234);
- assert(@typeOf(result) == f32);
- assert(result == 1234.0);
+ assertOrPanic(@typeOf(result) == f32);
+ assertOrPanic(result == 1234.0);
}
{
const result = @floatCast(f32, 1234.0);
- assert(@typeOf(result) == f32);
- assert(result == 1234.0);
+ assertOrPanic(@typeOf(result) == f32);
+ assertOrPanic(result == 1234.0);
}
}
test "comptime_int @intToFloat" {
{
const result = @intToFloat(f16, 1234);
- assert(@typeOf(result) == f16);
- assert(result == 1234.0);
+ assertOrPanic(@typeOf(result) == f16);
+ assertOrPanic(result == 1234.0);
}
{
const result = @intToFloat(f32, 1234);
- assert(@typeOf(result) == f32);
- assert(result == 1234.0);
+ assertOrPanic(@typeOf(result) == f32);
+ assertOrPanic(result == 1234.0);
}
}
test "@bytesToSlice keeps pointer alignment" {
var bytes = []u8{ 0x01, 0x02, 0x03, 0x04 };
const numbers = @bytesToSlice(u32, bytes[0..]);
- comptime assert(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32);
+ comptime assertOrPanic(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32);
}
test "@intCast i32 to u7" {
var x: u128 = maxInt(u128);
var y: i32 = 120;
var z = x >> @intCast(u7, y);
- assert(z == 0xff);
+ assertOrPanic(z == 0xff);
}
test "implicit cast undefined to optional" {
- assert(MakeType(void).getNull() == null);
- assert(MakeType(void).getNonNull() != null);
+ assertOrPanic(MakeType(void).getNull() == null);
+ assertOrPanic(MakeType(void).getNonNull() != null);
}
fn MakeType(comptime T: type) type {
@@ -397,16 +399,16 @@ test "implicit cast from *[N]T to ?[*]T" {
var y: [4]u16 = [4]u16{ 0, 1, 2, 3 };
x = &y;
- assert(std.mem.eql(u16, x.?[0..4], y[0..4]));
+ assertOrPanic(std.mem.eql(u16, x.?[0..4], y[0..4]));
x.?[0] = 8;
y[3] = 6;
- assert(std.mem.eql(u16, x.?[0..4], y[0..4]));
+ assertOrPanic(std.mem.eql(u16, x.?[0..4], y[0..4]));
}
test "implicit cast from *T to ?*c_void" {
var a: u8 = 1;
incrementVoidPtrValue(&a);
- std.debug.assert(a == 2);
+ std.debug.assertOrPanic(a == 2);
}
fn incrementVoidPtrValue(value: ?*c_void) void {
@@ -416,7 +418,7 @@ fn incrementVoidPtrValue(value: ?*c_void) void {
test "implicit cast from [*]T to ?*c_void" {
var a = []u8{ 3, 2, 1 };
incrementVoidPtrArray(a[0..].ptr, 3);
- assert(std.mem.eql(u8, a, []u8{ 4, 3, 2 }));
+ assertOrPanic(std.mem.eql(u8, a, []u8{ 4, 3, 2 }));
}
fn incrementVoidPtrArray(array: ?*c_void, len: usize) void {
@@ -440,27 +442,27 @@ pub const FUNCTION_CONSTANT = @intToPtr(PFN_void, maxInt(usize));
pub const PFN_void = extern fn (*c_void) void;
fn foobar(func: PFN_void) void {
- std.debug.assert(@ptrToInt(func) == maxInt(usize));
+ std.debug.assertOrPanic(@ptrToInt(func) == maxInt(usize));
}
test "implicit ptr to *c_void" {
var a: u32 = 1;
var ptr: *c_void = &a;
var b: *u32 = @ptrCast(*u32, ptr);
- assert(b.* == 1);
+ assertOrPanic(b.* == 1);
var ptr2: ?*c_void = &a;
var c: *u32 = @ptrCast(*u32, ptr2.?);
- assert(c.* == 1);
+ assertOrPanic(c.* == 1);
}
test "@intCast to comptime_int" {
- assert(@intCast(comptime_int, 0) == 0);
+ assertOrPanic(@intCast(comptime_int, 0) == 0);
}
test "implicit cast comptime numbers to any type when the value fits" {
const a: u64 = 255;
var b: u8 = a;
- assert(b == 255);
+ assertOrPanic(b == 255);
}
test "@intToEnum passed a comptime_int to an enum with one item" {
@@ -468,5 +470,5 @@ test "@intToEnum passed a comptime_int to an enum with one item" {
A,
};
const x = @intToEnum(E, 0);
- assert(x == E.A);
+ assertOrPanic(x == E.A);
}
diff --git a/test/cases/const_slice_child.zig b/test/stage1/behavior/const_slice_child.zig
similarity index 80%
rename from test/cases/const_slice_child.zig
rename to test/stage1/behavior/const_slice_child.zig
index 07d02d5df06f..5b9b70a55801 100644
--- a/test/cases/const_slice_child.zig
+++ b/test/stage1/behavior/const_slice_child.zig
@@ -1,5 +1,5 @@
const debug = @import("std").debug;
-const assert = debug.assert;
+const assertOrPanic = debug.assertOrPanic;
var argv: [*]const [*]const u8 = undefined;
@@ -15,10 +15,10 @@ test "const slice child" {
}
fn foo(args: [][]const u8) void {
- assert(args.len == 3);
- assert(streql(args[0], "one"));
- assert(streql(args[1], "two"));
- assert(streql(args[2], "three"));
+ assertOrPanic(args.len == 3);
+ assertOrPanic(streql(args[0], "one"));
+ assertOrPanic(streql(args[1], "two"));
+ assertOrPanic(streql(args[2], "three"));
}
fn bar(argc: usize) void {
diff --git a/test/cases/coroutine_await_struct.zig b/test/stage1/behavior/coroutine_await_struct.zig
similarity index 86%
rename from test/cases/coroutine_await_struct.zig
rename to test/stage1/behavior/coroutine_await_struct.zig
index 79168715d8e2..6ca2a301eca5 100644
--- a/test/cases/coroutine_await_struct.zig
+++ b/test/stage1/behavior/coroutine_await_struct.zig
@@ -1,6 +1,6 @@
const std = @import("std");
const builtin = @import("builtin");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
const Foo = struct {
x: i32,
@@ -18,8 +18,8 @@ test "coroutine await struct" {
await_seq('f');
resume await_a_promise;
await_seq('i');
- assert(await_final_result.x == 1234);
- assert(std.mem.eql(u8, await_points, "abcdefghi"));
+ assertOrPanic(await_final_result.x == 1234);
+ assertOrPanic(std.mem.eql(u8, await_points, "abcdefghi"));
}
async fn await_amain() void {
await_seq('b');
diff --git a/test/cases/coroutines.zig b/test/stage1/behavior/coroutines.zig
similarity index 86%
rename from test/cases/coroutines.zig
rename to test/stage1/behavior/coroutines.zig
index 89490ebc2c1c..a2327c506011 100644
--- a/test/cases/coroutines.zig
+++ b/test/stage1/behavior/coroutines.zig
@@ -1,6 +1,6 @@
const std = @import("std");
const builtin = @import("builtin");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
var x: i32 = 1;
@@ -9,9 +9,9 @@ test "create a coroutine and cancel it" {
defer da.deinit();
const p = try async<&da.allocator> simpleAsyncFn();
- comptime assert(@typeOf(p) == promise->void);
+ comptime assertOrPanic(@typeOf(p) == promise->void);
cancel p;
- assert(x == 2);
+ assertOrPanic(x == 2);
}
async fn simpleAsyncFn() void {
x += 1;
@@ -31,7 +31,7 @@ test "coroutine suspend, resume, cancel" {
cancel p;
seq('g');
- assert(std.mem.eql(u8, points, "abcdefg"));
+ assertOrPanic(std.mem.eql(u8, points, "abcdefg"));
}
async fn testAsyncSeq() void {
defer seq('e');
@@ -53,9 +53,9 @@ test "coroutine suspend with block" {
defer da.deinit();
const p = try async<&da.allocator> testSuspendBlock();
- std.debug.assert(!result);
+ std.debug.assertOrPanic(!result);
resume a_promise;
- std.debug.assert(result);
+ std.debug.assertOrPanic(result);
cancel p;
}
@@ -63,13 +63,13 @@ var a_promise: promise = undefined;
var result = false;
async fn testSuspendBlock() void {
suspend {
- comptime assert(@typeOf(@handle()) == promise->void);
+ comptime assertOrPanic(@typeOf(@handle()) == promise->void);
a_promise = @handle();
}
//Test to make sure that @handle() works as advertised (issue #1296)
//var our_handle: promise = @handle();
- assert( a_promise == @handle() );
+ assertOrPanic(a_promise == @handle());
result = true;
}
@@ -86,8 +86,8 @@ test "coroutine await" {
await_seq('f');
resume await_a_promise;
await_seq('i');
- assert(await_final_result == 1234);
- assert(std.mem.eql(u8, await_points, "abcdefghi"));
+ assertOrPanic(await_final_result == 1234);
+ assertOrPanic(std.mem.eql(u8, await_points, "abcdefghi"));
}
async fn await_amain() void {
await_seq('b');
@@ -123,8 +123,8 @@ test "coroutine await early return" {
early_seq('a');
const p = async<&da.allocator> early_amain() catch @panic("out of memory");
early_seq('f');
- assert(early_final_result == 1234);
- assert(std.mem.eql(u8, early_points, "abcdef"));
+ assertOrPanic(early_final_result == 1234);
+ assertOrPanic(std.mem.eql(u8, early_points, "abcdef"));
}
async fn early_amain() void {
early_seq('b');
@@ -170,7 +170,7 @@ test "async function with dot syntax" {
defer da.deinit();
const p = try async<&da.allocator> S.foo();
cancel p;
- assert(S.y == 2);
+ assertOrPanic(S.y == 2);
}
test "async fn pointer in a struct field" {
@@ -182,9 +182,9 @@ test "async fn pointer in a struct field" {
var da = std.heap.DirectAllocator.init();
defer da.deinit();
const p = (async<&da.allocator> foo.bar(&data)) catch unreachable;
- assert(data == 2);
+ assertOrPanic(data == 2);
cancel p;
- assert(data == 4);
+ assertOrPanic(data == 4);
}
async<*std.mem.Allocator> fn simpleAsyncFn2(y: *i32) void {
defer y.* += 2;
@@ -199,6 +199,7 @@ test "async fn with inferred error set" {
resume p;
cancel p;
}
+
async fn failing() !void {
suspend;
return error.Fail;
@@ -220,8 +221,7 @@ test "error return trace across suspend points - async return" {
cancel p2;
}
-// TODO https://github.com/ziglang/zig/issues/760
-fn nonFailing() promise->(anyerror!void) {
+fn nonFailing() (promise->anyerror!void) {
return async suspendThenFail() catch unreachable;
}
async fn suspendThenFail() anyerror!void {
@@ -230,9 +230,9 @@ async fn suspendThenFail() anyerror!void {
}
async fn printTrace(p: promise->(anyerror!void)) void {
(await p) catch |e| {
- std.debug.assert(e == error.Fail);
+ std.debug.assertOrPanic(e == error.Fail);
if (@errorReturnTrace()) |trace| {
- assert(trace.index == 1);
+ assertOrPanic(trace.index == 1);
} else switch (builtin.mode) {
builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"),
builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {},
@@ -246,7 +246,7 @@ test "break from suspend" {
var my_result: i32 = 1;
const p = try async testBreakFromSuspend(&my_result);
cancel p;
- std.debug.assert(my_result == 2);
+ std.debug.assertOrPanic(my_result == 2);
}
async fn testBreakFromSuspend(my_result: *i32) void {
suspend {
diff --git a/test/cases/defer.zig b/test/stage1/behavior/defer.zig
similarity index 72%
rename from test/cases/defer.zig
rename to test/stage1/behavior/defer.zig
index f9a2b69cd94b..1a5125d55cc9 100644
--- a/test/cases/defer.zig
+++ b/test/stage1/behavior/defer.zig
@@ -1,39 +1,4 @@
-const assert = @import("std").debug.assert;
-
-var result: [3]u8 = undefined;
-var index: usize = undefined;
-
-fn runSomeErrorDefers(x: bool) !bool {
- index = 0;
- defer {
- result[index] = 'a';
- index += 1;
- }
- errdefer {
- result[index] = 'b';
- index += 1;
- }
- defer {
- result[index] = 'c';
- index += 1;
- }
- return if (x) x else error.FalseNotAllowed;
-}
-
-test "mixing normal and error defers" {
- assert(runSomeErrorDefers(true) catch unreachable);
- assert(result[0] == 'c');
- assert(result[1] == 'a');
-
- const ok = runSomeErrorDefers(false) catch |err| x: {
- assert(err == error.FalseNotAllowed);
- break :x true;
- };
- assert(ok);
- assert(result[0] == 'c');
- assert(result[1] == 'b');
- assert(result[2] == 'a');
-}
+const assertOrPanic = @import("std").debug.assertOrPanic;
test "break and continue inside loop inside defer expression" {
testBreakContInDefer(10);
@@ -47,7 +12,7 @@ fn testBreakContInDefer(x: usize) void {
if (i < 5) continue;
if (i == 5) break;
}
- assert(i == 5);
+ assertOrPanic(i == 5);
}
}
@@ -59,11 +24,11 @@ test "defer and labeled break" {
break :blk;
}
- assert(i == 1);
+ assertOrPanic(i == 1);
}
test "errdefer does not apply to fn inside fn" {
- if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| assert(e == error.Bad);
+ if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| assertOrPanic(e == error.Bad);
}
fn testNestedFnErrDefer() anyerror!void {
@@ -76,3 +41,38 @@ fn testNestedFnErrDefer() anyerror!void {
};
return S.baz();
}
+
+var result: [3]u8 = undefined;
+var index: usize = undefined;
+
+fn runSomeErrorDefers(x: bool) !bool {
+ index = 0;
+ defer {
+ result[index] = 'a';
+ index += 1;
+ }
+ errdefer {
+ result[index] = 'b';
+ index += 1;
+ }
+ defer {
+ result[index] = 'c';
+ index += 1;
+ }
+ return if (x) x else error.FalseNotAllowed;
+}
+
+test "mixing normal and error defers" {
+ assertOrPanic(runSomeErrorDefers(true) catch unreachable);
+ assertOrPanic(result[0] == 'c');
+ assertOrPanic(result[1] == 'a');
+
+ const ok = runSomeErrorDefers(false) catch |err| x: {
+ assertOrPanic(err == error.FalseNotAllowed);
+ break :x true;
+ };
+ assertOrPanic(ok);
+ assertOrPanic(result[0] == 'c');
+ assertOrPanic(result[1] == 'b');
+ assertOrPanic(result[2] == 'a');
+}
diff --git a/test/cases/enum.zig b/test/stage1/behavior/enum.zig
similarity index 84%
rename from test/cases/enum.zig
rename to test/stage1/behavior/enum.zig
index 2dd552488c94..9de138ef78cd 100644
--- a/test/cases/enum.zig
+++ b/test/stage1/behavior/enum.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
const mem = @import("std").mem;
test "enum type" {
@@ -11,16 +11,16 @@ test "enum type" {
};
const bar = Bar.B;
- assert(bar == Bar.B);
- assert(@memberCount(Foo) == 3);
- assert(@memberCount(Bar) == 4);
- assert(@sizeOf(Foo) == @sizeOf(FooNoVoid));
- assert(@sizeOf(Bar) == 1);
+ assertOrPanic(bar == Bar.B);
+ assertOrPanic(@memberCount(Foo) == 3);
+ assertOrPanic(@memberCount(Bar) == 4);
+ assertOrPanic(@sizeOf(Foo) == @sizeOf(FooNoVoid));
+ assertOrPanic(@sizeOf(Bar) == 1);
}
test "enum as return value" {
switch (returnAnInt(13)) {
- Foo.One => |value| assert(value == 13),
+ Foo.One => |value| assertOrPanic(value == 13),
else => unreachable,
}
}
@@ -92,14 +92,14 @@ test "enum to int" {
}
fn shouldEqual(n: Number, expected: u3) void {
- assert(@enumToInt(n) == expected);
+ assertOrPanic(@enumToInt(n) == expected);
}
test "int to enum" {
testIntToEnumEval(3);
}
fn testIntToEnumEval(x: i32) void {
- assert(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three);
+ assertOrPanic(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three);
}
const IntToEnumNumber = enum {
Zero,
@@ -110,8 +110,8 @@ const IntToEnumNumber = enum {
};
test "@tagName" {
- assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
- comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
+ assertOrPanic(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
+ comptime assertOrPanic(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
}
fn testEnumTagNameBare(n: BareNumber) []const u8 {
@@ -126,8 +126,8 @@ const BareNumber = enum {
test "enum alignment" {
comptime {
- assert(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
- assert(@alignOf(AlignTestEnum) >= @alignOf(u64));
+ assertOrPanic(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
+ assertOrPanic(@alignOf(AlignTestEnum) >= @alignOf(u64));
}
}
@@ -663,10 +663,10 @@ const ValueCount257 = enum {
test "enum sizes" {
comptime {
- assert(@sizeOf(ValueCount1) == 0);
- assert(@sizeOf(ValueCount2) == 1);
- assert(@sizeOf(ValueCount256) == 1);
- assert(@sizeOf(ValueCount257) == 2);
+ assertOrPanic(@sizeOf(ValueCount1) == 0);
+ assertOrPanic(@sizeOf(ValueCount2) == 1);
+ assertOrPanic(@sizeOf(ValueCount256) == 1);
+ assertOrPanic(@sizeOf(ValueCount257) == 2);
}
}
@@ -685,12 +685,12 @@ test "set enum tag type" {
{
var x = Small.One;
x = Small.Two;
- comptime assert(@TagType(Small) == u2);
+ comptime assertOrPanic(@TagType(Small) == u2);
}
{
var x = Small2.One;
x = Small2.Two;
- comptime assert(@TagType(Small2) == u2);
+ comptime assertOrPanic(@TagType(Small2) == u2);
}
}
@@ -737,17 +737,17 @@ const bit_field_1 = BitFieldOfEnums{
test "bit field access with enum fields" {
var data = bit_field_1;
- assert(getA(&data) == A.Two);
- assert(getB(&data) == B.Three3);
- assert(getC(&data) == C.Four4);
- comptime assert(@sizeOf(BitFieldOfEnums) == 1);
+ assertOrPanic(getA(&data) == A.Two);
+ assertOrPanic(getB(&data) == B.Three3);
+ assertOrPanic(getC(&data) == C.Four4);
+ comptime assertOrPanic(@sizeOf(BitFieldOfEnums) == 1);
data.b = B.Four3;
- assert(data.b == B.Four3);
+ assertOrPanic(data.b == B.Four3);
data.a = A.Three;
- assert(data.a == A.Three);
- assert(data.b == B.Four3);
+ assertOrPanic(data.a == A.Three);
+ assertOrPanic(data.b == B.Four3);
}
fn getA(data: *const BitFieldOfEnums) A {
@@ -768,7 +768,7 @@ test "casting enum to its tag type" {
}
fn testCastEnumToTagType(value: Small2) void {
- assert(@enumToInt(value) == 1);
+ assertOrPanic(@enumToInt(value) == 1);
}
const MultipleChoice = enum(u32) {
@@ -784,8 +784,8 @@ test "enum with specified tag values" {
}
fn testEnumWithSpecifiedTagValues(x: MultipleChoice) void {
- assert(@enumToInt(x) == 60);
- assert(1234 == switch (x) {
+ assertOrPanic(@enumToInt(x) == 60);
+ assertOrPanic(1234 == switch (x) {
MultipleChoice.A => 1,
MultipleChoice.B => 2,
MultipleChoice.C => u32(1234),
@@ -811,8 +811,8 @@ test "enum with specified and unspecified tag values" {
}
fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
- assert(@enumToInt(x) == 1000);
- assert(1234 == switch (x) {
+ assertOrPanic(@enumToInt(x) == 1000);
+ assertOrPanic(1234 == switch (x) {
MultipleChoice2.A => 1,
MultipleChoice2.B => 2,
MultipleChoice2.C => 3,
@@ -826,8 +826,8 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
}
test "cast integer literal to enum" {
- assert(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1);
- assert(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B);
+ assertOrPanic(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1);
+ assertOrPanic(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B);
}
const EnumWithOneMember = enum {
@@ -865,14 +865,14 @@ const EnumWithTagValues = enum(u4) {
D = 1 << 3,
};
test "enum with tag values don't require parens" {
- assert(@enumToInt(EnumWithTagValues.C) == 0b0100);
+ assertOrPanic(@enumToInt(EnumWithTagValues.C) == 0b0100);
}
test "enum with 1 field but explicit tag type should still have the tag type" {
const Enum = enum(u8) {
B = 2,
};
- comptime @import("std").debug.assert(@sizeOf(Enum) == @sizeOf(u8));
+ comptime @import("std").debug.assertOrPanic(@sizeOf(Enum) == @sizeOf(u8));
}
test "empty extern enum with members" {
@@ -881,14 +881,14 @@ test "empty extern enum with members" {
B,
C,
};
- assert(@sizeOf(E) == @sizeOf(c_int));
+ assertOrPanic(@sizeOf(E) == @sizeOf(c_int));
}
-test "aoeu" {
+test "tag name with assigned enum values" {
const LocalFoo = enum {
A = 1,
B = 0,
};
var b = LocalFoo.B;
- assert(mem.eql(u8, @tagName(b), "B"));
+ assertOrPanic(mem.eql(u8, @tagName(b), "B"));
}
diff --git a/test/cases/enum_with_members.zig b/test/stage1/behavior/enum_with_members.zig
similarity index 63%
rename from test/cases/enum_with_members.zig
rename to test/stage1/behavior/enum_with_members.zig
index 088496bd2f41..49af1ceae78e 100644
--- a/test/cases/enum_with_members.zig
+++ b/test/stage1/behavior/enum_with_members.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
const mem = @import("std").mem;
const fmt = @import("std").fmt;
@@ -19,9 +19,9 @@ test "enum with members" {
const b = ET{ .UINT = 42 };
var buf: [20]u8 = undefined;
- assert((a.print(buf[0..]) catch unreachable) == 3);
- assert(mem.eql(u8, buf[0..3], "-42"));
+ assertOrPanic((a.print(buf[0..]) catch unreachable) == 3);
+ assertOrPanic(mem.eql(u8, buf[0..3], "-42"));
- assert((b.print(buf[0..]) catch unreachable) == 2);
- assert(mem.eql(u8, buf[0..2], "42"));
+ assertOrPanic((b.print(buf[0..]) catch unreachable) == 2);
+ assertOrPanic(mem.eql(u8, buf[0..2], "42"));
}
diff --git a/test/cases/error.zig b/test/stage1/behavior/error.zig
similarity index 59%
rename from test/cases/error.zig
rename to test/stage1/behavior/error.zig
index a731f39021f7..35f8cc5d16c0 100644
--- a/test/cases/error.zig
+++ b/test/stage1/behavior/error.zig
@@ -1,5 +1,6 @@
const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
+const assertError = std.debug.assertError;
const mem = std.mem;
const builtin = @import("builtin");
@@ -18,7 +19,7 @@ pub fn baz() anyerror!i32 {
}
test "error wrapping" {
- assert((baz() catch unreachable) == 15);
+ assertOrPanic((baz() catch unreachable) == 15);
}
fn gimmeItBroke() []const u8 {
@@ -26,14 +27,14 @@ fn gimmeItBroke() []const u8 {
}
test "@errorName" {
- assert(mem.eql(u8, @errorName(error.AnError), "AnError"));
- assert(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
+ assertOrPanic(mem.eql(u8, @errorName(error.AnError), "AnError"));
+ assertOrPanic(mem.eql(u8, @errorName(error.ALongerErrorName), "ALongerErrorName"));
}
test "error values" {
const a = @errorToInt(error.err1);
const b = @errorToInt(error.err2);
- assert(a != b);
+ assertOrPanic(a != b);
}
test "redefinition of error values allowed" {
@@ -46,8 +47,8 @@ fn shouldBeNotEqual(a: anyerror, b: anyerror) void {
test "error binary operator" {
const a = errBinaryOperatorG(true) catch 3;
const b = errBinaryOperatorG(false) catch 3;
- assert(a == 3);
- assert(b == 10);
+ assertOrPanic(a == 3);
+ assertOrPanic(b == 10);
}
fn errBinaryOperatorG(x: bool) anyerror!isize {
return if (x) error.ItBroke else isize(10);
@@ -55,7 +56,7 @@ fn errBinaryOperatorG(x: bool) anyerror!isize {
test "unwrap simple value from error" {
const i = unwrapSimpleValueFromErrorDo() catch unreachable;
- assert(i == 13);
+ assertOrPanic(i == 13);
}
fn unwrapSimpleValueFromErrorDo() anyerror!isize {
return 13;
@@ -81,13 +82,13 @@ test "error union type " {
fn testErrorUnionType() void {
const x: anyerror!i32 = 1234;
- if (x) |value| assert(value == 1234) else |_| unreachable;
- assert(@typeId(@typeOf(x)) == builtin.TypeId.ErrorUnion);
- assert(@typeId(@typeOf(x).ErrorSet) == builtin.TypeId.ErrorSet);
- assert(@typeOf(x).ErrorSet == anyerror);
+ if (x) |value| assertOrPanic(value == 1234) else |_| unreachable;
+ assertOrPanic(@typeId(@typeOf(x)) == builtin.TypeId.ErrorUnion);
+ assertOrPanic(@typeId(@typeOf(x).ErrorSet) == builtin.TypeId.ErrorSet);
+ assertOrPanic(@typeOf(x).ErrorSet == anyerror);
}
-test "error set type " {
+test "error set type" {
testErrorSetType();
comptime testErrorSetType();
}
@@ -98,12 +99,12 @@ const MyErrSet = error{
};
fn testErrorSetType() void {
- assert(@memberCount(MyErrSet) == 2);
+ assertOrPanic(@memberCount(MyErrSet) == 2);
const a: MyErrSet!i32 = 5678;
const b: MyErrSet!i32 = MyErrSet.OutOfMemory;
- if (a) |value| assert(value == 5678) else |err| switch (err) {
+ if (a) |value| assertOrPanic(value == 5678) else |err| switch (err) {
error.OutOfMemory => unreachable,
error.FileNotFound => unreachable,
}
@@ -126,7 +127,7 @@ const Set2 = error{
fn testExplicitErrorSetCast(set1: Set1) void {
var x = @errSetCast(Set2, set1);
var y = @errSetCast(Set1, x);
- assert(y == error.A);
+ assertOrPanic(y == error.A);
}
test "comptime test error for empty error set" {
@@ -137,12 +138,12 @@ test "comptime test error for empty error set" {
const EmptyErrorSet = error{};
fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void {
- if (x) |v| assert(v == 1234) else |err| @compileError("bad");
+ if (x) |v| assertOrPanic(v == 1234) else |err| @compileError("bad");
}
test "syntax: optional operator in front of error union operator" {
comptime {
- assert(?(anyerror!i32) == ?(anyerror!i32));
+ assertOrPanic(?(anyerror!i32) == ?(anyerror!i32));
}
}
@@ -165,11 +166,17 @@ test "error union peer type resolution" {
}
fn testErrorUnionPeerTypeResolution(x: i32) void {
- const y = switch (x) {
+ // TODO https://github.com/ziglang/zig/pull/1682#issuecomment-451303797
+ const y: anyerror!i32 = switch (x) {
1 => bar_1(),
2 => baz_1(),
else => quux_1(),
};
+ if (y) |_| {
+ @panic("expected error");
+ } else |e| {
+ assertOrPanic(e == error.A);
+ }
}
fn bar_1() anyerror {
@@ -243,3 +250,76 @@ fn intLiteral(str: []const u8) !?i64 {
return error.T;
}
+
+test "nested error union function call in optional unwrap" {
+ const S = struct {
+ const Foo = struct {
+ a: i32,
+ };
+
+ fn errorable() !i32 {
+ var x: Foo = (try getFoo()) orelse return error.Other;
+ return x.a;
+ }
+
+ fn errorable2() !i32 {
+ var x: Foo = (try getFoo2()) orelse return error.Other;
+ return x.a;
+ }
+
+ fn errorable3() !i32 {
+ var x: Foo = (try getFoo3()) orelse return error.Other;
+ return x.a;
+ }
+
+ fn getFoo() anyerror!?Foo {
+ return Foo{ .a = 1234 };
+ }
+
+ fn getFoo2() anyerror!?Foo {
+ return error.Failure;
+ }
+
+ fn getFoo3() anyerror!?Foo {
+ return null;
+ }
+ };
+ assertOrPanic((try S.errorable()) == 1234);
+ assertError(S.errorable2(), error.Failure);
+ assertError(S.errorable3(), error.Other);
+ comptime {
+ assertOrPanic((try S.errorable()) == 1234);
+ // TODO uncomment this
+ //assertError(S.errorable2(), error.Failure);
+ assertError(S.errorable3(), error.Other);
+ }
+}
+
+test "widen cast integer payload of error union function call" {
+ const S = struct {
+ fn errorable() !u64 {
+ var x = u64(try number());
+ return x;
+ }
+
+ fn number() anyerror!u32 {
+ return 1234;
+ }
+ };
+ assertOrPanic((try S.errorable()) == 1234);
+}
+
+test "return function call to error set from error union function" {
+ const S = struct {
+ fn errorable() anyerror!i32 {
+ return fail();
+ }
+
+ fn fail() anyerror {
+ return error.Failure;
+ }
+ };
+ assertError(S.errorable(), error.Failure);
+ // TODO uncomment this
+ //comptime assertError(S.errorable(), error.Failure);
+}
diff --git a/test/cases/eval.zig b/test/stage1/behavior/eval.zig
similarity index 69%
rename from test/cases/eval.zig
rename to test/stage1/behavior/eval.zig
index a9eded151ebc..7341df71993c 100644
--- a/test/cases/eval.zig
+++ b/test/stage1/behavior/eval.zig
@@ -1,9 +1,9 @@
const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
const builtin = @import("builtin");
test "compile time recursion" {
- assert(some_data.len == 21);
+ assertOrPanic(some_data.len == 21);
}
var some_data: [@intCast(usize, fibonacci(7))]u8 = undefined;
fn fibonacci(x: i32) i32 {
@@ -16,7 +16,7 @@ fn unwrapAndAddOne(blah: ?i32) i32 {
}
const should_be_1235 = unwrapAndAddOne(1234);
test "static add one" {
- assert(should_be_1235 == 1235);
+ assertOrPanic(should_be_1235 == 1235);
}
test "inlined loop" {
@@ -24,7 +24,7 @@ test "inlined loop" {
comptime var sum = 0;
inline while (i <= 5) : (i += 1)
sum += i;
- assert(sum == 15);
+ assertOrPanic(sum == 15);
}
fn gimme1or2(comptime a: bool) i32 {
@@ -34,12 +34,12 @@ fn gimme1or2(comptime a: bool) i32 {
return z;
}
test "inline variable gets result of const if" {
- assert(gimme1or2(true) == 1);
- assert(gimme1or2(false) == 2);
+ assertOrPanic(gimme1or2(true) == 1);
+ assertOrPanic(gimme1or2(false) == 2);
}
test "static function evaluation" {
- assert(statically_added_number == 3);
+ assertOrPanic(statically_added_number == 3);
}
const statically_added_number = staticAdd(1, 2);
fn staticAdd(a: i32, b: i32) i32 {
@@ -47,26 +47,28 @@ fn staticAdd(a: i32, b: i32) i32 {
}
test "const expr eval on single expr blocks" {
- assert(constExprEvalOnSingleExprBlocksFn(1, true) == 3);
+ assertOrPanic(constExprEvalOnSingleExprBlocksFn(1, false) == 3);
+ comptime assertOrPanic(constExprEvalOnSingleExprBlocksFn(1, false) == 3);
}
fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 {
const literal = 3;
+ // TODO: See https://github.com/ziglang/zig/pull/1682#issuecomment-451303797
const result = if (b) b: {
- break :b literal;
- } else b: {
break :b x;
+ } else b: {
+ break :b literal;
};
return result;
}
test "statically initialized list" {
- assert(static_point_list[0].x == 1);
- assert(static_point_list[0].y == 2);
- assert(static_point_list[1].x == 3);
- assert(static_point_list[1].y == 4);
+ assertOrPanic(static_point_list[0].x == 1);
+ assertOrPanic(static_point_list[0].y == 2);
+ assertOrPanic(static_point_list[1].x == 3);
+ assertOrPanic(static_point_list[1].y == 4);
}
const Point = struct {
x: i32,
@@ -84,8 +86,8 @@ fn makePoint(x: i32, y: i32) Point {
}
test "static eval list init" {
- assert(static_vec3.data[2] == 1.0);
- assert(vec3(0.0, 0.0, 3.0).data[2] == 3.0);
+ assertOrPanic(static_vec3.data[2] == 1.0);
+ assertOrPanic(vec3(0.0, 0.0, 3.0).data[2] == 3.0);
}
const static_vec3 = vec3(0.0, 0.0, 1.0);
pub const Vec3 = struct {
@@ -101,12 +103,12 @@ pub fn vec3(x: f32, y: f32, z: f32) Vec3 {
test "constant expressions" {
var array: [array_size]u8 = undefined;
- assert(@sizeOf(@typeOf(array)) == 20);
+ assertOrPanic(@sizeOf(@typeOf(array)) == 20);
}
const array_size: u8 = 20;
test "constant struct with negation" {
- assert(vertices[0].x == -0.6);
+ assertOrPanic(vertices[0].x == -0.6);
}
const Vertex = struct {
x: f32,
@@ -141,7 +143,7 @@ const vertices = []Vertex{
test "statically initialized struct" {
st_init_str_foo.x += 1;
- assert(st_init_str_foo.x == 14);
+ assertOrPanic(st_init_str_foo.x == 14);
}
const StInitStrFoo = struct {
x: i32,
@@ -154,7 +156,7 @@ var st_init_str_foo = StInitStrFoo{
test "statically initalized array literal" {
const y: [4]u8 = st_init_arr_lit_x;
- assert(y[3] == 4);
+ assertOrPanic(y[3] == 4);
}
const st_init_arr_lit_x = []u8{
1,
@@ -166,15 +168,15 @@ const st_init_arr_lit_x = []u8{
test "const slice" {
comptime {
const a = "1234567890";
- assert(a.len == 10);
+ assertOrPanic(a.len == 10);
const b = a[1..2];
- assert(b.len == 1);
- assert(b[0] == '2');
+ assertOrPanic(b.len == 1);
+ assertOrPanic(b[0] == '2');
}
}
test "try to trick eval with runtime if" {
- assert(testTryToTrickEvalWithRuntimeIf(true) == 10);
+ assertOrPanic(testTryToTrickEvalWithRuntimeIf(true) == 10);
}
fn testTryToTrickEvalWithRuntimeIf(b: bool) usize {
@@ -200,16 +202,16 @@ fn letsTryToCompareBools(a: bool, b: bool) bool {
return max(bool, a, b);
}
test "inlined block and runtime block phi" {
- assert(letsTryToCompareBools(true, true));
- assert(letsTryToCompareBools(true, false));
- assert(letsTryToCompareBools(false, true));
- assert(!letsTryToCompareBools(false, false));
+ assertOrPanic(letsTryToCompareBools(true, true));
+ assertOrPanic(letsTryToCompareBools(true, false));
+ assertOrPanic(letsTryToCompareBools(false, true));
+ assertOrPanic(!letsTryToCompareBools(false, false));
comptime {
- assert(letsTryToCompareBools(true, true));
- assert(letsTryToCompareBools(true, false));
- assert(letsTryToCompareBools(false, true));
- assert(!letsTryToCompareBools(false, false));
+ assertOrPanic(letsTryToCompareBools(true, true));
+ assertOrPanic(letsTryToCompareBools(true, false));
+ assertOrPanic(letsTryToCompareBools(false, true));
+ assertOrPanic(!letsTryToCompareBools(false, false));
}
}
@@ -254,14 +256,14 @@ fn performFn(comptime prefix_char: u8, start_value: i32) i32 {
}
test "comptime iterate over fn ptr list" {
- assert(performFn('t', 1) == 6);
- assert(performFn('o', 0) == 1);
- assert(performFn('w', 99) == 99);
+ assertOrPanic(performFn('t', 1) == 6);
+ assertOrPanic(performFn('o', 0) == 1);
+ assertOrPanic(performFn('w', 99) == 99);
}
test "eval @setRuntimeSafety at compile-time" {
const result = comptime fnWithSetRuntimeSafety();
- assert(result == 1234);
+ assertOrPanic(result == 1234);
}
fn fnWithSetRuntimeSafety() i32 {
@@ -271,7 +273,7 @@ fn fnWithSetRuntimeSafety() i32 {
test "eval @setFloatMode at compile-time" {
const result = comptime fnWithFloatMode();
- assert(result == 1234.0);
+ assertOrPanic(result == 1234.0);
}
fn fnWithFloatMode() f32 {
@@ -292,15 +294,15 @@ var simple_struct = SimpleStruct{ .field = 1234 };
const bound_fn = simple_struct.method;
test "call method on bound fn referring to var instance" {
- assert(bound_fn() == 1237);
+ assertOrPanic(bound_fn() == 1237);
}
test "ptr to local array argument at comptime" {
comptime {
var bytes: [10]u8 = undefined;
modifySomeBytes(bytes[0..]);
- assert(bytes[0] == 'a');
- assert(bytes[9] == 'b');
+ assertOrPanic(bytes[0] == 'a');
+ assertOrPanic(bytes[9] == 'b');
}
}
@@ -328,9 +330,9 @@ fn testCompTimeUIntComparisons(x: u32) void {
}
test "const ptr to variable data changes at runtime" {
- assert(foo_ref.name[0] == 'a');
+ assertOrPanic(foo_ref.name[0] == 'a');
foo_ref.name = "b";
- assert(foo_ref.name[0] == 'b');
+ assertOrPanic(foo_ref.name[0] == 'b');
}
const Foo = struct {
@@ -341,8 +343,8 @@ var foo_contents = Foo{ .name = "a" };
const foo_ref = &foo_contents;
test "create global array with for loop" {
- assert(global_array[5] == 5 * 5);
- assert(global_array[9] == 9 * 9);
+ assertOrPanic(global_array[5] == 5 * 5);
+ assertOrPanic(global_array[9] == 9 * 9);
}
const global_array = x: {
@@ -357,7 +359,7 @@ test "compile-time downcast when the bits fit" {
comptime {
const spartan_count: u16 = 255;
const byte = @intCast(u8, spartan_count);
- assert(byte == 255);
+ assertOrPanic(byte == 255);
}
}
@@ -365,44 +367,45 @@ const hi1 = "hi";
const hi2 = hi1;
test "const global shares pointer with other same one" {
assertEqualPtrs(&hi1[0], &hi2[0]);
- comptime assert(&hi1[0] == &hi2[0]);
+ comptime assertOrPanic(&hi1[0] == &hi2[0]);
}
fn assertEqualPtrs(ptr1: *const u8, ptr2: *const u8) void {
- assert(ptr1 == ptr2);
+ assertOrPanic(ptr1 == ptr2);
}
test "@setEvalBranchQuota" {
comptime {
- // 1001 for the loop and then 1 more for the assert fn call
+ // 1001 for the loop and then 1 more for the assertOrPanic fn call
@setEvalBranchQuota(1002);
var i = 0;
var sum = 0;
while (i < 1001) : (i += 1) {
sum += i;
}
- assert(sum == 500500);
+ assertOrPanic(sum == 500500);
}
}
// TODO test "float literal at compile time not lossy" {
-// TODO assert(16777216.0 + 1.0 == 16777217.0);
-// TODO assert(9007199254740992.0 + 1.0 == 9007199254740993.0);
+// TODO assertOrPanic(16777216.0 + 1.0 == 16777217.0);
+// TODO assertOrPanic(9007199254740992.0 + 1.0 == 9007199254740993.0);
// TODO }
test "f32 at compile time is lossy" {
- assert(f32(1 << 24) + 1 == 1 << 24);
+ assertOrPanic(f32(1 << 24) + 1 == 1 << 24);
}
test "f64 at compile time is lossy" {
- assert(f64(1 << 53) + 1 == 1 << 53);
+ assertOrPanic(f64(1 << 53) + 1 == 1 << 53);
}
test "f128 at compile time is lossy" {
- assert(f128(10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0);
+ assertOrPanic(f128(10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0);
}
-// TODO need a better implementation of bigfloat_init_bigint
-// assert(f128(1 << 113) == 10384593717069655257060992658440192);
+comptime {
+ assertOrPanic(f128(1 << 113) == 10384593717069655257060992658440192);
+}
pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type {
return struct {
@@ -413,15 +416,15 @@ pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) type {
test "string literal used as comptime slice is memoized" {
const a = "link";
const b = "link";
- comptime assert(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node);
- comptime assert(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node);
+ comptime assertOrPanic(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node);
+ comptime assertOrPanic(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node);
}
test "comptime slice of undefined pointer of length 0" {
const slice1 = ([*]i32)(undefined)[0..0];
- assert(slice1.len == 0);
+ assertOrPanic(slice1.len == 0);
const slice2 = ([*]i32)(undefined)[100..100];
- assert(slice2.len == 0);
+ assertOrPanic(slice2.len == 0);
}
fn copyWithPartialInline(s: []u32, b: []u8) void {
@@ -443,16 +446,16 @@ test "binary math operator in partially inlined function" {
r.* = @intCast(u8, i + 1);
copyWithPartialInline(s[0..], b[0..]);
- assert(s[0] == 0x1020304);
- assert(s[1] == 0x5060708);
- assert(s[2] == 0x90a0b0c);
- assert(s[3] == 0xd0e0f10);
+ assertOrPanic(s[0] == 0x1020304);
+ assertOrPanic(s[1] == 0x5060708);
+ assertOrPanic(s[2] == 0x90a0b0c);
+ assertOrPanic(s[3] == 0xd0e0f10);
}
test "comptime function with the same args is memoized" {
comptime {
- assert(MakeType(i32) == MakeType(i32));
- assert(MakeType(i32) != MakeType(f64));
+ assertOrPanic(MakeType(i32) == MakeType(i32));
+ assertOrPanic(MakeType(i32) != MakeType(f64));
}
}
@@ -468,7 +471,7 @@ test "comptime function with mutable pointer is not memoized" {
const ptr = &x;
increment(ptr);
increment(ptr);
- assert(x == 3);
+ assertOrPanic(x == 3);
}
}
@@ -494,14 +497,14 @@ fn doesAlotT(comptime T: type, value: usize) T {
}
test "@setEvalBranchQuota at same scope as generic function call" {
- assert(doesAlotT(u32, 2) == 2);
+ assertOrPanic(doesAlotT(u32, 2) == 2);
}
test "comptime slice of slice preserves comptime var" {
comptime {
var buff: [10]u8 = undefined;
buff[0..][0..][0] = 1;
- assert(buff[0..][0..][0] == 1);
+ assertOrPanic(buff[0..][0..][0] == 1);
}
}
@@ -510,7 +513,7 @@ test "comptime slice of pointer preserves comptime var" {
var buff: [10]u8 = undefined;
var a = buff[0..].ptr;
a[0..1][0] = 1;
- assert(buff[0..][0..][0] == 1);
+ assertOrPanic(buff[0..][0..][0] == 1);
}
}
@@ -524,9 +527,9 @@ const SingleFieldStruct = struct {
test "const ptr to comptime mutable data is not memoized" {
comptime {
var foo = SingleFieldStruct{ .x = 1 };
- assert(foo.read_x() == 1);
+ assertOrPanic(foo.read_x() == 1);
foo.x = 2;
- assert(foo.read_x() == 2);
+ assertOrPanic(foo.read_x() == 2);
}
}
@@ -535,7 +538,7 @@ test "array concat of slices gives slice" {
var a: []const u8 = "aoeu";
var b: []const u8 = "asdf";
const c = a ++ b;
- assert(std.mem.eql(u8, c, "aoeuasdf"));
+ assertOrPanic(std.mem.eql(u8, c, "aoeuasdf"));
}
}
@@ -552,14 +555,14 @@ test "comptime shlWithOverflow" {
break :amt amt;
};
- assert(ct_shifted == rt_shifted);
+ assertOrPanic(ct_shifted == rt_shifted);
}
test "runtime 128 bit integer division" {
var a: u128 = 152313999999999991610955792383;
var b: u128 = 10000000000000000000;
var c = a / b;
- assert(c == 15231399999);
+ assertOrPanic(c == 15231399999);
}
pub const Info = struct {
@@ -572,20 +575,20 @@ test "comptime modification of const struct field" {
comptime {
var res = diamond_info;
res.version = 1;
- assert(diamond_info.version == 0);
- assert(res.version == 1);
+ assertOrPanic(diamond_info.version == 0);
+ assertOrPanic(res.version == 1);
}
}
test "pointer to type" {
comptime {
var T: type = i32;
- assert(T == i32);
+ assertOrPanic(T == i32);
var ptr = &T;
- assert(@typeOf(ptr) == *type);
+ assertOrPanic(@typeOf(ptr) == *type);
ptr.* = f32;
- assert(T == f32);
- assert(*T == *f32);
+ assertOrPanic(T == f32);
+ assertOrPanic(*T == *f32);
}
}
@@ -594,17 +597,17 @@ test "slice of type" {
var types_array = []type{ i32, f64, type };
for (types_array) |T, i| {
switch (i) {
- 0 => assert(T == i32),
- 1 => assert(T == f64),
- 2 => assert(T == type),
+ 0 => assertOrPanic(T == i32),
+ 1 => assertOrPanic(T == f64),
+ 2 => assertOrPanic(T == type),
else => unreachable,
}
}
for (types_array[0..]) |T, i| {
switch (i) {
- 0 => assert(T == i32),
- 1 => assert(T == f64),
- 2 => assert(T == type),
+ 0 => assertOrPanic(T == i32),
+ 1 => assertOrPanic(T == f64),
+ 2 => assertOrPanic(T == type),
else => unreachable,
}
}
@@ -621,7 +624,7 @@ fn wrap(comptime T: type) Wrapper {
test "function which returns struct with type field causes implicit comptime" {
const ty = wrap(i32).T;
- assert(ty == i32);
+ assertOrPanic(ty == i32);
}
test "call method with comptime pass-by-non-copying-value self parameter" {
@@ -635,12 +638,12 @@ test "call method with comptime pass-by-non-copying-value self parameter" {
const s = S{ .a = 2 };
var b = s.b();
- assert(b == 2);
+ assertOrPanic(b == 2);
}
test "@tagName of @typeId" {
const str = @tagName(@typeId(u8));
- assert(std.mem.eql(u8, str, "Int"));
+ assertOrPanic(std.mem.eql(u8, str, "Int"));
}
test "setting backward branch quota just before a generic fn call" {
@@ -661,8 +664,8 @@ fn testVarInsideInlineLoop(args: ...) void {
comptime var i = 0;
inline while (i < args.len) : (i += 1) {
const x = args[i];
- if (i == 0) assert(x);
- if (i == 1) assert(x == 42);
+ if (i == 0) assertOrPanic(x);
+ if (i == 1) assertOrPanic(x == 42);
}
}
@@ -672,7 +675,7 @@ test "inline for with same type but different values" {
var a: T = undefined;
res += a.len;
}
- assert(res == 5);
+ assertOrPanic(res == 5);
}
test "refer to the type of a generic function" {
@@ -686,29 +689,30 @@ fn doNothingWithType(comptime T: type) void {}
test "zero extend from u0 to u1" {
var zero_u0: u0 = 0;
var zero_u1: u1 = zero_u0;
- assert(zero_u1 == 0);
+ assertOrPanic(zero_u1 == 0);
}
test "bit shift a u1" {
var x: u1 = 1;
var y = x << 0;
- assert(y == 1);
+ assertOrPanic(y == 1);
}
test "@intCast to a u0" {
var x: u8 = 0;
var y: u0 = @intCast(u0, x);
- assert(y == 0);
+ assertOrPanic(y == 0);
}
-test "@bytesToslice on a packed struct" {
+test "@bytesToSlice on a packed struct" {
const F = packed struct {
a: u8,
};
var b = [1]u8{9};
- var f = @bytesToSlice(F, b);
- assert(f[0].a == 9);
+ // TODO https://github.com/ziglang/zig/pull/1682#issuecomment-452813480
+ var f = @bytesToSlice(F, b[0..]);
+ assertOrPanic(f[0].a == 9);
}
test "comptime pointer cast array and then slice" {
@@ -720,8 +724,8 @@ test "comptime pointer cast array and then slice" {
const ptrB: [*]const u8 = &array;
const sliceB: []const u8 = ptrB[0..2];
- assert(sliceA[1] == 2);
- assert(sliceB[1] == 2);
+ assertOrPanic(sliceA[1] == 2);
+ assertOrPanic(sliceB[1] == 2);
}
test "slice bounds in comptime concatenation" {
@@ -730,47 +734,47 @@ test "slice bounds in comptime concatenation" {
break :blk b[0..1];
};
const str = "" ++ bs;
- assert(str.len == 1);
- assert(std.mem.eql(u8, str, "1"));
+ assertOrPanic(str.len == 1);
+ assertOrPanic(std.mem.eql(u8, str, "1"));
const str2 = bs ++ "";
- assert(str2.len == 1);
- assert(std.mem.eql(u8, str2, "1"));
+ assertOrPanic(str2.len == 1);
+ assertOrPanic(std.mem.eql(u8, str2, "1"));
}
test "comptime bitwise operators" {
comptime {
- assert(3 & 1 == 1);
- assert(3 & -1 == 3);
- assert(-3 & -1 == -3);
- assert(3 | -1 == -1);
- assert(-3 | -1 == -1);
- assert(3 ^ -1 == -4);
- assert(-3 ^ -1 == 2);
- assert(~i8(-1) == 0);
- assert(~i128(-1) == 0);
- assert(18446744073709551615 & 18446744073709551611 == 18446744073709551611);
- assert(-18446744073709551615 & -18446744073709551611 == -18446744073709551615);
- assert(~u128(0) == 0xffffffffffffffffffffffffffffffff);
+ assertOrPanic(3 & 1 == 1);
+ assertOrPanic(3 & -1 == 3);
+ assertOrPanic(-3 & -1 == -3);
+ assertOrPanic(3 | -1 == -1);
+ assertOrPanic(-3 | -1 == -1);
+ assertOrPanic(3 ^ -1 == -4);
+ assertOrPanic(-3 ^ -1 == 2);
+ assertOrPanic(~i8(-1) == 0);
+ assertOrPanic(~i128(-1) == 0);
+ assertOrPanic(18446744073709551615 & 18446744073709551611 == 18446744073709551611);
+ assertOrPanic(-18446744073709551615 & -18446744073709551611 == -18446744073709551615);
+ assertOrPanic(~u128(0) == 0xffffffffffffffffffffffffffffffff);
}
}
test "*align(1) u16 is the same as *align(1:0:2) u16" {
comptime {
- assert(*align(1:0:2) u16 == *align(1) u16);
+ assertOrPanic(*align(1:0:2) u16 == *align(1) u16);
// TODO add parsing support for this syntax
- //assert(*align(:0:2) u16 == *u16);
+ //assertOrPanic(*align(:0:2) u16 == *u16);
}
}
test "array concatenation forces comptime" {
var a = oneItem(3) ++ oneItem(4);
- assert(std.mem.eql(i32, a, []i32{3, 4}));
+ assertOrPanic(std.mem.eql(i32, a, []i32{ 3, 4 }));
}
test "array multiplication forces comptime" {
var a = oneItem(3) ** scalar(2);
- assert(std.mem.eql(i32, a, []i32{3, 3}));
+ assertOrPanic(std.mem.eql(i32, a, []i32{ 3, 3 }));
}
fn oneItem(x: i32) [1]i32 {
diff --git a/test/cases/field_parent_ptr.zig b/test/stage1/behavior/field_parent_ptr.zig
similarity index 69%
rename from test/cases/field_parent_ptr.zig
rename to test/stage1/behavior/field_parent_ptr.zig
index 00d4e0f36721..ed2487c02081 100644
--- a/test/cases/field_parent_ptr.zig
+++ b/test/stage1/behavior/field_parent_ptr.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
test "@fieldParentPtr non-first field" {
testParentFieldPtr(&foo.c);
@@ -25,17 +25,17 @@ const foo = Foo{
};
fn testParentFieldPtr(c: *const i32) void {
- assert(c == &foo.c);
+ assertOrPanic(c == &foo.c);
const base = @fieldParentPtr(Foo, "c", c);
- assert(base == &foo);
- assert(&base.c == c);
+ assertOrPanic(base == &foo);
+ assertOrPanic(&base.c == c);
}
fn testParentFieldPtrFirst(a: *const bool) void {
- assert(a == &foo.a);
+ assertOrPanic(a == &foo.a);
const base = @fieldParentPtr(Foo, "a", a);
- assert(base == &foo);
- assert(&base.a == a);
+ assertOrPanic(base == &foo);
+ assertOrPanic(&base.a == a);
}
diff --git a/test/cases/fn.zig b/test/stage1/behavior/fn.zig
similarity index 78%
rename from test/cases/fn.zig
rename to test/stage1/behavior/fn.zig
index 8908bd785475..3011bc41d074 100644
--- a/test/cases/fn.zig
+++ b/test/stage1/behavior/fn.zig
@@ -1,7 +1,7 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
test "params" {
- assert(testParamsAdd(22, 11) == 33);
+ assertOrPanic(testParamsAdd(22, 11) == 33);
}
fn testParamsAdd(a: i32, b: i32) i32 {
return a + b;
@@ -21,32 +21,32 @@ test "void parameters" {
fn voidFun(a: i32, b: void, c: i32, d: void) void {
const v = b;
const vv: void = if (a == 1) v else {};
- assert(a + c == 3);
+ assertOrPanic(a + c == 3);
return vv;
}
test "mutable local variables" {
var zero: i32 = 0;
- assert(zero == 0);
+ assertOrPanic(zero == 0);
var i = i32(0);
while (i != 3) {
i += 1;
}
- assert(i == 3);
+ assertOrPanic(i == 3);
}
test "separate block scopes" {
{
const no_conflict: i32 = 5;
- assert(no_conflict == 5);
+ assertOrPanic(no_conflict == 5);
}
const c = x: {
const no_conflict = i32(10);
break :x no_conflict;
};
- assert(c == 10);
+ assertOrPanic(c == 10);
}
test "call function with empty string" {
@@ -59,7 +59,7 @@ fn @"weird function name"() i32 {
return 1234;
}
test "weird function name" {
- assert(@"weird function name"() == 1234);
+ assertOrPanic(@"weird function name"() == 1234);
}
test "implicit cast function unreachable return" {
@@ -80,7 +80,7 @@ test "function pointers" {
fn4,
};
for (fns) |f, i| {
- assert(f() == @intCast(u32, i) + 5);
+ assertOrPanic(f() == @intCast(u32, i) + 5);
}
}
fn fn1() u32 {
@@ -97,7 +97,7 @@ fn fn4() u32 {
}
test "inline function call" {
- assert(@inlineCall(add, 3, 9) == 12);
+ assertOrPanic(@inlineCall(add, 3, 9) == 12);
}
fn add(a: i32, b: i32) i32 {
@@ -110,7 +110,7 @@ test "number literal as an argument" {
}
fn numberLiteralArg(a: var) void {
- assert(a == 3);
+ assertOrPanic(a == 3);
}
test "assign inline fn to const variable" {
@@ -121,7 +121,7 @@ test "assign inline fn to const variable" {
inline fn inlineFn() void {}
test "pass by non-copying value" {
- assert(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
+ assertOrPanic(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
}
const Point = struct {
@@ -134,17 +134,17 @@ fn addPointCoords(pt: Point) i32 {
}
test "pass by non-copying value through var arg" {
- assert(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3);
+ assertOrPanic(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3);
}
fn addPointCoordsVar(pt: var) i32 {
- comptime assert(@typeOf(pt) == Point);
+ comptime assertOrPanic(@typeOf(pt) == Point);
return pt.x + pt.y;
}
test "pass by non-copying value as method" {
var pt = Point2{ .x = 1, .y = 2 };
- assert(pt.addPointCoords() == 3);
+ assertOrPanic(pt.addPointCoords() == 3);
}
const Point2 = struct {
@@ -158,7 +158,7 @@ const Point2 = struct {
test "pass by non-copying value as method, which is generic" {
var pt = Point3{ .x = 1, .y = 2 };
- assert(pt.addPointCoords(i32) == 3);
+ assertOrPanic(pt.addPointCoords(i32) == 3);
}
const Point3 = struct {
@@ -173,7 +173,7 @@ const Point3 = struct {
test "pass by non-copying value as method, at comptime" {
comptime {
var pt = Point2{ .x = 1, .y = 2 };
- assert(pt.addPointCoords() == 3);
+ assertOrPanic(pt.addPointCoords() == 3);
}
}
@@ -189,7 +189,7 @@ fn outer(y: u32) fn (u32) u32 {
test "return inner function which references comptime variable of outer function" {
var func = outer(10);
- assert(func(3) == 7);
+ assertOrPanic(func(3) == 7);
}
test "extern struct with stdcallcc fn pointer" {
@@ -203,5 +203,6 @@ test "extern struct with stdcallcc fn pointer" {
var s: S = undefined;
s.ptr = S.foo;
- assert(s.ptr() == 1234);
+ assertOrPanic(s.ptr() == 1234);
}
+
diff --git a/test/cases/fn_in_struct_in_comptime.zig b/test/stage1/behavior/fn_in_struct_in_comptime.zig
similarity index 72%
rename from test/cases/fn_in_struct_in_comptime.zig
rename to test/stage1/behavior/fn_in_struct_in_comptime.zig
index fabb57e9cbcb..0af076d40acf 100644
--- a/test/cases/fn_in_struct_in_comptime.zig
+++ b/test/stage1/behavior/fn_in_struct_in_comptime.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
fn get_foo() fn (*u8) usize {
comptime {
@@ -13,5 +13,5 @@ fn get_foo() fn (*u8) usize {
test "define a function in an anonymous struct in comptime" {
const foo = get_foo();
- assert(foo(@intToPtr(*u8, 12345)) == 12345);
+ assertOrPanic(foo(@intToPtr(*u8, 12345)) == 12345);
}
diff --git a/test/cases/for.zig b/test/stage1/behavior/for.zig
similarity index 89%
rename from test/cases/for.zig
rename to test/stage1/behavior/for.zig
index aecd8b9a0784..b6d1ef24c42f 100644
--- a/test/cases/for.zig
+++ b/test/stage1/behavior/for.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
const mem = std.mem;
test "continue in for loop" {
@@ -26,7 +26,7 @@ test "for loop with pointer elem var" {
var target: [source.len]u8 = undefined;
mem.copy(u8, target[0..], source);
mangleString(target[0..]);
- assert(mem.eql(u8, target, "bcdefgh"));
+ assertOrPanic(mem.eql(u8, target, "bcdefgh"));
}
fn mangleString(s: []u8) void {
for (s) |*c| {
@@ -68,7 +68,7 @@ test "basic for loop" {
buf_index += 1;
}
- assert(mem.eql(u8, buffer[0..buf_index], expected_result));
+ assertOrPanic(mem.eql(u8, buffer[0..buf_index], expected_result));
}
test "break from outer for loop" {
@@ -85,7 +85,7 @@ fn testBreakOuter() void {
break :outer;
}
}
- assert(count == 1);
+ assertOrPanic(count == 1);
}
test "continue outer for loop" {
@@ -102,5 +102,5 @@ fn testContinueOuter() void {
continue :outer;
}
}
- assert(counter == array.len);
+ assertOrPanic(counter == array.len);
}
diff --git a/test/cases/generics.zig b/test/stage1/behavior/generics.zig
similarity index 68%
rename from test/cases/generics.zig
rename to test/stage1/behavior/generics.zig
index 52aa013989e1..a0928634a7c3 100644
--- a/test/cases/generics.zig
+++ b/test/stage1/behavior/generics.zig
@@ -1,9 +1,9 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
test "simple generic fn" {
- assert(max(i32, 3, -1) == 3);
- assert(max(f32, 0.123, 0.456) == 0.456);
- assert(add(2, 3) == 5);
+ assertOrPanic(max(i32, 3, -1) == 3);
+ assertOrPanic(max(f32, 0.123, 0.456) == 0.456);
+ assertOrPanic(add(2, 3) == 5);
}
fn max(comptime T: type, a: T, b: T) T {
@@ -16,7 +16,7 @@ fn add(comptime a: i32, b: i32) i32 {
const the_max = max(u32, 1234, 5678);
test "compile time generic eval" {
- assert(the_max == 5678);
+ assertOrPanic(the_max == 5678);
}
fn gimmeTheBigOne(a: u32, b: u32) u32 {
@@ -32,19 +32,19 @@ fn sameButWithFloats(a: f64, b: f64) f64 {
}
test "fn with comptime args" {
- assert(gimmeTheBigOne(1234, 5678) == 5678);
- assert(shouldCallSameInstance(34, 12) == 34);
- assert(sameButWithFloats(0.43, 0.49) == 0.49);
+ assertOrPanic(gimmeTheBigOne(1234, 5678) == 5678);
+ assertOrPanic(shouldCallSameInstance(34, 12) == 34);
+ assertOrPanic(sameButWithFloats(0.43, 0.49) == 0.49);
}
test "var params" {
- assert(max_i32(12, 34) == 34);
- assert(max_f64(1.2, 3.4) == 3.4);
+ assertOrPanic(max_i32(12, 34) == 34);
+ assertOrPanic(max_f64(1.2, 3.4) == 3.4);
}
comptime {
- assert(max_i32(12, 34) == 34);
- assert(max_f64(1.2, 3.4) == 3.4);
+ assertOrPanic(max_i32(12, 34) == 34);
+ assertOrPanic(max_f64(1.2, 3.4) == 3.4);
}
fn max_var(a: var, b: var) @typeOf(a + b) {
@@ -76,8 +76,8 @@ test "function with return type type" {
var list2: List(i32) = undefined;
list.length = 10;
list2.length = 10;
- assert(list.prealloc_items.len == 8);
- assert(list2.prealloc_items.len == 8);
+ assertOrPanic(list.prealloc_items.len == 8);
+ assertOrPanic(list2.prealloc_items.len == 8);
}
test "generic struct" {
@@ -89,9 +89,9 @@ test "generic struct" {
.value = true,
.next = null,
};
- assert(a1.value == 13);
- assert(a1.value == a1.getVal());
- assert(b1.getVal());
+ assertOrPanic(a1.value == 13);
+ assertOrPanic(a1.value == a1.getVal());
+ assertOrPanic(b1.getVal());
}
fn GenNode(comptime T: type) type {
return struct {
@@ -104,7 +104,7 @@ fn GenNode(comptime T: type) type {
}
test "const decls in struct" {
- assert(GenericDataThing(3).count_plus_one == 4);
+ assertOrPanic(GenericDataThing(3).count_plus_one == 4);
}
fn GenericDataThing(comptime count: isize) type {
return struct {
@@ -113,15 +113,15 @@ fn GenericDataThing(comptime count: isize) type {
}
test "use generic param in generic param" {
- assert(aGenericFn(i32, 3, 4) == 7);
+ assertOrPanic(aGenericFn(i32, 3, 4) == 7);
}
fn aGenericFn(comptime T: type, comptime a: T, b: T) T {
return a + b;
}
test "generic fn with implicit cast" {
- assert(getFirstByte(u8, []u8{13}) == 13);
- assert(getFirstByte(u16, []u16{
+ assertOrPanic(getFirstByte(u8, []u8{13}) == 13);
+ assertOrPanic(getFirstByte(u16, []u16{
0,
13,
}) == 0);
@@ -146,6 +146,6 @@ fn foo2(arg: var) bool {
}
test "array of generic fns" {
- assert(foos[0](true));
- assert(!foos[1](true));
+ assertOrPanic(foos[0](true));
+ assertOrPanic(!foos[1](true));
}
diff --git a/test/cases/if.zig b/test/stage1/behavior/if.zig
similarity index 85%
rename from test/cases/if.zig
rename to test/stage1/behavior/if.zig
index 808936bfa5fc..58d1b8fd734f 100644
--- a/test/cases/if.zig
+++ b/test/stage1/behavior/if.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
test "if statements" {
shouldBeEqual(1, 1);
@@ -24,7 +24,7 @@ fn firstEqlThird(a: i32, b: i32, c: i32) void {
}
test "else if expression" {
- assert(elseIfExpressionF(1) == 1);
+ assertOrPanic(elseIfExpressionF(1) == 1);
}
fn elseIfExpressionF(c: u8) u8 {
if (c == 0) {
diff --git a/test/stage1/behavior/import.zig b/test/stage1/behavior/import.zig
new file mode 100644
index 000000000000..736e4c219ddc
--- /dev/null
+++ b/test/stage1/behavior/import.zig
@@ -0,0 +1,10 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+const a_namespace = @import("import/a_namespace.zig");
+
+test "call fn via namespace lookup" {
+ assertOrPanic(a_namespace.foo() == 1234);
+}
+
+test "importing the same thing gives the same import" {
+ assertOrPanic(@import("std") == @import("std"));
+}
diff --git a/test/cases/import/a_namespace.zig b/test/stage1/behavior/import/a_namespace.zig
similarity index 100%
rename from test/cases/import/a_namespace.zig
rename to test/stage1/behavior/import/a_namespace.zig
diff --git a/test/cases/incomplete_struct_param_tld.zig b/test/stage1/behavior/incomplete_struct_param_tld.zig
similarity index 78%
rename from test/cases/incomplete_struct_param_tld.zig
rename to test/stage1/behavior/incomplete_struct_param_tld.zig
index f1ac03a29279..d062311b2e9f 100644
--- a/test/cases/incomplete_struct_param_tld.zig
+++ b/test/stage1/behavior/incomplete_struct_param_tld.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
const A = struct {
b: B,
@@ -26,5 +26,5 @@ test "incomplete struct param top level declaration" {
.c = C{ .x = 13 },
},
};
- assert(foo(a) == 13);
+ assertOrPanic(foo(a) == 13);
}
diff --git a/test/cases/inttoptr.zig b/test/stage1/behavior/inttoptr.zig
similarity index 99%
rename from test/cases/inttoptr.zig
rename to test/stage1/behavior/inttoptr.zig
index ba3cc52f0905..bf657fc86a9c 100644
--- a/test/cases/inttoptr.zig
+++ b/test/stage1/behavior/inttoptr.zig
@@ -24,4 +24,3 @@ fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void {
return;
}
}
-
diff --git a/test/cases/ir_block_deps.zig b/test/stage1/behavior/ir_block_deps.zig
similarity index 64%
rename from test/cases/ir_block_deps.zig
rename to test/stage1/behavior/ir_block_deps.zig
index 5c1b18c00e45..bc61e11df7a2 100644
--- a/test/cases/ir_block_deps.zig
+++ b/test/stage1/behavior/ir_block_deps.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
fn foo(id: u64) !i32 {
return switch (id) {
@@ -16,6 +16,6 @@ fn getErrInt() anyerror!i32 {
}
test "ir block deps" {
- assert((foo(1) catch unreachable) == 0);
- assert((foo(2) catch unreachable) == 0);
+ assertOrPanic((foo(1) catch unreachable) == 0);
+ assertOrPanic((foo(2) catch unreachable) == 0);
}
diff --git a/test/cases/math.zig b/test/stage1/behavior/math.zig
similarity index 56%
rename from test/cases/math.zig
rename to test/stage1/behavior/math.zig
index 7d6b1bd9acbc..9d6a5a499799 100644
--- a/test/cases/math.zig
+++ b/test/stage1/behavior/math.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
const maxInt = std.math.maxInt;
const minInt = std.math.minInt;
@@ -8,57 +8,57 @@ test "division" {
comptime testDivision();
}
fn testDivision() void {
- assert(div(u32, 13, 3) == 4);
- assert(div(f16, 1.0, 2.0) == 0.5);
- assert(div(f32, 1.0, 2.0) == 0.5);
-
- assert(divExact(u32, 55, 11) == 5);
- assert(divExact(i32, -55, 11) == -5);
- assert(divExact(f16, 55.0, 11.0) == 5.0);
- assert(divExact(f16, -55.0, 11.0) == -5.0);
- assert(divExact(f32, 55.0, 11.0) == 5.0);
- assert(divExact(f32, -55.0, 11.0) == -5.0);
-
- assert(divFloor(i32, 5, 3) == 1);
- assert(divFloor(i32, -5, 3) == -2);
- assert(divFloor(f16, 5.0, 3.0) == 1.0);
- assert(divFloor(f16, -5.0, 3.0) == -2.0);
- assert(divFloor(f32, 5.0, 3.0) == 1.0);
- assert(divFloor(f32, -5.0, 3.0) == -2.0);
- assert(divFloor(i32, -0x80000000, -2) == 0x40000000);
- assert(divFloor(i32, 0, -0x80000000) == 0);
- assert(divFloor(i32, -0x40000001, 0x40000000) == -2);
- assert(divFloor(i32, -0x80000000, 1) == -0x80000000);
-
- assert(divTrunc(i32, 5, 3) == 1);
- assert(divTrunc(i32, -5, 3) == -1);
- assert(divTrunc(f16, 5.0, 3.0) == 1.0);
- assert(divTrunc(f16, -5.0, 3.0) == -1.0);
- assert(divTrunc(f32, 5.0, 3.0) == 1.0);
- assert(divTrunc(f32, -5.0, 3.0) == -1.0);
- assert(divTrunc(f64, 5.0, 3.0) == 1.0);
- assert(divTrunc(f64, -5.0, 3.0) == -1.0);
+ assertOrPanic(div(u32, 13, 3) == 4);
+ assertOrPanic(div(f16, 1.0, 2.0) == 0.5);
+ assertOrPanic(div(f32, 1.0, 2.0) == 0.5);
+
+ assertOrPanic(divExact(u32, 55, 11) == 5);
+ assertOrPanic(divExact(i32, -55, 11) == -5);
+ assertOrPanic(divExact(f16, 55.0, 11.0) == 5.0);
+ assertOrPanic(divExact(f16, -55.0, 11.0) == -5.0);
+ assertOrPanic(divExact(f32, 55.0, 11.0) == 5.0);
+ assertOrPanic(divExact(f32, -55.0, 11.0) == -5.0);
+
+ assertOrPanic(divFloor(i32, 5, 3) == 1);
+ assertOrPanic(divFloor(i32, -5, 3) == -2);
+ assertOrPanic(divFloor(f16, 5.0, 3.0) == 1.0);
+ assertOrPanic(divFloor(f16, -5.0, 3.0) == -2.0);
+ assertOrPanic(divFloor(f32, 5.0, 3.0) == 1.0);
+ assertOrPanic(divFloor(f32, -5.0, 3.0) == -2.0);
+ assertOrPanic(divFloor(i32, -0x80000000, -2) == 0x40000000);
+ assertOrPanic(divFloor(i32, 0, -0x80000000) == 0);
+ assertOrPanic(divFloor(i32, -0x40000001, 0x40000000) == -2);
+ assertOrPanic(divFloor(i32, -0x80000000, 1) == -0x80000000);
+
+ assertOrPanic(divTrunc(i32, 5, 3) == 1);
+ assertOrPanic(divTrunc(i32, -5, 3) == -1);
+ assertOrPanic(divTrunc(f16, 5.0, 3.0) == 1.0);
+ assertOrPanic(divTrunc(f16, -5.0, 3.0) == -1.0);
+ assertOrPanic(divTrunc(f32, 5.0, 3.0) == 1.0);
+ assertOrPanic(divTrunc(f32, -5.0, 3.0) == -1.0);
+ assertOrPanic(divTrunc(f64, 5.0, 3.0) == 1.0);
+ assertOrPanic(divTrunc(f64, -5.0, 3.0) == -1.0);
comptime {
- assert(
+ assertOrPanic(
1194735857077236777412821811143690633098347576 % 508740759824825164163191790951174292733114988 == 177254337427586449086438229241342047632117600,
);
- assert(
+ assertOrPanic(
@rem(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -177254337427586449086438229241342047632117600,
);
- assert(
+ assertOrPanic(
1194735857077236777412821811143690633098347576 / 508740759824825164163191790951174292733114988 == 2,
);
- assert(
+ assertOrPanic(
@divTrunc(-1194735857077236777412821811143690633098347576, 508740759824825164163191790951174292733114988) == -2,
);
- assert(
+ assertOrPanic(
@divTrunc(1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == -2,
);
- assert(
+ assertOrPanic(
@divTrunc(-1194735857077236777412821811143690633098347576, -508740759824825164163191790951174292733114988) == 2,
);
- assert(
+ assertOrPanic(
4126227191251978491697987544882340798050766755606969681711 % 10 == 1,
);
}
@@ -78,9 +78,9 @@ fn divTrunc(comptime T: type, a: T, b: T) T {
test "@addWithOverflow" {
var result: u8 = undefined;
- assert(@addWithOverflow(u8, 250, 100, &result));
- assert(!@addWithOverflow(u8, 100, 150, &result));
- assert(result == 250);
+ assertOrPanic(@addWithOverflow(u8, 250, 100, &result));
+ assertOrPanic(!@addWithOverflow(u8, 100, 150, &result));
+ assertOrPanic(result == 250);
}
// TODO test mulWithOverflow
@@ -88,9 +88,9 @@ test "@addWithOverflow" {
test "@shlWithOverflow" {
var result: u16 = undefined;
- assert(@shlWithOverflow(u16, 0b0010111111111111, 3, &result));
- assert(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result));
- assert(result == 0b1011111111111100);
+ assertOrPanic(@shlWithOverflow(u16, 0b0010111111111111, 3, &result));
+ assertOrPanic(!@shlWithOverflow(u16, 0b0010111111111111, 2, &result));
+ assertOrPanic(result == 0b1011111111111100);
}
test "@clz" {
@@ -99,11 +99,11 @@ test "@clz" {
}
fn testClz() void {
- assert(clz(u8(0b00001010)) == 4);
- assert(clz(u8(0b10001010)) == 0);
- assert(clz(u8(0b00000000)) == 8);
- assert(clz(u128(0xffffffffffffffff)) == 64);
- assert(clz(u128(0x10000000000000000)) == 63);
+ assertOrPanic(clz(u8(0b00001010)) == 4);
+ assertOrPanic(clz(u8(0b10001010)) == 0);
+ assertOrPanic(clz(u8(0b00000000)) == 8);
+ assertOrPanic(clz(u128(0xffffffffffffffff)) == 64);
+ assertOrPanic(clz(u128(0x10000000000000000)) == 63);
}
fn clz(x: var) usize {
@@ -116,9 +116,9 @@ test "@ctz" {
}
fn testCtz() void {
- assert(ctz(u8(0b10100000)) == 5);
- assert(ctz(u8(0b10001010)) == 1);
- assert(ctz(u8(0b00000000)) == 8);
+ assertOrPanic(ctz(u8(0b10100000)) == 5);
+ assertOrPanic(ctz(u8(0b10001010)) == 1);
+ assertOrPanic(ctz(u8(0b00000000)) == 8);
}
fn ctz(x: var) usize {
@@ -128,27 +128,27 @@ fn ctz(x: var) usize {
test "assignment operators" {
var i: u32 = 0;
i += 5;
- assert(i == 5);
+ assertOrPanic(i == 5);
i -= 2;
- assert(i == 3);
+ assertOrPanic(i == 3);
i *= 20;
- assert(i == 60);
+ assertOrPanic(i == 60);
i /= 3;
- assert(i == 20);
+ assertOrPanic(i == 20);
i %= 11;
- assert(i == 9);
+ assertOrPanic(i == 9);
i <<= 1;
- assert(i == 18);
+ assertOrPanic(i == 18);
i >>= 2;
- assert(i == 4);
+ assertOrPanic(i == 4);
i = 6;
i &= 5;
- assert(i == 4);
+ assertOrPanic(i == 4);
i ^= 6;
- assert(i == 2);
+ assertOrPanic(i == 2);
i = 6;
i |= 3;
- assert(i == 7);
+ assertOrPanic(i == 7);
}
test "three expr in a row" {
@@ -170,14 +170,14 @@ fn testThreeExprInARow(f: bool, t: bool) void {
assertFalse(i32(7) != --(i32(7)));
}
fn assertFalse(b: bool) void {
- assert(!b);
+ assertOrPanic(!b);
}
test "const number literal" {
const one = 1;
const eleven = ten + one;
- assert(eleven == 11);
+ assertOrPanic(eleven == 11);
}
const ten = 10;
@@ -187,9 +187,9 @@ test "unsigned wrapping" {
}
fn testUnsignedWrappingEval(x: u32) void {
const zero = x +% 1;
- assert(zero == 0);
+ assertOrPanic(zero == 0);
const orig = zero -% 1;
- assert(orig == maxInt(u32));
+ assertOrPanic(orig == maxInt(u32));
}
test "signed wrapping" {
@@ -198,9 +198,9 @@ test "signed wrapping" {
}
fn testSignedWrappingEval(x: i32) void {
const min_val = x +% 1;
- assert(min_val == minInt(i32));
+ assertOrPanic(min_val == minInt(i32));
const max_val = min_val -% 1;
- assert(max_val == maxInt(i32));
+ assertOrPanic(max_val == maxInt(i32));
}
test "negation wrapping" {
@@ -208,9 +208,9 @@ test "negation wrapping" {
comptime testNegationWrappingEval(minInt(i16));
}
fn testNegationWrappingEval(x: i16) void {
- assert(x == -32768);
+ assertOrPanic(x == -32768);
const neg = -%x;
- assert(neg == -32768);
+ assertOrPanic(neg == -32768);
}
test "unsigned 64-bit division" {
@@ -219,8 +219,8 @@ test "unsigned 64-bit division" {
}
fn test_u64_div() void {
const result = divWithResult(1152921504606846976, 34359738365);
- assert(result.quotient == 33554432);
- assert(result.remainder == 100663296);
+ assertOrPanic(result.quotient == 33554432);
+ assertOrPanic(result.remainder == 100663296);
}
fn divWithResult(a: u64, b: u64) DivResult {
return DivResult{
@@ -234,36 +234,36 @@ const DivResult = struct {
};
test "binary not" {
- assert(comptime x: {
+ assertOrPanic(comptime x: {
break :x ~u16(0b1010101010101010) == 0b0101010101010101;
});
- assert(comptime x: {
+ assertOrPanic(comptime x: {
break :x ~u64(2147483647) == 18446744071562067968;
});
testBinaryNot(0b1010101010101010);
}
fn testBinaryNot(x: u16) void {
- assert(~x == 0b0101010101010101);
+ assertOrPanic(~x == 0b0101010101010101);
}
test "small int addition" {
var x: @IntType(false, 2) = 0;
- assert(x == 0);
+ assertOrPanic(x == 0);
x += 1;
- assert(x == 1);
+ assertOrPanic(x == 1);
x += 1;
- assert(x == 2);
+ assertOrPanic(x == 2);
x += 1;
- assert(x == 3);
+ assertOrPanic(x == 3);
var result: @typeOf(x) = 3;
- assert(@addWithOverflow(@typeOf(x), x, 1, &result));
+ assertOrPanic(@addWithOverflow(@typeOf(x), x, 1, &result));
- assert(result == 0);
+ assertOrPanic(result == 0);
}
test "float equality" {
@@ -276,20 +276,20 @@ test "float equality" {
fn testFloatEqualityImpl(x: f64, y: f64) void {
const y2 = x + 1.0;
- assert(y == y2);
+ assertOrPanic(y == y2);
}
test "allow signed integer division/remainder when values are comptime known and positive or exact" {
- assert(5 / 3 == 1);
- assert(-5 / -3 == 1);
- assert(-6 / 3 == -2);
+ assertOrPanic(5 / 3 == 1);
+ assertOrPanic(-5 / -3 == 1);
+ assertOrPanic(-6 / 3 == -2);
- assert(5 % 3 == 2);
- assert(-6 % 3 == 0);
+ assertOrPanic(5 % 3 == 2);
+ assertOrPanic(-6 % 3 == 0);
}
test "hex float literal parsing" {
- comptime assert(0x1.0 == 1.0);
+ comptime assertOrPanic(0x1.0 == 1.0);
}
test "quad hex float literal parsing in range" {
@@ -304,7 +304,7 @@ test "quad hex float literal parsing accurate" {
// implied 1 is dropped, with an exponent of 0 (0x3fff) after biasing.
const expected: u128 = 0x3fff1111222233334444555566667777;
- assert(@bitCast(u128, a) == expected);
+ assertOrPanic(@bitCast(u128, a) == expected);
}
test "hex float literal within range" {
@@ -319,7 +319,7 @@ test "truncating shift left" {
}
fn testShlTrunc(x: u16) void {
const shifted = x << 1;
- assert(shifted == 65534);
+ assertOrPanic(shifted == 65534);
}
test "truncating shift right" {
@@ -328,7 +328,7 @@ test "truncating shift right" {
}
fn testShrTrunc(x: u16) void {
const shifted = x >> 1;
- assert(shifted == 32767);
+ assertOrPanic(shifted == 32767);
}
test "exact shift left" {
@@ -337,7 +337,7 @@ test "exact shift left" {
}
fn testShlExact(x: u8) void {
const shifted = @shlExact(x, 2);
- assert(shifted == 0b11010100);
+ assertOrPanic(shifted == 0b11010100);
}
test "exact shift right" {
@@ -346,22 +346,22 @@ test "exact shift right" {
}
fn testShrExact(x: u8) void {
const shifted = @shrExact(x, 2);
- assert(shifted == 0b00101101);
+ assertOrPanic(shifted == 0b00101101);
}
test "comptime_int addition" {
comptime {
- assert(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950);
- assert(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380);
+ assertOrPanic(35361831660712422535336160538497375248 + 101752735581729509668353361206450473702 == 137114567242441932203689521744947848950);
+ assertOrPanic(594491908217841670578297176641415611445982232488944558774612 + 390603545391089362063884922208143568023166603618446395589768 == 985095453608931032642182098849559179469148836107390954364380);
}
}
test "comptime_int multiplication" {
comptime {
- assert(
+ assertOrPanic(
45960427431263824329884196484953148229 * 128339149605334697009938835852565949723 == 5898522172026096622534201617172456926982464453350084962781392314016180490567,
);
- assert(
+ assertOrPanic(
594491908217841670578297176641415611445982232488944558774612 * 390603545391089362063884922208143568023166603618446395589768 == 232210647056203049913662402532976186578842425262306016094292237500303028346593132411865381225871291702600263463125370016,
);
}
@@ -369,7 +369,7 @@ test "comptime_int multiplication" {
test "comptime_int shifting" {
comptime {
- assert((u128(1) << 127) == 0x80000000000000000000000000000000);
+ assertOrPanic((u128(1) << 127) == 0x80000000000000000000000000000000);
}
}
@@ -377,16 +377,16 @@ test "comptime_int multi-limb shift and mask" {
comptime {
var a = 0xefffffffa0000001eeeeeeefaaaaaaab;
- assert(u32(a & 0xffffffff) == 0xaaaaaaab);
+ assertOrPanic(u32(a & 0xffffffff) == 0xaaaaaaab);
a >>= 32;
- assert(u32(a & 0xffffffff) == 0xeeeeeeef);
+ assertOrPanic(u32(a & 0xffffffff) == 0xeeeeeeef);
a >>= 32;
- assert(u32(a & 0xffffffff) == 0xa0000001);
+ assertOrPanic(u32(a & 0xffffffff) == 0xa0000001);
a >>= 32;
- assert(u32(a & 0xffffffff) == 0xefffffff);
+ assertOrPanic(u32(a & 0xffffffff) == 0xefffffff);
a >>= 32;
- assert(a == 0);
+ assertOrPanic(a == 0);
}
}
@@ -394,7 +394,7 @@ test "comptime_int multi-limb partial shift right" {
comptime {
var a = 0x1ffffffffeeeeeeee;
a >>= 16;
- assert(a == 0x1ffffffffeeee);
+ assertOrPanic(a == 0x1ffffffffeeee);
}
}
@@ -404,23 +404,23 @@ test "xor" {
}
fn test_xor() void {
- assert(0xFF ^ 0x00 == 0xFF);
- assert(0xF0 ^ 0x0F == 0xFF);
- assert(0xFF ^ 0xF0 == 0x0F);
- assert(0xFF ^ 0x0F == 0xF0);
- assert(0xFF ^ 0xFF == 0x00);
+ assertOrPanic(0xFF ^ 0x00 == 0xFF);
+ assertOrPanic(0xF0 ^ 0x0F == 0xFF);
+ assertOrPanic(0xFF ^ 0xF0 == 0x0F);
+ assertOrPanic(0xFF ^ 0x0F == 0xF0);
+ assertOrPanic(0xFF ^ 0xFF == 0x00);
}
test "comptime_int xor" {
comptime {
- assert(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
- assert(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
- assert(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF);
- assert(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000);
- assert(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000);
- assert(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
- assert(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF);
- assert(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000);
+ assertOrPanic(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0x00000000000000000000000000000000 == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+ assertOrPanic(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0x0000000000000000FFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+ assertOrPanic(0xFFFFFFFFFFFFFFFF0000000000000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x0000000000000000FFFFFFFFFFFFFFFF);
+ assertOrPanic(0x0000000000000000FFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFFFF0000000000000000);
+ assertOrPanic(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000000000000000000000000000);
+ assertOrPanic(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0x00000000FFFFFFFF00000000FFFFFFFF == 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
+ assertOrPanic(0xFFFFFFFF00000000FFFFFFFF00000000 ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0x00000000FFFFFFFF00000000FFFFFFFF);
+ assertOrPanic(0x00000000FFFFFFFF00000000FFFFFFFF ^ 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0xFFFFFFFF00000000FFFFFFFF00000000);
}
}
@@ -434,23 +434,23 @@ fn make_f128(x: f128) f128 {
}
fn test_f128() void {
- assert(@sizeOf(f128) == 16);
- assert(make_f128(1.0) == 1.0);
- assert(make_f128(1.0) != 1.1);
- assert(make_f128(1.0) > 0.9);
- assert(make_f128(1.0) >= 0.9);
- assert(make_f128(1.0) >= 1.0);
+ assertOrPanic(@sizeOf(f128) == 16);
+ assertOrPanic(make_f128(1.0) == 1.0);
+ assertOrPanic(make_f128(1.0) != 1.1);
+ assertOrPanic(make_f128(1.0) > 0.9);
+ assertOrPanic(make_f128(1.0) >= 0.9);
+ assertOrPanic(make_f128(1.0) >= 1.0);
should_not_be_zero(1.0);
}
fn should_not_be_zero(x: f128) void {
- assert(x != 0.0);
+ assertOrPanic(x != 0.0);
}
test "comptime float rem int" {
comptime {
var x = f32(1) % 2;
- assert(x == 1.0);
+ assertOrPanic(x == 1.0);
}
}
@@ -465,8 +465,8 @@ test "remainder division" {
}
fn remdiv(comptime T: type) void {
- assert(T(1) == T(1) % T(2));
- assert(T(1) == T(7) % T(3));
+ assertOrPanic(T(1) == T(1) % T(2));
+ assertOrPanic(T(1) == T(7) % T(3));
}
test "@sqrt" {
@@ -480,19 +480,19 @@ test "@sqrt" {
const x = 14.0;
const y = x * x;
const z = @sqrt(@typeOf(y), y);
- comptime assert(z == x);
+ comptime assertOrPanic(z == x);
}
fn testSqrt(comptime T: type, x: T) void {
- assert(@sqrt(T, x * x) == x);
+ assertOrPanic(@sqrt(T, x * x) == x);
}
test "comptime_int param and return" {
const a = comptimeAdd(35361831660712422535336160538497375248, 101752735581729509668353361206450473702);
- assert(a == 137114567242441932203689521744947848950);
+ assertOrPanic(a == 137114567242441932203689521744947848950);
const b = comptimeAdd(594491908217841670578297176641415611445982232488944558774612, 390603545391089362063884922208143568023166603618446395589768);
- assert(b == 985095453608931032642182098849559179469148836107390954364380);
+ assertOrPanic(b == 985095453608931032642182098849559179469148836107390954364380);
}
fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int {
diff --git a/test/cases/merge_error_sets.zig b/test/stage1/behavior/merge_error_sets.zig
similarity index 100%
rename from test/cases/merge_error_sets.zig
rename to test/stage1/behavior/merge_error_sets.zig
diff --git a/test/cases/misc.zig b/test/stage1/behavior/misc.zig
similarity index 61%
rename from test/cases/misc.zig
rename to test/stage1/behavior/misc.zig
index 1a34d54e9e15..8d2555ddddb3 100644
--- a/test/cases/misc.zig
+++ b/test/stage1/behavior/misc.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
const mem = std.mem;
const cstr = std.cstr;
const builtin = @import("builtin");
@@ -26,38 +26,38 @@ test "call disabled extern fn" {
}
test "@IntType builtin" {
- assert(@IntType(true, 8) == i8);
- assert(@IntType(true, 16) == i16);
- assert(@IntType(true, 32) == i32);
- assert(@IntType(true, 64) == i64);
-
- assert(@IntType(false, 8) == u8);
- assert(@IntType(false, 16) == u16);
- assert(@IntType(false, 32) == u32);
- assert(@IntType(false, 64) == u64);
-
- assert(i8.bit_count == 8);
- assert(i16.bit_count == 16);
- assert(i32.bit_count == 32);
- assert(i64.bit_count == 64);
-
- assert(i8.is_signed);
- assert(i16.is_signed);
- assert(i32.is_signed);
- assert(i64.is_signed);
- assert(isize.is_signed);
-
- assert(!u8.is_signed);
- assert(!u16.is_signed);
- assert(!u32.is_signed);
- assert(!u64.is_signed);
- assert(!usize.is_signed);
+ assertOrPanic(@IntType(true, 8) == i8);
+ assertOrPanic(@IntType(true, 16) == i16);
+ assertOrPanic(@IntType(true, 32) == i32);
+ assertOrPanic(@IntType(true, 64) == i64);
+
+ assertOrPanic(@IntType(false, 8) == u8);
+ assertOrPanic(@IntType(false, 16) == u16);
+ assertOrPanic(@IntType(false, 32) == u32);
+ assertOrPanic(@IntType(false, 64) == u64);
+
+ assertOrPanic(i8.bit_count == 8);
+ assertOrPanic(i16.bit_count == 16);
+ assertOrPanic(i32.bit_count == 32);
+ assertOrPanic(i64.bit_count == 64);
+
+ assertOrPanic(i8.is_signed);
+ assertOrPanic(i16.is_signed);
+ assertOrPanic(i32.is_signed);
+ assertOrPanic(i64.is_signed);
+ assertOrPanic(isize.is_signed);
+
+ assertOrPanic(!u8.is_signed);
+ assertOrPanic(!u16.is_signed);
+ assertOrPanic(!u32.is_signed);
+ assertOrPanic(!u64.is_signed);
+ assertOrPanic(!usize.is_signed);
}
test "floating point primitive bit counts" {
- assert(f16.bit_count == 16);
- assert(f32.bit_count == 32);
- assert(f64.bit_count == 64);
+ assertOrPanic(f16.bit_count == 16);
+ assertOrPanic(f32.bit_count == 32);
+ assertOrPanic(f64.bit_count == 64);
}
test "short circuit" {
@@ -72,7 +72,7 @@ fn testShortCircuit(f: bool, t: bool) void {
var hit_4 = f;
if (t or x: {
- assert(f);
+ assertOrPanic(f);
break :x f;
}) {
hit_1 = t;
@@ -81,31 +81,31 @@ fn testShortCircuit(f: bool, t: bool) void {
hit_2 = t;
break :x f;
}) {
- assert(f);
+ assertOrPanic(f);
}
if (t and x: {
hit_3 = t;
break :x f;
}) {
- assert(f);
+ assertOrPanic(f);
}
if (f and x: {
- assert(f);
+ assertOrPanic(f);
break :x f;
}) {
- assert(f);
+ assertOrPanic(f);
} else {
hit_4 = t;
}
- assert(hit_1);
- assert(hit_2);
- assert(hit_3);
- assert(hit_4);
+ assertOrPanic(hit_1);
+ assertOrPanic(hit_2);
+ assertOrPanic(hit_3);
+ assertOrPanic(hit_4);
}
test "truncate" {
- assert(testTruncate(0x10fd) == 0xfd);
+ assertOrPanic(testTruncate(0x10fd) == 0xfd);
}
fn testTruncate(x: u32) u8 {
return @truncate(u8, x);
@@ -116,16 +116,16 @@ fn first4KeysOfHomeRow() []const u8 {
}
test "return string from function" {
- assert(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
+ assertOrPanic(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
}
const g1: i32 = 1233 + 1;
var g2: i32 = 0;
test "global variables" {
- assert(g2 == 0);
+ assertOrPanic(g2 == 0);
g2 = g1;
- assert(g2 == 1234);
+ assertOrPanic(g2 == 1234);
}
test "memcpy and memset intrinsics" {
@@ -142,7 +142,7 @@ test "builtin static eval" {
const x: i32 = comptime x: {
break :x 1 + 2 + 3;
};
- assert(x == comptime 6);
+ assertOrPanic(x == comptime 6);
}
test "slicing" {
@@ -163,7 +163,7 @@ test "slicing" {
test "constant equal function pointers" {
const alias = emptyFn;
- assert(comptime x: {
+ assertOrPanic(comptime x: {
break :x emptyFn == alias;
});
}
@@ -171,25 +171,25 @@ test "constant equal function pointers" {
fn emptyFn() void {}
test "hex escape" {
- assert(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
+ assertOrPanic(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
}
test "string concatenation" {
- assert(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));
+ assertOrPanic(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));
}
test "array mult operator" {
- assert(mem.eql(u8, "ab" ** 5, "ababababab"));
+ assertOrPanic(mem.eql(u8, "ab" ** 5, "ababababab"));
}
test "string escapes" {
- assert(mem.eql(u8, "\"", "\x22"));
- assert(mem.eql(u8, "\'", "\x27"));
- assert(mem.eql(u8, "\n", "\x0a"));
- assert(mem.eql(u8, "\r", "\x0d"));
- assert(mem.eql(u8, "\t", "\x09"));
- assert(mem.eql(u8, "\\", "\x5c"));
- assert(mem.eql(u8, "\u1234\u0069", "\xe1\x88\xb4\x69"));
+ assertOrPanic(mem.eql(u8, "\"", "\x22"));
+ assertOrPanic(mem.eql(u8, "\'", "\x27"));
+ assertOrPanic(mem.eql(u8, "\n", "\x0a"));
+ assertOrPanic(mem.eql(u8, "\r", "\x0d"));
+ assertOrPanic(mem.eql(u8, "\t", "\x09"));
+ assertOrPanic(mem.eql(u8, "\\", "\x5c"));
+ assertOrPanic(mem.eql(u8, "\u1234\u0069", "\xe1\x88\xb4\x69"));
}
test "multiline string" {
@@ -199,7 +199,7 @@ test "multiline string" {
\\three
;
const s2 = "one\ntwo)\nthree";
- assert(mem.eql(u8, s1, s2));
+ assertOrPanic(mem.eql(u8, s1, s2));
}
test "multiline C string" {
@@ -209,11 +209,11 @@ test "multiline C string" {
c\\three
;
const s2 = c"one\ntwo)\nthree";
- assert(cstr.cmp(s1, s2) == 0);
+ assertOrPanic(cstr.cmp(s1, s2) == 0);
}
test "type equality" {
- assert(*const u8 != *u8);
+ assertOrPanic(*const u8 != *u8);
}
const global_a: i32 = 1234;
@@ -221,7 +221,7 @@ const global_b: *const i32 = &global_a;
const global_c: *const f32 = @ptrCast(*const f32, global_b);
test "compile time global reinterpret" {
const d = @ptrCast(*const i32, global_c);
- assert(d.* == 1234);
+ assertOrPanic(d.* == 1234);
}
test "explicit cast maybe pointers" {
@@ -247,8 +247,8 @@ test "cast undefined" {
fn testCastUndefined(x: []const u8) void {}
test "cast small unsigned to larger signed" {
- assert(castSmallUnsignedToLargerSigned1(200) == i16(200));
- assert(castSmallUnsignedToLargerSigned2(9999) == i64(9999));
+ assertOrPanic(castSmallUnsignedToLargerSigned1(200) == i16(200));
+ assertOrPanic(castSmallUnsignedToLargerSigned2(9999) == i64(9999));
}
fn castSmallUnsignedToLargerSigned1(x: u8) i16 {
return x;
@@ -258,7 +258,7 @@ fn castSmallUnsignedToLargerSigned2(x: u16) i64 {
}
test "implicit cast after unreachable" {
- assert(outer() == 1234);
+ assertOrPanic(outer() == 1234);
}
fn inner() i32 {
return 1234;
@@ -273,13 +273,13 @@ test "pointer dereferencing" {
y.* += 1;
- assert(x == 4);
- assert(y.* == 4);
+ assertOrPanic(x == 4);
+ assertOrPanic(y.* == 4);
}
test "call result of if else expression" {
- assert(mem.eql(u8, f2(true), "a"));
- assert(mem.eql(u8, f2(false), "b"));
+ assertOrPanic(mem.eql(u8, f2(true), "a"));
+ assertOrPanic(mem.eql(u8, f2(false), "b"));
}
fn f2(x: bool) []const u8 {
return (if (x) fA else fB)();
@@ -321,8 +321,8 @@ const test3_bar = Test3Foo{ .Two = 13 };
fn test3_1(f: Test3Foo) void {
switch (f) {
Test3Foo.Three => |pt| {
- assert(pt.x == 3);
- assert(pt.y == 4);
+ assertOrPanic(pt.x == 3);
+ assertOrPanic(pt.y == 4);
},
else => unreachable,
}
@@ -330,14 +330,14 @@ fn test3_1(f: Test3Foo) void {
fn test3_2(f: Test3Foo) void {
switch (f) {
Test3Foo.Two => |x| {
- assert(x == 13);
+ assertOrPanic(x == 13);
},
else => unreachable,
}
}
test "character literals" {
- assert('\'' == single_quote);
+ assertOrPanic('\'' == single_quote);
}
const single_quote = '\'';
@@ -346,13 +346,13 @@ test "take address of parameter" {
}
fn testTakeAddressOfParameter(f: f32) void {
const f_ptr = &f;
- assert(f_ptr.* == 12.34);
+ assertOrPanic(f_ptr.* == 12.34);
}
test "pointer comparison" {
const a = ([]const u8)("a");
const b = &a;
- assert(ptrEql(b, b));
+ assertOrPanic(ptrEql(b, b));
}
fn ptrEql(a: *const []const u8, b: *const []const u8) bool {
return a == b;
@@ -367,36 +367,31 @@ test "C string concatenation" {
{
var i: u32 = 0;
while (i < len_with_null) : (i += 1) {
- assert(a[i] == b[i]);
+ assertOrPanic(a[i] == b[i]);
}
}
- assert(a[len] == 0);
- assert(b[len] == 0);
+ assertOrPanic(a[len] == 0);
+ assertOrPanic(b[len] == 0);
}
test "cast slice to u8 slice" {
- assert(@sizeOf(i32) == 4);
- var big_thing_array = []i32{
- 1,
- 2,
- 3,
- 4,
- };
+ assertOrPanic(@sizeOf(i32) == 4);
+ var big_thing_array = []i32{ 1, 2, 3, 4 };
const big_thing_slice: []i32 = big_thing_array[0..];
const bytes = @sliceToBytes(big_thing_slice);
- assert(bytes.len == 4 * 4);
+ assertOrPanic(bytes.len == 4 * 4);
bytes[4] = 0;
bytes[5] = 0;
bytes[6] = 0;
bytes[7] = 0;
- assert(big_thing_slice[1] == 0);
+ assertOrPanic(big_thing_slice[1] == 0);
const big_thing_again = @bytesToSlice(i32, bytes);
- assert(big_thing_again[2] == 3);
+ assertOrPanic(big_thing_again[2] == 3);
big_thing_again[2] = -1;
- assert(bytes[8] == maxInt(u8));
- assert(bytes[9] == maxInt(u8));
- assert(bytes[10] == maxInt(u8));
- assert(bytes[11] == maxInt(u8));
+ assertOrPanic(bytes[8] == maxInt(u8));
+ assertOrPanic(bytes[9] == maxInt(u8));
+ assertOrPanic(bytes[10] == maxInt(u8));
+ assertOrPanic(bytes[11] == maxInt(u8));
}
test "pointer to void return type" {
@@ -413,7 +408,7 @@ fn testPointerToVoidReturnType2() *const void {
test "non const ptr to aliased type" {
const int = i32;
- assert(?*int == ?*i32);
+ assertOrPanic(?*int == ?*i32);
}
test "array 2D const double ptr" {
@@ -426,8 +421,8 @@ test "array 2D const double ptr" {
fn testArray2DConstDoublePtr(ptr: *const f32) void {
const ptr2 = @ptrCast([*]const f32, ptr);
- assert(ptr2[0] == 1.0);
- assert(ptr2[1] == 2.0);
+ assertOrPanic(ptr2[0] == 1.0);
+ assertOrPanic(ptr2[1] == 2.0);
}
const Tid = builtin.TypeId;
@@ -449,32 +444,32 @@ const AUnion = union {
test "@typeId" {
comptime {
- assert(@typeId(type) == Tid.Type);
- assert(@typeId(void) == Tid.Void);
- assert(@typeId(bool) == Tid.Bool);
- assert(@typeId(noreturn) == Tid.NoReturn);
- assert(@typeId(i8) == Tid.Int);
- assert(@typeId(u8) == Tid.Int);
- assert(@typeId(i64) == Tid.Int);
- assert(@typeId(u64) == Tid.Int);
- assert(@typeId(f32) == Tid.Float);
- assert(@typeId(f64) == Tid.Float);
- assert(@typeId(*f32) == Tid.Pointer);
- assert(@typeId([2]u8) == Tid.Array);
- assert(@typeId(AStruct) == Tid.Struct);
- assert(@typeId(@typeOf(1)) == Tid.ComptimeInt);
- assert(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat);
- assert(@typeId(@typeOf(undefined)) == Tid.Undefined);
- assert(@typeId(@typeOf(null)) == Tid.Null);
- assert(@typeId(?i32) == Tid.Optional);
- assert(@typeId(anyerror!i32) == Tid.ErrorUnion);
- assert(@typeId(anyerror) == Tid.ErrorSet);
- assert(@typeId(AnEnum) == Tid.Enum);
- assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);
- assert(@typeId(AUnionEnum) == Tid.Union);
- assert(@typeId(AUnion) == Tid.Union);
- assert(@typeId(fn () void) == Tid.Fn);
- assert(@typeId(@typeOf(builtin)) == Tid.Namespace);
+ assertOrPanic(@typeId(type) == Tid.Type);
+ assertOrPanic(@typeId(void) == Tid.Void);
+ assertOrPanic(@typeId(bool) == Tid.Bool);
+ assertOrPanic(@typeId(noreturn) == Tid.NoReturn);
+ assertOrPanic(@typeId(i8) == Tid.Int);
+ assertOrPanic(@typeId(u8) == Tid.Int);
+ assertOrPanic(@typeId(i64) == Tid.Int);
+ assertOrPanic(@typeId(u64) == Tid.Int);
+ assertOrPanic(@typeId(f32) == Tid.Float);
+ assertOrPanic(@typeId(f64) == Tid.Float);
+ assertOrPanic(@typeId(*f32) == Tid.Pointer);
+ assertOrPanic(@typeId([2]u8) == Tid.Array);
+ assertOrPanic(@typeId(AStruct) == Tid.Struct);
+ assertOrPanic(@typeId(@typeOf(1)) == Tid.ComptimeInt);
+ assertOrPanic(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat);
+ assertOrPanic(@typeId(@typeOf(undefined)) == Tid.Undefined);
+ assertOrPanic(@typeId(@typeOf(null)) == Tid.Null);
+ assertOrPanic(@typeId(?i32) == Tid.Optional);
+ assertOrPanic(@typeId(anyerror!i32) == Tid.ErrorUnion);
+ assertOrPanic(@typeId(anyerror) == Tid.ErrorSet);
+ assertOrPanic(@typeId(AnEnum) == Tid.Enum);
+ assertOrPanic(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);
+ assertOrPanic(@typeId(AUnionEnum) == Tid.Union);
+ assertOrPanic(@typeId(AUnion) == Tid.Union);
+ assertOrPanic(@typeId(fn () void) == Tid.Fn);
+ assertOrPanic(@typeId(@typeOf(builtin)) == Tid.Namespace);
// TODO bound fn
// TODO arg tuple
// TODO opaque
@@ -490,13 +485,13 @@ test "@typeName" {
Unused,
};
comptime {
- assert(mem.eql(u8, @typeName(i64), "i64"));
- assert(mem.eql(u8, @typeName(*usize), "*usize"));
+ assertOrPanic(mem.eql(u8, @typeName(i64), "i64"));
+ assertOrPanic(mem.eql(u8, @typeName(*usize), "*usize"));
// https://github.com/ziglang/zig/issues/675
- assert(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)"));
- assert(mem.eql(u8, @typeName(Struct), "Struct"));
- assert(mem.eql(u8, @typeName(Union), "Union"));
- assert(mem.eql(u8, @typeName(Enum), "Enum"));
+ assertOrPanic(mem.eql(u8, @typeName(TypeFromFn(u8)), "TypeFromFn(u8)"));
+ assertOrPanic(mem.eql(u8, @typeName(Struct), "Struct"));
+ assertOrPanic(mem.eql(u8, @typeName(Union), "Union"));
+ assertOrPanic(mem.eql(u8, @typeName(Enum), "Enum"));
}
}
@@ -504,28 +499,16 @@ fn TypeFromFn(comptime T: type) type {
return struct {};
}
-test "volatile load and store" {
- var number: i32 = 1234;
- const ptr = (*volatile i32)(&number);
- ptr.* += 1;
- assert(ptr.* == 1235);
+test "double implicit cast in same expression" {
+ var x = i32(u16(nine()));
+ assertOrPanic(x == 9);
}
-
-test "slice string literal has type []const u8" {
- comptime {
- assert(@typeOf("aoeu"[0..]) == []const u8);
- const array = []i32{
- 1,
- 2,
- 3,
- 4,
- };
- assert(@typeOf(array[0..]) == []const i32);
- }
+fn nine() u8 {
+ return 9;
}
test "global variable initialized to global variable array element" {
- assert(global_ptr == &gdt[0]);
+ assertOrPanic(global_ptr == &gdt[0]);
}
const GDTEntry = struct {
field: i32,
@@ -543,16 +526,12 @@ export fn writeToVRam() void {
vram[0] = 'X';
}
-test "pointer child field" {
- assert((*u32).Child == u32);
-}
-
const OpaqueA = @OpaqueType();
const OpaqueB = @OpaqueType();
test "@OpaqueType" {
- assert(*OpaqueA != *OpaqueB);
- assert(mem.eql(u8, @typeName(OpaqueA), "OpaqueA"));
- assert(mem.eql(u8, @typeName(OpaqueB), "OpaqueB"));
+ assertOrPanic(*OpaqueA != *OpaqueB);
+ assertOrPanic(mem.eql(u8, @typeName(OpaqueA), "OpaqueA"));
+ assertOrPanic(mem.eql(u8, @typeName(OpaqueB), "OpaqueB"));
}
test "variable is allowed to be a pointer to an opaque type" {
@@ -581,25 +560,6 @@ test "implicit comptime while" {
}
}
-test "struct inside function" {
- testStructInFn();
- comptime testStructInFn();
-}
-
-fn testStructInFn() void {
- const BlockKind = u32;
-
- const Block = struct {
- kind: BlockKind,
- };
-
- var block = Block{ .kind = 1234 };
-
- block.kind += 1;
-
- assert(block.kind == 1235);
-}
-
fn fnThatClosesOverLocalConst() type {
const c = 1;
return struct {
@@ -611,7 +571,7 @@ fn fnThatClosesOverLocalConst() type {
test "function closes over local const" {
const x = fnThatClosesOverLocalConst().g();
- assert(x == 1);
+ assertOrPanic(x == 1);
}
test "cold function" {
@@ -648,21 +608,21 @@ export fn testPackedStuff(a: *const PackedStruct, b: *const PackedUnion, c: Pack
test "slicing zero length array" {
const s1 = ""[0..];
const s2 = ([]u32{})[0..];
- assert(s1.len == 0);
- assert(s2.len == 0);
- assert(mem.eql(u8, s1, ""));
- assert(mem.eql(u32, s2, []u32{}));
+ assertOrPanic(s1.len == 0);
+ assertOrPanic(s2.len == 0);
+ assertOrPanic(mem.eql(u8, s1, ""));
+ assertOrPanic(mem.eql(u32, s2, []u32{}));
}
const addr1 = @ptrCast(*const u8, emptyFn);
test "comptime cast fn to ptr" {
const addr2 = @ptrCast(*const u8, emptyFn);
- comptime assert(addr1 == addr2);
+ comptime assertOrPanic(addr1 == addr2);
}
test "equality compare fn ptrs" {
var a = emptyFn;
- assert(a == a);
+ assertOrPanic(a == a);
}
test "self reference through fn ptr field" {
@@ -677,5 +637,51 @@ test "self reference through fn ptr field" {
};
var a: S.A = undefined;
a.f = S.foo;
- assert(a.f(a) == 12);
+ assertOrPanic(a.f(a) == 12);
+}
+
+test "volatile load and store" {
+ var number: i32 = 1234;
+ const ptr = (*volatile i32)(&number);
+ ptr.* += 1;
+ assertOrPanic(ptr.* == 1235);
+}
+
+test "slice string literal has type []const u8" {
+ comptime {
+ assertOrPanic(@typeOf("aoeu"[0..]) == []const u8);
+ const array = []i32{ 1, 2, 3, 4 };
+ assertOrPanic(@typeOf(array[0..]) == []const i32);
+ }
+}
+
+test "pointer child field" {
+ assertOrPanic((*u32).Child == u32);
+}
+
+test "struct inside function" {
+ testStructInFn();
+ comptime testStructInFn();
+}
+
+fn testStructInFn() void {
+ const BlockKind = u32;
+
+ const Block = struct {
+ kind: BlockKind,
+ };
+
+ var block = Block{ .kind = 1234 };
+
+ block.kind += 1;
+
+ assertOrPanic(block.kind == 1235);
+}
+
+test "fn call returning scalar optional in equality expression" {
+ assertOrPanic(getNull() == null);
+}
+
+fn getNull() ?*i32 {
+ return null;
}
diff --git a/test/cases/namespace_depends_on_compile_var/a.zig b/test/stage1/behavior/namespace_depends_on_compile_var/a.zig
similarity index 100%
rename from test/cases/namespace_depends_on_compile_var/a.zig
rename to test/stage1/behavior/namespace_depends_on_compile_var/a.zig
diff --git a/test/cases/namespace_depends_on_compile_var/b.zig b/test/stage1/behavior/namespace_depends_on_compile_var/b.zig
similarity index 100%
rename from test/cases/namespace_depends_on_compile_var/b.zig
rename to test/stage1/behavior/namespace_depends_on_compile_var/b.zig
diff --git a/test/cases/namespace_depends_on_compile_var/index.zig b/test/stage1/behavior/namespace_depends_on_compile_var/index.zig
similarity index 62%
rename from test/cases/namespace_depends_on_compile_var/index.zig
rename to test/stage1/behavior/namespace_depends_on_compile_var/index.zig
index ccc49d9367d8..fe3e0cc02093 100644
--- a/test/cases/namespace_depends_on_compile_var/index.zig
+++ b/test/stage1/behavior/namespace_depends_on_compile_var/index.zig
@@ -1,11 +1,11 @@
const builtin = @import("builtin");
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
test "namespace depends on compile var" {
if (some_namespace.a_bool) {
- assert(some_namespace.a_bool);
+ assertOrPanic(some_namespace.a_bool);
} else {
- assert(!some_namespace.a_bool);
+ assertOrPanic(!some_namespace.a_bool);
}
}
const some_namespace = switch (builtin.os) {
diff --git a/test/cases/new_stack_call.zig b/test/stage1/behavior/new_stack_call.zig
similarity index 72%
rename from test/cases/new_stack_call.zig
rename to test/stage1/behavior/new_stack_call.zig
index 5912550d545a..b9ae2d27cdb7 100644
--- a/test/cases/new_stack_call.zig
+++ b/test/stage1/behavior/new_stack_call.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
var new_stack_bytes: [1024]u8 = undefined;
@@ -10,17 +10,17 @@ test "calling a function with a new stack" {
const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg);
_ = targetFunction(arg);
- assert(arg == 1234);
- assert(a < b);
+ assertOrPanic(arg == 1234);
+ assertOrPanic(a < b);
}
fn targetFunction(x: i32) usize {
- assert(x == 1234);
+ assertOrPanic(x == 1234);
var local_variable: i32 = 42;
const ptr = &local_variable;
ptr.* += 1;
- assert(local_variable == 43);
+ assertOrPanic(local_variable == 43);
return @ptrToInt(ptr);
}
diff --git a/test/cases/null.zig b/test/stage1/behavior/null.zig
similarity index 80%
rename from test/cases/null.zig
rename to test/stage1/behavior/null.zig
index 825db88b1e58..e2f86a05ba44 100644
--- a/test/cases/null.zig
+++ b/test/stage1/behavior/null.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
test "optional type" {
const x: ?bool = true;
@@ -17,13 +17,13 @@ test "optional type" {
const z = next_x orelse 1234;
- assert(z == 1234);
+ assertOrPanic(z == 1234);
const final_x: ?i32 = 13;
const num = final_x orelse unreachable;
- assert(num == 13);
+ assertOrPanic(num == 13);
}
test "test maybe object and get a pointer to the inner value" {
@@ -33,7 +33,7 @@ test "test maybe object and get a pointer to the inner value" {
b.* = false;
}
- assert(maybe_bool.? == false);
+ assertOrPanic(maybe_bool.? == false);
}
test "rhs maybe unwrap return" {
@@ -47,9 +47,9 @@ test "maybe return" {
}
fn maybeReturnImpl() void {
- assert(foo(1235).?);
+ assertOrPanic(foo(1235).?);
if (foo(null) != null) unreachable;
- assert(!foo(1234).?);
+ assertOrPanic(!foo(1234).?);
}
fn foo(x: ?i32) ?bool {
@@ -58,7 +58,7 @@ fn foo(x: ?i32) ?bool {
}
test "if var maybe pointer" {
- assert(shouldBeAPlus1(Particle{
+ assertOrPanic(shouldBeAPlus1(Particle{
.a = 14,
.b = 1,
.c = 1,
@@ -84,10 +84,10 @@ const Particle = struct {
test "null literal outside function" {
const is_null = here_is_a_null_literal.context == null;
- assert(is_null);
+ assertOrPanic(is_null);
const is_non_null = here_is_a_null_literal.context != null;
- assert(!is_non_null);
+ assertOrPanic(!is_non_null);
}
const SillyStruct = struct {
context: ?i32,
@@ -98,8 +98,8 @@ test "test null runtime" {
testTestNullRuntime(null);
}
fn testTestNullRuntime(x: ?i32) void {
- assert(x == null);
- assert(!(x != null));
+ assertOrPanic(x == null);
+ assertOrPanic(!(x != null));
}
test "optional void" {
@@ -108,8 +108,8 @@ test "optional void" {
}
fn optionalVoidImpl() void {
- assert(bar(null) == null);
- assert(bar({}) != null);
+ assertOrPanic(bar(null) == null);
+ assertOrPanic(bar({}) != null);
}
fn bar(x: ?void) ?void {
@@ -133,7 +133,7 @@ test "unwrap optional which is field of global var" {
}
struct_with_optional.field = 1234;
if (struct_with_optional.field) |payload| {
- assert(payload == 1234);
+ assertOrPanic(payload == 1234);
} else {
unreachable;
}
@@ -141,13 +141,13 @@ test "unwrap optional which is field of global var" {
test "null with default unwrap" {
const x: i32 = null orelse 1;
- assert(x == 1);
+ assertOrPanic(x == 1);
}
test "optional types" {
comptime {
const opt_type_struct = StructWithOptionalType{ .t = u8 };
- assert(opt_type_struct.t != null and opt_type_struct.t.? == u8);
+ assertOrPanic(opt_type_struct.t != null and opt_type_struct.t.? == u8);
}
}
@@ -158,5 +158,5 @@ const StructWithOptionalType = struct {
test "optional pointer to 0 bit type null value at runtime" {
const EmptyStruct = struct {};
var x: ?*EmptyStruct = null;
- assert(x == null);
+ assertOrPanic(x == null);
}
diff --git a/test/stage1/behavior/optional.zig b/test/stage1/behavior/optional.zig
new file mode 100644
index 000000000000..a3db580e4a22
--- /dev/null
+++ b/test/stage1/behavior/optional.zig
@@ -0,0 +1,81 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+pub const EmptyStruct = struct {};
+
+test "optional pointer to size zero struct" {
+ var e = EmptyStruct{};
+ var o: ?*EmptyStruct = &e;
+ assertOrPanic(o != null);
+}
+
+test "equality compare nullable pointers" {
+ testNullPtrsEql();
+ comptime testNullPtrsEql();
+}
+
+fn testNullPtrsEql() void {
+ var number: i32 = 1234;
+
+ var x: ?*i32 = null;
+ var y: ?*i32 = null;
+ assertOrPanic(x == y);
+ y = &number;
+ assertOrPanic(x != y);
+ assertOrPanic(x != &number);
+ assertOrPanic(&number != x);
+ x = &number;
+ assertOrPanic(x == y);
+ assertOrPanic(x == &number);
+ assertOrPanic(&number == x);
+}
+
+test "address of unwrap optional" {
+ const S = struct {
+ const Foo = struct {
+ a: i32,
+ };
+
+ var global: ?Foo = null;
+
+ pub fn getFoo() anyerror!*Foo {
+ return &global.?;
+ }
+ };
+ S.global = S.Foo{ .a = 1234 };
+ const foo = S.getFoo() catch unreachable;
+ assertOrPanic(foo.a == 1234);
+}
+
+test "passing an optional integer as a parameter" {
+ const S = struct {
+ fn entry() bool {
+ var x: i32 = 1234;
+ return foo(x);
+ }
+
+ fn foo(x: ?i32) bool {
+ return x.? == 1234;
+ }
+ };
+ assertOrPanic(S.entry());
+ comptime assertOrPanic(S.entry());
+}
+
+test "unwrap function call with optional pointer return value" {
+ const S = struct {
+ fn entry() void {
+ assertOrPanic(foo().?.* == 1234);
+ assertOrPanic(bar() == null);
+ }
+ const global: i32 = 1234;
+ fn foo() ?*const i32 {
+ return &global;
+ }
+ fn bar() ?*i32 {
+ return null;
+ }
+ };
+ S.entry();
+ // TODO uncomment
+ //comptime S.entry();
+}
diff --git a/test/cases/pointers.zig b/test/stage1/behavior/pointers.zig
similarity index 50%
rename from test/cases/pointers.zig
rename to test/stage1/behavior/pointers.zig
index 47afb60a2efd..1142d89ab557 100644
--- a/test/cases/pointers.zig
+++ b/test/stage1/behavior/pointers.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
test "dereference pointer" {
comptime testDerefPtr();
@@ -10,33 +10,33 @@ fn testDerefPtr() void {
var x: i32 = 1234;
var y = &x;
y.* += 1;
- assert(x == 1235);
+ assertOrPanic(x == 1235);
}
test "pointer arithmetic" {
var ptr = c"abcd";
- assert(ptr[0] == 'a');
+ assertOrPanic(ptr[0] == 'a');
ptr += 1;
- assert(ptr[0] == 'b');
+ assertOrPanic(ptr[0] == 'b');
ptr += 1;
- assert(ptr[0] == 'c');
+ assertOrPanic(ptr[0] == 'c');
ptr += 1;
- assert(ptr[0] == 'd');
+ assertOrPanic(ptr[0] == 'd');
ptr += 1;
- assert(ptr[0] == 0);
+ assertOrPanic(ptr[0] == 0);
ptr -= 1;
- assert(ptr[0] == 'd');
+ assertOrPanic(ptr[0] == 'd');
ptr -= 1;
- assert(ptr[0] == 'c');
+ assertOrPanic(ptr[0] == 'c');
ptr -= 1;
- assert(ptr[0] == 'b');
+ assertOrPanic(ptr[0] == 'b');
ptr -= 1;
- assert(ptr[0] == 'a');
+ assertOrPanic(ptr[0] == 'a');
}
test "double pointer parsing" {
- comptime assert(PtrOf(PtrOf(i32)) == **i32);
+ comptime assertOrPanic(PtrOf(PtrOf(i32)) == **i32);
}
fn PtrOf(comptime T: type) type {
diff --git a/test/stage1/behavior/popcount.zig b/test/stage1/behavior/popcount.zig
new file mode 100644
index 000000000000..f7f8bb523bf4
--- /dev/null
+++ b/test/stage1/behavior/popcount.zig
@@ -0,0 +1,25 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+test "@popCount" {
+ comptime testPopCount();
+ testPopCount();
+}
+
+fn testPopCount() void {
+ {
+ var x: u32 = 0xaa;
+ assertOrPanic(@popCount(x) == 4);
+ }
+ {
+ var x: u32 = 0xaaaaaaaa;
+ assertOrPanic(@popCount(x) == 16);
+ }
+ {
+ var x: i16 = -1;
+ assertOrPanic(@popCount(x) == 16);
+ }
+ comptime {
+ assertOrPanic(@popCount(0b11111111000110001100010000100001000011000011100101010001) == 24);
+ }
+}
+
diff --git a/test/cases/ptrcast.zig b/test/stage1/behavior/ptrcast.zig
similarity index 100%
rename from test/cases/ptrcast.zig
rename to test/stage1/behavior/ptrcast.zig
diff --git a/test/cases/pub_enum/index.zig b/test/stage1/behavior/pub_enum/index.zig
similarity index 54%
rename from test/cases/pub_enum/index.zig
rename to test/stage1/behavior/pub_enum/index.zig
index 7fdd07b8a384..181113f6bf19 100644
--- a/test/cases/pub_enum/index.zig
+++ b/test/stage1/behavior/pub_enum/index.zig
@@ -1,13 +1,13 @@
const other = @import("other.zig");
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
test "pub enum" {
pubEnumTest(other.APubEnum.Two);
}
fn pubEnumTest(foo: other.APubEnum) void {
- assert(foo == other.APubEnum.Two);
+ assertOrPanic(foo == other.APubEnum.Two);
}
test "cast with imported symbol" {
- assert(other.size_t(42) == 42);
+ assertOrPanic(other.size_t(42) == 42);
}
diff --git a/test/cases/pub_enum/other.zig b/test/stage1/behavior/pub_enum/other.zig
similarity index 100%
rename from test/cases/pub_enum/other.zig
rename to test/stage1/behavior/pub_enum/other.zig
diff --git a/test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig b/test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig
similarity index 77%
rename from test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig
rename to test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig
index 3c94bb0d49bf..acbe6b245978 100644
--- a/test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig
+++ b/test/stage1/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig
@@ -1,14 +1,14 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
const mem = @import("std").mem;
var ok: bool = false;
test "reference a variable in an if after an if in the 2nd switch prong" {
foo(true, Num.Two, false, "aoeu");
- assert(!ok);
+ assertOrPanic(!ok);
foo(false, Num.One, false, "aoeu");
- assert(!ok);
+ assertOrPanic(!ok);
foo(true, Num.One, false, "aoeu");
- assert(ok);
+ assertOrPanic(ok);
}
const Num = enum {
@@ -32,6 +32,6 @@ fn foo(c: bool, k: Num, c2: bool, b: []const u8) void {
}
fn a(x: []const u8) void {
- assert(mem.eql(u8, x, "aoeu"));
+ assertOrPanic(mem.eql(u8, x, "aoeu"));
ok = true;
}
diff --git a/test/stage1/behavior/reflection.zig b/test/stage1/behavior/reflection.zig
new file mode 100644
index 000000000000..f4c142e0f755
--- /dev/null
+++ b/test/stage1/behavior/reflection.zig
@@ -0,0 +1,96 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+const mem = @import("std").mem;
+const reflection = @This();
+
+test "reflection: array, pointer, optional, error union type child" {
+ comptime {
+ assertOrPanic(([10]u8).Child == u8);
+ assertOrPanic((*u8).Child == u8);
+ assertOrPanic((anyerror!u8).Payload == u8);
+ assertOrPanic((?u8).Child == u8);
+ }
+}
+
+test "reflection: function return type, var args, and param types" {
+ comptime {
+ assertOrPanic(@typeOf(dummy).ReturnType == i32);
+ assertOrPanic(!@typeOf(dummy).is_var_args);
+ assertOrPanic(@typeOf(dummy_varargs).is_var_args);
+ assertOrPanic(@typeOf(dummy).arg_count == 3);
+ assertOrPanic(@ArgType(@typeOf(dummy), 0) == bool);
+ assertOrPanic(@ArgType(@typeOf(dummy), 1) == i32);
+ assertOrPanic(@ArgType(@typeOf(dummy), 2) == f32);
+ }
+}
+
+fn dummy(a: bool, b: i32, c: f32) i32 {
+ return 1234;
+}
+fn dummy_varargs(args: ...) void {}
+
+test "reflection: struct member types and names" {
+ comptime {
+ assertOrPanic(@memberCount(Foo) == 3);
+
+ assertOrPanic(@memberType(Foo, 0) == i32);
+ assertOrPanic(@memberType(Foo, 1) == bool);
+ assertOrPanic(@memberType(Foo, 2) == void);
+
+ assertOrPanic(mem.eql(u8, @memberName(Foo, 0), "one"));
+ assertOrPanic(mem.eql(u8, @memberName(Foo, 1), "two"));
+ assertOrPanic(mem.eql(u8, @memberName(Foo, 2), "three"));
+ }
+}
+
+test "reflection: enum member types and names" {
+ comptime {
+ assertOrPanic(@memberCount(Bar) == 4);
+
+ assertOrPanic(@memberType(Bar, 0) == void);
+ assertOrPanic(@memberType(Bar, 1) == i32);
+ assertOrPanic(@memberType(Bar, 2) == bool);
+ assertOrPanic(@memberType(Bar, 3) == f64);
+
+ assertOrPanic(mem.eql(u8, @memberName(Bar, 0), "One"));
+ assertOrPanic(mem.eql(u8, @memberName(Bar, 1), "Two"));
+ assertOrPanic(mem.eql(u8, @memberName(Bar, 2), "Three"));
+ assertOrPanic(mem.eql(u8, @memberName(Bar, 3), "Four"));
+ }
+}
+
+test "reflection: @field" {
+ var f = Foo{
+ .one = 42,
+ .two = true,
+ .three = void{},
+ };
+
+ assertOrPanic(f.one == f.one);
+ assertOrPanic(@field(f, "o" ++ "ne") == f.one);
+ assertOrPanic(@field(f, "t" ++ "wo") == f.two);
+ assertOrPanic(@field(f, "th" ++ "ree") == f.three);
+ assertOrPanic(@field(Foo, "const" ++ "ant") == Foo.constant);
+ assertOrPanic(@field(Bar, "O" ++ "ne") == Bar.One);
+ assertOrPanic(@field(Bar, "T" ++ "wo") == Bar.Two);
+ assertOrPanic(@field(Bar, "Th" ++ "ree") == Bar.Three);
+ assertOrPanic(@field(Bar, "F" ++ "our") == Bar.Four);
+ assertOrPanic(@field(reflection, "dum" ++ "my")(true, 1, 2) == dummy(true, 1, 2));
+ @field(f, "o" ++ "ne") = 4;
+ assertOrPanic(f.one == 4);
+}
+
+const Foo = struct {
+ const constant = 52;
+
+ one: i32,
+ two: bool,
+ three: void,
+};
+
+const Bar = union(enum) {
+ One: void,
+ Two: i32,
+ Three: bool,
+ Four: f64,
+};
+
diff --git a/test/stage1/behavior/sizeof_and_typeof.zig b/test/stage1/behavior/sizeof_and_typeof.zig
new file mode 100644
index 000000000000..ddaea4c24299
--- /dev/null
+++ b/test/stage1/behavior/sizeof_and_typeof.zig
@@ -0,0 +1,69 @@
+const builtin = @import("builtin");
+const assertOrPanic = @import("std").debug.assertOrPanic;
+
+test "@sizeOf and @typeOf" {
+ const y: @typeOf(x) = 120;
+ assertOrPanic(@sizeOf(@typeOf(y)) == 2);
+}
+const x: u16 = 13;
+const z: @typeOf(x) = 19;
+
+const A = struct {
+ a: u8,
+ b: u32,
+ c: u8,
+ d: u3,
+ e: u5,
+ f: u16,
+ g: u16,
+};
+
+const P = packed struct {
+ a: u8,
+ b: u32,
+ c: u8,
+ d: u3,
+ e: u5,
+ f: u16,
+ g: u16,
+};
+
+test "@byteOffsetOf" {
+ // Packed structs have fixed memory layout
+ assertOrPanic(@byteOffsetOf(P, "a") == 0);
+ assertOrPanic(@byteOffsetOf(P, "b") == 1);
+ assertOrPanic(@byteOffsetOf(P, "c") == 5);
+ assertOrPanic(@byteOffsetOf(P, "d") == 6);
+ assertOrPanic(@byteOffsetOf(P, "e") == 6);
+ assertOrPanic(@byteOffsetOf(P, "f") == 7);
+ assertOrPanic(@byteOffsetOf(P, "g") == 9);
+
+ // Normal struct fields can be moved/padded
+ var a: A = undefined;
+ assertOrPanic(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a"));
+ assertOrPanic(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b"));
+ assertOrPanic(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c"));
+ assertOrPanic(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d"));
+ assertOrPanic(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e"));
+ assertOrPanic(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f"));
+ assertOrPanic(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g"));
+}
+
+test "@bitOffsetOf" {
+ // Packed structs have fixed memory layout
+ assertOrPanic(@bitOffsetOf(P, "a") == 0);
+ assertOrPanic(@bitOffsetOf(P, "b") == 8);
+ assertOrPanic(@bitOffsetOf(P, "c") == 40);
+ assertOrPanic(@bitOffsetOf(P, "d") == 48);
+ assertOrPanic(@bitOffsetOf(P, "e") == 51);
+ assertOrPanic(@bitOffsetOf(P, "f") == 56);
+ assertOrPanic(@bitOffsetOf(P, "g") == 72);
+
+ assertOrPanic(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a"));
+ assertOrPanic(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b"));
+ assertOrPanic(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c"));
+ assertOrPanic(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d"));
+ assertOrPanic(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e"));
+ assertOrPanic(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f"));
+ assertOrPanic(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g"));
+}
diff --git a/test/cases/slice.zig b/test/stage1/behavior/slice.zig
similarity index 62%
rename from test/cases/slice.zig
rename to test/stage1/behavior/slice.zig
index b4b43bdd1933..cc29e43485b2 100644
--- a/test/cases/slice.zig
+++ b/test/stage1/behavior/slice.zig
@@ -1,20 +1,20 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
const mem = @import("std").mem;
const x = @intToPtr([*]i32, 0x1000)[0..0x500];
const y = x[0x100..];
test "compile time slice of pointer to hard coded address" {
- assert(@ptrToInt(x.ptr) == 0x1000);
- assert(x.len == 0x500);
+ assertOrPanic(@ptrToInt(x.ptr) == 0x1000);
+ assertOrPanic(x.len == 0x500);
- assert(@ptrToInt(y.ptr) == 0x1100);
- assert(y.len == 0x400);
+ assertOrPanic(@ptrToInt(y.ptr) == 0x1100);
+ assertOrPanic(y.len == 0x400);
}
test "slice child property" {
var array: [5]i32 = undefined;
var slice = array[0..];
- assert(@typeOf(slice).Child == i32);
+ assertOrPanic(@typeOf(slice).Child == i32);
}
test "runtime safety lets us slice from len..len" {
@@ -23,7 +23,7 @@ test "runtime safety lets us slice from len..len" {
2,
3,
};
- assert(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), ""));
+ assertOrPanic(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), ""));
}
fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 {
@@ -36,5 +36,5 @@ test "implicitly cast array of size 0 to slice" {
}
fn assertLenIsZero(msg: []const u8) void {
- assert(msg.len == 0);
+ assertOrPanic(msg.len == 0);
}
diff --git a/test/cases/struct.zig b/test/stage1/behavior/struct.zig
similarity index 64%
rename from test/cases/struct.zig
rename to test/stage1/behavior/struct.zig
index bbbd21912c32..92ae2baa152d 100644
--- a/test/cases/struct.zig
+++ b/test/stage1/behavior/struct.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
const builtin = @import("builtin");
const maxInt = std.math.maxInt;
@@ -12,7 +12,7 @@ const empty_global_instance = StructWithNoFields{};
test "call struct static method" {
const result = StructWithNoFields.add(3, 4);
- assert(result == 7);
+ assertOrPanic(result == 7);
}
test "return empty struct instance" {
@@ -24,8 +24,8 @@ fn returnEmptyStructInstance() StructWithNoFields {
const should_be_11 = StructWithNoFields.add(5, 6);
-test "invake static method in global scope" {
- assert(should_be_11 == 11);
+test "invoke static method in global scope" {
+ assertOrPanic(should_be_11 == 11);
}
test "void struct fields" {
@@ -34,8 +34,8 @@ test "void struct fields" {
.b = 1,
.c = void{},
};
- assert(foo.b == 1);
- assert(@sizeOf(VoidStructFieldsFoo) == 4);
+ assertOrPanic(foo.b == 1);
+ assertOrPanic(@sizeOf(VoidStructFieldsFoo) == 4);
}
const VoidStructFieldsFoo = struct {
a: void,
@@ -50,7 +50,7 @@ test "structs" {
foo.b = foo.a == 1;
testFoo(foo);
testMutation(&foo);
- assert(foo.c == 100);
+ assertOrPanic(foo.c == 100);
}
const StructFoo = struct {
a: i32,
@@ -58,7 +58,7 @@ const StructFoo = struct {
c: f32,
};
fn testFoo(foo: StructFoo) void {
- assert(foo.b);
+ assertOrPanic(foo.b);
}
fn testMutation(foo: *StructFoo) void {
foo.c = 100;
@@ -83,7 +83,7 @@ test "struct point to self" {
root.next = &node;
- assert(node.next.next.next.val.x == 1);
+ assertOrPanic(node.next.next.next.val.x == 1);
}
test "struct byval assign" {
@@ -92,18 +92,18 @@ test "struct byval assign" {
foo1.a = 1234;
foo2.a = 0;
- assert(foo2.a == 0);
+ assertOrPanic(foo2.a == 0);
foo2 = foo1;
- assert(foo2.a == 1234);
+ assertOrPanic(foo2.a == 1234);
}
fn structInitializer() void {
const val = Val{ .x = 42 };
- assert(val.x == 42);
+ assertOrPanic(val.x == 42);
}
test "fn call of struct field" {
- assert(callStructField(Foo{ .ptr = aFunc }) == 13);
+ assertOrPanic(callStructField(Foo{ .ptr = aFunc }) == 13);
}
const Foo = struct {
@@ -122,7 +122,7 @@ test "store member function in variable" {
const instance = MemberFnTestFoo{ .x = 1234 };
const memberFn = MemberFnTestFoo.member;
const result = memberFn(instance);
- assert(result == 1234);
+ assertOrPanic(result == 1234);
}
const MemberFnTestFoo = struct {
x: i32,
@@ -134,12 +134,12 @@ const MemberFnTestFoo = struct {
test "call member function directly" {
const instance = MemberFnTestFoo{ .x = 1234 };
const result = MemberFnTestFoo.member(instance);
- assert(result == 1234);
+ assertOrPanic(result == 1234);
}
test "member functions" {
const r = MemberFnRand{ .seed = 1234 };
- assert(r.getSeed() == 1234);
+ assertOrPanic(r.getSeed() == 1234);
}
const MemberFnRand = struct {
seed: u32,
@@ -150,7 +150,7 @@ const MemberFnRand = struct {
test "return struct byval from function" {
const bar = makeBar(1234, 5678);
- assert(bar.y == 5678);
+ assertOrPanic(bar.y == 5678);
}
const Bar = struct {
x: i32,
@@ -165,7 +165,7 @@ fn makeBar(x: i32, y: i32) Bar {
test "empty struct method call" {
const es = EmptyStruct{};
- assert(es.method() == 1234);
+ assertOrPanic(es.method() == 1234);
}
const EmptyStruct = struct {
fn method(es: *const EmptyStruct) i32 {
@@ -182,7 +182,7 @@ fn testReturnEmptyStructFromFn() EmptyStruct2 {
}
test "pass slice of empty struct to fn" {
- assert(testPassSliceOfEmptyStructToFn([]EmptyStruct2{EmptyStruct2{}}) == 1);
+ assertOrPanic(testPassSliceOfEmptyStructToFn([]EmptyStruct2{EmptyStruct2{}}) == 1);
}
fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize {
return slice.len;
@@ -200,7 +200,7 @@ test "packed struct" {
};
foo.y += 1;
const four = foo.x + foo.y;
- assert(four == 4);
+ assertOrPanic(four == 4);
}
const BitField1 = packed struct {
@@ -217,17 +217,17 @@ const bit_field_1 = BitField1{
test "bit field access" {
var data = bit_field_1;
- assert(getA(&data) == 1);
- assert(getB(&data) == 2);
- assert(getC(&data) == 3);
- comptime assert(@sizeOf(BitField1) == 1);
+ assertOrPanic(getA(&data) == 1);
+ assertOrPanic(getB(&data) == 2);
+ assertOrPanic(getC(&data) == 3);
+ comptime assertOrPanic(@sizeOf(BitField1) == 1);
data.b += 1;
- assert(data.b == 3);
+ assertOrPanic(data.b == 3);
data.a += 1;
- assert(data.a == 2);
- assert(data.b == 3);
+ assertOrPanic(data.a == 2);
+ assertOrPanic(data.b == 3);
}
fn getA(data: *const BitField1) u3 {
@@ -254,8 +254,8 @@ const Foo96Bits = packed struct {
test "packed struct 24bits" {
comptime {
- assert(@sizeOf(Foo24Bits) == 3);
- assert(@sizeOf(Foo96Bits) == 12);
+ assertOrPanic(@sizeOf(Foo24Bits) == 3);
+ assertOrPanic(@sizeOf(Foo96Bits) == 12);
}
var value = Foo96Bits{
@@ -265,28 +265,28 @@ test "packed struct 24bits" {
.d = 0,
};
value.a += 1;
- assert(value.a == 1);
- assert(value.b == 0);
- assert(value.c == 0);
- assert(value.d == 0);
+ assertOrPanic(value.a == 1);
+ assertOrPanic(value.b == 0);
+ assertOrPanic(value.c == 0);
+ assertOrPanic(value.d == 0);
value.b += 1;
- assert(value.a == 1);
- assert(value.b == 1);
- assert(value.c == 0);
- assert(value.d == 0);
+ assertOrPanic(value.a == 1);
+ assertOrPanic(value.b == 1);
+ assertOrPanic(value.c == 0);
+ assertOrPanic(value.d == 0);
value.c += 1;
- assert(value.a == 1);
- assert(value.b == 1);
- assert(value.c == 1);
- assert(value.d == 0);
+ assertOrPanic(value.a == 1);
+ assertOrPanic(value.b == 1);
+ assertOrPanic(value.c == 1);
+ assertOrPanic(value.d == 0);
value.d += 1;
- assert(value.a == 1);
- assert(value.b == 1);
- assert(value.c == 1);
- assert(value.d == 1);
+ assertOrPanic(value.a == 1);
+ assertOrPanic(value.b == 1);
+ assertOrPanic(value.c == 1);
+ assertOrPanic(value.d == 1);
}
const FooArray24Bits = packed struct {
@@ -297,43 +297,43 @@ const FooArray24Bits = packed struct {
test "packed array 24bits" {
comptime {
- assert(@sizeOf([9]Foo24Bits) == 9 * 3);
- assert(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2);
+ assertOrPanic(@sizeOf([9]Foo24Bits) == 9 * 3);
+ assertOrPanic(@sizeOf(FooArray24Bits) == 2 + 2 * 3 + 2);
}
var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1);
bytes[bytes.len - 1] = 0xaa;
const ptr = &@bytesToSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0];
- assert(ptr.a == 0);
- assert(ptr.b[0].field == 0);
- assert(ptr.b[1].field == 0);
- assert(ptr.c == 0);
+ assertOrPanic(ptr.a == 0);
+ assertOrPanic(ptr.b[0].field == 0);
+ assertOrPanic(ptr.b[1].field == 0);
+ assertOrPanic(ptr.c == 0);
ptr.a = maxInt(u16);
- assert(ptr.a == maxInt(u16));
- assert(ptr.b[0].field == 0);
- assert(ptr.b[1].field == 0);
- assert(ptr.c == 0);
+ assertOrPanic(ptr.a == maxInt(u16));
+ assertOrPanic(ptr.b[0].field == 0);
+ assertOrPanic(ptr.b[1].field == 0);
+ assertOrPanic(ptr.c == 0);
ptr.b[0].field = maxInt(u24);
- assert(ptr.a == maxInt(u16));
- assert(ptr.b[0].field == maxInt(u24));
- assert(ptr.b[1].field == 0);
- assert(ptr.c == 0);
+ assertOrPanic(ptr.a == maxInt(u16));
+ assertOrPanic(ptr.b[0].field == maxInt(u24));
+ assertOrPanic(ptr.b[1].field == 0);
+ assertOrPanic(ptr.c == 0);
ptr.b[1].field = maxInt(u24);
- assert(ptr.a == maxInt(u16));
- assert(ptr.b[0].field == maxInt(u24));
- assert(ptr.b[1].field == maxInt(u24));
- assert(ptr.c == 0);
+ assertOrPanic(ptr.a == maxInt(u16));
+ assertOrPanic(ptr.b[0].field == maxInt(u24));
+ assertOrPanic(ptr.b[1].field == maxInt(u24));
+ assertOrPanic(ptr.c == 0);
ptr.c = maxInt(u16);
- assert(ptr.a == maxInt(u16));
- assert(ptr.b[0].field == maxInt(u24));
- assert(ptr.b[1].field == maxInt(u24));
- assert(ptr.c == maxInt(u16));
+ assertOrPanic(ptr.a == maxInt(u16));
+ assertOrPanic(ptr.b[0].field == maxInt(u24));
+ assertOrPanic(ptr.b[1].field == maxInt(u24));
+ assertOrPanic(ptr.c == maxInt(u16));
- assert(bytes[bytes.len - 1] == 0xaa);
+ assertOrPanic(bytes[bytes.len - 1] == 0xaa);
}
const FooStructAligned = packed struct {
@@ -347,17 +347,17 @@ const FooArrayOfAligned = packed struct {
test "aligned array of packed struct" {
comptime {
- assert(@sizeOf(FooStructAligned) == 2);
- assert(@sizeOf(FooArrayOfAligned) == 2 * 2);
+ assertOrPanic(@sizeOf(FooStructAligned) == 2);
+ assertOrPanic(@sizeOf(FooArrayOfAligned) == 2 * 2);
}
var bytes = []u8{0xbb} ** @sizeOf(FooArrayOfAligned);
const ptr = &@bytesToSlice(FooArrayOfAligned, bytes[0..bytes.len])[0];
- assert(ptr.a[0].a == 0xbb);
- assert(ptr.a[0].b == 0xbb);
- assert(ptr.a[1].a == 0xbb);
- assert(ptr.a[1].b == 0xbb);
+ assertOrPanic(ptr.a[0].a == 0xbb);
+ assertOrPanic(ptr.a[0].b == 0xbb);
+ assertOrPanic(ptr.a[1].a == 0xbb);
+ assertOrPanic(ptr.a[1].b == 0xbb);
}
test "runtime struct initialization of bitfield" {
@@ -370,10 +370,10 @@ test "runtime struct initialization of bitfield" {
.y = @intCast(u4, x2),
};
- assert(s1.x == x1);
- assert(s1.y == x1);
- assert(s2.x == @intCast(u4, x2));
- assert(s2.y == @intCast(u4, x2));
+ assertOrPanic(s1.x == x1);
+ assertOrPanic(s1.y == x1);
+ assertOrPanic(s2.x == @intCast(u4, x2));
+ assertOrPanic(s2.y == @intCast(u4, x2));
}
var x1 = u4(1);
@@ -400,18 +400,18 @@ test "native bit field understands endianness" {
@memcpy(bytes[0..].ptr, @ptrCast([*]u8, &all), 8);
var bitfields = @ptrCast(*Bitfields, bytes[0..].ptr).*;
- assert(bitfields.f1 == 0x1111);
- assert(bitfields.f2 == 0x2222);
- assert(bitfields.f3 == 0x33);
- assert(bitfields.f4 == 0x44);
- assert(bitfields.f5 == 0x5);
- assert(bitfields.f6 == 0x6);
- assert(bitfields.f7 == 0x77);
+ assertOrPanic(bitfields.f1 == 0x1111);
+ assertOrPanic(bitfields.f2 == 0x2222);
+ assertOrPanic(bitfields.f3 == 0x33);
+ assertOrPanic(bitfields.f4 == 0x44);
+ assertOrPanic(bitfields.f5 == 0x5);
+ assertOrPanic(bitfields.f6 == 0x6);
+ assertOrPanic(bitfields.f7 == 0x77);
}
test "align 1 field before self referential align 8 field as slice return type" {
const result = alloc(Expr);
- assert(result.len == 0);
+ assertOrPanic(result.len == 0);
}
const Expr = union(enum) {
@@ -434,10 +434,10 @@ test "call method with mutable reference to struct with no fields" {
};
var s = S{};
- assert(S.doC(&s));
- assert(s.doC());
- assert(S.do(&s));
- assert(s.do());
+ assertOrPanic(S.doC(&s));
+ assertOrPanic(s.doC());
+ assertOrPanic(S.do(&s));
+ assertOrPanic(s.do());
}
test "implicit cast packed struct field to const ptr" {
@@ -453,7 +453,7 @@ test "implicit cast packed struct field to const ptr" {
var lup: LevelUpMove = undefined;
lup.level = 12;
const res = LevelUpMove.toInt(lup.level);
- assert(res == 12);
+ assertOrPanic(res == 12);
}
test "pointer to packed struct member in a stack variable" {
@@ -464,7 +464,7 @@ test "pointer to packed struct member in a stack variable" {
var s = S{ .a = 2, .b = 0 };
var b_ptr = &s.b;
- assert(s.b == 0);
+ assertOrPanic(s.b == 0);
b_ptr.* = 2;
- assert(s.b == 2);
+ assertOrPanic(s.b == 2);
}
diff --git a/test/cases/struct_contains_null_ptr_itself.zig b/test/stage1/behavior/struct_contains_null_ptr_itself.zig
similarity index 81%
rename from test/cases/struct_contains_null_ptr_itself.zig
rename to test/stage1/behavior/struct_contains_null_ptr_itself.zig
index 21175974b3d8..4cc479f31c4a 100644
--- a/test/cases/struct_contains_null_ptr_itself.zig
+++ b/test/stage1/behavior/struct_contains_null_ptr_itself.zig
@@ -1,9 +1,9 @@
const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
test "struct contains null pointer which contains original struct" {
var x: ?*NodeLineComment = null;
- assert(x == null);
+ assertOrPanic(x == null);
}
pub const Node = struct {
diff --git a/test/cases/struct_contains_slice_of_itself.zig b/test/stage1/behavior/struct_contains_slice_of_itself.zig
similarity index 68%
rename from test/cases/struct_contains_slice_of_itself.zig
rename to test/stage1/behavior/struct_contains_slice_of_itself.zig
index aa3075312cc7..15780a7c4456 100644
--- a/test/cases/struct_contains_slice_of_itself.zig
+++ b/test/stage1/behavior/struct_contains_slice_of_itself.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
const Node = struct {
payload: i32,
@@ -39,12 +39,12 @@ test "struct contains slice of itself" {
.payload = 1234,
.children = nodes[0..],
};
- assert(root.payload == 1234);
- assert(root.children[0].payload == 1);
- assert(root.children[1].payload == 2);
- assert(root.children[2].payload == 3);
- assert(root.children[2].children[0].payload == 31);
- assert(root.children[2].children[1].payload == 32);
+ assertOrPanic(root.payload == 1234);
+ assertOrPanic(root.children[0].payload == 1);
+ assertOrPanic(root.children[1].payload == 2);
+ assertOrPanic(root.children[2].payload == 3);
+ assertOrPanic(root.children[2].children[0].payload == 31);
+ assertOrPanic(root.children[2].children[1].payload == 32);
}
test "struct contains aligned slice of itself" {
@@ -76,10 +76,10 @@ test "struct contains aligned slice of itself" {
.payload = 1234,
.children = nodes[0..],
};
- assert(root.payload == 1234);
- assert(root.children[0].payload == 1);
- assert(root.children[1].payload == 2);
- assert(root.children[2].payload == 3);
- assert(root.children[2].children[0].payload == 31);
- assert(root.children[2].children[1].payload == 32);
+ assertOrPanic(root.payload == 1234);
+ assertOrPanic(root.children[0].payload == 1);
+ assertOrPanic(root.children[1].payload == 2);
+ assertOrPanic(root.children[2].payload == 3);
+ assertOrPanic(root.children[2].children[0].payload == 31);
+ assertOrPanic(root.children[2].children[1].payload == 32);
}
diff --git a/test/cases/switch.zig b/test/stage1/behavior/switch.zig
similarity index 72%
rename from test/cases/switch.zig
rename to test/stage1/behavior/switch.zig
index 1162fdd4b2ea..4ac971397e04 100644
--- a/test/cases/switch.zig
+++ b/test/stage1/behavior/switch.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
test "switch with numbers" {
testSwitchWithNumbers(13);
@@ -10,14 +10,14 @@ fn testSwitchWithNumbers(x: u32) void {
13 => true,
else => false,
};
- assert(result);
+ assertOrPanic(result);
}
test "switch with all ranges" {
- assert(testSwitchWithAllRanges(50, 3) == 1);
- assert(testSwitchWithAllRanges(101, 0) == 2);
- assert(testSwitchWithAllRanges(300, 5) == 3);
- assert(testSwitchWithAllRanges(301, 6) == 6);
+ assertOrPanic(testSwitchWithAllRanges(50, 3) == 1);
+ assertOrPanic(testSwitchWithAllRanges(101, 0) == 2);
+ assertOrPanic(testSwitchWithAllRanges(300, 5) == 3);
+ assertOrPanic(testSwitchWithAllRanges(301, 6) == 6);
}
fn testSwitchWithAllRanges(x: u32, y: u32) u32 {
@@ -40,7 +40,7 @@ test "implicit comptime switch" {
};
comptime {
- assert(result + 1 == 14);
+ assertOrPanic(result + 1 == 14);
}
}
@@ -71,7 +71,7 @@ fn nonConstSwitch(foo: SwitchStatmentFoo) void {
SwitchStatmentFoo.C => 3,
SwitchStatmentFoo.D => 4,
};
- assert(val == 3);
+ assertOrPanic(val == 3);
}
const SwitchStatmentFoo = enum {
A,
@@ -93,10 +93,10 @@ const SwitchProngWithVarEnum = union(enum) {
fn switchProngWithVarFn(a: SwitchProngWithVarEnum) void {
switch (a) {
SwitchProngWithVarEnum.One => |x| {
- assert(x == 13);
+ assertOrPanic(x == 13);
},
SwitchProngWithVarEnum.Two => |x| {
- assert(x == 13.0);
+ assertOrPanic(x == 13.0);
},
SwitchProngWithVarEnum.Meh => |x| {
const v: void = x;
@@ -116,7 +116,7 @@ fn testSwitchEnumPtrCapture() void {
else => unreachable,
}
switch (value) {
- SwitchProngWithVarEnum.One => |x| assert(x == 1235),
+ SwitchProngWithVarEnum.One => |x| assertOrPanic(x == 1235),
else => unreachable,
}
}
@@ -127,7 +127,7 @@ test "switch with multiple expressions" {
4, 5, 6 => 2,
else => i32(3),
};
- assert(x == 2);
+ assertOrPanic(x == 2);
}
fn returnsFive() i32 {
return 5;
@@ -149,12 +149,12 @@ fn returnsFalse() bool {
}
}
test "switch on const enum with var" {
- assert(!returnsFalse());
+ assertOrPanic(!returnsFalse());
}
test "switch on type" {
- assert(trueIfBoolFalseOtherwise(bool));
- assert(!trueIfBoolFalseOtherwise(i32));
+ assertOrPanic(trueIfBoolFalseOtherwise(bool));
+ assertOrPanic(!trueIfBoolFalseOtherwise(i32));
}
fn trueIfBoolFalseOtherwise(comptime T: type) bool {
@@ -170,16 +170,16 @@ test "switch handles all cases of number" {
}
fn testSwitchHandleAllCases() void {
- assert(testSwitchHandleAllCasesExhaustive(0) == 3);
- assert(testSwitchHandleAllCasesExhaustive(1) == 2);
- assert(testSwitchHandleAllCasesExhaustive(2) == 1);
- assert(testSwitchHandleAllCasesExhaustive(3) == 0);
+ assertOrPanic(testSwitchHandleAllCasesExhaustive(0) == 3);
+ assertOrPanic(testSwitchHandleAllCasesExhaustive(1) == 2);
+ assertOrPanic(testSwitchHandleAllCasesExhaustive(2) == 1);
+ assertOrPanic(testSwitchHandleAllCasesExhaustive(3) == 0);
- assert(testSwitchHandleAllCasesRange(100) == 0);
- assert(testSwitchHandleAllCasesRange(200) == 1);
- assert(testSwitchHandleAllCasesRange(201) == 2);
- assert(testSwitchHandleAllCasesRange(202) == 4);
- assert(testSwitchHandleAllCasesRange(230) == 3);
+ assertOrPanic(testSwitchHandleAllCasesRange(100) == 0);
+ assertOrPanic(testSwitchHandleAllCasesRange(200) == 1);
+ assertOrPanic(testSwitchHandleAllCasesRange(201) == 2);
+ assertOrPanic(testSwitchHandleAllCasesRange(202) == 4);
+ assertOrPanic(testSwitchHandleAllCasesRange(230) == 3);
}
fn testSwitchHandleAllCasesExhaustive(x: u2) u2 {
@@ -207,8 +207,8 @@ test "switch all prongs unreachable" {
}
fn testAllProngsUnreachable() void {
- assert(switchWithUnreachable(1) == 2);
- assert(switchWithUnreachable(2) == 10);
+ assertOrPanic(switchWithUnreachable(1) == 2);
+ assertOrPanic(switchWithUnreachable(2) == 10);
}
fn switchWithUnreachable(x: i32) i32 {
@@ -230,7 +230,7 @@ test "capture value of switch with all unreachable prongs" {
const x = return_a_number() catch |err| switch (err) {
else => unreachable,
};
- assert(x == 1);
+ assertOrPanic(x == 1);
}
test "switching on booleans" {
@@ -239,14 +239,14 @@ test "switching on booleans" {
}
fn testSwitchOnBools() void {
- assert(testSwitchOnBoolsTrueAndFalse(true) == false);
- assert(testSwitchOnBoolsTrueAndFalse(false) == true);
+ assertOrPanic(testSwitchOnBoolsTrueAndFalse(true) == false);
+ assertOrPanic(testSwitchOnBoolsTrueAndFalse(false) == true);
- assert(testSwitchOnBoolsTrueWithElse(true) == false);
- assert(testSwitchOnBoolsTrueWithElse(false) == true);
+ assertOrPanic(testSwitchOnBoolsTrueWithElse(true) == false);
+ assertOrPanic(testSwitchOnBoolsTrueWithElse(false) == true);
- assert(testSwitchOnBoolsFalseWithElse(true) == false);
- assert(testSwitchOnBoolsFalseWithElse(false) == true);
+ assertOrPanic(testSwitchOnBoolsFalseWithElse(true) == false);
+ assertOrPanic(testSwitchOnBoolsFalseWithElse(false) == true);
}
fn testSwitchOnBoolsTrueAndFalse(x: bool) bool {
diff --git a/test/cases/switch_prong_err_enum.zig b/test/stage1/behavior/switch_prong_err_enum.zig
similarity index 79%
rename from test/cases/switch_prong_err_enum.zig
rename to test/stage1/behavior/switch_prong_err_enum.zig
index 89060690fc01..6ac1919f0d5a 100644
--- a/test/cases/switch_prong_err_enum.zig
+++ b/test/stage1/behavior/switch_prong_err_enum.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
var read_count: u64 = 0;
@@ -22,9 +22,9 @@ fn doThing(form_id: u64) anyerror!FormValue {
test "switch prong returns error enum" {
switch (doThing(17) catch unreachable) {
FormValue.Address => |payload| {
- assert(payload == 1);
+ assertOrPanic(payload == 1);
},
else => unreachable,
}
- assert(read_count == 1);
+ assertOrPanic(read_count == 1);
}
diff --git a/test/cases/switch_prong_implicit_cast.zig b/test/stage1/behavior/switch_prong_implicit_cast.zig
similarity index 82%
rename from test/cases/switch_prong_implicit_cast.zig
rename to test/stage1/behavior/switch_prong_implicit_cast.zig
index 56d37e290f1c..4ca031e2e11b 100644
--- a/test/cases/switch_prong_implicit_cast.zig
+++ b/test/stage1/behavior/switch_prong_implicit_cast.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
const FormValue = union(enum) {
One: void,
@@ -18,5 +18,5 @@ test "switch prong implicit cast" {
FormValue.One => false,
FormValue.Two => |x| x,
};
- assert(result);
+ assertOrPanic(result);
}
diff --git a/test/cases/syntax.zig b/test/stage1/behavior/syntax.zig
similarity index 99%
rename from test/cases/syntax.zig
rename to test/stage1/behavior/syntax.zig
index 0c8c3c5ed314..451e39614292 100644
--- a/test/cases/syntax.zig
+++ b/test/stage1/behavior/syntax.zig
@@ -57,3 +57,4 @@ fn asm_lists() void {
:::"a","b",);
}
}
+
diff --git a/test/cases/this.zig b/test/stage1/behavior/this.zig
similarity index 74%
rename from test/cases/this.zig
rename to test/stage1/behavior/this.zig
index c7be074f36c2..0e3a7a03ae07 100644
--- a/test/cases/this.zig
+++ b/test/stage1/behavior/this.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
const module = @This();
@@ -20,7 +20,7 @@ fn add(x: i32, y: i32) i32 {
}
test "this refer to module call private fn" {
- assert(module.add(1, 2) == 3);
+ assertOrPanic(module.add(1, 2) == 3);
}
test "this refer to container" {
@@ -29,6 +29,7 @@ test "this refer to container" {
.y = 34,
};
pt.addOne();
- assert(pt.x == 13);
- assert(pt.y == 35);
+ assertOrPanic(pt.x == 13);
+ assertOrPanic(pt.y == 35);
}
+
diff --git a/test/cases/truncate.zig b/test/stage1/behavior/truncate.zig
similarity index 65%
rename from test/cases/truncate.zig
rename to test/stage1/behavior/truncate.zig
index 02b5085ccd25..b7904bc7fbca 100644
--- a/test/cases/truncate.zig
+++ b/test/stage1/behavior/truncate.zig
@@ -1,8 +1,8 @@
const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
test "truncate u0 to larger integer allowed and has comptime known result" {
var x: u0 = 0;
const y = @truncate(u8, x);
- comptime assert(y == 0);
+ comptime assertOrPanic(y == 0);
}
diff --git a/test/cases/try.zig b/test/stage1/behavior/try.zig
similarity index 66%
rename from test/cases/try.zig
rename to test/stage1/behavior/try.zig
index 450a9af6ac0b..fb802d02c626 100644
--- a/test/cases/try.zig
+++ b/test/stage1/behavior/try.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
test "try on error union" {
tryOnErrorUnionImpl();
@@ -11,7 +11,7 @@ fn tryOnErrorUnionImpl() void {
error.CrappedOut => i32(2),
else => unreachable,
};
- assert(x == 11);
+ assertOrPanic(x == 11);
}
fn returnsTen() anyerror!i32 {
@@ -19,11 +19,11 @@ fn returnsTen() anyerror!i32 {
}
test "try without vars" {
- const result1 = if (failIfTrue(true)) 1 else |_| i32(2);
- assert(result1 == 2);
+ const result1: i32 = if (failIfTrue(true)) 1 else |_| 2;
+ assertOrPanic(result1 == 2);
- const result2 = if (failIfTrue(false)) 1 else |_| i32(2);
- assert(result2 == 1);
+ const result2: i32 = if (failIfTrue(false)) 1 else |_| 2;
+ assertOrPanic(result2 == 1);
}
fn failIfTrue(ok: bool) anyerror!void {
@@ -38,6 +38,6 @@ test "try then not executed with assignment" {
if (failIfTrue(true)) {
unreachable;
} else |err| {
- assert(err == error.ItBroke);
+ assertOrPanic(err == error.ItBroke);
}
}
diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig
new file mode 100644
index 000000000000..5ad80e06e178
--- /dev/null
+++ b/test/stage1/behavior/type_info.zig
@@ -0,0 +1,264 @@
+const assertOrPanic = @import("std").debug.assertOrPanic;
+const mem = @import("std").mem;
+const TypeInfo = @import("builtin").TypeInfo;
+const TypeId = @import("builtin").TypeId;
+
+test "type info: tag type, void info" {
+ testBasic();
+ comptime testBasic();
+}
+
+fn testBasic() void {
+ assertOrPanic(@TagType(TypeInfo) == TypeId);
+ const void_info = @typeInfo(void);
+ assertOrPanic(TypeId(void_info) == TypeId.Void);
+ assertOrPanic(void_info.Void == {});
+}
+
+test "type info: integer, floating point type info" {
+ testIntFloat();
+ comptime testIntFloat();
+}
+
+fn testIntFloat() void {
+ const u8_info = @typeInfo(u8);
+ assertOrPanic(TypeId(u8_info) == TypeId.Int);
+ assertOrPanic(!u8_info.Int.is_signed);
+ assertOrPanic(u8_info.Int.bits == 8);
+
+ const f64_info = @typeInfo(f64);
+ assertOrPanic(TypeId(f64_info) == TypeId.Float);
+ assertOrPanic(f64_info.Float.bits == 64);
+}
+
+test "type info: pointer type info" {
+ testPointer();
+ comptime testPointer();
+}
+
+fn testPointer() void {
+ const u32_ptr_info = @typeInfo(*u32);
+ assertOrPanic(TypeId(u32_ptr_info) == TypeId.Pointer);
+ assertOrPanic(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.One);
+ assertOrPanic(u32_ptr_info.Pointer.is_const == false);
+ assertOrPanic(u32_ptr_info.Pointer.is_volatile == false);
+ assertOrPanic(u32_ptr_info.Pointer.alignment == @alignOf(u32));
+ assertOrPanic(u32_ptr_info.Pointer.child == u32);
+}
+
+test "type info: unknown length pointer type info" {
+ testUnknownLenPtr();
+ comptime testUnknownLenPtr();
+}
+
+fn testUnknownLenPtr() void {
+ const u32_ptr_info = @typeInfo([*]const volatile f64);
+ assertOrPanic(TypeId(u32_ptr_info) == TypeId.Pointer);
+ assertOrPanic(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many);
+ assertOrPanic(u32_ptr_info.Pointer.is_const == true);
+ assertOrPanic(u32_ptr_info.Pointer.is_volatile == true);
+ assertOrPanic(u32_ptr_info.Pointer.alignment == @alignOf(f64));
+ assertOrPanic(u32_ptr_info.Pointer.child == f64);
+}
+
+test "type info: slice type info" {
+ testSlice();
+ comptime testSlice();
+}
+
+fn testSlice() void {
+ const u32_slice_info = @typeInfo([]u32);
+ assertOrPanic(TypeId(u32_slice_info) == TypeId.Pointer);
+ assertOrPanic(u32_slice_info.Pointer.size == TypeInfo.Pointer.Size.Slice);
+ assertOrPanic(u32_slice_info.Pointer.is_const == false);
+ assertOrPanic(u32_slice_info.Pointer.is_volatile == false);
+ assertOrPanic(u32_slice_info.Pointer.alignment == 4);
+ assertOrPanic(u32_slice_info.Pointer.child == u32);
+}
+
+test "type info: array type info" {
+ testArray();
+ comptime testArray();
+}
+
+fn testArray() void {
+ const arr_info = @typeInfo([42]bool);
+ assertOrPanic(TypeId(arr_info) == TypeId.Array);
+ assertOrPanic(arr_info.Array.len == 42);
+ assertOrPanic(arr_info.Array.child == bool);
+}
+
+test "type info: optional type info" {
+ testOptional();
+ comptime testOptional();
+}
+
+fn testOptional() void {
+ const null_info = @typeInfo(?void);
+ assertOrPanic(TypeId(null_info) == TypeId.Optional);
+ assertOrPanic(null_info.Optional.child == void);
+}
+
+test "type info: promise info" {
+ testPromise();
+ comptime testPromise();
+}
+
+fn testPromise() void {
+ const null_promise_info = @typeInfo(promise);
+ assertOrPanic(TypeId(null_promise_info) == TypeId.Promise);
+ assertOrPanic(null_promise_info.Promise.child == null);
+
+ const promise_info = @typeInfo(promise->usize);
+ assertOrPanic(TypeId(promise_info) == TypeId.Promise);
+ assertOrPanic(promise_info.Promise.child.? == usize);
+}
+
+test "type info: error set, error union info" {
+ testErrorSet();
+ comptime testErrorSet();
+}
+
+fn testErrorSet() void {
+ const TestErrorSet = error{
+ First,
+ Second,
+ Third,
+ };
+
+ const error_set_info = @typeInfo(TestErrorSet);
+ assertOrPanic(TypeId(error_set_info) == TypeId.ErrorSet);
+ assertOrPanic(error_set_info.ErrorSet.errors.len == 3);
+ assertOrPanic(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First"));
+ assertOrPanic(error_set_info.ErrorSet.errors[2].value == @errorToInt(TestErrorSet.Third));
+
+ const error_union_info = @typeInfo(TestErrorSet!usize);
+ assertOrPanic(TypeId(error_union_info) == TypeId.ErrorUnion);
+ assertOrPanic(error_union_info.ErrorUnion.error_set == TestErrorSet);
+ assertOrPanic(error_union_info.ErrorUnion.payload == usize);
+}
+
+test "type info: enum info" {
+ testEnum();
+ comptime testEnum();
+}
+
+fn testEnum() void {
+ const Os = enum {
+ Windows,
+ Macos,
+ Linux,
+ FreeBSD,
+ };
+
+ const os_info = @typeInfo(Os);
+ assertOrPanic(TypeId(os_info) == TypeId.Enum);
+ assertOrPanic(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto);
+ assertOrPanic(os_info.Enum.fields.len == 4);
+ assertOrPanic(mem.eql(u8, os_info.Enum.fields[1].name, "Macos"));
+ assertOrPanic(os_info.Enum.fields[3].value == 3);
+ assertOrPanic(os_info.Enum.tag_type == u2);
+ assertOrPanic(os_info.Enum.defs.len == 0);
+}
+
+test "type info: union info" {
+ testUnion();
+ comptime testUnion();
+}
+
+fn testUnion() void {
+ const typeinfo_info = @typeInfo(TypeInfo);
+ assertOrPanic(TypeId(typeinfo_info) == TypeId.Union);
+ assertOrPanic(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
+ assertOrPanic(typeinfo_info.Union.tag_type.? == TypeId);
+ assertOrPanic(typeinfo_info.Union.fields.len == 24);
+ assertOrPanic(typeinfo_info.Union.fields[4].enum_field != null);
+ assertOrPanic(typeinfo_info.Union.fields[4].enum_field.?.value == 4);
+ assertOrPanic(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
+ assertOrPanic(typeinfo_info.Union.defs.len == 20);
+
+ const TestNoTagUnion = union {
+ Foo: void,
+ Bar: u32,
+ };
+
+ const notag_union_info = @typeInfo(TestNoTagUnion);
+ assertOrPanic(TypeId(notag_union_info) == TypeId.Union);
+ assertOrPanic(notag_union_info.Union.tag_type == null);
+ assertOrPanic(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto);
+ assertOrPanic(notag_union_info.Union.fields.len == 2);
+ assertOrPanic(notag_union_info.Union.fields[0].enum_field == null);
+ assertOrPanic(notag_union_info.Union.fields[1].field_type == u32);
+
+ const TestExternUnion = extern union {
+ foo: *c_void,
+ };
+
+ const extern_union_info = @typeInfo(TestExternUnion);
+ assertOrPanic(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern);
+ assertOrPanic(extern_union_info.Union.tag_type == null);
+ assertOrPanic(extern_union_info.Union.fields[0].enum_field == null);
+ assertOrPanic(extern_union_info.Union.fields[0].field_type == *c_void);
+}
+
+test "type info: struct info" {
+ testStruct();
+ comptime testStruct();
+}
+
+fn testStruct() void {
+ const struct_info = @typeInfo(TestStruct);
+ assertOrPanic(TypeId(struct_info) == TypeId.Struct);
+ assertOrPanic(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed);
+ assertOrPanic(struct_info.Struct.fields.len == 3);
+ assertOrPanic(struct_info.Struct.fields[1].offset == null);
+ assertOrPanic(struct_info.Struct.fields[2].field_type == *TestStruct);
+ assertOrPanic(struct_info.Struct.defs.len == 2);
+ assertOrPanic(struct_info.Struct.defs[0].is_pub);
+ assertOrPanic(!struct_info.Struct.defs[0].data.Fn.is_extern);
+ assertOrPanic(struct_info.Struct.defs[0].data.Fn.lib_name == null);
+ assertOrPanic(struct_info.Struct.defs[0].data.Fn.return_type == void);
+ assertOrPanic(struct_info.Struct.defs[0].data.Fn.fn_type == fn (*const TestStruct) void);
+}
+
+const TestStruct = packed struct {
+ const Self = @This();
+
+ fieldA: usize,
+ fieldB: void,
+ fieldC: *Self,
+
+ pub fn foo(self: *const Self) void {}
+};
+
+test "type info: function type info" {
+ testFunction();
+ comptime testFunction();
+}
+
+fn testFunction() void {
+ const fn_info = @typeInfo(@typeOf(foo));
+ assertOrPanic(TypeId(fn_info) == TypeId.Fn);
+ assertOrPanic(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified);
+ assertOrPanic(fn_info.Fn.is_generic);
+ assertOrPanic(fn_info.Fn.args.len == 2);
+ assertOrPanic(fn_info.Fn.is_var_args);
+ assertOrPanic(fn_info.Fn.return_type == null);
+ assertOrPanic(fn_info.Fn.async_allocator_type == null);
+
+ const test_instance: TestStruct = undefined;
+ const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));
+ assertOrPanic(TypeId(bound_fn_info) == TypeId.BoundFn);
+ assertOrPanic(bound_fn_info.BoundFn.args[0].arg_type.? == *const TestStruct);
+}
+
+fn foo(comptime a: usize, b: bool, args: ...) usize {
+ return 0;
+}
+
+test "typeInfo with comptime parameter in struct fn def" {
+ const S = struct {
+ pub fn func(comptime x: f32) void {}
+ };
+ comptime var info = @typeInfo(S);
+}
diff --git a/test/cases/undefined.zig b/test/stage1/behavior/undefined.zig
similarity index 59%
rename from test/cases/undefined.zig
rename to test/stage1/behavior/undefined.zig
index 83c620d21159..333e217d493b 100644
--- a/test/cases/undefined.zig
+++ b/test/stage1/behavior/undefined.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
const mem = @import("std").mem;
fn initStaticArray() [10]i32 {
@@ -11,16 +11,16 @@ fn initStaticArray() [10]i32 {
}
const static_array = initStaticArray();
test "init static array to undefined" {
- assert(static_array[0] == 1);
- assert(static_array[4] == 2);
- assert(static_array[7] == 3);
- assert(static_array[9] == 4);
+ assertOrPanic(static_array[0] == 1);
+ assertOrPanic(static_array[4] == 2);
+ assertOrPanic(static_array[7] == 3);
+ assertOrPanic(static_array[9] == 4);
comptime {
- assert(static_array[0] == 1);
- assert(static_array[4] == 2);
- assert(static_array[7] == 3);
- assert(static_array[9] == 4);
+ assertOrPanic(static_array[0] == 1);
+ assertOrPanic(static_array[4] == 2);
+ assertOrPanic(static_array[7] == 3);
+ assertOrPanic(static_array[9] == 4);
}
}
@@ -40,12 +40,12 @@ test "assign undefined to struct" {
comptime {
var foo: Foo = undefined;
setFooX(&foo);
- assert(foo.x == 2);
+ assertOrPanic(foo.x == 2);
}
{
var foo: Foo = undefined;
setFooX(&foo);
- assert(foo.x == 2);
+ assertOrPanic(foo.x == 2);
}
}
@@ -53,16 +53,17 @@ test "assign undefined to struct with method" {
comptime {
var foo: Foo = undefined;
foo.setFooXMethod();
- assert(foo.x == 3);
+ assertOrPanic(foo.x == 3);
}
{
var foo: Foo = undefined;
foo.setFooXMethod();
- assert(foo.x == 3);
+ assertOrPanic(foo.x == 3);
}
}
test "type name of undefined" {
const x = undefined;
- assert(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)"));
+ assertOrPanic(mem.eql(u8, @typeName(@typeOf(x)), "(undefined)"));
}
+
diff --git a/test/cases/underscore.zig b/test/stage1/behavior/underscore.zig
similarity index 91%
rename from test/cases/underscore.zig
rename to test/stage1/behavior/underscore.zig
index da1c97659cf3..7443319336b0 100644
--- a/test/cases/underscore.zig
+++ b/test/stage1/behavior/underscore.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
test "ignore lval with underscore" {
_ = false;
diff --git a/test/cases/union.zig b/test/stage1/behavior/union.zig
similarity index 77%
rename from test/cases/union.zig
rename to test/stage1/behavior/union.zig
index 019a7012daf0..c8e8feb11ea6 100644
--- a/test/cases/union.zig
+++ b/test/stage1/behavior/union.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
const Value = union(enum) {
Int: u64,
@@ -27,11 +27,11 @@ const array = []Value{
test "unions embedded in aggregate types" {
switch (array[1]) {
- Value.Array => |arr| assert(arr[4] == 3),
+ Value.Array => |arr| assertOrPanic(arr[4] == 3),
else => unreachable,
}
switch ((err catch unreachable).val1) {
- Value.Int => |x| assert(x == 1234),
+ Value.Int => |x| assertOrPanic(x == 1234),
else => unreachable,
}
}
@@ -43,18 +43,18 @@ const Foo = union {
test "basic unions" {
var foo = Foo{ .int = 1 };
- assert(foo.int == 1);
+ assertOrPanic(foo.int == 1);
foo = Foo{ .float = 12.34 };
- assert(foo.float == 12.34);
+ assertOrPanic(foo.float == 12.34);
}
test "comptime union field access" {
comptime {
var foo = Foo{ .int = 0 };
- assert(foo.int == 0);
+ assertOrPanic(foo.int == 0);
foo = Foo{ .float = 42.42 };
- assert(foo.float == 42.42);
+ assertOrPanic(foo.float == 42.42);
}
}
@@ -62,10 +62,10 @@ test "init union with runtime value" {
var foo: Foo = undefined;
setFloat(&foo, 12.34);
- assert(foo.float == 12.34);
+ assertOrPanic(foo.float == 12.34);
setInt(&foo, 42);
- assert(foo.int == 42);
+ assertOrPanic(foo.int == 42);
}
fn setFloat(foo: *Foo, x: f64) void {
@@ -83,9 +83,9 @@ const FooExtern = extern union {
test "basic extern unions" {
var foo = FooExtern{ .int = 1 };
- assert(foo.int == 1);
+ assertOrPanic(foo.int == 1);
foo.float = 12.34;
- assert(foo.float == 12.34);
+ assertOrPanic(foo.float == 12.34);
}
const Letter = enum {
@@ -105,11 +105,11 @@ test "union with specified enum tag" {
}
fn doTest() void {
- assert(bar(Payload{ .A = 1234 }) == -10);
+ assertOrPanic(bar(Payload{ .A = 1234 }) == -10);
}
fn bar(value: Payload) i32 {
- assert(Letter(value) == Letter.A);
+ assertOrPanic(Letter(value) == Letter.A);
return switch (value) {
Payload.A => |x| return x - 1244,
Payload.B => |x| if (x == 12.34) i32(20) else 21,
@@ -125,8 +125,8 @@ const MultipleChoice = union(enum(u32)) {
};
test "simple union(enum(u32))" {
var x = MultipleChoice.C;
- assert(x == MultipleChoice.C);
- assert(@enumToInt(@TagType(MultipleChoice)(x)) == 60);
+ assertOrPanic(x == MultipleChoice.C);
+ assertOrPanic(@enumToInt(@TagType(MultipleChoice)(x)) == 60);
}
const MultipleChoice2 = union(enum(u32)) {
@@ -142,14 +142,14 @@ const MultipleChoice2 = union(enum(u32)) {
};
test "union(enum(u32)) with specified and unspecified tag values" {
- comptime assert(@TagType(@TagType(MultipleChoice2)) == u32);
+ comptime assertOrPanic(@TagType(@TagType(MultipleChoice2)) == u32);
testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
}
fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
- assert(@enumToInt(@TagType(MultipleChoice2)(x)) == 60);
- assert(1123 == switch (x) {
+ assertOrPanic(@enumToInt(@TagType(MultipleChoice2)(x)) == 60);
+ assertOrPanic(1123 == switch (x) {
MultipleChoice2.A => 1,
MultipleChoice2.B => 2,
MultipleChoice2.C => |v| i32(1000) + v,
@@ -167,7 +167,7 @@ const ExternPtrOrInt = extern union {
int: u64,
};
test "extern union size" {
- comptime assert(@sizeOf(ExternPtrOrInt) == 8);
+ comptime assertOrPanic(@sizeOf(ExternPtrOrInt) == 8);
}
const PackedPtrOrInt = packed union {
@@ -175,14 +175,14 @@ const PackedPtrOrInt = packed union {
int: u64,
};
test "extern union size" {
- comptime assert(@sizeOf(PackedPtrOrInt) == 8);
+ comptime assertOrPanic(@sizeOf(PackedPtrOrInt) == 8);
}
const ZeroBits = union {
OnlyField: void,
};
test "union with only 1 field which is void should be zero bits" {
- comptime assert(@sizeOf(ZeroBits) == 0);
+ comptime assertOrPanic(@sizeOf(ZeroBits) == 0);
}
const TheTag = enum {
@@ -196,9 +196,9 @@ const TheUnion = union(TheTag) {
C: i32,
};
test "union field access gives the enum values" {
- assert(TheUnion.A == TheTag.A);
- assert(TheUnion.B == TheTag.B);
- assert(TheUnion.C == TheTag.C);
+ assertOrPanic(TheUnion.A == TheTag.A);
+ assertOrPanic(TheUnion.B == TheTag.B);
+ assertOrPanic(TheUnion.C == TheTag.C);
}
test "cast union to tag type of union" {
@@ -207,12 +207,12 @@ test "cast union to tag type of union" {
}
fn testCastUnionToTagType(x: TheUnion) void {
- assert(TheTag(x) == TheTag.B);
+ assertOrPanic(TheTag(x) == TheTag.B);
}
test "cast tag type of union to union" {
var x: Value2 = Letter2.B;
- assert(Letter2(x) == Letter2.B);
+ assertOrPanic(Letter2(x) == Letter2.B);
}
const Letter2 = enum {
A,
@@ -227,11 +227,11 @@ const Value2 = union(Letter2) {
test "implicit cast union to its tag type" {
var x: Value2 = Letter2.B;
- assert(x == Letter2.B);
+ assertOrPanic(x == Letter2.B);
giveMeLetterB(x);
}
fn giveMeLetterB(x: Letter2) void {
- assert(x == Value2.B);
+ assertOrPanic(x == Value2.B);
}
pub const PackThis = union(enum) {
@@ -244,7 +244,7 @@ test "constant packed union" {
}
fn testConstPackedUnion(expected_tokens: []const PackThis) void {
- assert(expected_tokens[0].StringLiteral == 1);
+ assertOrPanic(expected_tokens[0].StringLiteral == 1);
}
test "switch on union with only 1 field" {
@@ -256,7 +256,7 @@ test "switch on union with only 1 field" {
z = PartialInstWithPayload{ .Compiled = 1234 };
switch (z) {
PartialInstWithPayload.Compiled => |x| {
- assert(x == 1234);
+ assertOrPanic(x == 1234);
return;
},
}
@@ -282,11 +282,11 @@ test "access a member of tagged union with conflicting enum tag name" {
const B = void;
};
- comptime assert(Bar.A == u8);
+ comptime assertOrPanic(Bar.A == u8);
}
test "tagged union initialization with runtime void" {
- assert(testTaggedUnionInit({}));
+ assertOrPanic(testTaggedUnionInit({}));
}
const TaggedUnionWithAVoid = union(enum) {
@@ -324,9 +324,9 @@ test "union with only 1 field casted to its enum type" {
var e = Expr{ .Literal = Literal{ .Bool = true } };
const Tag = @TagType(Expr);
- comptime assert(@TagType(Tag) == comptime_int);
+ comptime assertOrPanic(@TagType(Tag) == comptime_int);
var t = Tag(e);
- assert(t == Expr.Literal);
+ assertOrPanic(t == Expr.Literal);
}
test "union with only 1 field casted to its enum type which has enum value specified" {
@@ -344,9 +344,9 @@ test "union with only 1 field casted to its enum type which has enum value speci
};
var e = Expr{ .Literal = Literal{ .Bool = true } };
- comptime assert(@TagType(Tag) == comptime_int);
+ comptime assertOrPanic(@TagType(Tag) == comptime_int);
var t = Tag(e);
- assert(t == Expr.Literal);
- assert(@enumToInt(t) == 33);
- comptime assert(@enumToInt(t) == 33);
+ assertOrPanic(t == Expr.Literal);
+ assertOrPanic(@enumToInt(t) == 33);
+ comptime assertOrPanic(@enumToInt(t) == 33);
}
diff --git a/test/cases/var_args.zig b/test/stage1/behavior/var_args.zig
similarity index 56%
rename from test/cases/var_args.zig
rename to test/stage1/behavior/var_args.zig
index 3eb6e304486b..1f782a3bb3a3 100644
--- a/test/cases/var_args.zig
+++ b/test/stage1/behavior/var_args.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
fn add(args: ...) i32 {
var sum = i32(0);
@@ -12,9 +12,9 @@ fn add(args: ...) i32 {
}
test "add arbitrary args" {
- assert(add(i32(1), i32(2), i32(3), i32(4)) == 10);
- assert(add(i32(1234)) == 1234);
- assert(add() == 0);
+ assertOrPanic(add(i32(1), i32(2), i32(3), i32(4)) == 10);
+ assertOrPanic(add(i32(1234)) == 1234);
+ assertOrPanic(add() == 0);
}
fn readFirstVarArg(args: ...) void {
@@ -26,9 +26,9 @@ test "send void arg to var args" {
}
test "pass args directly" {
- assert(addSomeStuff(i32(1), i32(2), i32(3), i32(4)) == 10);
- assert(addSomeStuff(i32(1234)) == 1234);
- assert(addSomeStuff() == 0);
+ assertOrPanic(addSomeStuff(i32(1), i32(2), i32(3), i32(4)) == 10);
+ assertOrPanic(addSomeStuff(i32(1234)) == 1234);
+ assertOrPanic(addSomeStuff() == 0);
}
fn addSomeStuff(args: ...) i32 {
@@ -36,24 +36,24 @@ fn addSomeStuff(args: ...) i32 {
}
test "runtime parameter before var args" {
- assert(extraFn(10) == 0);
- assert(extraFn(10, false) == 1);
- assert(extraFn(10, false, true) == 2);
+ assertOrPanic(extraFn(10) == 0);
+ assertOrPanic(extraFn(10, false) == 1);
+ assertOrPanic(extraFn(10, false, true) == 2);
// TODO issue #313
//comptime {
- // assert(extraFn(10) == 0);
- // assert(extraFn(10, false) == 1);
- // assert(extraFn(10, false, true) == 2);
+ // assertOrPanic(extraFn(10) == 0);
+ // assertOrPanic(extraFn(10, false) == 1);
+ // assertOrPanic(extraFn(10, false, true) == 2);
//}
}
fn extraFn(extra: u32, args: ...) usize {
if (args.len >= 1) {
- assert(args[0] == false);
+ assertOrPanic(args[0] == false);
}
if (args.len >= 2) {
- assert(args[1] == true);
+ assertOrPanic(args[1] == true);
}
return args.len;
}
@@ -71,8 +71,8 @@ fn foo2(args: ...) bool {
}
test "array of var args functions" {
- assert(foos[0]());
- assert(!foos[1]());
+ assertOrPanic(foos[0]());
+ assertOrPanic(!foos[1]());
}
test "pass zero length array to var args param" {
diff --git a/test/cases/void.zig b/test/stage1/behavior/void.zig
similarity index 67%
rename from test/cases/void.zig
rename to test/stage1/behavior/void.zig
index 7121ac664b94..431d3f4eb103 100644
--- a/test/cases/void.zig
+++ b/test/stage1/behavior/void.zig
@@ -1,4 +1,4 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
const Foo = struct {
a: void,
@@ -13,14 +13,14 @@ test "compare void with void compile time known" {
.b = 1,
.c = {},
};
- assert(foo.a == {});
+ assertOrPanic(foo.a == {});
}
}
test "iterate over a void slice" {
var j: usize = 0;
for (times(10)) |_, i| {
- assert(i == j);
+ assertOrPanic(i == j);
j += 1;
}
}
@@ -28,3 +28,8 @@ test "iterate over a void slice" {
fn times(n: usize) []const void {
return ([*]void)(undefined)[0..n];
}
+
+test "void optional" {
+ var x: ?void = {};
+ assertOrPanic(x != null);
+}
diff --git a/test/cases/while.zig b/test/stage1/behavior/while.zig
similarity index 83%
rename from test/cases/while.zig
rename to test/stage1/behavior/while.zig
index f774e0ec6b32..579b4e4db852 100644
--- a/test/cases/while.zig
+++ b/test/stage1/behavior/while.zig
@@ -1,12 +1,12 @@
-const assert = @import("std").debug.assert;
+const assertOrPanic = @import("std").debug.assertOrPanic;
test "while loop" {
var i: i32 = 0;
while (i < 4) {
i += 1;
}
- assert(i == 4);
- assert(whileLoop1() == 1);
+ assertOrPanic(i == 4);
+ assertOrPanic(whileLoop1() == 1);
}
fn whileLoop1() i32 {
return whileLoop2();
@@ -16,8 +16,9 @@ fn whileLoop2() i32 {
return 1;
}
}
+
test "static eval while" {
- assert(static_eval_while_number == 1);
+ assertOrPanic(static_eval_while_number == 1);
}
const static_eval_while_number = staticWhileLoop1();
fn staticWhileLoop1() i32 {
@@ -31,7 +32,7 @@ fn staticWhileLoop2() i32 {
test "continue and break" {
runContinueAndBreakTest();
- assert(continue_and_break_counter == 8);
+ assertOrPanic(continue_and_break_counter == 8);
}
var continue_and_break_counter: i32 = 0;
fn runContinueAndBreakTest() void {
@@ -44,7 +45,7 @@ fn runContinueAndBreakTest() void {
}
break;
}
- assert(i == 4);
+ assertOrPanic(i == 4);
}
test "return with implicit cast from while loop" {
@@ -65,7 +66,7 @@ test "while with continue expression" {
sum += i;
}
}
- assert(sum == 40);
+ assertOrPanic(sum == 40);
}
test "while with else" {
@@ -77,8 +78,8 @@ test "while with else" {
} else {
got_else += 1;
}
- assert(sum == 10);
- assert(got_else == 1);
+ assertOrPanic(sum == 10);
+ assertOrPanic(got_else == 1);
}
test "while with optional as condition" {
@@ -87,7 +88,7 @@ test "while with optional as condition" {
while (getNumberOrNull()) |value| {
sum += value;
}
- assert(sum == 45);
+ assertOrPanic(sum == 45);
}
test "while with optional as condition with else" {
@@ -96,12 +97,12 @@ test "while with optional as condition with else" {
var got_else: i32 = 0;
while (getNumberOrNull()) |value| {
sum += value;
- assert(got_else == 0);
+ assertOrPanic(got_else == 0);
} else {
got_else += 1;
}
- assert(sum == 45);
- assert(got_else == 1);
+ assertOrPanic(sum == 45);
+ assertOrPanic(got_else == 1);
}
test "while with error union condition" {
@@ -111,11 +112,11 @@ test "while with error union condition" {
while (getNumberOrErr()) |value| {
sum += value;
} else |err| {
- assert(err == error.OutOfNumbers);
+ assertOrPanic(err == error.OutOfNumbers);
got_else += 1;
}
- assert(sum == 45);
- assert(got_else == 1);
+ assertOrPanic(sum == 45);
+ assertOrPanic(got_else == 1);
}
var numbers_left: i32 = undefined;
@@ -137,7 +138,7 @@ test "while on optional with else result follow else prong" {
break value;
} else
i32(2);
- assert(result == 2);
+ assertOrPanic(result == 2);
}
test "while on optional with else result follow break prong" {
@@ -145,7 +146,7 @@ test "while on optional with else result follow break prong" {
break value;
} else
i32(2);
- assert(result == 10);
+ assertOrPanic(result == 10);
}
test "while on error union with else result follow else prong" {
@@ -153,7 +154,7 @@ test "while on error union with else result follow else prong" {
break value;
} else |err|
i32(2);
- assert(result == 2);
+ assertOrPanic(result == 2);
}
test "while on error union with else result follow break prong" {
@@ -161,7 +162,7 @@ test "while on error union with else result follow break prong" {
break value;
} else |err|
i32(2);
- assert(result == 10);
+ assertOrPanic(result == 10);
}
test "while on bool with else result follow else prong" {
@@ -169,7 +170,7 @@ test "while on bool with else result follow else prong" {
break i32(10);
} else
i32(2);
- assert(result == 2);
+ assertOrPanic(result == 2);
}
test "while on bool with else result follow break prong" {
@@ -177,7 +178,7 @@ test "while on bool with else result follow break prong" {
break i32(10);
} else
i32(2);
- assert(result == 10);
+ assertOrPanic(result == 10);
}
test "break from outer while loop" {
diff --git a/test/cases/widening.zig b/test/stage1/behavior/widening.zig
similarity index 75%
rename from test/cases/widening.zig
rename to test/stage1/behavior/widening.zig
index cf6ab4ca0fb4..7577868aff54 100644
--- a/test/cases/widening.zig
+++ b/test/stage1/behavior/widening.zig
@@ -1,5 +1,5 @@
const std = @import("std");
-const assert = std.debug.assert;
+const assertOrPanic = std.debug.assertOrPanic;
const mem = std.mem;
test "integer widening" {
@@ -9,13 +9,13 @@ test "integer widening" {
var d: u64 = c;
var e: u64 = d;
var f: u128 = e;
- assert(f == a);
+ assertOrPanic(f == a);
}
test "implicit unsigned integer to signed integer" {
var a: u8 = 250;
var b: i16 = a;
- assert(b == 250);
+ assertOrPanic(b == 250);
}
test "float widening" {
@@ -23,5 +23,6 @@ test "float widening" {
var b: f32 = a;
var c: f64 = b;
var d: f128 = c;
- assert(d == a);
+ assertOrPanic(d == a);
}
+