Browse Source

Allow nested procedures to access `@(static)` and `@(thread_local)` variables

gingerBill 4 years ago
parent
commit
05a3bdad58
3 changed files with 35 additions and 14 deletions
  1. 4 2
      src/check_expr.cpp
  2. 8 3
      src/checker.cpp
  3. 23 9
      src/llvm_backend.cpp

+ 4 - 2
src/check_expr.cpp

@@ -1075,8 +1075,10 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ
 	if (e->parent_proc_decl != nullptr &&
 	if (e->parent_proc_decl != nullptr &&
 	    e->parent_proc_decl != c->curr_proc_decl) {
 	    e->parent_proc_decl != c->curr_proc_decl) {
 		if (e->kind == Entity_Variable) {
 		if (e->kind == Entity_Variable) {
-			error(n, "Nested procedures do not capture its parent's variables: %.*s", LIT(name));
-			return nullptr;
+			if ((e->flags & EntityFlag_Static) == 0) {
+				error(n, "Nested procedures do not capture its parent's variables: %.*s", LIT(name));
+				return nullptr;
+			}
 		} else if (e->kind == Entity_Label) {
 		} else if (e->kind == Entity_Label) {
 			error(n, "Nested procedures do not capture its parent's labels: %.*s", LIT(name));
 			error(n, "Nested procedures do not capture its parent's labels: %.*s", LIT(name));
 			return nullptr;
 			return nullptr;

+ 8 - 3
src/checker.cpp

@@ -368,9 +368,14 @@ void scope_lookup_parent(Scope *scope, String const &name, Scope **scope_, Entit
 				if (e->kind == Entity_Label) {
 				if (e->kind == Entity_Label) {
 					continue;
 					continue;
 				}
 				}
-				if (e->kind == Entity_Variable &&
-				    !(e->scope->flags&ScopeFlag_File)) {
-					continue;
+				if (e->kind == Entity_Variable) {
+					if (e->scope->flags&ScopeFlag_File) {
+						// Global variables are file to access
+					} else if (e->flags&EntityFlag_Static) {
+						// Allow static/thread_local variables to be referenced
+					} else {
+						continue;
+					}
 				}
 				}
 			}
 			}
 
 

+ 23 - 9
src/llvm_backend.cpp

@@ -12875,6 +12875,7 @@ void lb_generate_code(lbGenerator *gen) {
 		lbValue var;
 		lbValue var;
 		lbValue init;
 		lbValue init;
 		DeclInfo *decl;
 		DeclInfo *decl;
+		bool is_initialized;
 	};
 	};
 	auto global_variables = array_make<GlobalVariable>(permanent_allocator(), 0, global_variable_max_count);
 	auto global_variables = array_make<GlobalVariable>(permanent_allocator(), 0, global_variable_max_count);
 
 
@@ -12937,15 +12938,22 @@ void lb_generate_code(lbGenerator *gen) {
 		var.var = g;
 		var.var = g;
 		var.decl = decl;
 		var.decl = decl;
 
 
-		if (decl->init_expr != nullptr && !is_type_any(e->type)) {
+		if (decl->init_expr != nullptr) {
 			TypeAndValue tav = type_and_value_of_expr(decl->init_expr);
 			TypeAndValue tav = type_and_value_of_expr(decl->init_expr);
-			if (tav.mode != Addressing_Invalid) {
-				if (tav.value.kind != ExactValue_Invalid) {
-					ExactValue v = tav.value;
-					lbValue init = lb_const_value(m, tav.type, v);
-					LLVMSetInitializer(g.value, init.value);
+			if (!is_type_any(e->type)) {
+				if (tav.mode != Addressing_Invalid) {
+					if (tav.value.kind != ExactValue_Invalid) {
+						ExactValue v = tav.value;
+						lbValue init = lb_const_value(m, tav.type, v);
+						LLVMSetInitializer(g.value, init.value);
+						var.is_initialized = true;
+					}
 				}
 				}
 			}
 			}
+			if (!var.is_initialized &&
+			    (is_type_untyped_nil(tav.type) || is_type_untyped_undef(tav.type))) {
+				var.is_initialized = true;
+			}
 		}
 		}
 
 
 		array_add(&global_variables, var);
 		array_add(&global_variables, var);
@@ -13146,10 +13154,13 @@ void lb_generate_code(lbGenerator *gen) {
 			auto *var = &global_variables[i];
 			auto *var = &global_variables[i];
 			if (var->decl->init_expr != nullptr)  {
 			if (var->decl->init_expr != nullptr)  {
 				lbValue init = lb_build_expr(p, var->decl->init_expr);
 				lbValue init = lb_build_expr(p, var->decl->init_expr);
-				if (!lb_is_const(init)) {
-					var->init = init;
+				if (lb_is_const(init)) {
+					if (!var->is_initialized) {
+						LLVMSetInitializer(var->var.value, init.value);
+						var->is_initialized = true;
+					}
 				} else {
 				} else {
-					LLVMSetInitializer(var->var.value, init.value);
+					var->init = init;
 				}
 				}
 			}
 			}
 
 
@@ -13166,6 +13177,7 @@ void lb_generate_code(lbGenerator *gen) {
 			}
 			}
 
 
 			if (var->init.value != nullptr) {
 			if (var->init.value != nullptr) {
+				GB_ASSERT(!var->is_initialized);
 				Type *t = type_deref(var->var.type);
 				Type *t = type_deref(var->var.type);
 
 
 				if (is_type_any(t)) {
 				if (is_type_any(t)) {
@@ -13182,6 +13194,8 @@ void lb_generate_code(lbGenerator *gen) {
 				} else {
 				} else {
 					lb_emit_store(p, var->var, lb_emit_conv(p, var->init, t));
 					lb_emit_store(p, var->var, lb_emit_conv(p, var->init, t));
 				}
 				}
+
+				var->is_initialized = true;
 			}
 			}
 		}
 		}