mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
add zeroes value
This commit is contained in:
parent
0d5ecc4312
commit
2ed949a6ae
@ -151,7 +151,7 @@ GotoExpression = "goto" Symbol
|
||||
|
||||
GroupedExpression = "(" Expression ")"
|
||||
|
||||
KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type"
|
||||
KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "zeroes" | "error" | "type"
|
||||
```
|
||||
|
||||
## Operator Precedence
|
||||
|
||||
@ -62,11 +62,18 @@ struct ConstErrValue {
|
||||
ConstExprValue *payload;
|
||||
};
|
||||
|
||||
struct ConstExprValue {
|
||||
bool ok; // true if constant expression evalution worked
|
||||
bool depends_on_compile_var;
|
||||
bool undef;
|
||||
enum ConstValSpecial {
|
||||
ConstValSpecialOther,
|
||||
ConstValSpecialUndef,
|
||||
ConstValSpecialZeroes,
|
||||
};
|
||||
|
||||
struct ConstExprValue {
|
||||
bool ok;
|
||||
bool depends_on_compile_var;
|
||||
ConstValSpecial special;
|
||||
|
||||
// populated if val_type == ConstValTypeOk
|
||||
union {
|
||||
BigNum x_bignum;
|
||||
bool x_bool;
|
||||
@ -167,6 +174,7 @@ enum NodeType {
|
||||
NodeTypeBoolLiteral,
|
||||
NodeTypeNullLiteral,
|
||||
NodeTypeUndefinedLiteral,
|
||||
NodeTypeZeroesLiteral,
|
||||
NodeTypeIfBoolExpr,
|
||||
NodeTypeIfVarExpr,
|
||||
NodeTypeWhileExpr,
|
||||
@ -694,6 +702,12 @@ struct AstNodeUndefinedLiteral {
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeZeroesLiteral {
|
||||
// populated by semantic analyzer
|
||||
StructValExprCodeGen resolved_struct_val_expr;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeSymbolExpr {
|
||||
Buf *symbol;
|
||||
|
||||
@ -791,6 +805,7 @@ struct AstNode {
|
||||
AstNodeStructValueField struct_val_field;
|
||||
AstNodeNullLiteral null_literal;
|
||||
AstNodeUndefinedLiteral undefined_literal;
|
||||
AstNodeZeroesLiteral zeroes_literal;
|
||||
AstNodeSymbolExpr symbol_expr;
|
||||
AstNodeBoolLiteral bool_literal;
|
||||
AstNodeBreakExpr break_expr;
|
||||
|
||||
@ -90,6 +90,7 @@ static AstNode *first_executing_node(AstNode *node) {
|
||||
case NodeTypeBoolLiteral:
|
||||
case NodeTypeNullLiteral:
|
||||
case NodeTypeUndefinedLiteral:
|
||||
case NodeTypeZeroesLiteral:
|
||||
case NodeTypeIfBoolExpr:
|
||||
case NodeTypeIfVarExpr:
|
||||
case NodeTypeLabel:
|
||||
@ -1849,6 +1850,7 @@ static void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only)
|
||||
case NodeTypeBoolLiteral:
|
||||
case NodeTypeNullLiteral:
|
||||
case NodeTypeUndefinedLiteral:
|
||||
case NodeTypeZeroesLiteral:
|
||||
case NodeTypeSymbol:
|
||||
case NodeTypePrefixOpExpr:
|
||||
case NodeTypeIfBoolExpr:
|
||||
@ -3937,7 +3939,19 @@ static TypeTableEntry *analyze_undefined_literal_expr(CodeGen *g, ImportTableEnt
|
||||
ConstExprValue *const_val = &expr->const_val;
|
||||
|
||||
const_val->ok = true;
|
||||
const_val->undef = true;
|
||||
const_val->special = ConstValSpecialUndef;
|
||||
|
||||
return expected_type ? expected_type : g->builtin_types.entry_undef;
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_zeroes_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
TypeTableEntry *expected_type, AstNode *node)
|
||||
{
|
||||
Expr *expr = get_resolved_expr(node);
|
||||
ConstExprValue *const_val = &expr->const_val;
|
||||
|
||||
const_val->ok = true;
|
||||
const_val->special = ConstValSpecialZeroes;
|
||||
|
||||
return expected_type ? expected_type : g->builtin_types.entry_undef;
|
||||
}
|
||||
@ -4252,7 +4266,7 @@ static TypeTableEntry *analyze_if_bool_expr(CodeGen *g, ImportTableEntry *import
|
||||
}
|
||||
|
||||
ConstExprValue *cond_val = &get_resolved_expr(*cond)->const_val;
|
||||
if (cond_val->undef) {
|
||||
if (cond_val->special == ConstValSpecialUndef) {
|
||||
add_node_error(g, first_executing_node(*cond), buf_sprintf("branch on undefined value"));
|
||||
return cond_type;
|
||||
}
|
||||
@ -6504,6 +6518,9 @@ static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEn
|
||||
case NodeTypeUndefinedLiteral:
|
||||
return_type = analyze_undefined_literal_expr(g, import, context, expected_type, node);
|
||||
break;
|
||||
case NodeTypeZeroesLiteral:
|
||||
return_type = analyze_zeroes_literal_expr(g, import, context, expected_type, node);
|
||||
break;
|
||||
case NodeTypeSymbol:
|
||||
return_type = analyze_symbol_expr(g, import, context, expected_type, node, pointer_only);
|
||||
break;
|
||||
@ -6771,6 +6788,7 @@ static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *conte
|
||||
case NodeTypeBoolLiteral:
|
||||
case NodeTypeNullLiteral:
|
||||
case NodeTypeUndefinedLiteral:
|
||||
case NodeTypeZeroesLiteral:
|
||||
case NodeTypeSymbol:
|
||||
case NodeTypePrefixOpExpr:
|
||||
case NodeTypeIfBoolExpr:
|
||||
@ -7029,6 +7047,8 @@ Expr *get_resolved_expr(AstNode *node) {
|
||||
return &node->data.null_literal.resolved_expr;
|
||||
case NodeTypeUndefinedLiteral:
|
||||
return &node->data.undefined_literal.resolved_expr;
|
||||
case NodeTypeZeroesLiteral:
|
||||
return &node->data.zeroes_literal.resolved_expr;
|
||||
case NodeTypeGoto:
|
||||
return &node->data.goto_expr.resolved_expr;
|
||||
case NodeTypeBreak:
|
||||
@ -7111,6 +7131,7 @@ static TopLevelDecl *get_as_top_level_decl(AstNode *node) {
|
||||
case NodeTypeBoolLiteral:
|
||||
case NodeTypeNullLiteral:
|
||||
case NodeTypeUndefinedLiteral:
|
||||
case NodeTypeZeroesLiteral:
|
||||
case NodeTypeLabel:
|
||||
case NodeTypeGoto:
|
||||
case NodeTypeBreak:
|
||||
|
||||
@ -171,6 +171,8 @@ static const char *node_type_str(NodeType node_type) {
|
||||
return "NullLiteral";
|
||||
case NodeTypeUndefinedLiteral:
|
||||
return "UndefinedLiteral";
|
||||
case NodeTypeZeroesLiteral:
|
||||
return "ZeroesLiteral";
|
||||
case NodeTypeIfBoolExpr:
|
||||
return "IfBoolExpr";
|
||||
case NodeTypeIfVarExpr:
|
||||
@ -591,6 +593,8 @@ static void render_node(AstRender *ar, AstNode *node) {
|
||||
zig_panic("TODO");
|
||||
case NodeTypeUndefinedLiteral:
|
||||
zig_panic("TODO");
|
||||
case NodeTypeZeroesLiteral:
|
||||
zig_panic("TODO");
|
||||
case NodeTypeIfBoolExpr:
|
||||
zig_panic("TODO");
|
||||
case NodeTypeIfVarExpr:
|
||||
|
||||
@ -3141,11 +3141,15 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
|
||||
}
|
||||
|
||||
bool have_init_expr = false;
|
||||
bool want_zeroes = false;
|
||||
if (var_decl->expr) {
|
||||
ConstExprValue *const_val = &get_resolved_expr(var_decl->expr)->const_val;
|
||||
if (!const_val->ok || !const_val->undef) {
|
||||
if (!const_val->ok || const_val->special == ConstValSpecialOther) {
|
||||
have_init_expr = true;
|
||||
}
|
||||
if (const_val->ok && const_val->special == ConstValSpecialZeroes) {
|
||||
want_zeroes = true;
|
||||
}
|
||||
}
|
||||
if (have_init_expr) {
|
||||
TypeTableEntry *expr_type = get_expr_type(var_decl->expr);
|
||||
@ -3204,7 +3208,8 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ignore_uninit && want_debug_safety(g, source_node)) {
|
||||
bool want_safe = want_debug_safety(g, source_node);
|
||||
if (!ignore_uninit && (want_safe || want_zeroes)) {
|
||||
TypeTableEntry *usize = g->builtin_types.entry_usize;
|
||||
uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, variable->type->type_ref);
|
||||
uint64_t align_bytes = get_memcpy_align(g, variable->type);
|
||||
@ -3212,7 +3217,7 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
|
||||
// memset uninitialized memory to 0xa
|
||||
set_debug_source_node(g, source_node);
|
||||
LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
|
||||
LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
|
||||
LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), want_zeroes ? 0x00 : 0xaa, false);
|
||||
LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, variable->value_ref, ptr_u8, "");
|
||||
LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false);
|
||||
LLVMValueRef align_in_bytes = LLVMConstInt(LLVMInt32Type(), align_bytes, false);
|
||||
@ -3535,6 +3540,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
|
||||
case NodeTypeCharLiteral:
|
||||
case NodeTypeNullLiteral:
|
||||
case NodeTypeUndefinedLiteral:
|
||||
case NodeTypeZeroesLiteral:
|
||||
case NodeTypeErrorType:
|
||||
case NodeTypeTypeLiteral:
|
||||
case NodeTypeArrayType:
|
||||
@ -3562,8 +3568,14 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
|
||||
static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val) {
|
||||
assert(const_val->ok);
|
||||
|
||||
if (const_val->undef) {
|
||||
return LLVMGetUndef(type_entry->type_ref);
|
||||
switch (const_val->special) {
|
||||
case ConstValSpecialUndef:
|
||||
return LLVMGetUndef(type_entry->type_ref);
|
||||
case ConstValSpecialZeroes:
|
||||
return LLVMConstNull(type_entry->type_ref);
|
||||
case ConstValSpecialOther:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
switch (type_entry->id) {
|
||||
|
||||
@ -545,7 +545,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
|
||||
ConstExprValue *const_val, TypeTableEntry *new_type)
|
||||
{
|
||||
const_val->depends_on_compile_var = other_val->depends_on_compile_var;
|
||||
const_val->undef = other_val->undef;
|
||||
const_val->special = other_val->special;
|
||||
|
||||
assert(other_val != const_val);
|
||||
switch (cast_op) {
|
||||
@ -572,7 +572,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
|
||||
const_val->data.x_ptr.ptr = ptr_val;
|
||||
const_val->data.x_ptr.len = 1;
|
||||
const_val->ok = true;
|
||||
const_val->undef = other_val->undef;
|
||||
const_val->special = other_val->special;
|
||||
const_val->depends_on_compile_var = other_val->depends_on_compile_var;
|
||||
} else {
|
||||
zig_panic("TODO");
|
||||
@ -608,7 +608,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
|
||||
|
||||
const_val->data.x_maybe = ptr_parent;
|
||||
const_val->ok = true;
|
||||
const_val->undef = other_val->undef;
|
||||
const_val->special = other_val->special;
|
||||
const_val->depends_on_compile_var = other_val->depends_on_compile_var;
|
||||
} else {
|
||||
zig_panic("TODO");
|
||||
@ -1277,6 +1277,7 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
|
||||
case NodeTypeSliceExpr:
|
||||
case NodeTypeNullLiteral:
|
||||
case NodeTypeUndefinedLiteral:
|
||||
case NodeTypeZeroesLiteral:
|
||||
case NodeTypeIfVarExpr:
|
||||
case NodeTypeSwitchExpr:
|
||||
case NodeTypeSwitchProng:
|
||||
|
||||
@ -606,7 +606,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand
|
||||
|
||||
/*
|
||||
PrimaryExpression = "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." "Symbol")
|
||||
KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type"
|
||||
KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "zeroes" | "error" | "type"
|
||||
*/
|
||||
static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
|
||||
Token *token = &pc->tokens->at(*token_index);
|
||||
@ -654,6 +654,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
|
||||
AstNode *node = ast_create_node(pc, NodeTypeUndefinedLiteral, token);
|
||||
*token_index += 1;
|
||||
return node;
|
||||
} else if (token->id == TokenIdKeywordZeroes) {
|
||||
AstNode *node = ast_create_node(pc, NodeTypeZeroesLiteral, token);
|
||||
*token_index += 1;
|
||||
return node;
|
||||
} else if (token->id == TokenIdKeywordType) {
|
||||
AstNode *node = ast_create_node(pc, NodeTypeTypeLiteral, token);
|
||||
*token_index += 1;
|
||||
@ -2539,6 +2543,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
|
||||
case NodeTypeUndefinedLiteral:
|
||||
// none
|
||||
break;
|
||||
case NodeTypeZeroesLiteral:
|
||||
// none
|
||||
break;
|
||||
case NodeTypeIfBoolExpr:
|
||||
visit_field(&node->data.if_bool_expr.condition, visit, context);
|
||||
visit_field(&node->data.if_bool_expr.then_block, visit, context);
|
||||
@ -2813,6 +2820,9 @@ AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index,
|
||||
case NodeTypeUndefinedLiteral:
|
||||
// none
|
||||
break;
|
||||
case NodeTypeZeroesLiteral:
|
||||
// none
|
||||
break;
|
||||
case NodeTypeIfBoolExpr:
|
||||
clone_subtree_field(&new_node->data.if_bool_expr.condition, old_node->data.if_bool_expr.condition, next_node_index);
|
||||
clone_subtree_field(&new_node->data.if_bool_expr.then_block, old_node->data.if_bool_expr.then_block, next_node_index);
|
||||
|
||||
@ -137,6 +137,7 @@ static const struct ZigKeyword zig_keywords[] = {
|
||||
{"var", TokenIdKeywordVar},
|
||||
{"volatile", TokenIdKeywordVolatile},
|
||||
{"while", TokenIdKeywordWhile},
|
||||
{"zeroes", TokenIdKeywordZeroes},
|
||||
};
|
||||
|
||||
bool is_zig_keyword(Buf *buf) {
|
||||
@ -1467,6 +1468,7 @@ const char * token_name(TokenId id) {
|
||||
case TokenIdKeywordNoAlias: return "noalias";
|
||||
case TokenIdKeywordSwitch: return "switch";
|
||||
case TokenIdKeywordUndefined: return "undefined";
|
||||
case TokenIdKeywordZeroes: return "zeroes";
|
||||
case TokenIdKeywordError: return "error";
|
||||
case TokenIdKeywordType: return "type";
|
||||
case TokenIdKeywordInline: return "inline";
|
||||
|
||||
@ -40,6 +40,7 @@ enum TokenId {
|
||||
TokenIdKeywordNoAlias,
|
||||
TokenIdKeywordSwitch,
|
||||
TokenIdKeywordUndefined,
|
||||
TokenIdKeywordZeroes,
|
||||
TokenIdKeywordError,
|
||||
TokenIdKeywordType,
|
||||
TokenIdKeywordInline,
|
||||
|
||||
18
test/cases/zeroes.zig
Normal file
18
test/cases/zeroes.zig
Normal file
@ -0,0 +1,18 @@
|
||||
const assert = @import("std").debug.assert;
|
||||
|
||||
struct Foo {
|
||||
a: f32,
|
||||
b: i32,
|
||||
c: bool,
|
||||
d: ?i32,
|
||||
}
|
||||
|
||||
#attribute("test")
|
||||
fn initializing_a_struct_with_zeroes() {
|
||||
const foo: Foo = zeroes;
|
||||
assert(foo.a == 0.0);
|
||||
assert(foo.b == 0);
|
||||
assert(foo.c == false);
|
||||
assert(if (const x ?= foo.d) false else true);
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ const str = std.str;
|
||||
const cstr = std.cstr;
|
||||
const other = @import("other.zig");
|
||||
const cases_return_type_type = @import("cases/return_type_type.zig");
|
||||
const test_zeroes = @import("cases/zeroes.zig");
|
||||
|
||||
// normal comment
|
||||
/// this is a documentation comment
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user