mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Fixes to $defined implementation.
This commit is contained in:
@@ -313,7 +313,7 @@ fn usz! List.index_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
foreach (i, v : self)
|
||||
{
|
||||
if (v == type) return i;
|
||||
if (equals(v, type)) return i;
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
}
|
||||
@@ -322,7 +322,7 @@ fn usz! List.rindex_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
foreach_r (i, v : self)
|
||||
{
|
||||
if (v == type) return i;
|
||||
if (equals(v, type)) return i;
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
}
|
||||
@@ -332,7 +332,7 @@ fn bool List.equals(&self, List other_list) @if(ELEMENT_IS_EQUATABLE)
|
||||
if (self.size != other_list.size) return false;
|
||||
foreach (i, v : self)
|
||||
{
|
||||
if (v != other_list.entries[i]) return false;
|
||||
if (!equals(v, other_list.entries[i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -348,7 +348,7 @@ fn bool List.contains(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
|
||||
{
|
||||
foreach (i, v : self)
|
||||
{
|
||||
if (v == value) return true;
|
||||
if (equals(v, value)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -364,7 +364,7 @@ fn usz List.remove(&self, Type value) @if(ELEMENT_IS_EQUATABLE)
|
||||
usz size = self.size;
|
||||
for (usz i = size; i > 0; i--)
|
||||
{
|
||||
if (self.entries[i - 1] != value) continue;
|
||||
if (!equals(self.entries[i - 1], value)) continue;
|
||||
for (usz j = i; j < size; j++)
|
||||
{
|
||||
self.entries[j - 1] = self.entries[j];
|
||||
|
||||
@@ -426,6 +426,7 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
|
||||
case EXPR_STRINGIFY:
|
||||
case EXPR_CT_EVAL:
|
||||
case EXPR_CT_CHECKS:
|
||||
case EXPR_CT_DEFINED:
|
||||
MACRO_COPY_EXPR(expr->inner_expr);
|
||||
return expr;
|
||||
case EXPR_TYPEID_INFO:
|
||||
|
||||
@@ -160,7 +160,7 @@ typedef enum
|
||||
case DECL_FINALIZE: case DECL_CT_ECHO: case DECL_CT_INCLUDE: case DECL_GLOBALS
|
||||
|
||||
#define NON_RUNTIME_EXPR EXPR_DESIGNATOR: case EXPR_POISONED: \
|
||||
case EXPR_CT_CHECKS: \
|
||||
case EXPR_CT_CHECKS: case EXPR_CT_DEFINED: \
|
||||
case EXPR_CT_ARG: case EXPR_TYPEINFO: case EXPR_CT_IDENT: case EXPR_HASH_IDENT: \
|
||||
case EXPR_COMPILER_CONST: case EXPR_CT_CALL: \
|
||||
case EXPR_ANYSWITCH: case EXPR_STRINGIFY: case EXPR_CT_EVAL
|
||||
@@ -220,6 +220,7 @@ typedef enum
|
||||
EXPR_CT_ARG,
|
||||
EXPR_CT_CALL,
|
||||
EXPR_CT_CHECKS,
|
||||
EXPR_CT_DEFINED,
|
||||
EXPR_CT_EVAL,
|
||||
EXPR_CT_IDENT,
|
||||
EXPR_DECL,
|
||||
|
||||
@@ -82,6 +82,7 @@ bool expr_may_addr(Expr *expr)
|
||||
return true;
|
||||
case EXPR_TEST_HOOK:
|
||||
return false;
|
||||
case NON_RUNTIME_EXPR:
|
||||
case EXPR_ASM:
|
||||
case EXPR_BINARY:
|
||||
case EXPR_BITASSIGN:
|
||||
@@ -90,36 +91,26 @@ bool expr_may_addr(Expr *expr)
|
||||
case EXPR_CALL:
|
||||
case EXPR_CAST:
|
||||
case EXPR_CATCH_UNWRAP:
|
||||
case EXPR_COMPILER_CONST:
|
||||
case EXPR_COMPOUND_LITERAL:
|
||||
case EXPR_COND:
|
||||
case EXPR_CONST:
|
||||
case EXPR_CT_ARG:
|
||||
case EXPR_CT_CALL:
|
||||
case EXPR_CT_CHECKS:
|
||||
case EXPR_CT_EVAL:
|
||||
case EXPR_CT_IDENT:
|
||||
case EXPR_DECL:
|
||||
case EXPR_DESIGNATED_INITIALIZER_LIST:
|
||||
case EXPR_DESIGNATOR:
|
||||
case EXPR_EXPRESSION_LIST:
|
||||
case EXPR_INITIALIZER_LIST:
|
||||
case EXPR_EXPR_BLOCK:
|
||||
case EXPR_OPTIONAL:
|
||||
case EXPR_FORCE_UNWRAP:
|
||||
case EXPR_HASH_IDENT:
|
||||
case EXPR_INITIALIZER_LIST:
|
||||
case EXPR_MACRO_BLOCK:
|
||||
case EXPR_MACRO_BODY_EXPANSION:
|
||||
case EXPR_NOP:
|
||||
case EXPR_OPERATOR_CHARS:
|
||||
case EXPR_POINTER_OFFSET:
|
||||
case EXPR_POISONED:
|
||||
case EXPR_POST_UNARY:
|
||||
case EXPR_RETHROW:
|
||||
case EXPR_RETVAL:
|
||||
case EXPR_SLICE_ASSIGN:
|
||||
case EXPR_SLICE_COPY:
|
||||
case EXPR_STRINGIFY:
|
||||
case EXPR_SUBSCRIPT_ADDR:
|
||||
case EXPR_SUBSCRIPT_ASSIGN:
|
||||
case EXPR_TERNARY:
|
||||
@@ -127,9 +118,7 @@ bool expr_may_addr(Expr *expr)
|
||||
case EXPR_TRY_UNWRAP_CHAIN:
|
||||
case EXPR_TYPEID:
|
||||
case EXPR_TYPEID_INFO:
|
||||
case EXPR_TYPEINFO:
|
||||
case EXPR_ANY:
|
||||
case EXPR_ANYSWITCH:
|
||||
case EXPR_VASPLAT:
|
||||
case EXPR_SWIZZLE:
|
||||
case EXPR_LAMBDA:
|
||||
@@ -203,6 +192,7 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
|
||||
case EXPR_OPERATOR_CHARS:
|
||||
case EXPR_STRINGIFY:
|
||||
case EXPR_CT_CHECKS:
|
||||
case EXPR_CT_DEFINED:
|
||||
case EXPR_LAMBDA:
|
||||
case EXPR_EMBED:
|
||||
return true;
|
||||
@@ -664,6 +654,7 @@ bool expr_is_pure(Expr *expr)
|
||||
case EXPR_CT_ARG:
|
||||
case EXPR_OPERATOR_CHARS:
|
||||
case EXPR_CT_CHECKS:
|
||||
case EXPR_CT_DEFINED:
|
||||
case EXPR_LAMBDA:
|
||||
case EXPR_EMBED:
|
||||
return true;
|
||||
|
||||
@@ -1032,6 +1032,17 @@ static Expr *parse_ct_eval(ParseContext *c, Expr *left)
|
||||
return expr;
|
||||
}
|
||||
|
||||
static Expr *parse_ct_defined(ParseContext *c, Expr *left)
|
||||
{
|
||||
assert(!left && "Unexpected left hand side");
|
||||
Expr *defined = expr_new(EXPR_CT_DEFINED, c->span);
|
||||
advance(c);
|
||||
CONSUME_OR_RET(TOKEN_LPAREN, poisoned_expr);
|
||||
ASSIGN_EXPR_OR_RET(defined->inner_expr, parse_expr(c), poisoned_expr);
|
||||
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_expr);
|
||||
return defined;
|
||||
|
||||
}
|
||||
/**
|
||||
* ct_sizeof ::= CT_SIZEOF '(' expr ')'
|
||||
*
|
||||
@@ -1093,7 +1104,7 @@ static Expr *parse_ct_embed(ParseContext *c, Expr *left)
|
||||
}
|
||||
|
||||
/**
|
||||
* ct_call ::= (ALIGNOF | DEFINED | EXTNAMEOF | OFFSETOF | NAMEOF | QNAMEOF) '(' flat_path ')'
|
||||
* ct_call ::= (ALIGNOF | EXTNAMEOF | OFFSETOF | NAMEOF | QNAMEOF) '(' flat_path ')'
|
||||
* flat_path ::= expr ('.' primary) | '[' expr ']')*
|
||||
*/
|
||||
static Expr *parse_ct_call(ParseContext *c, Expr *left)
|
||||
@@ -1894,7 +1905,7 @@ ParseRule rules[TOKEN_EOF + 1] = {
|
||||
[TOKEN_FN] = { parse_lambda, NULL, PREC_NONE },
|
||||
[TOKEN_CT_SIZEOF] = { parse_ct_sizeof, NULL, PREC_NONE },
|
||||
[TOKEN_CT_ALIGNOF] = { parse_ct_call, NULL, PREC_NONE },
|
||||
[TOKEN_CT_DEFINED] = { parse_ct_call, NULL, PREC_NONE },
|
||||
[TOKEN_CT_DEFINED] = { parse_ct_defined, NULL, PREC_NONE },
|
||||
[TOKEN_CT_CHECKS] = { parse_ct_checks, NULL, PREC_NONE },
|
||||
[TOKEN_CT_EMBED] = { parse_ct_embed, NULL, PREC_NONE },
|
||||
[TOKEN_CT_EVAL] = { parse_ct_eval, NULL, PREC_NONE },
|
||||
|
||||
@@ -483,6 +483,7 @@ static bool sema_binary_is_expr_lvalue(Expr *top_expr, Expr *expr)
|
||||
case EXPR_CT_ARG:
|
||||
case EXPR_CT_CALL:
|
||||
case EXPR_CT_CHECKS:
|
||||
case EXPR_CT_DEFINED:
|
||||
case EXPR_CT_EVAL:
|
||||
case EXPR_DECL:
|
||||
case EXPR_DESIGNATED_INITIALIZER_LIST:
|
||||
@@ -594,6 +595,7 @@ static bool expr_may_ref(Expr *expr)
|
||||
case EXPR_CT_ARG:
|
||||
case EXPR_CT_CALL:
|
||||
case EXPR_CT_CHECKS:
|
||||
case EXPR_CT_DEFINED:
|
||||
case EXPR_CT_EVAL:
|
||||
case EXPR_DECL:
|
||||
case EXPR_DESIGNATED_INITIALIZER_LIST:
|
||||
@@ -6788,7 +6790,7 @@ RETRY:
|
||||
case TYPE_INFO_POISON:
|
||||
return poisoned_type;
|
||||
case TYPE_INFO_GENERIC:
|
||||
TODO
|
||||
return poisoned_type;
|
||||
case TYPE_INFO_VECTOR:
|
||||
{
|
||||
ArraySize size;
|
||||
@@ -6820,6 +6822,7 @@ RETRY:
|
||||
Decl *decl = sema_find_path_symbol(context, type_info->unresolved.name, type_info->unresolved.path);
|
||||
if (!decl) return NULL;
|
||||
if (!decl_ok(decl)) return poisoned_type;
|
||||
if (type_info->kind == TYPE_INFO_CT_IDENTIFIER) return decl->var.init_expr->type_expr->type->canonical;
|
||||
return decl->type->canonical;
|
||||
}
|
||||
case TYPE_INFO_VATYPE:
|
||||
@@ -7224,9 +7227,15 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr
|
||||
{
|
||||
if (expr->resolve_status == RESOLVE_DONE) return expr_ok(expr);
|
||||
|
||||
Expr *main_var = expr->ct_call_expr.main_var;
|
||||
Type *type = NULL;
|
||||
Decl *decl = NULL;
|
||||
Expr *inner = expr->inner_expr;
|
||||
|
||||
Expr *main_var = inner;
|
||||
while (main_var->expr_kind == EXPR_ACCESS)
|
||||
{
|
||||
main_var = main_var->access_expr.parent;
|
||||
}
|
||||
|
||||
Decl *decl;
|
||||
RETRY:
|
||||
switch (main_var->expr_kind)
|
||||
{
|
||||
@@ -7237,51 +7246,46 @@ RETRY:
|
||||
if (!decl_ok(decl)) return false;
|
||||
// 2b. If it's missing, goto not defined
|
||||
if (!decl) goto NOT_DEFINED;
|
||||
type = decl->type;
|
||||
break;
|
||||
case EXPR_COMPILER_CONST:
|
||||
if (!sema_expr_analyse_compiler_const(context, main_var, false)) goto NOT_DEFINED;
|
||||
break;
|
||||
case EXPR_TYPEINFO:
|
||||
{
|
||||
type = sema_expr_check_type_exists(context, main_var->type_expr);
|
||||
Type *type = sema_expr_check_type_exists(context, main_var->type_expr);
|
||||
if (!type) goto NOT_DEFINED;
|
||||
if (!type_ok(type)) return false;
|
||||
main_var->type_expr = type_info_new_base(type, main_var->span);
|
||||
break;
|
||||
}
|
||||
case EXPR_BUILTIN:
|
||||
if (!sema_expr_analyse_builtin(context, main_var, false)) goto NOT_DEFINED;
|
||||
break;
|
||||
case EXPR_CT_EVAL:
|
||||
main_var = sema_ct_eval_expr(context, "$eval", main_var->inner_expr, false);
|
||||
if (!main_var) goto NOT_DEFINED;
|
||||
{
|
||||
Expr *eval = sema_ct_eval_expr(context, "$eval", main_var->inner_expr, false);
|
||||
if (!eval) goto NOT_DEFINED;
|
||||
expr_replace(main_var, eval);
|
||||
goto RETRY;
|
||||
}
|
||||
default:
|
||||
SEMA_ERROR(main_var, "Expected an identifier here.");
|
||||
return false;
|
||||
}
|
||||
|
||||
FOREACH_BEGIN_IDX(i, DesignatorElement *element, expr->ct_call_expr.flat_path)
|
||||
Decl *member = NULL;
|
||||
ArraySize index;
|
||||
Type *ret_type;
|
||||
bool missing = false;
|
||||
if (!sema_expr_analyse_decl_element(context,
|
||||
element,
|
||||
type,
|
||||
&member,
|
||||
&index,
|
||||
&ret_type,
|
||||
i,
|
||||
i == 0 ? main_var->span : expr->span,
|
||||
&missing))
|
||||
if (main_var != inner)
|
||||
{
|
||||
if (missing) goto NOT_DEFINED;
|
||||
return false;
|
||||
bool suppress_error = global_context.suppress_errors;
|
||||
global_context.suppress_errors = true;
|
||||
CallEnvKind eval_kind = context->call_env.kind;
|
||||
context->call_env.kind = CALL_ENV_CHECKS;
|
||||
bool success;
|
||||
SCOPE_START_WITH_FLAGS(SCOPE_CHECKS);
|
||||
success = sema_analyse_expr_lvalue(context, inner);
|
||||
SCOPE_END;
|
||||
context->call_env.kind = eval_kind;
|
||||
global_context.suppress_errors = suppress_error;
|
||||
if (!success) goto NOT_DEFINED;
|
||||
}
|
||||
type = ret_type;
|
||||
FOREACH_END();
|
||||
|
||||
expr_rewrite_const_bool(expr, type_bool, true);
|
||||
return true;
|
||||
|
||||
@@ -7588,6 +7592,8 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr)
|
||||
return sema_expr_analyse_generic_ident(context, expr);
|
||||
case EXPR_LAMBDA:
|
||||
return sema_expr_analyse_lambda(context, NULL, expr);
|
||||
case EXPR_CT_DEFINED:
|
||||
return sema_expr_analyse_ct_defined(context, expr);
|
||||
case EXPR_CT_CHECKS:
|
||||
return sema_expr_analyse_ct_checks(context, expr);
|
||||
case EXPR_CT_ARG:
|
||||
|
||||
@@ -253,6 +253,7 @@ RETRY:
|
||||
case EXPR_CT_ARG:
|
||||
case EXPR_CT_CALL:
|
||||
case EXPR_CT_CHECKS:
|
||||
case EXPR_CT_DEFINED:
|
||||
case EXPR_CT_EVAL:
|
||||
case EXPR_CT_IDENT:
|
||||
case EXPR_ANYSWITCH:
|
||||
|
||||
@@ -991,6 +991,7 @@ bool type_is_user_defined(Type *type)
|
||||
case TYPE_UNION:
|
||||
case TYPE_FAULTTYPE:
|
||||
case TYPE_DISTINCT:
|
||||
case TYPE_BITSTRUCT:
|
||||
return true;
|
||||
case TYPE_TYPEDEF:
|
||||
return type->decl != NULL;
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.4.578"
|
||||
#define COMPILER_VERSION "0.4.579"
|
||||
41
test/test_suite/compile_time_introspection/defined_2.c3t
Normal file
41
test/test_suite/compile_time_introspection/defined_2.c3t
Normal file
@@ -0,0 +1,41 @@
|
||||
module testing;
|
||||
import std::io;
|
||||
|
||||
fn void! main()
|
||||
{
|
||||
Bits b1;
|
||||
Bits b2;
|
||||
bool x = equals(b1, b2);
|
||||
}
|
||||
|
||||
bitstruct Bits : char
|
||||
{
|
||||
bool flag;
|
||||
}
|
||||
|
||||
fn bool Bits.equals(a, Bits b)
|
||||
{
|
||||
return a.flag == b.flag;
|
||||
}
|
||||
|
||||
/* #expect: testing.ll
|
||||
|
||||
define i64 @testing.main() #0 {
|
||||
entry:
|
||||
%b1 = alloca i8, align 1
|
||||
%b2 = alloca i8, align 1
|
||||
%x = alloca i8, align 1
|
||||
%a = alloca i8, align 1
|
||||
%b = alloca i8, align 1
|
||||
store i8 0, ptr %b1, align 1
|
||||
store i8 0, ptr %b2, align 1
|
||||
%0 = load i8, ptr %b1, align 1
|
||||
store i8 %0, ptr %a, align 1
|
||||
%1 = load i8, ptr %b2, align 1
|
||||
store i8 %1, ptr %b, align 1
|
||||
%2 = load i8, ptr %a, align 1
|
||||
%3 = load i8, ptr %b, align 1
|
||||
%4 = call i8 @testing.Bits.equals(i8 zeroext %2, i8 zeroext %3)
|
||||
store i8 %4, ptr %x, align 1
|
||||
ret i64 0
|
||||
}
|
||||
Reference in New Issue
Block a user