mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
enhance default hashing strategy for basic types (#1758)
* enhance default hashing strategy for basic types * fix * `$defined` in a global scope should accept testing normal macros. --------- Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
This commit is contained in:
committed by
GitHub
parent
14d8e93004
commit
a16316d7b4
@@ -376,21 +376,39 @@ macro String @str_upper(String $str) @builtin => $$str_upper($str);
|
||||
macro String @str_lower(String $str) @builtin => $$str_lower($str);
|
||||
macro uint @str_hash(String $str) @builtin => $$str_hash($str);
|
||||
|
||||
macro uint int.hash(int i) => i;
|
||||
macro uint uint.hash(uint i) => i;
|
||||
macro uint short.hash(short s) => s;
|
||||
macro uint ushort.hash(ushort s) => s;
|
||||
macro uint char.hash(char c) => c;
|
||||
macro uint ichar.hash(ichar c) => c;
|
||||
macro uint long.hash(long i) => (uint)((i >> 32) ^ i);
|
||||
macro uint ulong.hash(ulong i) => (uint)((i >> 32) ^ i);
|
||||
macro uint int128.hash(int128 i) => (uint)((i >> 96) ^ (i >> 64) ^ (i >> 32) ^ i);
|
||||
macro uint uint128.hash(uint128 i) => (uint)((i >> 96) ^ (i >> 64) ^ (i >> 32) ^ i);
|
||||
macro uint bool.hash(bool b) => (uint)b;
|
||||
macro uint typeid.hash(typeid t) => ((ulong)(uptr)t).hash();
|
||||
macro @generic_hash_core(h, value)
|
||||
{
|
||||
h ^= (uint)value; // insert lowest 32 bits
|
||||
h *= 0x96f59e5b; // diffuse them up
|
||||
h ^= h >> 16; // diffuse them down
|
||||
return h;
|
||||
}
|
||||
|
||||
macro @generic_hash(value)
|
||||
{
|
||||
uint h = @generic_hash_core((uint)0x3efd4391, value);
|
||||
$for (var $cnt = 4; $cnt < $sizeof(value); $cnt += 4)
|
||||
value >>= 32; // reduce value
|
||||
h = @generic_hash_core(h, value);
|
||||
$endfor
|
||||
return h;
|
||||
}
|
||||
|
||||
macro uint int.hash(int i) => @generic_hash(i);
|
||||
macro uint uint.hash(uint i) => @generic_hash(i);
|
||||
macro uint short.hash(short s) => @generic_hash(s);
|
||||
macro uint ushort.hash(ushort s) => @generic_hash(s);
|
||||
macro uint char.hash(char c) => @generic_hash(c);
|
||||
macro uint ichar.hash(ichar c) => @generic_hash(c);
|
||||
macro uint long.hash(long i) => @generic_hash(i);
|
||||
macro uint ulong.hash(ulong i) => @generic_hash(i);
|
||||
macro uint int128.hash(int128 i) => @generic_hash(i);
|
||||
macro uint uint128.hash(uint128 i) => @generic_hash(i);
|
||||
macro uint bool.hash(bool b) => @generic_hash(b);
|
||||
macro uint typeid.hash(typeid t) => @generic_hash(((ulong)(uptr)t));
|
||||
macro uint String.hash(String c) => (uint)fnv32a::encode(c);
|
||||
macro uint char[].hash(char[] c) => (uint)fnv32a::encode(c);
|
||||
macro uint void*.hash(void* ptr) => ((ulong)(uptr)ptr).hash();
|
||||
macro uint void*.hash(void* ptr) => @generic_hash(((ulong)(uptr)ptr));
|
||||
|
||||
distinct EmptySlot = void*;
|
||||
const EmptySlot EMPTY_MACRO_SLOT @builtin = null;
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
- Macros with default arguments to `&`, `#` and type parameters didn't work as expected. #1754.
|
||||
- `net::poll()` with negative timeout behaved incorrectly.
|
||||
- Return type inference bugs with macros #1757
|
||||
- `$defined` in a global scope should accept testing normal macros.
|
||||
|
||||
### Stdlib changes
|
||||
- Increase BitWriter.write_bits limit up to 32 bits.
|
||||
@@ -52,6 +53,7 @@
|
||||
- Add "tokenizer" to String.
|
||||
- Add "skip_empty" to split methods. Add split_to_buffer method.
|
||||
- Add `@enum_from_value`.
|
||||
- Updated hash function.
|
||||
|
||||
## 0.6.5 Change list
|
||||
|
||||
|
||||
@@ -1669,6 +1669,7 @@ typedef struct
|
||||
CallEnvKind kind : 8;
|
||||
bool ensures : 1;
|
||||
bool pure : 1;
|
||||
bool in_no_eval : 1;
|
||||
SourceSpan in_if_resolution;
|
||||
Decl **opt_returns;
|
||||
union
|
||||
|
||||
@@ -3962,7 +3962,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (context->call_env.kind == CALL_ENV_GLOBAL_INIT)
|
||||
if (context->call_env.kind == CALL_ENV_GLOBAL_INIT && !context->call_env.in_no_eval)
|
||||
{
|
||||
if (context->current_macro)
|
||||
{
|
||||
|
||||
@@ -8795,24 +8795,29 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
|
||||
{
|
||||
Expr *main_expr = list[i];
|
||||
SemaContext *active_context = context;
|
||||
bool in_no_eval = active_context->call_env.in_no_eval;
|
||||
active_context->call_env.in_no_eval = true;
|
||||
RETRY:
|
||||
switch (main_expr->expr_kind)
|
||||
{
|
||||
case EXPR_OTHER_CONTEXT:
|
||||
active_context->call_env.in_no_eval = in_no_eval;
|
||||
active_context = expr->expr_other_context.context;
|
||||
in_no_eval = active_context->call_env.in_no_eval;
|
||||
active_context->call_env.in_no_eval = true;
|
||||
main_expr = expr->expr_other_context.inner;
|
||||
goto RETRY;
|
||||
case EXPR_ACCESS:
|
||||
if (!sema_expr_analyse_access(active_context, main_expr, &failed, CHECK_VALUE))
|
||||
{
|
||||
if (!failed) return false;
|
||||
if (!failed) goto FAIL;
|
||||
success = false;
|
||||
}
|
||||
break;
|
||||
case EXPR_IDENTIFIER:
|
||||
{
|
||||
Decl *decl = sema_find_path_symbol(active_context, main_expr->identifier_expr.ident, main_expr->identifier_expr.path);
|
||||
if (!decl_ok(decl)) return false;
|
||||
if (!decl_ok(decl)) goto FAIL;
|
||||
success = decl != NULL;
|
||||
break;
|
||||
}
|
||||
@@ -8826,14 +8831,14 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
|
||||
main_expr->resolve_status = RESOLVE_RUNNING;
|
||||
if (!sema_expr_analyse_unary(active_context, main_expr, &failed, CHECK_VALUE))
|
||||
{
|
||||
if (!failed) return false;
|
||||
if (!failed) goto FAIL;
|
||||
success = false;
|
||||
}
|
||||
break;
|
||||
case EXPR_TYPEINFO:
|
||||
{
|
||||
Type *type = sema_expr_check_type_exists(active_context, main_expr->type_expr);
|
||||
if (!type_ok(type)) return false;
|
||||
if (!type_ok(type)) goto FAIL;
|
||||
success = type != NULL;
|
||||
break;
|
||||
}
|
||||
@@ -8843,7 +8848,7 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
|
||||
case EXPR_HASH_IDENT:
|
||||
{
|
||||
Decl *decl = sema_resolve_symbol(active_context, main_expr->hash_ident_expr.identifier, NULL, main_expr->span);
|
||||
if (!decl) return false;
|
||||
if (!decl) goto FAIL;
|
||||
main_expr = copy_expr_single(decl->var.init_expr);
|
||||
goto RETRY;
|
||||
}
|
||||
@@ -8851,7 +8856,7 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
|
||||
{
|
||||
if (!sema_expr_analyse_subscript(active_context, main_expr, CHECK_VALUE, true))
|
||||
{
|
||||
return false;
|
||||
goto FAIL;
|
||||
}
|
||||
if (!expr_ok(main_expr))
|
||||
{
|
||||
@@ -8862,14 +8867,14 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
|
||||
case EXPR_CAST:
|
||||
if (!sema_expr_analyse_cast(active_context, main_expr, &failed))
|
||||
{
|
||||
if (!failed) return false;
|
||||
if (!failed) goto FAIL;
|
||||
success = false;
|
||||
}
|
||||
break;
|
||||
case EXPR_CT_IDENT:
|
||||
{
|
||||
Decl *decl = sema_resolve_symbol(active_context, main_expr->ct_ident_expr.identifier, NULL, main_expr->span);
|
||||
if (!decl) return false;
|
||||
if (!decl) goto FAIL;
|
||||
break;
|
||||
}
|
||||
case EXPR_CALL:
|
||||
@@ -8877,23 +8882,23 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
|
||||
bool no_match;
|
||||
if (!sema_expr_analyse_call(active_context, main_expr, &no_match))
|
||||
{
|
||||
if (!no_match) return false;
|
||||
if (!no_match) goto FAIL;
|
||||
success = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EXPR_FORCE_UNWRAP:
|
||||
if (!sema_analyse_expr(active_context, main_expr->inner_expr)) return false;
|
||||
if (!sema_analyse_expr(active_context, main_expr->inner_expr)) goto FAIL;
|
||||
success = IS_OPTIONAL(main_expr->inner_expr);
|
||||
break;
|
||||
case EXPR_RETHROW:
|
||||
if (!sema_analyse_expr(active_context, main_expr->rethrow_expr.inner)) return false;
|
||||
if (!sema_analyse_expr(active_context, main_expr->rethrow_expr.inner)) goto FAIL;
|
||||
success = IS_OPTIONAL(main_expr->rethrow_expr.inner);
|
||||
break;
|
||||
case EXPR_OPTIONAL:
|
||||
if (!sema_expr_analyse_optional(active_context, main_expr, &failed))
|
||||
{
|
||||
if (!failed) return false;
|
||||
if (!failed) goto FAIL;
|
||||
success = false;
|
||||
}
|
||||
break;
|
||||
@@ -8966,10 +8971,15 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
|
||||
case EXPR_PTR_ACCESS:
|
||||
case EXPR_RVALUE:
|
||||
case EXPR_MAKE_ANY:
|
||||
if (!sema_analyse_expr(active_context, main_expr)) return false;
|
||||
if (!sema_analyse_expr(active_context, main_expr)) goto FAIL;
|
||||
break;
|
||||
}
|
||||
if (!success) break;
|
||||
active_context->call_env.in_no_eval = in_no_eval;
|
||||
if (success) continue;
|
||||
break;
|
||||
FAIL:
|
||||
active_context->call_env.in_no_eval = in_no_eval;
|
||||
return false;
|
||||
}
|
||||
expr_rewrite_const_bool(expr, type_bool, success);
|
||||
return true;
|
||||
|
||||
@@ -312,7 +312,11 @@ INLINE bool sema_resolve_evaltype(SemaContext *context, TypeInfo *type_info, Res
|
||||
INLINE bool sema_resolve_typeof(SemaContext *context, TypeInfo *type_info)
|
||||
{
|
||||
Expr *expr = type_info->unresolved_type_expr;
|
||||
if (!sema_analyse_expr_value(context, expr)) return false;
|
||||
bool in_no_eval = context->call_env.in_no_eval;
|
||||
context->call_env.in_no_eval = true;
|
||||
bool success = sema_analyse_expr_value(context, expr);
|
||||
context->call_env.in_no_eval = in_no_eval;
|
||||
if (!success) return false;
|
||||
Type *expr_type = expr->type;
|
||||
if (expr_type->type_kind == TYPE_FUNC_RAW) expr_type = type_get_func_ptr(expr_type);
|
||||
switch (sema_resolve_storage_type(context, expr_type))
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
import std;
|
||||
macro foo(int a)
|
||||
{
|
||||
int h = a;
|
||||
return a;
|
||||
}
|
||||
|
||||
$typeof(baz(2)) y;
|
||||
const ABC = $sizeof(baz(2));
|
||||
|
||||
macro baz(int x) => foo(x);
|
||||
|
||||
fn void main()
|
||||
{
|
||||
int x = ABC;
|
||||
int a = baz(3);
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
|
||||
@test.y = local_unnamed_addr global i32 0, align 4
|
||||
@test.ABC = local_unnamed_addr constant i64 4, align 8
|
||||
|
||||
entry:
|
||||
%x = alloca i32, align 4
|
||||
%a = alloca i32, align 4
|
||||
%h = alloca i32, align 4
|
||||
store i32 4, ptr %x, align 4
|
||||
store i32 3, ptr %h, align 4
|
||||
store i32 3, ptr %a, align 4
|
||||
ret void
|
||||
}
|
||||
Reference in New Issue
Block a user