Signed-off-by: Armin Weigl <tb46305@gmail.com>
---
v2:
rebase
improved error message
src/check.c | 36 ++++++++++++++++++++++++++++++++++--
tests/36-defines.ha | 2 +-
2 files changed, 35 insertions(+), 3 deletions(-)
diff --git a/src/check.c b/src/check.c
index 5440134..acfb566 100644
--- a/src/check.c
+++ b/src/check.c
@@ -3313,11 +3313,24 @@ check_expression(struct context *ctx,
static struct declaration *
check_const(struct context *ctx,
const struct scope_object *obj,
+ const struct location *loc,
const struct ast_global_decl *adecl)
{
struct declaration *decl = xcalloc(1, sizeof(struct declaration));
const struct scope_object *shadow_obj = scope_lookup(
ctx->defines, &adecl->ident);
+ if (obj != shadow_obj) {
+ // Shadowed by define
+ if (obj->type != shadow_obj->type) {
+ char *typename = gen_typename(obj->type);
+ char *shadow_typename = gen_typename(shadow_obj->type);
+ error(ctx, *loc, NULL,
+ "constant of type %s is shadowed by define of incompatible type %s",
+ typename, shadow_typename);
+ free(typename);
+ free(shadow_typename);
+ }
+ }
decl->type = DECL_CONST;
decl->constant.type = obj->type;
decl->constant.value = shadow_obj->value;
@@ -3491,7 +3504,7 @@ check_declaration(struct context *ctx,
struct declaration *decl = NULL;
switch (adecl->decl_type) {
case AST_DECL_CONST:
- decl = check_const(ctx, &idecl->obj, &adecl->constant);
+ decl = check_const(ctx, &idecl->obj, &adecl->loc, &adecl->constant);
break;
case AST_DECL_FUNC:
decl = check_function(ctx, &idecl->obj, adecl);
@@ -4304,9 +4317,28 @@ check_internal(struct type_store *ts,
scan_enum_field_aliases(&ctx, obj);
}
- // XXX: shadowed declarations are not checked for consistency
ctx.scope = ctx.defines;
+ for (const struct scope_object *obj = ctx.scope->objects;
+ obj; obj = obj->lnext) {
+ const struct scope_object *shadowed_obj =
+ scope_lookup(ctx.unit, &obj->name);
+ if (!shadowed_obj) {
+ continue;
+ }
+ if (shadowed_obj->otype == O_CONST) {
+ continue;
+ }
+ if (shadowed_obj->otype == O_SCAN) {
+ const struct incomplete_declaration *idecl =
+ (struct incomplete_declaration *)shadowed_obj;
+ if (idecl->decl.decl_type == AST_DECL_CONST) {
+ continue;
+ }
+ }
+ error(&ctx, defineloc, NULL, "define shadows non define");
+ }
+
struct declarations **next_decl = &unit->declarations;
// Perform actual declaration resolution
for (const struct scope_object *obj = ctx.unit->objects;
diff --git a/tests/36-defines.ha b/tests/36-defines.ha
index 90be8b5..c53d544 100644
--- a/tests/36-defines.ha
+++ b/tests/36-defines.ha
@@ -47,5 +47,5 @@ export fn main() void = {
import();
mandatory();
optional();
- // TODO: compatibility();
+ compatibility();
};
base-commit: 6ef434af84cd0e9d22951ea94e86c11698033294
--
2.39.1
> - // XXX: shadowed declarations are not checked for consistency
While these patches are certainly an improvement, this comment sadly still
applies, because define shadowing isn't entirely solved yet:
file zerodiv.ha:
def X:int = 10/Y;
def Y:int = 2;
fn main() void = {
static assert(X == 5);
};
Compiling this with harec -D"X:int=5" -D"Y:int=0" complains about division by
zero even though both the file without defines and file with both defines are
perfectly valid, because the shadowing isn't "atomic". I found out
about this a while ago but wasn't able to think of nice a solution and then
completely forgot about it until just now. It's a very low priority thing, so
I'm fine with merging this patch without fixing it, but I'd still like to see
it fixed before we remove that comment and start considering define shadowing
"solved".
> + const struct scope_object *shadowed_obj =
> + scope_lookup(ctx.unit, &obj->name);
> + if (!shadowed_obj) {
> + continue;
> + }
> + if (shadowed_obj->otype == O_CONST) {
> + continue;
> + }
> + if (shadowed_obj->otype == O_SCAN) {
> + const struct incomplete_declaration *idecl =
> + (struct incomplete_declaration *)shadowed_obj;
> + if (idecl->decl.decl_type == AST_DECL_CONST) {
You should ensure idecl->type == IDECL_DECL before reading idecl->decl,
otherwise weird stuff may happen with enum values. Adding a test ensuring those
cannot be shadowed to compatibility() would also be nice.