Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions ast/var_decl.c2
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ type VarDeclBits struct {
u32 addr_used : 1;
AutoAttr auto_attr : 2; // for parameters only
FormatAttr format_attr : 2; // for parameters only
u32 is_tlocal : 1; // local or global variables with thread local storage
}

public type BitFieldLayout struct {
Expand Down Expand Up @@ -320,6 +321,15 @@ public fn void VarDecl.setLocal(VarDecl* d, bool has_local) {
d.base.varDeclBits.has_local = has_local;
}

public fn bool VarDecl.isTLocal(const VarDecl* d) {
return d.base.varDeclBits.is_tlocal;
}

public fn void VarDecl.setTLocal(VarDecl* d) {
d.base.varDeclBits.has_local = true;
d.base.varDeclBits.is_tlocal = true;
}

public fn void VarDecl.setInitCall(VarDecl* d, bool has_init_call) {
d.base.varDeclBits.has_init_call = has_init_call;
}
Expand Down
1 change: 1 addition & 0 deletions generator/c/c_generator.c2
Original file line number Diff line number Diff line change
Expand Up @@ -1462,6 +1462,7 @@ const char[] C_defines =

#define NULL ((void*)0)
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
#define tlocal _Thread_local
```;

fn void Generator.emit_external_header(Generator* gen, const char* target) {
Expand Down
2 changes: 1 addition & 1 deletion generator/c/c_generator_stmt.c2
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import string_buffer;
fn void Generator.emitVarDecl(Generator* gen, VarDecl* vd, string_buffer.Buf* out, bool emit_init, bool first) {
Decl* d = (Decl*)vd;
if (first) {
if (vd.hasLocalQualifier()) out.add("static ");
if (vd.hasLocalQualifier()) out.add(vd.isTLocal() ? "tlocal " : "static ");
gen.emitTypePre(out, d.getType());
} else {
out.add1(',');
Expand Down
2 changes: 1 addition & 1 deletion generator/c2i/c2i_generator_decl.c2
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ fn void Generator.emitVarDecl(Generator* gen, string_buffer.Buf* out, const VarD
Decl* d = (Decl*)vd;

if (first) {
if (vd.hasLocalQualifier()) out.add("local ");
if (vd.hasLocalQualifier()) out.add(vd.isTLocal() ? "tlocal" : "local ");
gen.emitType(out, d.getType());
} else {
out.add1(',');
Expand Down
11 changes: 8 additions & 3 deletions parser/c2_parser.c2
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,8 @@ fn bool Parser.parseFunctionParams(Parser* p, DeclList* params, bool is_public,
param_default ::= EQUALS constant_expression.
*/
fn VarDecl* Parser.parseParamDecl(Parser* p, bool is_public, bool accept_default) {
if (p.tok.kind == KW_local) p.error("keyword 'local' is not allowed here");
if (p.tok.kind == KW_local || p.tok.kind == KW_tlocal)
p.error("keyword '%s' is not allowed here", p.tok.kind.str());

TypeRefHolder ref.init();
// Note: dont check arrays in this phase, but in Analyser
Expand Down Expand Up @@ -756,6 +757,9 @@ fn void Parser.parseArrayEntry(Parser* p) {
fn void Parser.parseVarDecl(Parser* p, bool is_public) {
if (p.tok.kind == KW_local) p.error("keyword 'local' cannot be used at file scope");

bool has_tlocal = (p.tok.kind == KW_tlocal);
if (has_tlocal) p.consumeToken();

bool need_semi = true;
TypeRefHolder ref.init();
p.parseTypeSpecifier(&ref);
Expand Down Expand Up @@ -814,8 +818,9 @@ fn void Parser.parseVarDecl(Parser* p, bool is_public) {
}

bool has_embed = p.builder.hasEmbedAttr();
Decl* d = (Decl*)p.builder.actOnGlobalVarDecl(name, loc, is_public, &ref, assignLoc, has_embed, initValue);
p.applyAttributes(d, num_attr);
VarDecl* vd = p.builder.actOnGlobalVarDecl(name, loc, is_public, &ref, assignLoc, has_embed, initValue);
if (has_tlocal) vd.setTLocal();
p.applyAttributes((Decl*)vd, num_attr);

if (p.tok.kind != Comma)
break;
Expand Down
17 changes: 10 additions & 7 deletions parser/c2_parser_stmt.c2
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ fn Stmt* Parser.parseStmt(Parser* p) {
case KW_int ... KW_unsigned: // C type keywords
case KW_const:
case KW_local:
case KW_tlocal:
case KW_volatile:
case KW_void:
// checkSemi, allowLocal, !isCondition
Expand Down Expand Up @@ -506,10 +507,10 @@ fn Stmt* Parser.parseWhileStmt(Parser* p) {
fn Stmt* Parser.parseDeclStmt(Parser* p, bool checkSemi, bool allowLocal, bool isCondition) {
VarDecl*[MaxMultiDecl] decls;
u32 num_decls = 0;
bool has_local = false;
if (p.tok.kind == KW_local) {
has_local = true;
if (!allowLocal) p.error("keyword 'local' is not allowed here");
bool has_local = (p.tok.kind == KW_local);
bool has_tlocal = (p.tok.kind == KW_tlocal);
if (has_local | has_tlocal) {
if (!allowLocal) p.error("keyword '%s' is not allowed here", p.tok.kind.str());
p.consumeToken();
}

Expand Down Expand Up @@ -548,7 +549,7 @@ fn Stmt* Parser.parseDeclStmt(Parser* p, bool checkSemi, bool allowLocal, bool i
case Dot:
if (p.peekToken(1) == Identifier
&& p.peekToken(2) == LParen) {
if (has_local)
if (has_local | has_tlocal)
p.error("local qualified variables cannot have an init call");
if (isCondition)
p.error("cannot use an init call inside a condition");
Expand All @@ -571,7 +572,9 @@ fn Stmt* Parser.parseDeclStmt(Parser* p, bool checkSemi, bool allowLocal, bool i
default:
break;
}
decls[num_decls++] = p.builder.actOnVarDecl(name, loc, &ref, assignLoc, initValue, has_local, has_init_call);
VarDecl* vd = p.builder.actOnVarDecl(name, loc, &ref, assignLoc, initValue, has_local, has_init_call);
if (has_tlocal) vd.setTLocal();
decls[num_decls++] = vd;
if (p.tok.kind != Comma)
break;
p.consumeToken();
Expand Down Expand Up @@ -628,7 +631,7 @@ fn bool Parser.isDeclaration(Parser* p) {
const Kind kind = p.tok.kind;
if (kind == Identifier) return p.isTypeSpec();
if (kind.isTypeKeyword() && (p.peekToken(1) != Dot)) return true;
if (kind == KW_local) return true;
if (kind == KW_local || kind == KW_tlocal) return true;
if (kind.isQualifier()) return true;
return false;
}
Expand Down
4 changes: 2 additions & 2 deletions parser/keywords.c2
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import token local;
import string;

public type Info struct {
// Note: should be big enough to hold all keywords (4+436+216 with alignment)
Kind[656] indexes;
// Note: should be big enough to hold all keywords (4+436+220 with alignment)
Kind[660] indexes;
u32 max_index;
}

Expand Down
2 changes: 2 additions & 0 deletions parser/token.c2
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ public type Kind enum u8 {
KW_struct,
KW_switch,
KW_template,
KW_tlocal,
KW_to_container,
KW_true,
KW_type,
Expand Down Expand Up @@ -298,6 +299,7 @@ const char*[Kind] token_names = {
[KW_struct] = "struct",
[KW_switch] = "switch",
[KW_template] = "template",
[KW_tlocal] = "tlocal",
[KW_to_container] = "to_container",
[KW_true] = "true",
[KW_type] = "type",
Expand Down
18 changes: 18 additions & 0 deletions test/c_generator/variables/tlocal_variable.c2t
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// @recipe bin
$warnings no-unused
$backend c

// @file{file1}
module test;

fn void test1() {
tlocal i32 a = 10;
}

// @expect{atleast, cgen/build.c}

static void test_test1(void)
{
tlocal int a = 10;
}

Loading