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