Browse Source

Allow for constant `[]typeid`

gingerBill 2 weeks ago
parent
commit
8be18d9a40
3 changed files with 61 additions and 17 deletions
  1. 21 0
      src/check_decl.cpp
  2. 15 12
      src/check_expr.cpp
  3. 25 5
      src/types.cpp

+ 21 - 0
src/check_decl.cpp

@@ -1686,7 +1686,28 @@ gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *e, Ast
 	check_expr_with_type_hint(ctx, &o, init_expr, e->type);
 	check_expr_with_type_hint(ctx, &o, init_expr, e->type);
 	check_init_variable(ctx, e, &o, str_lit("variable declaration"));
 	check_init_variable(ctx, e, &o, str_lit("variable declaration"));
 	if (e->Variable.is_rodata && o.mode != Addressing_Constant) {
 	if (e->Variable.is_rodata && o.mode != Addressing_Constant) {
+		ERROR_BLOCK();
 		error(o.expr, "Variables declared with @(rodata) must have constant initialization");
 		error(o.expr, "Variables declared with @(rodata) must have constant initialization");
+		Ast *expr = unparen_expr(o.expr);
+		if (is_type_struct(e->type) && expr && expr->kind == Ast_CompoundLit) {
+			ast_node(cl, CompoundLit, expr);
+			for (Ast *elem_ : cl->elems) {
+				Ast *elem = elem_;
+				if (elem->kind == Ast_FieldValue) {
+					elem = elem->FieldValue.value;
+				}
+				elem = unparen_expr(elem);
+
+				Entity *e = entity_of_node(elem);
+				if (elem->tav.mode != Addressing_Constant && e == nullptr && elem->kind != Ast_ProcLit) {
+					Token tok = ast_token(elem);
+					TokenPos pos = tok.pos;
+					gbString s = type_to_string(type_of_expr(elem));
+					error_line("%s Element is not constant, which is required for @(rodata), of type %s\n", token_pos_to_string(pos), s);
+					gb_string_free(s);
+				}
+			}
+		}
 	}
 	}
 
 
 	check_rtti_type_disallowed(e->token, e->type, "A variable declaration is using a type, %s, which has been disallowed");
 	check_rtti_type_disallowed(e->token, e->type, "A variable declaration is using a type, %s, which has been disallowed");

+ 15 - 12
src/check_expr.cpp

@@ -8655,7 +8655,7 @@ gb_internal bool check_range(CheckerContext *c, Ast *node, bool is_for_loop, Ope
 	return true;
 	return true;
 }
 }
 
 
-gb_internal bool check_is_operand_compound_lit_constant(CheckerContext *c, Operand *o) {
+gb_internal bool check_is_operand_compound_lit_constant(CheckerContext *c, Operand *o, Type *field_type) {
 	if (is_operand_nil(*o)) {
 	if (is_operand_nil(*o)) {
 		return true;
 		return true;
 	}
 	}
@@ -8670,6 +8670,9 @@ gb_internal bool check_is_operand_compound_lit_constant(CheckerContext *c, Opera
 			return true;
 			return true;
 		}
 		}
 	}
 	}
+	if (field_type != nullptr && is_type_typeid(field_type) && o->mode == Addressing_Type) {
+		return true;
+	}
 	return o->mode == Addressing_Constant;
 	return o->mode == Addressing_Constant;
 }
 }
 
 
@@ -9620,8 +9623,7 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As
 						break;
 						break;
 					}
 					}
 				}
 				}
-				if (is_constant &&
-				    (is_type_any(ft) || is_type_union(ft) || is_type_raw_union(ft) || is_type_typeid(ft))) {
+				if (is_constant && elem_cannot_be_constant(ft)) {
 					is_constant = false;
 					is_constant = false;
 				}
 				}
 			}
 			}
@@ -9656,11 +9658,11 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As
 		Operand o = {};
 		Operand o = {};
 		check_expr_or_type(c, &o, fv->value, field->type);
 		check_expr_or_type(c, &o, fv->value, field->type);
 
 
-		if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) {
+		if (elem_cannot_be_constant(field->type)) {
 			is_constant = false;
 			is_constant = false;
 		}
 		}
 		if (is_constant) {
 		if (is_constant) {
-			is_constant = check_is_operand_compound_lit_constant(c, &o);
+			is_constant = check_is_operand_compound_lit_constant(c, &o, field->type);
 		}
 		}
 
 
 		u8 prev_bit_field_bit_size = c->bit_field_bit_size;
 		u8 prev_bit_field_bit_size = c->bit_field_bit_size;
@@ -9886,14 +9888,11 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
 					Operand o = {};
 					Operand o = {};
 					check_expr_or_type(c, &o, elem, field->type);
 					check_expr_or_type(c, &o, elem, field->type);
 
 
-					if (is_type_any(field->type) ||
-					    is_type_raw_union(field->type) ||
-					    (is_type_union(field->type) && !is_type_union_constantable(field->type)) ||
-					    is_type_typeid(field->type)) {
+					if (elem_cannot_be_constant(field->type)) {
 						is_constant = false;
 						is_constant = false;
 					}
 					}
 					if (is_constant) {
 					if (is_constant) {
-						is_constant = check_is_operand_compound_lit_constant(c, &o);
+						is_constant = check_is_operand_compound_lit_constant(c, &o, field->type);
 					}
 					}
 
 
 					check_assignment(c, &o, field->type, str_lit("structure literal"));
 					check_assignment(c, &o, field->type, str_lit("structure literal"));
@@ -10070,7 +10069,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
 					check_expr_with_type_hint(c, &operand, fv->value, elem_type);
 					check_expr_with_type_hint(c, &operand, fv->value, elem_type);
 					check_assignment(c, &operand, elem_type, context_name);
 					check_assignment(c, &operand, elem_type, context_name);
 
 
-					is_constant = is_constant && operand.mode == Addressing_Constant;
+					if (is_constant) {
+						is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type);
+					}
 				}
 				}
 			}
 			}
 
 
@@ -10097,7 +10098,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
 				check_expr_with_type_hint(c, &operand, e, elem_type);
 				check_expr_with_type_hint(c, &operand, e, elem_type);
 				check_assignment(c, &operand, elem_type, context_name);
 				check_assignment(c, &operand, elem_type, context_name);
 
 
-				is_constant = is_constant && operand.mode == Addressing_Constant;
+				if (is_constant) {
+					is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type);
+				}
 			}
 			}
 
 
 			if (max < index) {
 			if (max < index) {

+ 25 - 5
src/types.cpp

@@ -1377,14 +1377,20 @@ gb_internal bool is_type_ordered_numeric(Type *t) {
 gb_internal bool is_type_constant_type(Type *t) {
 gb_internal bool is_type_constant_type(Type *t) {
 	t = core_type(t);
 	t = core_type(t);
 	if (t == nullptr) { return false; }
 	if (t == nullptr) { return false; }
-	if (t->kind == Type_Basic) {
+	switch (t->kind) {
+	case Type_Basic:
+		if (t->Basic.kind == Basic_typeid) {
+			return true;
+		}
 		return (t->Basic.flags & BasicFlag_ConstantType) != 0;
 		return (t->Basic.flags & BasicFlag_ConstantType) != 0;
-	}
-	if (t->kind == Type_BitSet) {
+	case Type_BitSet:
 		return true;
 		return true;
-	}
-	if (t->kind == Type_Proc) {
+	case Type_Proc:
 		return true;
 		return true;
+	case Type_Array:
+		return is_type_constant_type(t->Array.elem);
+	case Type_EnumeratedArray:
+		return is_type_constant_type(t->EnumeratedArray.elem);
 	}
 	}
 	return false;
 	return false;
 }
 }
@@ -2539,6 +2545,20 @@ gb_internal bool elem_type_can_be_constant(Type *t) {
 	return true;
 	return true;
 }
 }
 
 
+gb_internal bool elem_cannot_be_constant(Type *t) {
+	if (is_type_any(t)) {
+		return true;
+	}
+	if (is_type_union(t)) {
+		return !is_type_union_constantable(t);
+	}
+	if (is_type_raw_union(t)) {
+		return true;
+	}
+	return false;
+}
+
+
 gb_internal bool is_type_lock_free(Type *t) {
 gb_internal bool is_type_lock_free(Type *t) {
 	t = core_type(t);
 	t = core_type(t);
 	if (t == t_invalid) {
 	if (t == t_invalid) {