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 }