zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob ef8a3181 (10685B) - Raw


      1  * modify dbg_stmt ZIR instructions to have line/column rather than node indexes
      2  * AstGen threadlocal
      3  * extern "foo" for vars and for functions
      4  * namespace decls table can't reference ZIR memory because it can get modified on updates
      5    - change it for astgen worker to compare old and new ZIR, updating existing
      6      namespaces & decls, and creating a changelist.
      7  * reimplement semaDecl
      8  * use a hash map for instructions because the array is too big
      9    - no, actually modify the Zir.Inst.Ref strategy so that each decl gets
     10      their indexes starting at 0 so that we can use an array to store Sema
     11      results rather than a map.
     12 
     13  * keep track of file dependencies/dependants
     14  * unload files from memory when a dependency is dropped
     15 
     16  * implement the new AstGen compile errors
     17 
     18  * get rid of failed_root_src_file
     19  * get rid of Scope.DeclRef
     20  * get rid of NameHash
     21  * handle decl collision with usingnamespace
     22  * the decl doing the looking up needs to create a decl dependency
     23    on each usingnamespace decl
     24  * handle usingnamespace cycles
     25 
     26  * compile error for return inside defer expression
     27 
     28  * when block has noreturn statement
     29    - avoid emitting defers
     30    - compile error for unreachable code
     31  
     32  * detect `return error.Foo` and emit ZIR that unconditionally generates errdefers
     33  * `return`: check return operand and generate errdefers if necessary
     34 
     35  * have failed_trees and just put the file in there
     36    - this way we can emit all the parse errors not just the first one
     37    - but maybe we want just the first one?
     38 
     39  * need a var decl zir instruction which includes the name because we need to do the
     40    compile error for a local shadowing a decl with Sema looking up the decl name.
     41    - this means LocalVal and LocalPtr should use the string table
     42 
     43  * sort compile errors before presenting them to eliminate nondeterministic error reporting
     44 
     45  * when handling decls, catch the error and continue, so that
     46    AstGen can report more than one compile error.
     47 
     48  * AstGen: add result location pointers to function calls
     49  * nested function decl: how to refer to params?
     50 
     51 fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenIndex) ![]u8 {
     52     // TODO add namespaces, generic function signatrues
     53     const tree = scope.tree();
     54     const token_tags = tree.tokens.items(.tag);
     55     const base_name = switch (token_tags[base_token]) {
     56         .keyword_struct => "struct",
     57         .keyword_enum => "enum",
     58         .keyword_union => "union",
     59         .keyword_opaque => "opaque",
     60         else => unreachable,
     61     };
     62     const loc = tree.tokenLocation(0, base_token);
     63     return std.fmt.allocPrint(mod.gpa, "{s}:{d}:{d}", .{ base_name, loc.line, loc.column });
     64 }
     65 
     66 
     67 /// Returns `true` if the Decl type changed.
     68 /// Returns `true` if this is the first time analyzing the Decl.
     69 /// Returns `false` otherwise.
     70 fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
     71     switch (node_tags[decl_node]) {
     72         .@"usingnamespace" => {
     73             decl.analysis = .in_progress;
     74 
     75             var code: Zir = blk: {
     76                 var astgen = try AstGen.init(mod, decl, &analysis_arena.allocator);
     77                 defer astgen.deinit();
     78 
     79                 var gen_scope: Scope.GenZir = .{
     80                     .force_comptime = true,
     81                     .parent = &decl.namespace.base,
     82                     .astgen = &astgen,
     83                 };
     84                 defer gen_scope.instructions.deinit(mod.gpa);
     85 
     86                 const ns_type = try AstGen.typeExpr(&gen_scope, &gen_scope.base, type_expr);
     87 
     88             };
     89             try decl.namespace.usingnamespace_set.put(mod.gpa, ty.getNamespace().?, is_pub);
     90 
     91             decl.analysis = .complete;
     92             decl.generation = mod.generation;
     93             return true;
     94         },
     95         else => unreachable,
     96     }
     97 }
     98 
     99     if (mod.lookupIdentifier(scope, ident_name)) |decl| {
    100         const msg = msg: {
    101             const msg = try mod.errMsg(
    102                 scope,
    103                 name_src,
    104                 "redeclaration of '{s}'",
    105                 .{ident_name},
    106             );
    107             errdefer msg.destroy(gpa);
    108             try mod.errNoteNonLazy(decl.srcLoc(), msg, "previously declared here", .{});
    109             break :msg msg;
    110         };
    111         return mod.failWithOwnedErrorMsg(scope, msg);
    112     }
    113 
    114 
    115     const error_set = try arena.create(Module.ErrorSet);
    116     error_set.* = .{
    117         .owner_decl = astgen.decl,
    118         .node_offset = astgen.decl.nodeIndexToRelative(node),
    119         .names_ptr = fields.ptr,
    120         .names_len = @intCast(u32, fields.len),
    121     };
    122     const error_set_ty = try Type.Tag.error_set.create(arena, error_set);
    123     const error_set_val = try Value.Tag.ty.create(arena, error_set_ty);
    124     const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
    125         .ty = Type.initTag(.type),
    126         .val = error_set_val,
    127     });
    128     const decl_index = try mod.declareDeclDependency(astgen.decl, new_decl);
    129     const result = try gz.addDecl(.decl_val, decl_index, node);
    130     return rvalue(gz, scope, rl, result, node);
    131 
    132 
    133 
    134         // when implementing this be sure to add test coverage for the asm return type
    135         // not resolving into a type (the node_offset_asm_ret_ty  field of LazySrcLoc)
    136 
    137 
    138 
    139 pub fn analyzeNamespace(
    140     mod: *Module,
    141     namespace: *Scope.Namespace,
    142     decls: []const ast.Node.Index,
    143 ) InnerError!void {
    144     for (decls) |decl_node| switch (node_tags[decl_node]) {
    145         .@"comptime" => {
    146             const name_index = mod.getNextAnonNameIndex();
    147             const name = try std.fmt.allocPrint(mod.gpa, "__comptime_{d}", .{name_index});
    148             defer mod.gpa.free(name);
    149 
    150             const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
    151 
    152             const new_decl = try mod.createNewDecl(namespace, name, decl_node, name_hash, contents_hash);
    153             namespace.decls.putAssumeCapacity(new_decl, {});
    154             mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
    155         },
    156 
    157         // Container fields are handled in AstGen.
    158         .container_field_init,
    159         .container_field_align,
    160         .container_field,
    161         => continue,
    162 
    163         .test_decl => {
    164             if (mod.comp.bin_file.options.is_test) {
    165                 log.err("TODO: analyze test decl", .{});
    166             }
    167         },
    168         .@"usingnamespace" => {
    169             const name_index = mod.getNextAnonNameIndex();
    170             const name = try std.fmt.allocPrint(mod.gpa, "__usingnamespace_{d}", .{name_index});
    171             defer mod.gpa.free(name);
    172 
    173             const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
    174 
    175             const new_decl = try mod.createNewDecl(namespace, name, decl_node, name_hash, contents_hash);
    176             namespace.decls.putAssumeCapacity(new_decl, {});
    177 
    178             mod.ensureDeclAnalyzed(new_decl) catch |err| switch (err) {
    179                 error.OutOfMemory => return error.OutOfMemory,
    180                 error.AnalysisFail => continue,
    181             };
    182         },
    183         else => unreachable,
    184     };
    185 }
    186 
    187 /// Trailing:
    188 ///  0. `EmitH` if `module.emit_h != null`.
    189 ///  1. A per-Decl link object. Represents the position of the code in the output file.
    190 ///     This is populated regardless of semantic analysis and code generation.
    191 ///     Depending on the target, will be one of:
    192 ///     * Elf.TextBlock
    193 ///     * Coff.TextBlock
    194 ///     * MachO.TextBlock
    195 ///     * C.DeclBlock
    196 ///     * Wasm.DeclBlock
    197 ///     * void
    198 ///  2. If it is a function, a per-Decl link function object. Represents the
    199 ///     function in the linked output file, if the `Decl` is a function.
    200 ///     This is stored here and not in `Fn` because `Decl` survives across updates but
    201 ///     `Fn` does not. Depending on the target, will be one of:
    202 ///     * Elf.SrcFn
    203 ///     * Coff.SrcFn
    204 ///     * MachO.SrcFn
    205 ///     * C.FnBlock
    206 ///     * Wasm.FnData
    207 ///     * SpirV.FnData
    208 
    209 
    210         extra_index += @boolToInt(has_align);
    211         extra_index += @boolToInt(has_section);
    212 
    213     /// Contains un-analyzed ZIR instructions generated from Zig source AST.
    214     /// Even after we finish analysis, the ZIR is kept in memory, so that
    215     /// comptime and inline function calls can happen.
    216     /// Parameter names are stored here so that they may be referenced for debug info,
    217     /// without having source code bytes loaded into memory.
    218     /// The number of parameters is determined by referring to the type.
    219     /// The first N elements of `extra` are indexes into `string_bytes` to
    220     /// a null-terminated string.
    221     /// This memory is managed with gpa, must be freed when the function is freed.
    222     zir: Zir,
    223 
    224 
    225     if (fn_proto.lib_name) |lib_name_token| blk: {
    226         log.debug("extern fn symbol expected in lib '{s}'", .{lib_name_str});
    227         mod.comp.stage1AddLinkLib(lib_name_str) catch |err| {
    228             return mod.failTok(
    229                 &fn_type_scope.base,
    230                 lib_name_token,
    231                 "unable to add link lib '{s}': {s}",
    232                 .{ lib_name_str, @errorName(err) },
    233             );
    234         };
    235         const target = mod.comp.getTarget();
    236         if (target_util.is_libc_lib_name(target, lib_name_str)) {
    237             if (!mod.comp.bin_file.options.link_libc) {
    238                 return mod.failTok(
    239                     &fn_type_scope.base,
    240                     lib_name_token,
    241                     "dependency on libc must be explicitly specified in the build command",
    242                     .{},
    243                 );
    244             }
    245             break :blk;
    246         }
    247         if (target_util.is_libcpp_lib_name(target, lib_name_str)) {
    248             if (!mod.comp.bin_file.options.link_libcpp) {
    249                 return mod.failTok(
    250                     &fn_type_scope.base,
    251                     lib_name_token,
    252                     "dependency on libc++ must be explicitly specified in the build command",
    253                     .{},
    254                 );
    255             }
    256             break :blk;
    257         }
    258         if (!target.isWasm() and !mod.comp.bin_file.options.pic) {
    259             return mod.failTok(
    260                 &fn_type_scope.base,
    261                 lib_name_token,
    262                 "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",
    263                 .{ lib_name_str, lib_name_str },
    264             );
    265         }
    266     }
    267 
    268         const is_inline = decl_tv.ty.fnCallingConvention() == .Inline;
    269         const anal_state: Fn.Analysis = if (is_inline) .inline_only else .queued;
    270 
    271         new_func.* = .{
    272             .state = anal_state,
    273             .zir = fn_zir,
    274             .body = undefined,
    275             .owner_decl = decl,
    276         };
    277         fn_payload.* = .{
    278             .base = .{ .tag = .function },
    279             .data = new_func,
    280         };
    281