mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Fix foreach body copy. Moved deref / addr into special functions. Cleaned up access. Remove .sizeof .alignof .qnameof .nameof, create $qnameof $nameof
This commit is contained in:
committed by
Christoffer Lerno
parent
2815a6d02e
commit
9f42ddb68d
@@ -40,7 +40,7 @@ private func void LinkedList.linkFirst(LinkedList *list, Type value)
|
||||
private func void LinkedList.linkLast(LinkedList *list, Type value)
|
||||
{
|
||||
Node *last = list.last;
|
||||
Node *new_node = mem::alloc(Node.sizeof);
|
||||
Node *new_node = mem::alloc($sizeof(Node));
|
||||
*new_node = { .prev = last, .value = value };
|
||||
list.last = new_node;
|
||||
if (!last)
|
||||
|
||||
@@ -13,7 +13,7 @@ private func void List.ensureCapacity(List *list) @inline
|
||||
if (list.capacity == list.size)
|
||||
{
|
||||
list.capacity = list.capacity ? 2 * list.capacity : 16;
|
||||
list.entries = mem::realloc(list.entries, Type.sizeof * list.capacity);
|
||||
list.entries = mem::realloc(list.entries, $sizeof(Type) * list.capacity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ Allocator main_allocator = { &system_malloc_function, null };
|
||||
|
||||
macro malloc($Type)
|
||||
{
|
||||
return ($Type*)(mem::alloc($Type.sizeof));
|
||||
return ($Type*)(mem::alloc($sizeof($Type)));
|
||||
}
|
||||
|
||||
func void* alloc(usize size, usize elements = 1) @inline
|
||||
|
||||
@@ -1502,26 +1502,20 @@ extern const char *kw_max;
|
||||
extern const char *kw_min;
|
||||
extern const char *kw_elements;
|
||||
extern const char *kw_align;
|
||||
extern const char *kw_alignof;
|
||||
extern const char *kw_deprecated;
|
||||
extern const char *kw_distinct;
|
||||
extern const char *kw_ensure;
|
||||
extern const char *kw_inline;
|
||||
extern const char *kw_kindof;
|
||||
extern const char *kw_len;
|
||||
extern const char *kw_inf;
|
||||
extern const char *kw_nan;
|
||||
extern const char *kw_main;
|
||||
extern const char *kw_nameof;
|
||||
extern const char *kw_offsetof;
|
||||
extern const char *kw_ordinal;
|
||||
extern const char *kw_qnameof;
|
||||
extern const char *kw_reqparse;
|
||||
extern const char *kw_require;
|
||||
extern const char *kw_pure;
|
||||
extern const char *kw_param;
|
||||
extern const char *kw_errors;
|
||||
extern const char *kw_sizeof;
|
||||
extern const char *kw___ceil;
|
||||
extern const char *kw___round;
|
||||
extern const char *kw___sqrt;
|
||||
@@ -1530,6 +1524,9 @@ extern const char *kw_FILE;
|
||||
extern const char *kw_FUNC;
|
||||
extern const char *kw_LINE;
|
||||
extern const char *kw_LINEREAL;
|
||||
extern const char *kw_default_iterator;
|
||||
extern const char *kw_incr;
|
||||
extern const char *kw_check_assign;
|
||||
|
||||
#define AST_NEW_TOKEN(_kind, _token) new_ast(_kind, source_span_from_token_id((_token).id))
|
||||
#define AST_NEW(_kind, _loc) new_ast(_kind, _loc)
|
||||
@@ -1711,6 +1708,8 @@ void expr_const_fprint(FILE *__restrict file, ExprConst *expr);
|
||||
bool expr_const_int_overflowed(const ExprConst *expr);
|
||||
bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op);
|
||||
bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind);
|
||||
void expr_insert_addr(Expr *original);
|
||||
void expr_insert_deref(Expr *expr);
|
||||
bool expr_is_constant_eval(Expr *expr);
|
||||
const char *expr_const_to_error_string(const ExprConst *expr);
|
||||
static inline void expr_set_type(Expr *expr, Type *type)
|
||||
@@ -1788,6 +1787,7 @@ bool sema_analyse_decl(Context *context, Decl *decl);
|
||||
bool sema_analyse_ct_assert_stmt(Context *context, Ast *statement);
|
||||
bool sema_analyse_statement(Context *context, Ast *statement);
|
||||
bool sema_expr_analyse_assign_right_side(Context *context, Expr *expr, Type *left_type, Expr *right, ExprFailableStatus lhs_is_failable);
|
||||
bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr *call_expr, Expr *struct_var, Decl *decl);
|
||||
|
||||
Decl *sema_resolve_symbol_in_current_dynamic_scope(Context *context, const char *symbol);
|
||||
Decl *sema_resolve_parameterized_symbol(Context *context, TokenId symbol, Path *path);
|
||||
@@ -1796,6 +1796,7 @@ Decl *sema_find_extension_method_in_module(Module *module, Type *type, const cha
|
||||
Decl *sema_resolve_normal_symbol(Context *context, TokenId symbol, Path *path, bool handle_error);
|
||||
Decl *sema_resolve_string_symbol(Context *context, const char *symbol, SourceSpan span, Path *path);
|
||||
|
||||
bool sema_resolve_type(Context *context, Type *type);
|
||||
bool sema_resolve_type_info(Context *context, TypeInfo *type_info);
|
||||
bool sema_resolve_type_info_maybe_inferred(Context *context, TypeInfo *type_info, bool allow_inferred_type);
|
||||
bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info, bool allow_inferred_type, bool in_shallow);
|
||||
|
||||
@@ -333,7 +333,7 @@ Ast *copy_ast(Ast *source)
|
||||
MACRO_COPY_DECL(ast->foreach_stmt.index);
|
||||
MACRO_COPY_DECL(ast->foreach_stmt.variable);
|
||||
MACRO_COPY_EXPR(ast->foreach_stmt.enumeration);
|
||||
MACRO_COPY_AST(ast->for_stmt.body);
|
||||
MACRO_COPY_AST(ast->foreach_stmt.body);
|
||||
return ast;
|
||||
case AST_IF_STMT:
|
||||
copy_flow(ast);
|
||||
|
||||
@@ -454,7 +454,9 @@ typedef enum
|
||||
TOKEN_CT_ENDIF, // $endif
|
||||
TOKEN_CT_ENDSWITCH, // $endswitch
|
||||
TOKEN_CT_IF, // $if
|
||||
TOKEN_CT_NAMEOF, // $nameof
|
||||
TOKEN_CT_OFFSETOF, // $offsetof
|
||||
TOKEN_CT_QNAMEOF, // $qnameof
|
||||
TOKEN_CT_SIZEOF, // $sizeof
|
||||
TOKEN_CT_SWITCH, // $switch
|
||||
TOKEN_CT_TYPEOF, // $typeof
|
||||
|
||||
@@ -1139,5 +1139,7 @@ ParseRule rules[TOKEN_EOF + 1] = {
|
||||
[TOKEN_CT_SIZEOF] = { parse_ct_call, NULL, PREC_NONE },
|
||||
[TOKEN_CT_ALIGNOF] = { parse_ct_call, NULL, PREC_NONE },
|
||||
[TOKEN_CT_OFFSETOF] = { parse_ct_call, NULL, PREC_NONE },
|
||||
[TOKEN_CT_NAMEOF] = { parse_ct_call, NULL, PREC_NONE },
|
||||
[TOKEN_CT_QNAMEOF] = { parse_ct_call, NULL, PREC_NONE },
|
||||
[TOKEN_CT_TYPEOF] = { parse_typeof_expr, NULL, PREC_NONE },
|
||||
};
|
||||
|
||||
@@ -1070,6 +1070,8 @@ Ast *parse_stmt(Context *context)
|
||||
case TOKEN_CT_OFFSETOF:
|
||||
case TOKEN_CT_ALIGNOF:
|
||||
case TOKEN_CT_SIZEOF:
|
||||
case TOKEN_CT_QNAMEOF:
|
||||
case TOKEN_CT_NAMEOF:
|
||||
return parse_expr_stmt(context);
|
||||
case TOKEN_ASSERT:
|
||||
return parse_assert_stmt(context);
|
||||
|
||||
@@ -88,6 +88,48 @@ void expr_copy_types(Expr *to, Expr *from)
|
||||
to->original_type = from->original_type;
|
||||
}
|
||||
|
||||
void expr_insert_addr(Expr *original)
|
||||
{
|
||||
assert(original->resolve_status == RESOLVE_DONE);
|
||||
if (original->expr_kind == EXPR_UNARY && original->unary_expr.operator == UNARYOP_DEREF)
|
||||
{
|
||||
*original = *original->unary_expr.expr;
|
||||
return;
|
||||
}
|
||||
Expr *inner = expr_alloc();
|
||||
*inner = *original;
|
||||
original->expr_kind = EXPR_UNARY;
|
||||
expr_set_type(original, type_get_ptr(inner->type));
|
||||
original->unary_expr.operator = UNARYOP_ADDR;
|
||||
original->unary_expr.expr = inner;
|
||||
original->pure = false;
|
||||
original->constant = false;
|
||||
original->failable = inner->failable;
|
||||
}
|
||||
|
||||
void expr_insert_deref(Expr *original)
|
||||
{
|
||||
assert(original->resolve_status == RESOLVE_DONE);
|
||||
assert(original->type->canonical->type_kind == TYPE_POINTER);
|
||||
if (original->expr_kind == EXPR_UNARY && original->unary_expr.operator == UNARYOP_ADDR)
|
||||
{
|
||||
*original = *original->unary_expr.expr;
|
||||
return;
|
||||
}
|
||||
|
||||
Type *pointee = original->type->type_kind == TYPE_POINTER ? original->type->pointer : original->type->canonical->pointer;
|
||||
Expr *inner = expr_alloc();
|
||||
*inner = *original;
|
||||
original->expr_kind = EXPR_UNARY;
|
||||
expr_set_type(original, pointee);
|
||||
original->unary_expr.operator = UNARYOP_DEREF;
|
||||
original->unary_expr.expr = inner;
|
||||
original->pure = false;
|
||||
original->constant = false;
|
||||
original->failable = inner->failable;
|
||||
}
|
||||
|
||||
|
||||
static void expr_unify_binary_properties(Expr *expr, Expr *left, Expr *right)
|
||||
{
|
||||
expr->pure = left->pure & right->pure;
|
||||
@@ -1145,7 +1187,7 @@ static bool sema_check_stmt_compile_time(Context *context, Ast *ast)
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr *call_expr, Expr *struct_var, Decl *decl)
|
||||
bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr *call_expr, Expr *struct_var, Decl *decl)
|
||||
{
|
||||
assert(decl->decl_kind == DECL_MACRO);
|
||||
|
||||
@@ -1574,12 +1616,8 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr
|
||||
if (decl->decl_kind == DECL_FUNC || decl->decl_kind == DECL_MACRO)
|
||||
{
|
||||
expr->call_expr.is_type_method = true;
|
||||
struct_var = expr_new(EXPR_UNARY, func_expr->access_expr.parent->span);
|
||||
struct_var->unary_expr.expr = func_expr->access_expr.parent;
|
||||
struct_var->unary_expr.operator = UNARYOP_ADDR;
|
||||
struct_var->resolve_status = RESOLVE_DONE;
|
||||
assert(func_expr->access_expr.parent->resolve_status == RESOLVE_DONE);
|
||||
expr_set_type(struct_var, type_get_ptr(struct_var->unary_expr.expr->type));
|
||||
expr_insert_addr(func_expr->access_expr.parent);
|
||||
struct_var = func_expr->access_expr.parent;
|
||||
if (decl->decl_kind == DECL_MACRO)
|
||||
{
|
||||
return sema_expr_analyse_macro_call(context, to, expr, struct_var, decl);
|
||||
@@ -1843,17 +1881,6 @@ static inline bool sema_expr_analyse_slice(Context *context, Expr *expr)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void insert_access_deref(Expr *expr)
|
||||
{
|
||||
Expr *deref = expr_new(EXPR_UNARY, expr->span);
|
||||
deref->unary_expr.operator = UNARYOP_DEREF;
|
||||
deref->unary_expr.expr = expr->access_expr.parent;
|
||||
deref->resolve_status = RESOLVE_DONE;
|
||||
assert(expr->access_expr.parent->type->canonical->type_kind == TYPE_POINTER);
|
||||
expr_set_type(deref, expr->access_expr.parent->type->canonical->pointer);
|
||||
deref->failable = expr->access_expr.parent->failable;
|
||||
expr->access_expr.parent = deref;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_group(Context *context, Type *to, Expr *expr)
|
||||
{
|
||||
@@ -2093,31 +2120,7 @@ static inline bool sema_expr_analyse_type_access(Expr *expr, TypeInfo *parent, b
|
||||
Type *canonical = parent->type->canonical;
|
||||
const char *name = TOKSTR(identifier_token);
|
||||
|
||||
// Foo.sizeof => return the size in bytes, e.g. 11
|
||||
if (name == kw_sizeof)
|
||||
{
|
||||
expr_rewrite_to_int_const(expr, type_compint, type_size(canonical));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Foo.alignof => return the alignment, e.g. 4
|
||||
if (name == kw_alignof)
|
||||
{
|
||||
expr_rewrite_to_int_const(expr, type_compint, type_abi_alignment(canonical));
|
||||
return true;
|
||||
}
|
||||
// Foo.nameof => return the name, e.g. "Foo"
|
||||
if (name == kw_nameof)
|
||||
{
|
||||
expr_rewrite_to_string(expr, canonical->name);
|
||||
return true;
|
||||
}
|
||||
// Foo.qnameof => return the qualified name, e.g. "mylib::Foo"
|
||||
if (name == kw_qnameof)
|
||||
{
|
||||
expr_rewrite_to_string(expr, type_generate_qname(canonical));
|
||||
return true;
|
||||
}
|
||||
// 3. Handle float.nan, double.inf etc
|
||||
if (type_is_float(canonical))
|
||||
{
|
||||
if (name == kw_nan)
|
||||
@@ -2147,7 +2150,7 @@ static inline bool sema_expr_analyse_type_access(Expr *expr, TypeInfo *parent, b
|
||||
return true;
|
||||
}
|
||||
}
|
||||
//
|
||||
|
||||
if (!type_may_have_sub_elements(canonical))
|
||||
{
|
||||
SEMA_ERROR(expr, "'%s' does not have a property '%s'.", type_to_error_string(parent->type), name);
|
||||
@@ -2199,6 +2202,7 @@ static inline bool sema_expr_analyse_type_access(Expr *expr, TypeInfo *parent, b
|
||||
case DECL_ERR:
|
||||
case DECL_UNION:
|
||||
case DECL_STRUCT:
|
||||
case DECL_DISTINCT:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
@@ -2215,18 +2219,7 @@ static inline bool sema_expr_analyse_type_access(Expr *expr, TypeInfo *parent, b
|
||||
return true;
|
||||
}
|
||||
}
|
||||
VECEACH(decl->strukt.members, i)
|
||||
{
|
||||
Decl *member = decl->strukt.members[i];
|
||||
if (name == member->name)
|
||||
{
|
||||
expr->expr_kind = EXPR_MEMBER_ACCESS;
|
||||
expr->access_expr.ref = member;
|
||||
expr_set_type(expr, member->type);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
SEMA_ERROR(expr, "No function or member '%s.%s' found.", type_to_error_string(parent->type), name);
|
||||
SEMA_ERROR(expr, "No function '%s.%s' found.", type_to_error_string(parent->type), name);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2260,16 +2253,6 @@ static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr,
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
return true;
|
||||
}
|
||||
if (name == kw_sizeof && !is_macro)
|
||||
{
|
||||
expr_rewrite_to_int_const(expr, type_compint, type_size(ref->type));
|
||||
return true;
|
||||
}
|
||||
if (name == kw_alignof && !is_macro)
|
||||
{
|
||||
expr_rewrite_to_int_const(expr, type_compint, type_abi_alignment(ref->type));
|
||||
return true;
|
||||
}
|
||||
if (name == kw_ordinal && !is_macro)
|
||||
{
|
||||
if (ref->decl_kind == DECL_ENUM_CONSTANT)
|
||||
@@ -2279,20 +2262,6 @@ static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr,
|
||||
}
|
||||
}
|
||||
|
||||
if (name == kw_nameof && !is_macro)
|
||||
{
|
||||
expr_rewrite_to_string(expr, ref->name);
|
||||
return true;
|
||||
}
|
||||
if (name == kw_qnameof && !is_macro)
|
||||
{
|
||||
expr_rewrite_to_string(expr, ref->external_name ?: ref->name);
|
||||
return true;
|
||||
}
|
||||
if (name == kw_kindof && !is_macro)
|
||||
{
|
||||
TODO
|
||||
}
|
||||
// If we have something like struct Foo { Bar b; int c; struct d { int e; } }
|
||||
// If we are inspecting Foo.c we're done here. Otherwise handle struct d / Bar b case
|
||||
// The same way.
|
||||
@@ -2393,7 +2362,6 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
|
||||
if (TOKEN_IS_INVALID(identifier_token)) return false;
|
||||
|
||||
// 2. If our left hand side is a type, e.g. MyInt.abc, handle this here.
|
||||
Type *parent_type = parent->type;
|
||||
if (parent->expr_kind == EXPR_TYPEINFO)
|
||||
{
|
||||
return sema_expr_analyse_type_access(expr, parent->type_expr, was_group, is_macro, identifier_token);
|
||||
@@ -2414,14 +2382,11 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
|
||||
assert(parent->resolve_status == RESOLVE_DONE);
|
||||
|
||||
// 7. Is this a pointer? If so we insert a deref.
|
||||
Type *type = parent_type->canonical;
|
||||
bool is_pointer = type->type_kind == TYPE_POINTER;
|
||||
bool is_pointer = parent->type->canonical->type_kind == TYPE_POINTER;
|
||||
if (is_pointer)
|
||||
{
|
||||
type = type->pointer->canonical;
|
||||
parent_type = type;
|
||||
if (!sema_cast_rvalue(context, NULL, parent)) return false;
|
||||
insert_access_deref(expr);
|
||||
expr_insert_deref(expr->access_expr.parent);
|
||||
parent = expr->access_expr.parent;
|
||||
}
|
||||
|
||||
@@ -2429,6 +2394,7 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
|
||||
const char *kw = TOKSTR(identifier_token);
|
||||
Expr *current_parent = parent;
|
||||
|
||||
Type *type = parent->type->canonical;
|
||||
Type *flat_type = type_flatten(type);
|
||||
CHECK_DEEPER:
|
||||
|
||||
@@ -2445,7 +2411,7 @@ CHECK_DEEPER:
|
||||
}
|
||||
if (flat_type->type_kind == TYPE_ARRAY)
|
||||
{
|
||||
expr_rewrite_to_int_const(expr, type_compint, type->array.len);
|
||||
expr_rewrite_to_int_const(expr, type_compint, flat_type->array.len);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2453,7 +2419,7 @@ CHECK_DEEPER:
|
||||
// 9. At this point we may only have distinct, struct, union, error, enum
|
||||
if (!type_may_have_sub_elements(type))
|
||||
{
|
||||
SEMA_ERROR(expr, "There is no member or method '%s' on '%s'", kw, type_to_error_string(parent_type));
|
||||
SEMA_ERROR(expr, "There is no member or method '%s' on '%s'", kw, type_to_error_string(parent->type));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -5689,6 +5655,74 @@ static inline bool sema_expr_analyse_ct_sizeof(Context *context, Type *to, Expr
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool decl_is_local(Decl *decl)
|
||||
{
|
||||
if (decl->decl_kind != DECL_VAR) return false;
|
||||
VarDeclKind kind = decl->var.kind;
|
||||
return kind == VARDECL_PARAM_CT_TYPE
|
||||
|| kind == VARDECL_PARAM
|
||||
|| kind == VARDECL_PARAM_CT
|
||||
|| kind == VARDECL_LOCAL
|
||||
|| kind == VARDECL_LOCAL_CT_TYPE
|
||||
|| kind == VARDECL_LOCAL_CT
|
||||
|| kind == VARDECL_PARAM_REF
|
||||
|| kind == VARDECL_PARAM_EXPR
|
||||
|| kind == VARDECL_MEMBER;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_ct_nameof(Context *context, Type *to, Expr *expr)
|
||||
{
|
||||
if (expr->resolve_status == RESOLVE_DONE) return true;
|
||||
|
||||
Expr **elements = expr->ct_call_expr.arguments;
|
||||
unsigned count = vec_size(elements);
|
||||
if (count > 1)
|
||||
{
|
||||
SEMA_ERROR(elements[1], "The function only takes one argument.");
|
||||
return expr_poison(expr);
|
||||
}
|
||||
Expr *first_expr = elements[0];
|
||||
if (!sema_analyse_expr_value(context, NULL, first_expr)) return false;
|
||||
|
||||
bool qualified = expr->ct_call_expr.token_type == TOKEN_CT_QNAMEOF;
|
||||
|
||||
if (first_expr->expr_kind == EXPR_TYPEINFO)
|
||||
{
|
||||
Type *type = first_expr->type_expr->type->canonical;
|
||||
if (!sema_resolve_type(context, type)) return false;
|
||||
// TODO type_is_builtin is wrong also this does not cover virtual.
|
||||
if (!qualified || type_is_builtin(type->type_kind))
|
||||
{
|
||||
expr_rewrite_to_string(expr, type->name);
|
||||
return true;
|
||||
}
|
||||
scratch_buffer_clear();
|
||||
scratch_buffer_append(type->decl->module->name->module);
|
||||
scratch_buffer_append("::");
|
||||
scratch_buffer_append(type->name);
|
||||
expr_rewrite_to_string(expr, scratch_buffer_interned());
|
||||
return true;
|
||||
}
|
||||
if (first_expr->expr_kind != EXPR_IDENTIFIER)
|
||||
{
|
||||
SEMA_ERROR(first_expr, "Expected an identifier.");
|
||||
return false;
|
||||
}
|
||||
Decl *decl = first_expr->identifier_expr.decl;
|
||||
|
||||
if (!decl->module || !qualified || decl_is_local(decl))
|
||||
{
|
||||
expr_rewrite_to_string(expr, decl->name);
|
||||
return true;
|
||||
}
|
||||
scratch_buffer_clear();
|
||||
scratch_buffer_append(decl->module->name->module);
|
||||
scratch_buffer_append("::");
|
||||
scratch_buffer_append(decl->name);
|
||||
expr_rewrite_to_string(expr, scratch_buffer_interned());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static inline bool sema_expr_analyse_ct_alignof(Context *context, Type *to, Expr *expr)
|
||||
{
|
||||
@@ -5696,7 +5730,9 @@ static inline bool sema_expr_analyse_ct_alignof(Context *context, Type *to, Expr
|
||||
if (!sema_analyse_ct_call_parameters(context, expr)) return false;
|
||||
Type *type = expr->ct_call_expr.type->canonical;
|
||||
ExprFlatElement *elements = expr->ct_call_expr.flatpath;
|
||||
AlignSize align = expr->ct_call_expr.decl ? expr->ct_call_expr.decl->alignment : type_abi_alignment(type);
|
||||
|
||||
Decl *decl = expr->ct_call_expr.decl;
|
||||
AlignSize align = decl && !decl_is_user_defined_type(decl) ? expr->ct_call_expr.decl->alignment : type_abi_alignment(type);
|
||||
VECEACH(elements, i)
|
||||
{
|
||||
ExprFlatElement element = elements[i];
|
||||
@@ -5744,6 +5780,7 @@ static inline bool sema_expr_analyse_ct_alignof(Context *context, Type *to, Expr
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static inline bool sema_expr_analyse_ct_offsetof(Context *context, Type *to, Expr *expr)
|
||||
{
|
||||
Expr *first = expr->ct_call_expr.arguments[0];
|
||||
@@ -5812,6 +5849,10 @@ static inline bool sema_expr_analyse_ct_call(Context *context, Type *to, Expr *e
|
||||
return sema_expr_analyse_ct_alignof(context, to, expr);
|
||||
case TOKEN_CT_OFFSETOF:
|
||||
return sema_expr_analyse_ct_offsetof(context, to, expr);
|
||||
case TOKEN_CT_QNAMEOF:
|
||||
return sema_expr_analyse_ct_nameof(context, to, expr);
|
||||
case TOKEN_CT_NAMEOF:
|
||||
return sema_expr_analyse_ct_nameof(context, to, expr);
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
@@ -591,7 +591,43 @@ static inline bool sema_analyse_for_stmt(Context *context, Ast *statement)
|
||||
return success;
|
||||
}
|
||||
|
||||
static inline bool sema_inline_default_iterator(Context *context, Expr *expr)
|
||||
{
|
||||
Type *type = expr->type->canonical;
|
||||
if (!type_may_have_sub_elements(type)) return true;
|
||||
Decl *ambiguous = NULL;
|
||||
Decl *private = NULL;
|
||||
Decl *result = sema_resolve_method(context, type->decl, kw_default_iterator, &ambiguous, &private);
|
||||
if (!result)
|
||||
{
|
||||
SEMA_ERROR(expr, "There are multiple candidates for 'default_iterator' on %s.",
|
||||
type_quoted_error_string(expr->type));
|
||||
return false;
|
||||
}
|
||||
|
||||
Expr *call = expr_new(EXPR_CALL, expr->span);
|
||||
call->call_expr.arguments = NULL;
|
||||
call->call_expr.body = NULL;
|
||||
call->call_expr.unsplat_last = false;
|
||||
call->call_expr.is_type_method = true;
|
||||
bool success;
|
||||
switch (result->decl_kind)
|
||||
{
|
||||
case DECL_MACRO:
|
||||
success = sema_expr_analyse_macro_call(context, NULL, call, expr, result);
|
||||
break;
|
||||
case DECL_GENERIC:
|
||||
case DECL_FUNC:
|
||||
TODO
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
if (success)
|
||||
{
|
||||
expr_replace(expr, call);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement)
|
||||
{
|
||||
// Pull out the relevant data.
|
||||
|
||||
@@ -137,6 +137,44 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
|
||||
}
|
||||
|
||||
|
||||
bool sema_resolve_type(Context *context, Type *type)
|
||||
{
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_TYPEDEF:
|
||||
return sema_resolve_type(context, type->canonical);
|
||||
case TYPE_POISONED:
|
||||
case ALL_INTS:
|
||||
case ALL_FLOATS:
|
||||
case TYPE_VOID:
|
||||
case TYPE_BOOL:
|
||||
case TYPE_TYPEID:
|
||||
case TYPE_VIRTUAL_ANY:
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_STRLIT:
|
||||
case TYPE_VECTOR:
|
||||
return true;
|
||||
case TYPE_POINTER:
|
||||
return sema_resolve_type(context, type->pointer);
|
||||
case TYPE_ENUM:
|
||||
case TYPE_FUNC:
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_DISTINCT:
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
case TYPE_SUBARRAY:
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
return sema_resolve_type(context, type->array.base);
|
||||
case TYPE_TYPEINFO:
|
||||
TODO
|
||||
case TYPE_VIRTUAL:
|
||||
TODO;
|
||||
}
|
||||
return sema_analyse_decl(context, type->decl);
|
||||
}
|
||||
|
||||
bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info, bool allow_inferred_type, bool in_shallow)
|
||||
{
|
||||
if (type_info->resolve_status == RESOLVE_DONE) return type_info_ok(type_info);
|
||||
|
||||
@@ -37,7 +37,6 @@ static SymTab symtab;
|
||||
const char *attribute_list[NUMBER_OF_ATTRIBUTES];
|
||||
|
||||
const char *kw_align;
|
||||
const char *kw_alignof;
|
||||
const char *kw_deprecated;
|
||||
const char *kw_distinct;
|
||||
const char *kw_ensure;
|
||||
@@ -45,21 +44,16 @@ const char *kw_elements;
|
||||
const char *kw_errors;
|
||||
const char *kw_inf;
|
||||
const char *kw_inline;
|
||||
const char *kw_kindof;
|
||||
const char *kw_len;
|
||||
const char *kw_main;
|
||||
const char *kw_max;
|
||||
const char *kw_min;
|
||||
const char *kw_nan;
|
||||
const char *kw_nameof;
|
||||
const char *kw_offsetof;
|
||||
const char *kw_ordinal;
|
||||
const char *kw_param;
|
||||
const char *kw_pure;
|
||||
const char *kw_qnameof;
|
||||
const char *kw_reqparse;
|
||||
const char *kw_require;
|
||||
const char *kw_sizeof;
|
||||
const char *kw_std;
|
||||
const char *kw___ceil;
|
||||
const char *kw___round;
|
||||
@@ -69,6 +63,9 @@ const char *kw_FILE;
|
||||
const char *kw_FUNC;
|
||||
const char *kw_LINE;
|
||||
const char *kw_LINEREAL;
|
||||
const char *kw_default_iterator;
|
||||
const char *kw_incr;
|
||||
const char *kw_check_assign;
|
||||
|
||||
void symtab_init(uint32_t capacity)
|
||||
{
|
||||
@@ -103,7 +100,6 @@ void symtab_init(uint32_t capacity)
|
||||
TokenType type = TOKEN_IDENT;
|
||||
#define KW_DEF(x) symtab_add(x, sizeof(x) - 1, fnv1a(x, sizeof(x) - 1), &type)
|
||||
kw_align = KW_DEF("align");
|
||||
kw_alignof = KW_DEF("alignof");
|
||||
kw_deprecated = KW_DEF("deprecated");
|
||||
kw_distinct = KW_DEF("distinct");
|
||||
kw_elements = KW_DEF("elements");
|
||||
@@ -111,20 +107,15 @@ void symtab_init(uint32_t capacity)
|
||||
kw_errors = KW_DEF("errors");
|
||||
kw_inf = KW_DEF("inf");
|
||||
kw_inline = KW_DEF("inline");
|
||||
kw_kindof = KW_DEF("kindof");
|
||||
kw_len = KW_DEF("len");
|
||||
kw_main = KW_DEF("main");
|
||||
kw_max = KW_DEF("max");
|
||||
kw_min = KW_DEF("min");
|
||||
kw_nameof = KW_DEF("nameof");
|
||||
kw_nan = KW_DEF("nan");
|
||||
kw_offsetof = KW_DEF("offsetof");
|
||||
kw_ordinal = KW_DEF("ordinal");
|
||||
kw_param = KW_DEF("param");
|
||||
kw_pure = KW_DEF("pure");
|
||||
kw_qnameof = KW_DEF("qnameof");
|
||||
kw_require = KW_DEF("require");
|
||||
kw_sizeof = KW_DEF("sizeof");
|
||||
kw_std = KW_DEF("std");
|
||||
kw___ceil = KW_DEF("__ceil");
|
||||
kw___round = KW_DEF("__round");
|
||||
@@ -134,7 +125,9 @@ void symtab_init(uint32_t capacity)
|
||||
kw_LINEREAL = KW_DEF("LINEREAL");
|
||||
kw_FILE = KW_DEF("FILE");
|
||||
kw_FUNC = KW_DEF("FUNC");
|
||||
|
||||
kw_incr = KW_DEF("incr");
|
||||
kw_default_iterator = KW_DEF("default_iterator");
|
||||
kw_check_assign = KW_DEF("check_assign");
|
||||
attribute_list[ATTRIBUTE_INLINE] = kw_inline;
|
||||
attribute_list[ATTRIBUTE_NOINLINE] = KW_DEF("noinline");
|
||||
attribute_list[ATTRIBUTE_OPAQUE] = KW_DEF("opaque");
|
||||
|
||||
@@ -339,8 +339,12 @@ const char *token_type_to_string(TokenType type)
|
||||
return "$endswitch";
|
||||
case TOKEN_CT_IF:
|
||||
return "$if";
|
||||
case TOKEN_CT_NAMEOF:
|
||||
return "$nameof";
|
||||
case TOKEN_CT_OFFSETOF:
|
||||
return "$offsetof";
|
||||
case TOKEN_CT_QNAMEOF:
|
||||
return "$qnameof";
|
||||
case TOKEN_CT_SIZEOF:
|
||||
return "$sizeof";
|
||||
case TOKEN_CT_SWITCH:
|
||||
|
||||
55
test/test_suite/compile_time_introspection/qnameof.c3t
Normal file
55
test/test_suite/compile_time_introspection/qnameof.c3t
Normal file
@@ -0,0 +1,55 @@
|
||||
module qnametest;
|
||||
|
||||
extern func int printf(char *, ...);
|
||||
int x;
|
||||
|
||||
struct Blob { int z; int f; }
|
||||
|
||||
func void main()
|
||||
{
|
||||
int help;
|
||||
printf("printf: %s\n", $nameof(printf));
|
||||
printf("printfq: %s\n", $qnameof(printf));
|
||||
printf("Blobq: %s\n", $qnameof(Blob));
|
||||
printf("Blob: %s\n", $nameof(Blob));
|
||||
printf("xq: %s\n", $qnameof(x));
|
||||
printf("x: %s\n", $nameof(x));
|
||||
printf("helpq: %s\n", $qnameof(help));
|
||||
printf("mainq: %s\n", $qnameof(main));
|
||||
printf("Blob**[3]: %s\n", $nameof(Blob**[3]));
|
||||
}
|
||||
|
||||
// #expect: qnametest.ll
|
||||
|
||||
@.str = private constant [12 x i8] c"printf: %s\0A\00", align 1
|
||||
@.str.1 = private constant [7 x i8] c"printf\00", align 1
|
||||
@.str.2 = private constant [13 x i8] c"printfq: %s\0A\00", align 1
|
||||
@.str.3 = private constant [18 x i8] c"qnametest::printf\00", align 1
|
||||
@.str.4 = private constant [11 x i8] c"Blobq: %s\0A\00", align 1
|
||||
@.str.5 = private constant [16 x i8] c"qnametest::Blob\00", align 1
|
||||
@.str.6 = private constant [10 x i8] c"Blob: %s\0A\00", align 1
|
||||
@.str.7 = private constant [5 x i8] c"Blob\00", align 1
|
||||
@.str.8 = private constant [8 x i8] c"xq: %s\0A\00", align 1
|
||||
@.str.9 = private constant [13 x i8] c"qnametest::x\00", align 1
|
||||
@.str.10 = private constant [7 x i8] c"x: %s\0A\00", align 1
|
||||
@.str.11 = private constant [2 x i8] c"x\00", align 1
|
||||
@.str.12 = private constant [11 x i8] c"helpq: %s\0A\00", align 1
|
||||
@.str.13 = private constant [5 x i8] c"help\00", align 1
|
||||
@.str.14 = private constant [11 x i8] c"mainq: %s\0A\00", align 1
|
||||
@.str.15 = private constant [16 x i8] c"qnametest::main\00", align 1
|
||||
@.str.16 = private constant [15 x i8] c"Blob**[3]: %s\0A\00", align 1
|
||||
@.str.17 = private constant [10 x i8] c"Blob**[3]\00", align 1
|
||||
|
||||
define void @main()
|
||||
%help = alloca i32, align 4
|
||||
store i32 0, i32* %help, align 4
|
||||
%0 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.1, i32 0, i32 0))
|
||||
%1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.2, i32 0, i32 0), i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.3, i32 0, i32 0))
|
||||
%2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.4, i32 0, i32 0), i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.5, i32 0, i32 0))
|
||||
%3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.6, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.7, i32 0, i32 0))
|
||||
%4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.8, i32 0, i32 0), i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.9, i32 0, i32 0))
|
||||
%5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.10, i32 0, i32 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.11, i32 0, i32 0))
|
||||
%6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.12, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.13, i32 0, i32 0))
|
||||
%7 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.14, i32 0, i32 0), i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.15, i32 0, i32 0))
|
||||
%8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.16, i32 0, i32 0), i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.17, i32 0, i32 0))
|
||||
ret void
|
||||
@@ -8,8 +8,8 @@ enum MyEnum : short
|
||||
int myenum_max = MyEnum.max;
|
||||
int myenum_min = MyEnum.min;
|
||||
int myenum_elements = MyEnum.elements;
|
||||
int myenum_alignof = MyEnum.alignof;
|
||||
int myenum_sizeof = MyEnum.sizeof;
|
||||
int myenum_alignof = $alignof(MyEnum);
|
||||
int myenum_sizeof = $sizeof(MyEnum);
|
||||
|
||||
// #expect: compile_time.ll
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ func int Foo.func2(Foo* f, int i)
|
||||
|
||||
func void test_unknown_member()
|
||||
{
|
||||
int a = Foo.b; // #error: No function or member 'Foo.b' found.
|
||||
int a = Foo.b; // #error: No function 'Foo.b' found.
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -6,7 +6,7 @@ struct Foo
|
||||
long bar;
|
||||
}
|
||||
|
||||
private usize x = Foo.sizeof;
|
||||
private usize x = $sizeof(Foo);
|
||||
|
||||
private Foo foo1 = { 1, 2 };
|
||||
private Foo foo2 = { .foo = 2 };
|
||||
|
||||
@@ -7,7 +7,7 @@ struct Foo1 @packed @align(4)
|
||||
char foo;
|
||||
}
|
||||
|
||||
$assert(Foo1.sizeof == 12);
|
||||
$assert($sizeof(Foo1) == 12);
|
||||
Foo1 foo1 = { 1, 2 };
|
||||
|
||||
// <{ i8, i64, [3 x i8] }>
|
||||
@@ -17,7 +17,7 @@ struct Foo2 @packed @align(4)
|
||||
long bar;
|
||||
}
|
||||
|
||||
$assert(Foo2.sizeof == 12);
|
||||
$assert($sizeof(Foo2) == 12);
|
||||
Foo2 foo2 = { 1, 2 };
|
||||
|
||||
// <{ i8, i64, [7 x i8] }>
|
||||
@@ -28,7 +28,7 @@ struct Foo3 @packed @align(8)
|
||||
}
|
||||
|
||||
Foo3 foo3 = { 1, 2 };
|
||||
$assert(Foo3.sizeof == 16);
|
||||
$assert($sizeof(Foo3) == 16);
|
||||
|
||||
// <{ i8, i64 }>
|
||||
struct Foo4 @packed
|
||||
@@ -37,7 +37,7 @@ struct Foo4 @packed
|
||||
long bar;
|
||||
}
|
||||
|
||||
$assert(Foo4.sizeof == 9);
|
||||
$assert($sizeof(Foo4) == 9);
|
||||
Foo4 foo4 = { 1, 2 };
|
||||
|
||||
// { i32, [12 x i8], i8, [15 x i8] }
|
||||
@@ -47,7 +47,7 @@ struct Foo5
|
||||
ichar foo @align(16);
|
||||
}
|
||||
|
||||
$assert(Foo5.sizeof == 32);
|
||||
$assert($sizeof(Foo5) == 32);
|
||||
Foo5 foo5 = { 1, 2 };
|
||||
|
||||
func int test5(ichar x)
|
||||
@@ -64,7 +64,7 @@ struct Foo6 @packed
|
||||
short c;
|
||||
}
|
||||
|
||||
$assert(Foo6.sizeof == 8);
|
||||
$assert($sizeof(Foo6) == 8);
|
||||
Foo6 foo6 = { 1, 2, 3 };
|
||||
|
||||
// #expect: struct2.ll
|
||||
|
||||
Reference in New Issue
Block a user