Commit e269caae02

Andrew Kelley <superjoe30@gmail.com>
2016-01-23 07:12:33
implement undefined literal
1 parent 0e51c16
src/all_types.hpp
@@ -62,6 +62,7 @@ struct ConstPtrValue {
 struct ConstExprValue {
     bool ok; // true if constant expression evalution worked
     bool depends_on_compile_var;
+    bool undef;
 
     union {
         BigNum x_bignum;
@@ -808,6 +809,7 @@ enum TypeTableEntryId {
     TypeTableEntryIdStruct,
     TypeTableEntryIdNumLitFloat,
     TypeTableEntryIdNumLitInt,
+    TypeTableEntryIdUndefLit,
     TypeTableEntryIdMaybe,
     TypeTableEntryIdError,
     TypeTableEntryIdEnum,
@@ -949,6 +951,7 @@ struct CodeGen {
         TypeTableEntry *entry_invalid;
         TypeTableEntry *entry_num_lit_int;
         TypeTableEntry *entry_num_lit_float;
+        TypeTableEntry *entry_undef;
     } builtin_types;
 
     LLVMTargetDataRef target_data_ref;
src/analyze.cpp
@@ -111,6 +111,7 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {
         case TypeTableEntryIdMaybe:
         case TypeTableEntryIdFn:
         case TypeTableEntryIdError:
+        case TypeTableEntryIdUndefLit:
             // nothing to init
             break;
         case TypeTableEntryIdStruct:
@@ -1063,6 +1064,7 @@ static bool type_has_codegen_value(TypeTableEntryId id) {
         case TypeTableEntryIdUnreachable:
         case TypeTableEntryIdNumLitFloat:
         case TypeTableEntryIdNumLitInt:
+        case TypeTableEntryIdUndefLit:
             return false;
 
         case TypeTableEntryIdBool:
@@ -2481,10 +2483,9 @@ static TypeTableEntry *analyze_undefined_literal_expr(CodeGen *g, ImportTableEnt
     ConstExprValue *const_val = &expr->const_val;
 
     const_val->ok = true;
+    const_val->undef = true;
 
-    zig_panic("TODO");
-
-    return expected_type;
+    return expected_type ? expected_type : g->builtin_types.entry_undef;
 }
 
 
src/codegen.cpp
@@ -1725,84 +1725,91 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
     }
     if (variable->type->size_in_bits == 0) {
         return nullptr;
-    } else {
-        if (var_decl->expr) {
-            TypeTableEntry *expr_type = get_expr_type(var_decl->expr);
-            LLVMValueRef value;
-            if (unwrap_maybe) {
-                assert(var_decl->expr);
-                assert(expr_type->id == TypeTableEntryIdMaybe);
-                value = gen_unwrap_maybe(g, source_node, *init_value);
-                expr_type = expr_type->data.maybe.child_type;
-            } else {
-                value = *init_value;
-            }
-            gen_assign_raw(g, var_decl->expr, BinOpTypeAssign, variable->value_ref,
-                    value, variable->type, expr_type);
+    }
+
+    bool have_init_expr = false;
+    if (var_decl->expr) {
+        ConstExprValue *const_val = &get_resolved_expr(var_decl->expr)->const_val;
+        if (!const_val->ok || !const_val->undef) {
+            have_init_expr = true;
+        }
+    }
+    if (have_init_expr) {
+        TypeTableEntry *expr_type = get_expr_type(var_decl->expr);
+        LLVMValueRef value;
+        if (unwrap_maybe) {
+            assert(var_decl->expr);
+            assert(expr_type->id == TypeTableEntryIdMaybe);
+            value = gen_unwrap_maybe(g, source_node, *init_value);
+            expr_type = expr_type->data.maybe.child_type;
         } else {
-            bool ignore_uninit = false;
-            TypeTableEntry *var_type = get_type_for_type_node(var_decl->type);
-            if (var_type->id == TypeTableEntryIdStruct &&
-                var_type->data.structure.is_unknown_size_array)
-            {
-                assert(var_decl->type->type == NodeTypeArrayType);
-                AstNode *size_node = var_decl->type->data.array_type.size;
-                if (size_node) {
-                    ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val;
-                    if (!const_val->ok) {
-                        TypeTableEntry *ptr_type = var_type->data.structure.fields[0].type_entry;
-                        assert(ptr_type->id == TypeTableEntryIdPointer);
-                        TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
-
-                        LLVMValueRef size_val = gen_expr(g, size_node);
-
-                        add_debug_source_node(g, source_node);
-                        LLVMValueRef ptr_val = LLVMBuildArrayAlloca(g->builder, child_type->type_ref,
-                                size_val, "");
-
-                        // store the freshly allocated pointer in the unknown size array struct
-                        LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder,
-                                variable->value_ref, 0, "");
-                        LLVMBuildStore(g->builder, ptr_val, ptr_field_ptr);
-
-                        // store the size in the len field
-                        LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder,
-                                variable->value_ref, 1, "");
-                        LLVMBuildStore(g->builder, size_val, len_field_ptr);
-
-                        // don't clobber what we just did with debug initialization
-                        ignore_uninit = true;
-                    }
+            value = *init_value;
+        }
+        gen_assign_raw(g, var_decl->expr, BinOpTypeAssign, variable->value_ref,
+                value, variable->type, expr_type);
+    } else {
+        bool ignore_uninit = false;
+        TypeTableEntry *var_type = get_type_for_type_node(var_decl->type);
+        if (var_type->id == TypeTableEntryIdStruct &&
+            var_type->data.structure.is_unknown_size_array)
+        {
+            assert(var_decl->type->type == NodeTypeArrayType);
+            AstNode *size_node = var_decl->type->data.array_type.size;
+            if (size_node) {
+                ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val;
+                if (!const_val->ok) {
+                    TypeTableEntry *ptr_type = var_type->data.structure.fields[0].type_entry;
+                    assert(ptr_type->id == TypeTableEntryIdPointer);
+                    TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
+
+                    LLVMValueRef size_val = gen_expr(g, size_node);
+
+                    add_debug_source_node(g, source_node);
+                    LLVMValueRef ptr_val = LLVMBuildArrayAlloca(g->builder, child_type->type_ref,
+                            size_val, "");
+
+                    // store the freshly allocated pointer in the unknown size array struct
+                    LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder,
+                            variable->value_ref, 0, "");
+                    LLVMBuildStore(g->builder, ptr_val, ptr_field_ptr);
+
+                    // store the size in the len field
+                    LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder,
+                            variable->value_ref, 1, "");
+                    LLVMBuildStore(g->builder, size_val, len_field_ptr);
+
+                    // don't clobber what we just did with debug initialization
+                    ignore_uninit = true;
                 }
             }
-            if (!ignore_uninit && g->build_type != CodeGenBuildTypeRelease) {
-                // memset uninitialized memory to 0xa
-                add_debug_source_node(g, source_node);
-                LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
-                LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
-                LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, variable->value_ref, ptr_u8, "");
-                LLVMValueRef byte_count = LLVMConstInt(LLVMIntType(g->pointer_size_bytes * 8),
-                        variable->type->size_in_bits / 8, false);
-                LLVMValueRef align_in_bytes = LLVMConstInt(LLVMInt32Type(),
-                        variable->type->align_in_bits / 8, false);
-                LLVMValueRef params[] = {
-                    dest_ptr,
-                    fill_char,
-                    byte_count,
-                    align_in_bytes,
-                    LLVMConstNull(LLVMInt1Type()), // is volatile
-                };
-
-                LLVMBuildCall(g->builder, g->memset_fn_val, params, 5, "");
-            }
         }
+        if (!ignore_uninit && g->build_type != CodeGenBuildTypeRelease) {
+            // memset uninitialized memory to 0xa
+            add_debug_source_node(g, source_node);
+            LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
+            LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), 0xaa, false);
+            LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, variable->value_ref, ptr_u8, "");
+            LLVMValueRef byte_count = LLVMConstInt(LLVMIntType(g->pointer_size_bytes * 8),
+                    variable->type->size_in_bits / 8, false);
+            LLVMValueRef align_in_bytes = LLVMConstInt(LLVMInt32Type(),
+                    variable->type->align_in_bits / 8, false);
+            LLVMValueRef params[] = {
+                dest_ptr,
+                fill_char,
+                byte_count,
+                align_in_bytes,
+                LLVMConstNull(LLVMInt1Type()), // is volatile
+            };
 
-        LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(source_node->line + 1, source_node->column + 1,
-                g->cur_block_context->di_scope);
-        LLVMZigInsertDeclareAtEnd(g->dbuilder, variable->value_ref, variable->di_loc_var, debug_loc,
-                LLVMGetInsertBlock(g->builder));
-        return nullptr;
+            LLVMBuildCall(g->builder, g->memset_fn_val, params, 5, "");
+        }
     }
+
+    LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(source_node->line + 1, source_node->column + 1,
+            g->cur_block_context->di_scope);
+    LLVMZigInsertDeclareAtEnd(g->dbuilder, variable->value_ref, variable->di_loc_var, debug_loc,
+            LLVMGetInsertBlock(g->builder));
+    return nullptr;
 }
 
 static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {
@@ -2035,6 +2042,10 @@ static void build_label_blocks(CodeGen *g, AstNode *block_node) {
 static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val) {
     assert(const_val->ok);
 
+    if (const_val->undef) {
+        return LLVMConstNull(type_entry->type_ref);
+    }
+
     if (type_entry->id == TypeTableEntryIdInt) {
         return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false);
     } else if (type_entry->id == TypeTableEntryIdFloat) {
@@ -2389,6 +2400,11 @@ static void define_builtin_types(CodeGen *g) {
         buf_init_from_str(&entry->name, "(integer literal)");
         g->builtin_types.entry_num_lit_int = entry;
     }
+    {
+        TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUndefLit);
+        buf_init_from_str(&entry->name, "(undefined)");
+        g->builtin_types.entry_undef = entry;
+    }
 
     for (int i = 0; i < array_length(int_sizes_in_bits); i += 1) {
         int size_in_bits = int_sizes_in_bits[i];