lib/chant/src/parse/thread.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const ast = @import("../ast/root.zig");
 2 const constant = @import("constant.zig");
 3 const state = @import("state/root.zig");
 4 const Error = @import("error.zig").Error;
 5 
 6 const diagnostic = state.diagnostic;
 7 const Parser = state.Parser;
 8 
 9 pub const Scope = enum {
10     file,
11     block,
12 };
13 
14 pub fn validateTypedef(parser: *Parser, is_thread_local: bool) Error!void {
15     if (is_thread_local) {
16         return diagnostic.fail(parser, error.UnsupportedConstruct, "typedef cannot be thread_local");
17     }
18 }
19 
20 pub fn validateFunction(parser: *Parser, is_thread_local: bool) Error!void {
21     if (is_thread_local) {
22         return diagnostic.fail(parser, error.UnsupportedConstruct, "function declarations cannot be thread_local");
23     }
24 }
25 
26 pub fn validateParameter(parser: *Parser, is_thread_local: bool) Error!void {
27     if (is_thread_local) {
28         return diagnostic.fail(parser, error.UnsupportedConstruct, "parameters cannot be thread_local");
29     }
30 }
31 
32 pub fn validateObject(parser: *Parser, scope: Scope, storage: ast.Storage, c_type: *const ast.Type, initializer: ?*ast.Expr, is_thread_local: bool) Error!void {
33     if (!is_thread_local) return;
34     if (scope == .block and storage != .static and storage != .extern_storage) {
35         return diagnostic.fail(parser, error.UnsupportedConstruct, "block-scope thread_local requires static or extern");
36     }
37     if (isVariablyModified(c_type)) {
38         return diagnostic.fail(parser, error.UnsupportedConstruct, "thread_local object cannot have variably modified type");
39     }
40     if (initializer) |expr| {
41         if (!try constant.isInitializer(parser, expr)) {
42             return diagnostic.fail(parser, error.InvalidConstant, "thread_local initializer is not a constant initializer");
43         }
44     }
45 }
46 
47 fn isVariablyModified(c_type: *const ast.Type) bool {
48     switch (c_type.kind) {
49         .array => {
50             if (c_type.vla_len != null) return true;
51             if (c_type.child) |child| return isVariablyModified(child);
52             return false;
53         },
54         .pointer => {
55             if (c_type.child) |child| return isVariablyModified(child);
56             return false;
57         },
58         .function => {
59             if (c_type.child) |child| {
60                 if (isVariablyModified(child)) return true;
61             }
62             for (c_type.params) |param| {
63                 if (isVariablyModified(param.type)) return true;
64             }
65             return false;
66         },
67         else => return false,
68     }
69 }