mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Change anyerror { i64, i64 } -> i64. Cleaned up platform data and max tls / vector align. Initial work on bitstruct (just parsing). Updated try / catch semantics.
This commit is contained in:
committed by
Christoffer Lerno
parent
95836e98a2
commit
f180a0d44a
@@ -9,6 +9,6 @@ enum CompilerOptLevel
|
||||
}
|
||||
|
||||
const CompilerOptLevel COMPILER_OPT_LEVEL = (CompilerOptLevel)(${COMPILER_OPT_LEVEL});
|
||||
const bool LITTLE_ENDIAN = ${PLATFORM_LITTLE_ENDIAN};
|
||||
const bool BIG_ENDIAN = ${PLATFORM_BIG_ENDIAN};
|
||||
const bool I128_SUPPORT = ${PLATFORM_I128_SUPPORTED};
|
||||
const bool COMPILER_SAFE_MODE = ${COMPILER_SAFE_MODE};
|
||||
|
||||
@@ -11,14 +11,10 @@ enum AllocationKind
|
||||
REALLOC,
|
||||
FREE,
|
||||
}
|
||||
enum AllocationFailureKind
|
||||
{
|
||||
OUT_OF_MEMORY
|
||||
}
|
||||
|
||||
errtype AllocationFailure
|
||||
{
|
||||
AllocationFailureKind failureKind;
|
||||
OUT_OF_MEMORY
|
||||
}
|
||||
|
||||
define AllocatorFunction = func void!(void *data, void** pointer, usize bytes, usize alignment, AllocationKind kind);
|
||||
@@ -35,12 +31,12 @@ func void! system_malloc_function(void *unused, void** pointer, usize bytes, usi
|
||||
{
|
||||
case ALLOC:
|
||||
void* data = _malloc(bytes);
|
||||
if (!data) return AllocationFailure({ OUT_OF_MEMORY })!;
|
||||
if (!data) return AllocationFailure.OUT_OF_MEMORY!;
|
||||
*pointer = data;
|
||||
return;
|
||||
case REALLOC:
|
||||
void* data = _realloc(*pointer, bytes);
|
||||
if (!data) return AllocationFailure({ OUT_OF_MEMORY })!;
|
||||
if (!data) return AllocationFailure.OUT_OF_MEMORY!;
|
||||
*pointer = data;
|
||||
return;
|
||||
case FREE:
|
||||
|
||||
@@ -52,6 +52,8 @@ const char *decl_to_name(Decl *decl)
|
||||
{
|
||||
switch (decl->decl_kind)
|
||||
{
|
||||
case DECL_BITSTRUCT:
|
||||
return "bitstruct";
|
||||
case DECL_POISONED:
|
||||
return "poisoned decl";
|
||||
case DECL_CT_ASSERT:
|
||||
@@ -83,8 +85,10 @@ const char *decl_to_name(Decl *decl)
|
||||
return "enum";
|
||||
case DECL_ENUM_CONSTANT:
|
||||
return "enum value";
|
||||
case DECL_ERR:
|
||||
return "error";
|
||||
case DECL_ERRVALUE:
|
||||
return "err value";
|
||||
case DECL_ERRTYPE:
|
||||
return "errtype";
|
||||
case DECL_FUNC:
|
||||
return "function";
|
||||
case DECL_GENERIC:
|
||||
@@ -100,6 +104,9 @@ const char *decl_to_name(Decl *decl)
|
||||
case DECL_VAR:
|
||||
switch (decl->var.kind)
|
||||
{
|
||||
case VARDECL_ERASE:
|
||||
case VARDECL_REWRAPPED:
|
||||
UNREACHABLE
|
||||
case VARDECL_CONST:
|
||||
return "constant";
|
||||
case VARDECL_GLOBAL:
|
||||
@@ -122,8 +129,8 @@ const char *decl_to_name(Decl *decl)
|
||||
return "compile time variable";
|
||||
case VARDECL_LOCAL_CT_TYPE:
|
||||
return "compile time type variable";
|
||||
case VARDECL_ALIAS:
|
||||
return "alias";
|
||||
case VARDECL_UNWRAPPED:
|
||||
return "unwrapped";
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
@@ -162,7 +169,7 @@ Decl *decl_new_with_type(TokenId name, DeclKind decl_type, Visibility visibility
|
||||
case DECL_STRUCT:
|
||||
kind = TYPE_STRUCT;
|
||||
break;
|
||||
case DECL_ERR:
|
||||
case DECL_ERRTYPE:
|
||||
kind = TYPE_ERRTYPE;
|
||||
break;
|
||||
case DECL_ENUM:
|
||||
@@ -174,9 +181,13 @@ Decl *decl_new_with_type(TokenId name, DeclKind decl_type, Visibility visibility
|
||||
case DECL_TYPEDEF:
|
||||
kind = TYPE_TYPEDEF;
|
||||
break;
|
||||
case DECL_BITSTRUCT:
|
||||
kind = TYPE_BITSTRUCT;
|
||||
break;
|
||||
case DECL_POISONED:
|
||||
case DECL_VAR:
|
||||
case DECL_ENUM_CONSTANT:
|
||||
case DECL_ERRVALUE:
|
||||
case DECL_ARRAY_VALUE:
|
||||
case DECL_IMPORT:
|
||||
case DECL_MACRO:
|
||||
@@ -213,7 +224,7 @@ const char *decl_var_to_string(VarDeclKind kind)
|
||||
return "member";
|
||||
case VARDECL_PARAM:
|
||||
return "param";
|
||||
case VARDECL_ALIAS:
|
||||
case VARDECL_UNWRAPPED:
|
||||
return "alias";
|
||||
case VARDECL_PARAM_CT:
|
||||
return "$param";
|
||||
@@ -227,6 +238,9 @@ const char *decl_var_to_string(VarDeclKind kind)
|
||||
return "$local";
|
||||
case VARDECL_LOCAL_CT_TYPE:
|
||||
return "$Local";
|
||||
case VARDECL_REWRAPPED:
|
||||
case VARDECL_ERASE:
|
||||
UNREACHABLE
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
@@ -416,6 +430,12 @@ void fprint_type_recursive(Context *context, FILE *file, Type *type, int indent)
|
||||
}
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_BITSTRUCT:
|
||||
DUMP("(bitstruct");
|
||||
return;
|
||||
case TYPE_ERRTYPE:
|
||||
DUMPF("(errtype %s)", type->name);
|
||||
return;
|
||||
case TYPE_DISTINCT:
|
||||
DUMPF("(distinct %s)", type->name);
|
||||
return;
|
||||
@@ -443,9 +463,6 @@ void fprint_type_recursive(Context *context, FILE *file, Type *type, int indent)
|
||||
case TYPE_ENUM:
|
||||
DUMPF("(enum %s)", type->name);
|
||||
return;
|
||||
case TYPE_ERRTYPE:
|
||||
DUMPF("(errtype %s)", type->name);
|
||||
return;
|
||||
case TYPE_TYPEDEF:
|
||||
DUMPF("(typedef %s", type->name);
|
||||
DUMPTYPE(type->canonical);
|
||||
@@ -488,7 +505,7 @@ void fprint_type_recursive(Context *context, FILE *file, Type *type, int indent)
|
||||
case TYPE_STRLIT:
|
||||
DUMP("(ct string)");
|
||||
return;
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_ANYERR:
|
||||
DUMP("(any-error)");
|
||||
return;
|
||||
}
|
||||
@@ -603,6 +620,26 @@ void fprint_expr_recursive(Context *context, FILE *file, Expr *expr, int indent)
|
||||
DUMPEXPC(expr);
|
||||
DUMPDECL(expr->decl_expr);
|
||||
break;
|
||||
case EXPR_TRY_UNWRAP_CHAIN:
|
||||
DUMP("(try-unwrap-chain");
|
||||
DUMPEXPC(expr);
|
||||
DUMPEXPRS(expr->try_unwrap_chain_expr);
|
||||
break;
|
||||
case EXPR_CATCH_UNWRAP:
|
||||
DUMP("(catch-unwrap");
|
||||
DUMPEXPC(expr);
|
||||
DUMPEXPRS(expr->catch_unwrap_expr.exprs);
|
||||
break;
|
||||
case EXPR_TRY_UNWRAP:
|
||||
DUMP("(try-unwrap");
|
||||
DUMPEXPC(expr);
|
||||
DUMPEXPR(expr->try_unwrap_expr.init);
|
||||
break;
|
||||
case EXPR_TRY_DECL:
|
||||
DUMP("(try-decl");
|
||||
DUMPEXPC(expr);
|
||||
DUMPDECL(expr->try_decl_expr.decl);
|
||||
break;
|
||||
case EXPR_NOP:
|
||||
DUMP("(nop)");
|
||||
return;
|
||||
@@ -644,9 +681,9 @@ void fprint_expr_recursive(Context *context, FILE *file, Expr *expr, int indent)
|
||||
DUMPEXPC(expr);
|
||||
DUMPEXPR(expr->len_expr.inner);
|
||||
DUMPEND();
|
||||
case EXPR_DECL_LIST:
|
||||
case EXPR_COND:
|
||||
DUMP("(decllist");
|
||||
DUMPEXPRS(expr->dexpr_list_expr);
|
||||
DUMPEXPRS(expr->cond_expr);
|
||||
DUMPEND();
|
||||
case EXPR_FAILABLE:
|
||||
DUMP("(failable");
|
||||
@@ -710,16 +747,6 @@ void fprint_expr_recursive(Context *context, FILE *file, Expr *expr, int indent)
|
||||
DUMPEXPC(expr);
|
||||
DUMPEXPR(expr->post_expr.expr);
|
||||
DUMPEND();
|
||||
case EXPR_CATCH_OLD:
|
||||
DUMP("(catch");
|
||||
DUMPEXPC(expr);
|
||||
DUMPEXPR(expr->trycatch_expr);
|
||||
DUMPEND();
|
||||
case EXPR_TRY_OLD:
|
||||
DUMP("(try");
|
||||
DUMPEXPC(expr);
|
||||
DUMPEXPR(expr->trycatch_expr);
|
||||
DUMPEND();
|
||||
case EXPR_TRY:
|
||||
DUMPF("(try %d", expr->try_expr.is_try);
|
||||
DUMPEXPC(expr);
|
||||
@@ -895,6 +922,9 @@ void fprint_decl_recursive(Context *context, FILE *file, Decl *decl, int indent)
|
||||
if (!decl) return;
|
||||
switch (decl->decl_kind)
|
||||
{
|
||||
case DECL_BITSTRUCT:
|
||||
DUMP("(bitstruct)");
|
||||
return;
|
||||
case DECL_INTERFACE:
|
||||
DUMPF("(interface %s", decl->name);
|
||||
DUMPDECLS(decl->interface_decl.members);
|
||||
@@ -920,9 +950,12 @@ void fprint_decl_recursive(Context *context, FILE *file, Decl *decl, int indent)
|
||||
case VARDECL_LOCAL_CT_TYPE:
|
||||
DUMPTI(decl->var.type_info);
|
||||
break;
|
||||
case VARDECL_ALIAS:
|
||||
case VARDECL_UNWRAPPED:
|
||||
DUMPDECL(decl->var.alias);
|
||||
break;
|
||||
case VARDECL_ERASE:
|
||||
case VARDECL_REWRAPPED:
|
||||
UNREACHABLE
|
||||
}
|
||||
DUMPEND();
|
||||
case DECL_CT_ASSERT:
|
||||
@@ -980,9 +1013,10 @@ void fprint_decl_recursive(Context *context, FILE *file, Decl *decl, int indent)
|
||||
DUMPTI(decl->enums.type_info);
|
||||
DUMPDECLS(decl->enums.values);
|
||||
DUMPEND();
|
||||
case DECL_ERR:
|
||||
DUMPF("(error %s", decl->name);
|
||||
DUMPDECLS(decl->strukt.members);
|
||||
case DECL_ERRTYPE:
|
||||
DUMPF("(errtype %s", decl->name);
|
||||
DUMPTI(decl->enums.type_info);
|
||||
DUMPDECLS(decl->enums.values);
|
||||
DUMPEND();
|
||||
case DECL_ENUM_CONSTANT:
|
||||
if (!decl->enum_constant.expr)
|
||||
@@ -993,6 +1027,15 @@ void fprint_decl_recursive(Context *context, FILE *file, Decl *decl, int indent)
|
||||
DUMPF("(enum-constant %s", decl->name);
|
||||
DUMPEXPR(decl->enum_constant.expr);
|
||||
DUMPEND();
|
||||
case DECL_ERRVALUE:
|
||||
DUMPF("(errvalue %s)", decl->name);
|
||||
if (!decl->enum_constant.expr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
DUMPF("(enum-constant %s", decl->name);
|
||||
DUMPEXPR(decl->enum_constant.expr);
|
||||
DUMPEND();
|
||||
case DECL_TYPEDEF:
|
||||
DUMPF("(typedef %s", decl->name);
|
||||
if (decl->typedef_decl.is_func)
|
||||
|
||||
@@ -158,6 +158,7 @@ static void register_generic_decls(Module *module, Decl **decls)
|
||||
case DECL_POISONED:
|
||||
case DECL_ARRAY_VALUE:
|
||||
case DECL_ENUM_CONSTANT:
|
||||
case DECL_ERRVALUE:
|
||||
case DECL_IMPORT:
|
||||
case DECL_LABEL:
|
||||
case DECL_CT_ASSERT:
|
||||
@@ -184,13 +185,14 @@ static void register_generic_decls(Module *module, Decl **decls)
|
||||
case DECL_ENUM:
|
||||
case DECL_GENERIC:
|
||||
case DECL_INTERFACE:
|
||||
case DECL_ERR:
|
||||
case DECL_ERRTYPE:
|
||||
case DECL_FUNC:
|
||||
case DECL_MACRO:
|
||||
case DECL_STRUCT:
|
||||
case DECL_TYPEDEF:
|
||||
case DECL_UNION:
|
||||
case DECL_VAR:
|
||||
case DECL_BITSTRUCT:
|
||||
break;
|
||||
}
|
||||
if (decl->visibility > VISIBLE_MODULE)
|
||||
@@ -282,7 +284,7 @@ void compiler_compile(void)
|
||||
setup_int_define("C_LONG_SIZE", platform_target.width_c_long);
|
||||
setup_int_define("C_LONG_LONG_SIZE", platform_target.width_c_long_long);
|
||||
setup_bool_define("C_CHAR_IS_SIGNED", platform_target.signed_c_char);
|
||||
setup_bool_define("PLATFORM_LITTLE_ENDIAN", platform_target.little_endian);
|
||||
setup_bool_define("PLATFORM_BIG_ENDIAN", platform_target.big_endian);
|
||||
setup_bool_define("PLATFORM_I128_SUPPORTED", platform_target.int128);
|
||||
setup_int_define("COMPILER_OPT_LEVEL", (int)active_target.optimization_level);
|
||||
setup_int_define("COMPILER_SIZE_OPT_LEVEL", (int)active_target.size_optimization_level);
|
||||
|
||||
@@ -287,6 +287,12 @@ typedef struct
|
||||
} StructDecl;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
TypeInfo *base_type;
|
||||
Decl **members;
|
||||
} BitStructDecl;
|
||||
|
||||
typedef struct VarDecl_
|
||||
{
|
||||
VarDeclKind kind : 4;
|
||||
@@ -305,11 +311,13 @@ typedef struct VarDecl_
|
||||
{
|
||||
void *backend_debug_ref;
|
||||
unsigned scope_depth;
|
||||
Expr *start;
|
||||
};
|
||||
union
|
||||
{
|
||||
void *failable_ref;
|
||||
struct ABIArgInfo_ *abi_info;
|
||||
Expr *end;
|
||||
};
|
||||
} VarDecl;
|
||||
|
||||
@@ -536,6 +544,7 @@ typedef struct Decl_
|
||||
StructDecl strukt;
|
||||
EnumDecl enums;
|
||||
DistinctDecl distinct_decl;
|
||||
BitStructDecl bitstruct;
|
||||
};
|
||||
};
|
||||
ImportDecl import;
|
||||
@@ -857,11 +866,58 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool is_try;
|
||||
bool is_try : 1;
|
||||
Expr *expr;
|
||||
Expr *init;
|
||||
} ExprTryAssign;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool is_try : 1;
|
||||
Decl *decl;
|
||||
} ExprTryDecl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
Expr *variable;
|
||||
TypeInfo *type;
|
||||
};
|
||||
struct
|
||||
{
|
||||
Decl *decl;
|
||||
Expr *lhs;
|
||||
};
|
||||
};
|
||||
Expr **exprs;
|
||||
} ExprCatchUnwrap;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
Expr *variable;
|
||||
TypeInfo *type;
|
||||
Expr *init;
|
||||
};
|
||||
struct
|
||||
{
|
||||
bool assign_existing : 1;
|
||||
Expr *failable;
|
||||
union
|
||||
{
|
||||
Decl *decl;
|
||||
Expr *lhs;
|
||||
};
|
||||
};
|
||||
};
|
||||
} ExprTryUnwrap;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Expr *inner;
|
||||
@@ -896,11 +952,15 @@ struct Expr_
|
||||
ExprBinary binary_expr;
|
||||
ExprTernary ternary_expr;
|
||||
ExprUnary unary_expr;
|
||||
Expr** try_unwrap_chain_expr;
|
||||
ExprPostUnary post_expr;
|
||||
ExprTryUnwrap try_unwrap_expr;
|
||||
ExprCall call_expr;
|
||||
ExprSlice slice_expr;
|
||||
ExprTryExpr try_expr;
|
||||
ExprTryAssign try_assign_expr;
|
||||
ExprTryDecl try_decl_expr;
|
||||
ExprCatchUnwrap catch_unwrap_expr;
|
||||
ExprSubscript subscript_expr;
|
||||
ExprAccess access_expr;
|
||||
ExprDesignator designator_expr;
|
||||
@@ -923,7 +983,7 @@ struct Expr_
|
||||
ExprMacroBlock macro_block;
|
||||
|
||||
Expr* failable_expr;
|
||||
Expr** dexpr_list_expr;
|
||||
Expr** cond_expr;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1348,6 +1408,7 @@ typedef struct Context_
|
||||
STable local_symbols;
|
||||
Decl **global_decls;
|
||||
Decl **enums;
|
||||
Decl **errtypes;
|
||||
Decl **types;
|
||||
Decl **generic_defines;
|
||||
Decl **functions;
|
||||
@@ -1708,6 +1769,29 @@ static inline bool decl_is_struct_type(Decl *decl);
|
||||
static inline bool decl_is_callable_type(Decl *decl);
|
||||
static inline bool decl_is_user_defined_type(Decl *decl);
|
||||
static inline DeclKind decl_from_token(TokenType type);
|
||||
static inline bool decl_var_is_assignable(Decl *decl)
|
||||
{
|
||||
switch (decl->var.kind)
|
||||
{
|
||||
case VARDECL_GLOBAL:
|
||||
case VARDECL_LOCAL:
|
||||
case VARDECL_PARAM:
|
||||
case VARDECL_PARAM_CT:
|
||||
case VARDECL_PARAM_CT_TYPE:
|
||||
case VARDECL_PARAM_REF:
|
||||
case VARDECL_LOCAL_CT:
|
||||
case VARDECL_LOCAL_CT_TYPE:
|
||||
case VARDECL_UNWRAPPED:
|
||||
return true;
|
||||
case VARDECL_CONST:
|
||||
case VARDECL_MEMBER:
|
||||
case VARDECL_PARAM_EXPR:
|
||||
return false;
|
||||
case VARDECL_REWRAPPED:
|
||||
case VARDECL_ERASE:
|
||||
UNREACHABLE
|
||||
}
|
||||
}
|
||||
static inline Decl *decl_flatten(Decl *decl)
|
||||
{
|
||||
if (decl->decl_kind == DECL_DEFINE && decl->define_decl.define_kind != DEFINE_TYPE_GENERIC)
|
||||
@@ -1815,7 +1899,8 @@ bool sema_add_member(Context *context, Decl *decl);
|
||||
bool sema_add_local(Context *context, Decl *decl);
|
||||
bool sema_unwrap_var(Context *context, Decl *decl);
|
||||
bool sema_rewrap_var(Context *context, Decl *decl);
|
||||
|
||||
bool sema_erase_var(Context *context, Decl *decl);
|
||||
bool sema_erase_unwrapped(Context *context, Decl *decl);
|
||||
bool sema_analyse_expr_of_required_type(Context *context, Type *to, Expr *expr, bool may_be_failable);
|
||||
ArrayIndex sema_get_initializer_const_array_size(Context *context, Expr *initializer, bool *may_be_array, bool *is_const_size);
|
||||
bool sema_analyse_expr(Context *context, Type *to, Expr *expr);
|
||||
@@ -1882,6 +1967,8 @@ int target_alloca_addr_space();
|
||||
bool token_is_type(TokenType type);
|
||||
bool token_is_any_type(TokenType type);
|
||||
bool token_is_symbol(TokenType type);
|
||||
bool token_is_ident_keyword(TokenType token_type);
|
||||
bool token_is_ct_ident_keyword(TokenType token_type);
|
||||
const char *token_type_to_string(TokenType type);
|
||||
static inline TokenType advance_token(TokenId *token)
|
||||
{
|
||||
@@ -2116,6 +2203,21 @@ static inline void advance_and_verify(Context *context, TokenType token_type)
|
||||
advance(context);
|
||||
}
|
||||
|
||||
static inline Type *type_flatten_for_bitstruct(Type *type)
|
||||
{
|
||||
type = type->canonical;
|
||||
RETRY:
|
||||
while (type->type_kind == TYPE_DISTINCT)
|
||||
{
|
||||
type = type->decl->distinct_decl.base_type;
|
||||
}
|
||||
if (type->type_kind == TYPE_ENUM)
|
||||
{
|
||||
type = type->decl->enums.type_info->type->canonical;
|
||||
goto RETRY;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
static inline Type *type_flatten_distinct(Type *type)
|
||||
{
|
||||
@@ -2142,6 +2244,10 @@ static inline Type *type_flatten(Type *type)
|
||||
type = type->decl->enums.type_info->type;
|
||||
continue;
|
||||
}
|
||||
if (type->type_kind == TYPE_ANYERR || type->type_kind == TYPE_ERRTYPE)
|
||||
{
|
||||
type = type_iptr->canonical;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -2181,7 +2287,6 @@ static inline bool type_is_structlike(Type *type)
|
||||
{
|
||||
case TYPE_UNION:
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_ERRTYPE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -2193,22 +2298,30 @@ static inline Type *type_lowering(Type *type)
|
||||
{
|
||||
Type *canonical = type_flatten(type);
|
||||
if (canonical->type_kind == TYPE_ENUM) return canonical->decl->enums.type_info->type->canonical;
|
||||
if (canonical->type_kind == TYPE_TYPEID) return type_usize->canonical;
|
||||
if (canonical->type_kind == TYPE_TYPEID) return type_iptr->canonical;
|
||||
if (canonical->type_kind == TYPE_ERRTYPE) return type_iptr->canonical;
|
||||
if (canonical->type_kind == TYPE_BITSTRUCT) return type_lowering(canonical->decl->bitstruct.base_type->type);
|
||||
return canonical;
|
||||
}
|
||||
|
||||
static inline Decl *decl_raw(Decl *decl)
|
||||
{
|
||||
if (decl->decl_kind != DECL_VAR || decl->var.kind != VARDECL_ALIAS) return decl;
|
||||
if (decl->decl_kind != DECL_VAR || decl->var.kind != VARDECL_UNWRAPPED) return decl;
|
||||
decl = decl->var.alias;
|
||||
assert(decl->decl_kind != DECL_VAR || decl->var.kind != VARDECL_ALIAS);
|
||||
assert(decl->decl_kind != DECL_VAR || decl->var.kind != VARDECL_UNWRAPPED);
|
||||
return decl;
|
||||
}
|
||||
|
||||
static inline bool decl_is_struct_type(Decl *decl)
|
||||
{
|
||||
DeclKind kind = decl->decl_kind;
|
||||
return (kind == DECL_UNION) | (kind == DECL_STRUCT) | (kind == DECL_ERR);
|
||||
return (kind == DECL_UNION) | (kind == DECL_STRUCT);
|
||||
}
|
||||
|
||||
static inline bool decl_is_enum_kind(Decl *decl)
|
||||
{
|
||||
DeclKind kind = decl->decl_kind;
|
||||
return (kind == DECL_ENUM) | (kind == DECL_ERRTYPE);
|
||||
}
|
||||
|
||||
static inline bool decl_is_callable_type(Decl *decl)
|
||||
@@ -2220,7 +2333,7 @@ static inline bool decl_is_callable_type(Decl *decl)
|
||||
static inline bool decl_is_user_defined_type(Decl *decl)
|
||||
{
|
||||
DeclKind kind = decl->decl_kind;
|
||||
return (kind == DECL_UNION) | (kind == DECL_STRUCT) | (kind == DECL_ERR)
|
||||
return (kind == DECL_UNION) | (kind == DECL_STRUCT)
|
||||
| (kind == DECL_ENUM) | (kind == DECL_DISTINCT);
|
||||
}
|
||||
|
||||
|
||||
@@ -187,7 +187,8 @@ void context_register_global_decl(Context *context, Decl *decl)
|
||||
case DECL_STRUCT:
|
||||
case DECL_UNION:
|
||||
case DECL_TYPEDEF:
|
||||
case DECL_ERR:
|
||||
case DECL_ERRTYPE:
|
||||
case DECL_BITSTRUCT:
|
||||
vec_add(context->types, decl);
|
||||
decl_set_external_name(decl);
|
||||
break;
|
||||
@@ -202,6 +203,7 @@ void context_register_global_decl(Context *context, Decl *decl)
|
||||
case DECL_ARRAY_VALUE:
|
||||
vec_add(context->incr_array, decl);
|
||||
return;
|
||||
case DECL_ERRVALUE:
|
||||
case DECL_ENUM_CONSTANT:
|
||||
case DECL_IMPORT:
|
||||
case DECL_CT_ELSE:
|
||||
|
||||
@@ -77,12 +77,26 @@ Expr *copy_expr(Expr *source_expr)
|
||||
case EXPR_UNDEF:
|
||||
case EXPR_NOP:
|
||||
return expr;
|
||||
case EXPR_TRY_DECL:
|
||||
MACRO_COPY_DECL(expr->try_decl_expr.decl);
|
||||
return expr;
|
||||
case EXPR_DECL:
|
||||
MACRO_COPY_DECL(expr->decl_expr);
|
||||
return expr;
|
||||
case EXPR_CT_CALL:
|
||||
MACRO_COPY_EXPR_LIST(expr->ct_call_expr.arguments);
|
||||
return expr;
|
||||
case EXPR_TRY_UNWRAP:
|
||||
MACRO_COPY_EXPR(expr->try_unwrap_expr.init);
|
||||
MACRO_COPY_TYPE(expr->try_unwrap_expr.type);
|
||||
return expr;
|
||||
case EXPR_TRY_UNWRAP_CHAIN:
|
||||
MACRO_COPY_EXPR_LIST(expr->try_unwrap_chain_expr);
|
||||
return expr;
|
||||
case EXPR_CATCH_UNWRAP:
|
||||
MACRO_COPY_EXPR_LIST(expr->catch_unwrap_expr.exprs);
|
||||
MACRO_COPY_TYPE(expr->catch_unwrap_expr.type);
|
||||
return expr;
|
||||
case EXPR_PLACEHOLDER:
|
||||
case EXPR_CONST_IDENTIFIER:
|
||||
case EXPR_CT_IDENT:
|
||||
@@ -111,10 +125,6 @@ Expr *copy_expr(Expr *source_expr)
|
||||
case EXPR_LEN:
|
||||
MACRO_COPY_EXPR(expr->len_expr.inner);
|
||||
return expr;
|
||||
case EXPR_CATCH_OLD:
|
||||
case EXPR_TRY_OLD:
|
||||
MACRO_COPY_EXPR(expr->trycatch_expr);
|
||||
return expr;
|
||||
case EXPR_TRY_ASSIGN:
|
||||
MACRO_COPY_EXPR(expr->try_assign_expr.expr);
|
||||
MACRO_COPY_EXPR(expr->try_assign_expr.init);
|
||||
@@ -122,8 +132,8 @@ Expr *copy_expr(Expr *source_expr)
|
||||
case EXPR_TRY:
|
||||
MACRO_COPY_EXPR(expr->try_expr.expr);
|
||||
return expr;
|
||||
case EXPR_DECL_LIST:
|
||||
MACRO_COPY_EXPR_LIST(expr->dexpr_list_expr);
|
||||
case EXPR_COND:
|
||||
MACRO_COPY_EXPR_LIST(expr->cond_expr);
|
||||
return expr;
|
||||
case EXPR_FAILABLE:
|
||||
MACRO_COPY_EXPR(expr->failable_expr);
|
||||
@@ -496,12 +506,12 @@ Decl *copy_decl(Decl *decl)
|
||||
break;
|
||||
case DECL_UNION:
|
||||
case DECL_STRUCT:
|
||||
case DECL_ERR:
|
||||
copy_decl_type(copy);
|
||||
MACRO_COPY_DECL_LIST(copy->strukt.members);
|
||||
MACRO_COPY_DECL_LIST(copy->methods);
|
||||
break;
|
||||
case DECL_ENUM:
|
||||
case DECL_ERRTYPE:
|
||||
copy_decl_type(copy);
|
||||
MACRO_COPY_DECL_LIST(copy->methods);
|
||||
MACRO_COPY_DECL_LIST(copy->enums.parameters);
|
||||
@@ -521,7 +531,7 @@ Decl *copy_decl(Decl *decl)
|
||||
break;
|
||||
case DECL_VAR:
|
||||
MACRO_COPY_TYPE(copy->var.type_info);
|
||||
if (copy->var.kind == VARDECL_ALIAS)
|
||||
if (copy->var.kind == VARDECL_UNWRAPPED)
|
||||
{
|
||||
MACRO_COPY_DECL(copy->var.alias);
|
||||
}
|
||||
@@ -530,6 +540,9 @@ Decl *copy_decl(Decl *decl)
|
||||
MACRO_COPY_EXPR(copy->var.init_expr);
|
||||
}
|
||||
break;
|
||||
case DECL_BITSTRUCT:
|
||||
TODO
|
||||
break;
|
||||
case DECL_LABEL:
|
||||
TODO
|
||||
break;
|
||||
@@ -537,6 +550,10 @@ Decl *copy_decl(Decl *decl)
|
||||
MACRO_COPY_EXPR(copy->enum_constant.expr);
|
||||
MACRO_COPY_EXPR_LIST(copy->enum_constant.args);
|
||||
break;
|
||||
case DECL_ERRVALUE:
|
||||
MACRO_COPY_EXPR(copy->enum_constant.expr);
|
||||
MACRO_COPY_EXPR_LIST(copy->enum_constant.args);
|
||||
break;
|
||||
case DECL_TYPEDEF:
|
||||
if (copy->typedef_decl.is_func)
|
||||
{
|
||||
|
||||
@@ -84,9 +84,12 @@ typedef enum
|
||||
typedef enum
|
||||
{
|
||||
CAST_ERROR,
|
||||
CAST_ERBOOL,
|
||||
CAST_EUBOOL,
|
||||
CAST_EUER,
|
||||
CAST_EUINT,
|
||||
CAST_EREU,
|
||||
CAST_ERINT,
|
||||
CAST_XIERR,
|
||||
CAST_PTRPTR,
|
||||
CAST_PTRXI,
|
||||
@@ -132,6 +135,7 @@ typedef enum
|
||||
DECL_POISONED = 0,
|
||||
DECL_ATTRIBUTE,
|
||||
DECL_ARRAY_VALUE,
|
||||
DECL_BITSTRUCT,
|
||||
DECL_CT_CASE,
|
||||
DECL_CT_ELIF,
|
||||
DECL_CT_ELSE,
|
||||
@@ -142,7 +146,8 @@ typedef enum
|
||||
DECL_DISTINCT,
|
||||
DECL_ENUM,
|
||||
DECL_ENUM_CONSTANT,
|
||||
DECL_ERR,
|
||||
DECL_ERRTYPE,
|
||||
DECL_ERRVALUE,
|
||||
DECL_FUNC,
|
||||
DECL_GENERIC,
|
||||
DECL_IMPORT,
|
||||
@@ -178,12 +183,12 @@ typedef enum
|
||||
EXPR_MACRO_BODY_EXPANSION,
|
||||
EXPR_CALL,
|
||||
EXPR_CAST,
|
||||
EXPR_CATCH_OLD,
|
||||
EXPR_CATCH_UNWRAP,
|
||||
EXPR_COMPOUND_LITERAL,
|
||||
EXPR_CONST,
|
||||
EXPR_CONST_IDENTIFIER,
|
||||
EXPR_CT_IDENT,
|
||||
EXPR_DECL_LIST,
|
||||
EXPR_COND,
|
||||
EXPR_DECL,
|
||||
EXPR_DESIGNATOR,
|
||||
EXPR_ELSE,
|
||||
@@ -208,9 +213,11 @@ typedef enum
|
||||
EXPR_SLICE_ASSIGN,
|
||||
EXPR_SUBSCRIPT,
|
||||
EXPR_TERNARY,
|
||||
EXPR_TRY_OLD,
|
||||
EXPR_TRY,
|
||||
EXPR_TRY_UNWRAP,
|
||||
EXPR_TRY_UNWRAP_CHAIN,
|
||||
EXPR_TRY_ASSIGN,
|
||||
EXPR_TRY_DECL,
|
||||
EXPR_TYPEID,
|
||||
EXPR_TYPEINFO,
|
||||
EXPR_TYPEOF,
|
||||
@@ -409,6 +416,7 @@ typedef enum
|
||||
TOKEN_ASSERT,
|
||||
TOKEN_ASM,
|
||||
TOKEN_ATTRIBUTE,
|
||||
TOKEN_BITSTRUCT,
|
||||
TOKEN_BREAK,
|
||||
TOKEN_CASE,
|
||||
TOKEN_CATCH_OLD,
|
||||
@@ -520,8 +528,9 @@ typedef enum
|
||||
TYPE_FUNC,
|
||||
TYPE_STRUCT,
|
||||
TYPE_UNION,
|
||||
TYPE_BITSTRUCT,
|
||||
TYPE_ERRTYPE,
|
||||
TYPE_ERR_UNION,
|
||||
TYPE_ANYERR,
|
||||
TYPE_TYPEDEF,
|
||||
TYPE_STRLIT,
|
||||
TYPE_DISTINCT,
|
||||
@@ -577,7 +586,9 @@ typedef enum
|
||||
VARDECL_PARAM_EXPR = 8,
|
||||
VARDECL_LOCAL_CT = 9,
|
||||
VARDECL_LOCAL_CT_TYPE = 10,
|
||||
VARDECL_ALIAS = 11,
|
||||
VARDECL_UNWRAPPED = 11,
|
||||
VARDECL_ERASE = 12,
|
||||
VARDECL_REWRAPPED = 13,
|
||||
} VarDeclKind;
|
||||
|
||||
typedef enum
|
||||
@@ -602,6 +613,7 @@ typedef enum
|
||||
ATTR_MEMBER = 1 << 8,
|
||||
ATTR_INTERFACE = 1 << 9,
|
||||
ATTR_CALL = 1 << 10,
|
||||
ATTR_BITSTRUCT = 1 << 11,
|
||||
} AttributeDomain;
|
||||
|
||||
typedef enum
|
||||
@@ -623,6 +635,7 @@ typedef enum
|
||||
ATTRIBUTE_VECCALL,
|
||||
ATTRIBUTE_REGCALL,
|
||||
ATTRIBUTE_FASTCALL,
|
||||
ATTRIBUTE_OVERLAP,
|
||||
ATTRIBUTE_NONE,
|
||||
NUMBER_OF_ATTRIBUTES = ATTRIBUTE_NONE,
|
||||
} AttributeType;
|
||||
|
||||
@@ -32,6 +32,8 @@ static void header_print_type(FILE *file, Type *type)
|
||||
{
|
||||
case TYPE_POISONED:
|
||||
UNREACHABLE
|
||||
case TYPE_BITSTRUCT:
|
||||
TODO
|
||||
case TYPE_VOID:
|
||||
OUTPUT("void");
|
||||
return;
|
||||
@@ -90,6 +92,7 @@ static void header_print_type(FILE *file, Type *type)
|
||||
OUTPUT("*");
|
||||
return;
|
||||
case TYPE_ENUM:
|
||||
case TYPE_ERRTYPE:
|
||||
OUTPUT("enum %s__", type->decl->external_name);
|
||||
return;
|
||||
case TYPE_FUNC:
|
||||
@@ -103,9 +106,7 @@ static void header_print_type(FILE *file, Type *type)
|
||||
case TYPE_DISTINCT:
|
||||
header_print_type(file, type->decl->distinct_decl.base_type);
|
||||
return;
|
||||
case TYPE_ERRTYPE:
|
||||
break;
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_ANYERR:
|
||||
break;
|
||||
case TYPE_TYPEDEF:
|
||||
break;
|
||||
@@ -192,11 +193,13 @@ static void header_gen_decl(FILE *file, int indent, Decl *decl)
|
||||
{
|
||||
case NON_TYPE_DECLS:
|
||||
case DECL_ENUM_CONSTANT:
|
||||
case DECL_ERRVALUE:
|
||||
case DECL_POISONED:
|
||||
case DECL_VAR:
|
||||
case DECL_INTERFACE:
|
||||
UNREACHABLE
|
||||
case DECL_FUNC:
|
||||
case DECL_BITSTRUCT:
|
||||
TODO
|
||||
case DECL_TYPEDEF:
|
||||
case DECL_DISTINCT:
|
||||
@@ -210,7 +213,7 @@ static void header_gen_decl(FILE *file, int indent, Decl *decl)
|
||||
case DECL_ENUM:
|
||||
header_gen_enum(file, indent, decl);
|
||||
return;
|
||||
case DECL_ERR:
|
||||
case DECL_ERRTYPE:
|
||||
header_gen_err(file, indent, decl);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -633,15 +633,15 @@ static inline bool scan_char(Lexer *lexer)
|
||||
lexer->lexing_start = start;
|
||||
return add_error_token(lexer, "Expected a four character hex value after \\u.");
|
||||
}
|
||||
if (platform_target.little_endian)
|
||||
if (platform_target.big_endian)
|
||||
{
|
||||
bytes.b[width++] = (uint8_t)(hex & 0xFF);
|
||||
bytes.b[width++] = (uint8_t)(hex >> 8);
|
||||
bytes.b[width++] = (uint8_t)(hex & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes.b[width++] = (uint8_t)(hex >> 8);
|
||||
bytes.b[width++] = (uint8_t)(hex & 0xFF);
|
||||
bytes.b[width++] = (uint8_t)(hex >> 8);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -653,19 +653,19 @@ static inline bool scan_char(Lexer *lexer)
|
||||
lexer->lexing_start = start;
|
||||
return add_error_token(lexer, "Expected an eight character hex value after \\U.");
|
||||
}
|
||||
if (platform_target.little_endian)
|
||||
if (platform_target.big_endian)
|
||||
{
|
||||
bytes.b[width++] = (uint8_t)(hex & 0xFF);
|
||||
bytes.b[width++] = (uint8_t)((hex >> 8) & 0xFF);
|
||||
bytes.b[width++] = (uint8_t)((hex >> 16) & 0xFF);
|
||||
bytes.b[width++] = (uint8_t)(hex >> 24);
|
||||
bytes.b[width++] = (uint8_t)((hex >> 16) & 0xFF);
|
||||
bytes.b[width++] = (uint8_t)((hex >> 8) & 0xFF);
|
||||
bytes.b[width++] = (uint8_t)(hex & 0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes.b[width++] = (uint8_t)(hex >> 24);
|
||||
bytes.b[width++] = (uint8_t)((hex >> 16) & 0xFF);
|
||||
bytes.b[width++] = (uint8_t)((hex >> 8) & 0xFF);
|
||||
bytes.b[width++] = (uint8_t)(hex & 0xFF);
|
||||
bytes.b[width++] = (uint8_t)((hex >> 8) & 0xFF);
|
||||
bytes.b[width++] = (uint8_t)((hex >> 16) & 0xFF);
|
||||
bytes.b[width++] = (uint8_t)(hex >> 24);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -684,9 +684,9 @@ void llvm_codegen_setup()
|
||||
intrinsics_setup = true;
|
||||
}
|
||||
|
||||
void gencontext_emit_introspection_type(GenContext *context, Decl *decl)
|
||||
void gencontext_emit_introspection_type(GenContext *c, Decl *decl)
|
||||
{
|
||||
llvm_get_type(context, decl->type);
|
||||
llvm_get_type(c, decl->type);
|
||||
if (decl_is_struct_type(decl))
|
||||
{
|
||||
Decl **decls = decl->strukt.members;
|
||||
@@ -695,14 +695,31 @@ void gencontext_emit_introspection_type(GenContext *context, Decl *decl)
|
||||
Decl *member_decl = decls[i];
|
||||
if (decl_is_struct_type(member_decl))
|
||||
{
|
||||
gencontext_emit_introspection_type(context, member_decl);
|
||||
gencontext_emit_introspection_type(c, member_decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
LLVMValueRef global_name = LLVMAddGlobal(context->module, llvm_get_type(context, type_char), decl->name ? decl->name : "anon");
|
||||
if (decl_is_enum_kind(decl))
|
||||
{
|
||||
unsigned elements = vec_size(decl->enums.values);
|
||||
LLVMTypeRef element_type = llvm_get_type(c, type_voidptr);
|
||||
LLVMTypeRef elements_type = LLVMArrayType(element_type, elements);
|
||||
scratch_buffer_clear();
|
||||
scratch_buffer_append(decl->external_name);
|
||||
scratch_buffer_append("$elements");
|
||||
LLVMValueRef enum_elements = LLVMAddGlobal(c->module, elements_type, scratch_buffer_to_string());
|
||||
LLVMSetGlobalConstant(enum_elements, 1);
|
||||
LLVMSetInitializer(enum_elements, LLVMConstNull(elements_type));
|
||||
for (unsigned i = 0; i < elements; i++)
|
||||
{
|
||||
LLVMValueRef index[2] = { llvm_const_int(c, type_usize, i) };
|
||||
decl->enums.values[i]->backend_ref = LLVMConstInBoundsGEP(enum_elements, index, 1);
|
||||
}
|
||||
}
|
||||
LLVMValueRef global_name = LLVMAddGlobal(c->module, llvm_get_type(c, type_char), decl->name ? decl->name : "anon");
|
||||
LLVMSetGlobalConstant(global_name, 1);
|
||||
LLVMSetInitializer(global_name, LLVMConstInt(llvm_get_type(context, type_char), 1, false));
|
||||
decl->type->backend_typeid = LLVMConstPointerCast(global_name, llvm_get_type(context, type_typeid));
|
||||
LLVMSetInitializer(global_name, LLVMConstInt(llvm_get_type(c, type_char), 1, false));
|
||||
decl->type->backend_typeid = LLVMConstPointerCast(global_name, llvm_get_type(c, type_typeid));
|
||||
|
||||
switch (decl->visibility)
|
||||
{
|
||||
@@ -730,10 +747,12 @@ void llvm_value_set_bool(BEValue *value, LLVMValueRef llvm_value)
|
||||
|
||||
void llvm_value_set(BEValue *value, LLVMValueRef llvm_value, Type *type)
|
||||
{
|
||||
type = type_flatten(type);
|
||||
assert(llvm_value || type == type_void);
|
||||
value->value = llvm_value;
|
||||
value->alignment = type_abi_alignment(type);
|
||||
value->kind = BE_VALUE;
|
||||
value->type = type_flatten(type);
|
||||
value->type = type;
|
||||
}
|
||||
|
||||
bool llvm_value_is_const(BEValue *value)
|
||||
@@ -768,7 +787,6 @@ void llvm_value_set_address(BEValue *value, LLVMValueRef llvm_value, Type *type)
|
||||
|
||||
void llvm_value_fold_failable(GenContext *c, BEValue *value)
|
||||
{
|
||||
|
||||
if (value->kind == BE_ADDRESS_FAILABLE)
|
||||
{
|
||||
LLVMBasicBlockRef after_block = llvm_basic_block_new(c, "after_check");
|
||||
@@ -860,7 +878,7 @@ void llvm_value_rvalue(GenContext *c, BEValue *value)
|
||||
}
|
||||
|
||||
|
||||
static void gencontext_emit_type_decls(GenContext *context, Decl *decl)
|
||||
static void llvm_emit_type_decls(GenContext *context, Decl *decl)
|
||||
{
|
||||
switch (decl->decl_kind)
|
||||
{
|
||||
@@ -878,17 +896,19 @@ static void gencontext_emit_type_decls(GenContext *context, Decl *decl)
|
||||
// TODO
|
||||
break;
|
||||
case DECL_ENUM_CONSTANT:
|
||||
case DECL_ERRVALUE:
|
||||
// TODO
|
||||
break;;
|
||||
case DECL_STRUCT:
|
||||
case DECL_UNION:
|
||||
case DECL_ERR:
|
||||
case DECL_ENUM:
|
||||
case DECL_ERRTYPE:
|
||||
case DECL_BITSTRUCT:
|
||||
gencontext_emit_introspection_type(context, decl);
|
||||
break;
|
||||
case DECL_INTERFACE:
|
||||
// TODO
|
||||
break;
|
||||
case DECL_ENUM:
|
||||
// TODO
|
||||
break;
|
||||
case NON_TYPE_DECLS:
|
||||
@@ -982,7 +1002,7 @@ void *llvm_gen(Module *module)
|
||||
}
|
||||
VECEACH(context->types, i)
|
||||
{
|
||||
gencontext_emit_type_decls(gen_context, context->types[i]);
|
||||
llvm_emit_type_decls(gen_context, context->types[i]);
|
||||
}
|
||||
VECEACH(context->functions, i)
|
||||
{
|
||||
@@ -1084,6 +1104,7 @@ void llvm_store_bevalue_aligned(GenContext *c, LLVMValueRef destination, BEValue
|
||||
{
|
||||
case BE_BOOLEAN:
|
||||
value->value = LLVMBuildZExt(c->builder, value->value, c->byte_type, "");
|
||||
value->kind = BE_VALUE;
|
||||
FALLTHROUGH;
|
||||
case BE_VALUE:
|
||||
llvm_store_aligned(c, destination, value->value, alignment ?: type_abi_alignment(value->type));
|
||||
|
||||
@@ -160,7 +160,7 @@ static ABIArgInfo *riscv_classify_argument_type(Type *type, bool is_fixed, unsig
|
||||
}
|
||||
|
||||
|
||||
if (is_fixed && platform_target.riscv.flen && (type->type_kind == TYPE_STRUCT || type->type_kind == TYPE_ERRTYPE))
|
||||
if (is_fixed && platform_target.riscv.flen && type->type_kind == TYPE_STRUCT)
|
||||
{
|
||||
AbiType *field1 = NULL;
|
||||
AbiType *field2 = NULL;
|
||||
|
||||
@@ -137,14 +137,14 @@ ABIArgInfo *x64_classify_reg_call_struct_type_check(Type *type, Registers *neede
|
||||
assert(x64_type_is_structure(type));
|
||||
|
||||
// These are all passed in two registers.
|
||||
if (type->type_kind == TYPE_ERR_UNION || type->type_kind == TYPE_SUBARRAY || type->type_kind == TYPE_VIRTUAL || type->type_kind == TYPE_VIRTUAL_ANY)
|
||||
if (type->type_kind == TYPE_SUBARRAY || type->type_kind == TYPE_VIRTUAL || type->type_kind == TYPE_VIRTUAL_ANY)
|
||||
{
|
||||
needed_registers->int_registers += 2;
|
||||
return abi_arg_new_direct();
|
||||
}
|
||||
|
||||
// Struct, err type handled =>
|
||||
assert(type->type_kind == TYPE_STRUCT || type->type_kind == TYPE_ERRTYPE);
|
||||
assert(type->type_kind == TYPE_STRUCT);
|
||||
|
||||
// Variable array structs are always passed by pointer.
|
||||
if (type->decl->has_variable_array) return x64_indirect_return_result(type);
|
||||
@@ -404,13 +404,15 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X
|
||||
case TYPE_DISTINCT:
|
||||
case TYPE_STRLIT:
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
case TYPE_ANYERR:
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_BITSTRUCT:
|
||||
UNREACHABLE
|
||||
case TYPE_VOID:
|
||||
*current = CLASS_NO_CLASS;
|
||||
break;
|
||||
case TYPE_I128:
|
||||
case TYPE_U128:
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_SUBARRAY:
|
||||
case TYPE_VIRTUAL:
|
||||
case TYPE_VIRTUAL_ANY:
|
||||
@@ -443,7 +445,6 @@ static void x64_classify(Type *type, ByteSize offset_base, X64Class *lo_class, X
|
||||
break;
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_ERRTYPE:
|
||||
x64_classify_struct_union(type, offset_base, current, lo_class, hi_class, named);
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
@@ -477,7 +478,7 @@ bool x64_bits_contain_no_user_data(Type *type, unsigned start, unsigned end)
|
||||
// No overlap
|
||||
return true;
|
||||
}
|
||||
if (type->type_kind == TYPE_STRUCT || type->type_kind == TYPE_ERRTYPE || type->type_kind == TYPE_UNION)
|
||||
if (type->type_kind == TYPE_STRUCT || type->type_kind == TYPE_UNION)
|
||||
{
|
||||
Decl **members = type->decl->strukt.members;
|
||||
VECEACH(members, i)
|
||||
@@ -499,7 +500,7 @@ bool x64_contains_float_at_offset(Type *type, unsigned offset)
|
||||
if (offset == 0 && type->type_kind == TYPE_F32) return true;
|
||||
|
||||
// If this is a struct, recurse into the field at the specified offset.
|
||||
if (type->type_kind == TYPE_ERRTYPE || type->type_kind == TYPE_STRUCT)
|
||||
if (type->type_kind == TYPE_STRUCT)
|
||||
{
|
||||
Decl *member = x64_get_member_at_offset(type->decl, offset);
|
||||
offset -= member->offset;
|
||||
@@ -562,7 +563,6 @@ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_ty
|
||||
}
|
||||
break;
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_ERRTYPE:
|
||||
{
|
||||
Decl *member = x64_get_member_at_offset(type->decl, offset);
|
||||
if (member)
|
||||
@@ -571,9 +571,6 @@ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_ty
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TYPE_ERR_UNION:
|
||||
if (offset < 16) return abi_type_new_plain(type_ulong);
|
||||
break;
|
||||
case TYPE_VIRTUAL_ANY:
|
||||
if (offset < 8) return abi_type_new_plain(type_ulong);
|
||||
if (offset < 16) return abi_type_new_plain(type_voidptr);
|
||||
@@ -605,6 +602,9 @@ AbiType *x64_get_int_type_at_offset(Type *type, unsigned offset, Type *source_ty
|
||||
case TYPE_DISTINCT:
|
||||
case TYPE_STRLIT:
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
case TYPE_ANYERR:
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_BITSTRUCT:
|
||||
UNREACHABLE
|
||||
case TYPE_I128:
|
||||
case TYPE_U128:
|
||||
@@ -850,9 +850,7 @@ bool x64_type_is_structure(Type *type)
|
||||
{
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_SUBARRAY:
|
||||
case TYPE_VIRTUAL_ANY:
|
||||
case TYPE_VIRTUAL:
|
||||
|
||||
@@ -117,15 +117,16 @@ static bool x86_should_return_type_in_reg(Type *type)
|
||||
case TYPE_ENUM:
|
||||
case TYPE_STRLIT:
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_TYPEID:
|
||||
case TYPE_ANYERR:
|
||||
case TYPE_BITSTRUCT:
|
||||
UNREACHABLE
|
||||
case ALL_INTS:
|
||||
case ALL_FLOATS:
|
||||
case TYPE_BOOL:
|
||||
case TYPE_POINTER:
|
||||
case TYPE_TYPEID:
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_SUBARRAY:
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_VIRTUAL_ANY:
|
||||
case TYPE_VIRTUAL:
|
||||
return true;
|
||||
@@ -292,10 +293,6 @@ static inline bool x86_can_expand_indirect_aggregate_arg(Type *type)
|
||||
// arguments. If so, we prefer to do the latter to avoid inhibiting
|
||||
// optimizations.
|
||||
|
||||
// Error unions can always be expanded since they are two pointers wide.
|
||||
if (type->canonical->type_kind == TYPE_ERR_UNION) return true;
|
||||
|
||||
if (type->canonical->type_kind == TYPE_ERRTYPE) return true;
|
||||
if (!type_is_union_struct(type)) return false;
|
||||
|
||||
ByteSize size = 0;
|
||||
@@ -593,11 +590,14 @@ static ABIArgInfo *x86_classify_argument(CallABI call, Regs *regs, Type *type)
|
||||
case TYPE_TYPEDEF:
|
||||
case TYPE_VOID:
|
||||
case TYPE_ENUM:
|
||||
case TYPE_ANYERR:
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_DISTINCT:
|
||||
case TYPE_FUNC:
|
||||
case TYPE_TYPEID:
|
||||
case TYPE_STRLIT:
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
case TYPE_BITSTRUCT:
|
||||
UNREACHABLE
|
||||
case ALL_FLOATS:
|
||||
case ALL_INTS:
|
||||
@@ -606,14 +606,12 @@ static ABIArgInfo *x86_classify_argument(CallABI call, Regs *regs, Type *type)
|
||||
return x86_classify_primitives(call, regs, type);
|
||||
case TYPE_VECTOR:
|
||||
return x86_classify_vector(regs, type);
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_SUBARRAY:
|
||||
case TYPE_VIRTUAL_ANY:
|
||||
case TYPE_VIRTUAL:
|
||||
case TYPE_ARRAY:
|
||||
case TYPE_ERR_UNION:
|
||||
return x86_classify_aggregate(call, regs, type);
|
||||
case TYPE_TYPEINFO:
|
||||
UNREACHABLE
|
||||
|
||||
@@ -520,9 +520,12 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type *
|
||||
return type->backend_debug_type = llvm_debug_pointer_type(c, type);
|
||||
case TYPE_ENUM:
|
||||
return type->backend_debug_type = llvm_debug_enum_type(c, type, scope);
|
||||
case TYPE_ERRTYPE:
|
||||
return type->backend_debug_type = llvm_debug_enum_type(c, type, scope);
|
||||
case TYPE_FUNC:
|
||||
return type->backend_debug_type = llvm_debug_func_type(c, type);
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_BITSTRUCT:
|
||||
TODO
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
return type->backend_debug_type = llvm_debug_structlike_type(c, type, scope);
|
||||
@@ -533,7 +536,8 @@ static inline LLVMMetadataRef llvm_get_debug_type_internal(GenContext *c, Type *
|
||||
return type->backend_debug_type = llvm_debug_array_type(c, type);
|
||||
case TYPE_SUBARRAY:
|
||||
return type->backend_debug_type = llvm_debug_subarray_type(c, type);
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_ANYERR:
|
||||
// TODO
|
||||
return type->backend_debug_type = llvm_debug_errunion_type(c, type);
|
||||
case TYPE_VIRTUAL:
|
||||
case TYPE_VIRTUAL_ANY:
|
||||
|
||||
@@ -15,10 +15,8 @@ static void llvm_emit_initialize_designated(GenContext *c, BEValue *ref, uint64_
|
||||
|
||||
LLVMValueRef llvm_emit_is_no_error_value(GenContext *c, BEValue *value)
|
||||
{
|
||||
assert(value->kind == BE_ADDRESS);
|
||||
LLVMValueRef val = LLVMBuildStructGEP2(c->builder, llvm_get_type(c, value->type), value->value, 0, "err_domain");
|
||||
LLVMValueRef domain = llvm_emit_load_aligned(c, llvm_get_type(c, type_uptr), val, value->alignment, "");
|
||||
return LLVMBuildICmp(c->builder, LLVMIntEQ, domain, llvm_get_zero(c, type_uptr), "not_err");
|
||||
llvm_value_rvalue(c, value);
|
||||
return LLVMBuildICmp(c->builder, LLVMIntEQ, value->value, llvm_get_zero(c, type_anyerr), "not_err");
|
||||
}
|
||||
|
||||
LLVMTypeRef llvm_const_padding_type(GenContext *c, ByteSize size)
|
||||
@@ -114,12 +112,7 @@ LLVMValueRef llvm_coerce_int_ptr(GenContext *c, LLVMValueRef value, LLVMTypeRef
|
||||
// 4. Are int types not matching?
|
||||
if (to_int_type != from)
|
||||
{
|
||||
if (platform_target.little_endian)
|
||||
{
|
||||
// Little-endian targets preserve the low bits. No shifts required.
|
||||
value = LLVMBuildIntCast2(c->builder, value, to_int_type, false, "");
|
||||
}
|
||||
else
|
||||
if (platform_target.big_endian)
|
||||
{
|
||||
// Big endian, preserve the high bits.
|
||||
ByteSize to_size = llvm_abi_size(c, to_int_type);
|
||||
@@ -135,6 +128,11 @@ LLVMValueRef llvm_coerce_int_ptr(GenContext *c, LLVMValueRef value, LLVMTypeRef
|
||||
value = LLVMBuildShl(c->builder, value, LLVMConstInt(from, (to_size - from_size) * 8, false), "");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Little-endian targets preserve the low bits. No shifts required.
|
||||
value = LLVMBuildIntCast2(c->builder, value, to_int_type, false, "");
|
||||
}
|
||||
}
|
||||
if (to_is_pointer)
|
||||
{
|
||||
@@ -435,7 +433,6 @@ static void gencontext_emit_member_addr(GenContext *c, BEValue *value, Decl *par
|
||||
llvm_value_addr(c, value);
|
||||
llvm_value_set_address_align(value, llvm_emit_bitcast(c, value->value, type_get_ptr(found->type)), found->type, value->alignment);
|
||||
break;
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_STRUCT:
|
||||
llvm_value_struct_gep(c, value, value, index);
|
||||
break;
|
||||
@@ -503,6 +500,9 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, BEValue *value, Type *to_
|
||||
|
||||
switch (cast_kind)
|
||||
{
|
||||
case CAST_ERBOOL:
|
||||
case CAST_EUINT:
|
||||
case CAST_ERINT:
|
||||
case CAST_VRBOOL:
|
||||
case CAST_VRPTR:
|
||||
case CAST_PTRVR:
|
||||
@@ -2033,7 +2033,8 @@ static void gencontext_emit_typeid(GenContext *context, BEValue *be_value, Expr
|
||||
|
||||
void gencontext_emit_trycatch_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
{
|
||||
|
||||
TODO
|
||||
/*
|
||||
LLVMBasicBlockRef error_block = llvm_basic_block_new(c, "error_block");
|
||||
LLVMBasicBlockRef no_err_block = llvm_basic_block_new(c, "noerr_block");
|
||||
LLVMBasicBlockRef phi_block = llvm_basic_block_new(c, "phi_trycatch_block");
|
||||
@@ -2071,6 +2072,7 @@ void gencontext_emit_trycatch_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
LLVMAddIncoming(phi, logic_values, blocks, 2);
|
||||
|
||||
llvm_value_set(value, phi, expr->type);
|
||||
*/
|
||||
}
|
||||
|
||||
void llvm_emit_try_assign_try_catch(GenContext *c, bool is_try, BEValue *be_value, BEValue *var_addr, BEValue *catch_addr, Expr *rhs)
|
||||
@@ -2149,7 +2151,7 @@ void llvm_emit_try_assign_expr(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
}
|
||||
}
|
||||
|
||||
void gencontext_emit_try_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
void llvm_emit_try_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
{
|
||||
|
||||
LLVMBasicBlockRef error_block = llvm_basic_block_new(c, "error_block");
|
||||
@@ -2567,6 +2569,10 @@ static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVM
|
||||
case TYPE_DISTINCT:
|
||||
case TYPE_STRLIT:
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
case TYPE_ENUM:
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_ANYERR:
|
||||
case TYPE_BITSTRUCT:
|
||||
UNREACHABLE
|
||||
break;
|
||||
case TYPE_BOOL:
|
||||
@@ -2574,15 +2580,11 @@ static void llvm_expand_type_to_args(GenContext *context, Type *param_type, LLVM
|
||||
case ALL_UNSIGNED_INTS:
|
||||
case ALL_REAL_FLOATS:
|
||||
case TYPE_POINTER:
|
||||
case TYPE_ENUM:
|
||||
case TYPE_ERRTYPE:
|
||||
vec_add(*values, LLVMBuildLoad2(context->builder, llvm_get_type(context, param_type), expand_ptr, "loadexpanded"));
|
||||
return;
|
||||
case TYPE_TYPEDEF:
|
||||
param_type = param_type->canonical;
|
||||
goto REDO;
|
||||
case TYPE_ERR_UNION:
|
||||
TODO
|
||||
case TYPE_STRUCT:
|
||||
gencontext_expand_struct_to_args(context, param_type, expand_ptr, values);
|
||||
break;
|
||||
@@ -3191,7 +3193,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr)
|
||||
|
||||
// 17c. If we have an error var, or we aren't interested in the error variable
|
||||
// - then it's straightforward. We just jump to the catch block.
|
||||
LLVMBasicBlockRef after_block = llvm_basic_block_new(c, "after_check");
|
||||
LLVMBasicBlockRef after_block = llvm_basic_block_new(c, "after.errcheck");
|
||||
if (error_var || !c->error_var)
|
||||
{
|
||||
llvm_emit_cond_br(c, &no_err, after_block, c->catch_block);
|
||||
@@ -3311,7 +3313,9 @@ static inline void llvm_emit_macro_block(GenContext *context, BEValue *be_value,
|
||||
case VARDECL_MEMBER:
|
||||
case VARDECL_LOCAL_CT:
|
||||
case VARDECL_LOCAL_CT_TYPE:
|
||||
case VARDECL_ALIAS:
|
||||
case VARDECL_UNWRAPPED:
|
||||
case VARDECL_REWRAPPED:
|
||||
case VARDECL_ERASE:
|
||||
UNREACHABLE
|
||||
case VARDECL_PARAM_REF:
|
||||
{
|
||||
@@ -3444,15 +3448,137 @@ static void llvm_emit_macro_body_expansion(GenContext *c, BEValue *value, Expr *
|
||||
llvm_emit_stmt(c, body_expr->body_expansion_expr.ast);
|
||||
}
|
||||
|
||||
void llvm_emit_try_unwrap(GenContext *c, BEValue *value, Expr *expr)
|
||||
{
|
||||
if (!expr->try_unwrap_expr.failable)
|
||||
{
|
||||
LLVMValueRef fail_ref = decl_failable_ref(expr->try_unwrap_expr.decl);
|
||||
LLVMValueRef errv = llvm_emit_load_aligned(c, llvm_get_type(c, type_anyerr), fail_ref, 0, "load.err");
|
||||
LLVMValueRef result = LLVMBuildICmp(c->builder, LLVMIntEQ, errv, llvm_get_zero(c, type_anyerr), "result");
|
||||
llvm_value_set_bool(value, result);
|
||||
return;
|
||||
}
|
||||
BEValue addr;
|
||||
if (expr->try_unwrap_expr.assign_existing)
|
||||
{
|
||||
llvm_emit_expr(c, &addr, expr->try_unwrap_expr.lhs);
|
||||
}
|
||||
else
|
||||
{
|
||||
llvm_emit_local_decl(c, expr->try_unwrap_expr.decl);
|
||||
llvm_value_set_decl_address(&addr, expr->try_unwrap_expr.decl);
|
||||
}
|
||||
assert(llvm_value_is_addr(&addr));
|
||||
llvm_emit_try_assign_try_catch(c, true, value, &addr, NULL, expr->try_unwrap_expr.failable);
|
||||
}
|
||||
|
||||
void llvm_emit_catch_unwrap(GenContext *c, BEValue *value, Expr *expr)
|
||||
{
|
||||
BEValue addr;
|
||||
if (expr->catch_unwrap_expr.lhs)
|
||||
{
|
||||
llvm_emit_expr(c, &addr, expr->catch_unwrap_expr.lhs);
|
||||
}
|
||||
else if (expr->catch_unwrap_expr.decl)
|
||||
{
|
||||
llvm_emit_local_decl(c, expr->catch_unwrap_expr.decl);
|
||||
llvm_value_set_decl_address(&addr, expr->catch_unwrap_expr.decl);
|
||||
}
|
||||
else
|
||||
{
|
||||
LLVMValueRef temp_err = llvm_emit_alloca_aligned(c, type_anyerr, "temp_err");
|
||||
llvm_value_set_address(&addr, temp_err, type_anyerr);
|
||||
}
|
||||
|
||||
PUSH_ERROR();
|
||||
|
||||
LLVMBasicBlockRef catch_block = llvm_basic_block_new(c, "end_block");
|
||||
|
||||
c->error_var = addr.value;
|
||||
c->catch_block = catch_block;
|
||||
|
||||
VECEACH(expr->catch_unwrap_expr.exprs, i)
|
||||
{
|
||||
BEValue val;
|
||||
LLVMBasicBlockRef block = llvm_basic_block_new(c, "testblock");
|
||||
llvm_emit_br(c, block);
|
||||
llvm_emit_block(c, block);
|
||||
llvm_emit_expr(c, &val, expr->catch_unwrap_expr.exprs[i]);
|
||||
llvm_value_fold_failable(c, &val);
|
||||
}
|
||||
|
||||
POP_ERROR();
|
||||
|
||||
llvm_store_bevalue_raw(c, &addr, llvm_get_zero(c, type_anyerr));
|
||||
llvm_emit_br(c, catch_block);
|
||||
llvm_emit_block(c, catch_block);
|
||||
llvm_value_rvalue(c, &addr);
|
||||
llvm_value_set(value, addr.value, type_anyerr);
|
||||
}
|
||||
|
||||
void llvm_emit_try_unwrap_chain(GenContext *c, BEValue *value, Expr *expr)
|
||||
{
|
||||
Expr **exprs = expr->try_unwrap_chain_expr;
|
||||
unsigned elements = vec_size(exprs);
|
||||
assert(elements > 0);
|
||||
|
||||
LLVMBasicBlockRef next_block = NULL;
|
||||
LLVMBasicBlockRef end_block = llvm_basic_block_new(c, "end_chain");
|
||||
LLVMBasicBlockRef fail_block = llvm_basic_block_new(c, "fail_chain");
|
||||
|
||||
if (elements == 1)
|
||||
{
|
||||
llvm_emit_expr(c, value, exprs[0]);
|
||||
assert(llvm_value_is_bool(value));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned i = 0; i < elements; i++)
|
||||
{
|
||||
if (next_block)
|
||||
{
|
||||
llvm_emit_br(c, next_block);
|
||||
llvm_emit_block(c, next_block);
|
||||
}
|
||||
next_block = llvm_basic_block_new(c, "chain_next");
|
||||
Expr *link = exprs[i];
|
||||
BEValue res;
|
||||
llvm_emit_expr(c, &res, link);
|
||||
assert(llvm_value_is_bool(&res));
|
||||
llvm_emit_cond_br(c, &res, next_block, fail_block);
|
||||
}
|
||||
llvm_emit_block(c, next_block);
|
||||
llvm_emit_br(c, end_block);
|
||||
llvm_emit_block(c, fail_block);
|
||||
llvm_emit_br(c, end_block);
|
||||
}
|
||||
|
||||
// Finally set up our phi
|
||||
llvm_emit_block(c, end_block);
|
||||
LLVMValueRef chain_result = LLVMBuildPhi(c->builder, c->bool_type, "chain.phi");
|
||||
LLVMValueRef logic_values[2] = { LLVMConstInt(c->bool_type, 1, 0), LLVMConstNull(c->bool_type) };
|
||||
LLVMBasicBlockRef blocks[2] = { next_block, fail_block };
|
||||
LLVMAddIncoming(chain_result, logic_values, blocks, 2);
|
||||
|
||||
llvm_value_set_bool(value, chain_result);
|
||||
|
||||
}
|
||||
|
||||
void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
{
|
||||
EMIT_LOC(c, expr);
|
||||
switch (expr->expr_kind)
|
||||
{
|
||||
case EXPR_DESIGNATOR:
|
||||
case EXPR_MEMBER_ACCESS:
|
||||
assert(expr->access_expr.ref->decl_kind == DECL_ERRVALUE);
|
||||
llvm_value_set(value,
|
||||
LLVMBuildPtrToInt(c->builder, expr->access_expr.ref->backend_ref, llvm_get_type(c, type_anyerr), ""),
|
||||
type_anyerr);
|
||||
return;
|
||||
case EXPR_DESIGNATOR:
|
||||
case EXPR_POISONED:
|
||||
case EXPR_DECL_LIST:
|
||||
case EXPR_COND:
|
||||
case EXPR_TYPEINFO:
|
||||
case EXPR_ENUM_CONSTANT:
|
||||
case EXPR_MACRO_EXPANSION:
|
||||
@@ -3461,7 +3587,17 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
case EXPR_PLACEHOLDER:
|
||||
case EXPR_CT_CALL:
|
||||
case EXPR_FLATPATH:
|
||||
case EXPR_TRY_DECL:
|
||||
UNREACHABLE
|
||||
case EXPR_TRY_UNWRAP_CHAIN:
|
||||
llvm_emit_try_unwrap_chain(c, value, expr);
|
||||
return;
|
||||
case EXPR_TRY_UNWRAP:
|
||||
llvm_emit_try_unwrap(c, value, expr);
|
||||
return;
|
||||
case EXPR_CATCH_UNWRAP:
|
||||
llvm_emit_catch_unwrap(c, value, expr);
|
||||
return;
|
||||
case EXPR_UNDEF:
|
||||
// Should never reach this.
|
||||
UNREACHABLE
|
||||
@@ -3481,15 +3617,11 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
gencontext_emit_failable(c, value, expr);
|
||||
return;
|
||||
case EXPR_TRY:
|
||||
gencontext_emit_try_expr(c, value, expr);
|
||||
llvm_emit_try_expr(c, value, expr);
|
||||
return;
|
||||
case EXPR_TRY_ASSIGN:
|
||||
llvm_emit_try_assign_expr(c, value, expr);
|
||||
return;
|
||||
case EXPR_TRY_OLD:
|
||||
case EXPR_CATCH_OLD:
|
||||
gencontext_emit_trycatch_expr(c, value, expr);
|
||||
return;
|
||||
case EXPR_NOP:
|
||||
return;
|
||||
case EXPR_ELSE:
|
||||
|
||||
@@ -633,14 +633,15 @@ void llvm_emit_extern_decl(GenContext *context, Decl *decl)
|
||||
decl->backend_ref = LLVMAddGlobal(context->module, llvm_get_type(context, decl->type), decl->extname ?: decl->external_name);
|
||||
LLVMSetVisibility(decl->backend_ref, LLVMDefaultVisibility);
|
||||
break;
|
||||
case DECL_BITSTRUCT:
|
||||
case DECL_STRUCT:
|
||||
case DECL_UNION:
|
||||
case DECL_ERR:
|
||||
llvm_emit_methods(context, decl->methods);
|
||||
llvm_get_type(context, decl->type);
|
||||
// TODO // Fix typeid
|
||||
break;
|
||||
case DECL_ENUM:
|
||||
case DECL_ERRTYPE:
|
||||
llvm_emit_methods(context, decl->methods);
|
||||
// TODO // Fix typeid
|
||||
return;
|
||||
@@ -649,6 +650,7 @@ void llvm_emit_extern_decl(GenContext *context, Decl *decl)
|
||||
case NON_TYPE_DECLS:
|
||||
case DECL_INTERFACE:
|
||||
case DECL_ENUM_CONSTANT:
|
||||
case DECL_ERRVALUE:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,14 +298,14 @@ static inline LLVMValueRef gencontext_emit_load(GenContext *c, Type *type, LLVMV
|
||||
static inline LLVMValueRef decl_failable_ref(Decl *decl)
|
||||
{
|
||||
assert(decl->decl_kind == DECL_VAR);
|
||||
if (decl->var.kind == VARDECL_ALIAS) return decl_failable_ref(decl->var.alias);
|
||||
if (decl->var.kind == VARDECL_UNWRAPPED) return decl_failable_ref(decl->var.alias);
|
||||
if (!decl->var.failable) return NULL;
|
||||
return decl->var.failable_ref;
|
||||
}
|
||||
|
||||
static inline LLVMValueRef decl_ref(Decl *decl)
|
||||
{
|
||||
if (decl->decl_kind == DECL_VAR && decl->var.kind == VARDECL_ALIAS) return decl_ref(decl->var.alias);
|
||||
if (decl->decl_kind == DECL_VAR && decl->var.kind == VARDECL_UNWRAPPED) return decl_ref(decl->var.alias);
|
||||
return decl->backend_ref;
|
||||
}
|
||||
|
||||
|
||||
@@ -110,25 +110,25 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl)
|
||||
|
||||
void llvm_emit_decl_expr_list_ignore_result(GenContext *context, Expr *expr)
|
||||
{
|
||||
assert(expr->expr_kind == EXPR_DECL_LIST);
|
||||
VECEACH(expr->dexpr_list_expr, i)
|
||||
assert(expr->expr_kind == EXPR_COND);
|
||||
VECEACH(expr->cond_expr, i)
|
||||
{
|
||||
BEValue value;
|
||||
llvm_emit_expr(context, &value, expr->dexpr_list_expr[i]);
|
||||
llvm_emit_expr(context, &value, expr->cond_expr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void gencontext_emit_decl_expr_list(GenContext *context, BEValue *be_value, Expr *expr, bool bool_cast)
|
||||
{
|
||||
assert(expr->expr_kind == EXPR_DECL_LIST);
|
||||
ByteSize size = vec_size(expr->dexpr_list_expr);
|
||||
assert(expr->expr_kind == EXPR_COND);
|
||||
ByteSize size = vec_size(expr->cond_expr);
|
||||
ByteSize last_index = size - 1;
|
||||
for (ByteSize i = 0; i < last_index; i++)
|
||||
{
|
||||
BEValue value;
|
||||
llvm_emit_expr(context, &value, expr->dexpr_list_expr[i]);
|
||||
llvm_emit_expr(context, &value, expr->cond_expr[i]);
|
||||
}
|
||||
Expr *last = expr->dexpr_list_expr[last_index];
|
||||
Expr *last = expr->cond_expr[last_index];
|
||||
Type *type = last->type;
|
||||
llvm_emit_expr(context, be_value, last);
|
||||
if (last->expr_kind == EXPR_DECL)
|
||||
|
||||
@@ -12,10 +12,13 @@ static inline LLVMTypeRef llvm_type_from_decl(GenContext *c, Decl *decl)
|
||||
{
|
||||
case DECL_VAR:
|
||||
case DECL_ENUM_CONSTANT:
|
||||
case DECL_ERRVALUE:
|
||||
case DECL_POISONED:
|
||||
case DECL_INTERFACE:
|
||||
case NON_TYPE_DECLS:
|
||||
UNREACHABLE
|
||||
case DECL_BITSTRUCT:
|
||||
return llvm_get_type(c, decl->bitstruct.base_type->type);
|
||||
case DECL_FUNC:
|
||||
{
|
||||
VECEACH(decl->func_decl.function_signature.params, i)
|
||||
@@ -85,31 +88,8 @@ static inline LLVMTypeRef llvm_type_from_decl(GenContext *c, Decl *decl)
|
||||
}
|
||||
case DECL_ENUM:
|
||||
return llvm_get_type(c, decl->type);
|
||||
case DECL_ERR:
|
||||
{
|
||||
LLVMTypeRef err_type = LLVMStructCreateNamed(c->context, decl->name);
|
||||
// Avoid recursive issues.
|
||||
decl->type->backend_type = err_type;
|
||||
LLVMTypeRef *types = NULL;
|
||||
unsigned size = 0;
|
||||
VECEACH(decl->strukt.members, i)
|
||||
{
|
||||
Type *type = decl->strukt.members[i]->type->canonical;
|
||||
unsigned alignment = type_abi_alignment(type);
|
||||
if (size % alignment != 0)
|
||||
{
|
||||
size += alignment - size % alignment;
|
||||
}
|
||||
size += type_size(type);
|
||||
vec_add(types, llvm_get_type(c, type));
|
||||
}
|
||||
if (decl->strukt.padding)
|
||||
{
|
||||
vec_add(types, llvm_const_padding_type(c, decl->strukt.padding));
|
||||
}
|
||||
LLVMStructSetBody(err_type, types, vec_size(types), false);
|
||||
return err_type;
|
||||
}
|
||||
case DECL_ERRTYPE:
|
||||
return llvm_get_type(c, type_iptr);
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
@@ -159,15 +139,9 @@ static void param_expand(GenContext *context, LLVMTypeRef** params_ref, Type *ty
|
||||
return;
|
||||
}
|
||||
case TYPE_ENUM:
|
||||
param_expand(context, params_ref, type_lowering(type));
|
||||
return;
|
||||
case TYPE_ERR_UNION:
|
||||
param_expand(context, params_ref, type_usize->canonical);
|
||||
param_expand(context, params_ref, type_usize->canonical);
|
||||
return;
|
||||
case TYPE_ANYERR:
|
||||
case TYPE_ERRTYPE:
|
||||
// TODO
|
||||
param_expand(context, params_ref, type_usize->canonical);
|
||||
param_expand(context, params_ref, type_lowering(type));
|
||||
return;
|
||||
case TYPE_UNION:
|
||||
{
|
||||
@@ -338,23 +312,18 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type)
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
UNREACHABLE
|
||||
case TYPE_TYPEID:
|
||||
return any_type->backend_type = LLVMIntTypeInContext(c->context, any_type->builtin.bitsize);
|
||||
case TYPE_ANYERR:
|
||||
case TYPE_ERRTYPE:
|
||||
return any_type->backend_type = llvm_get_type(c, type_iptr);
|
||||
case TYPE_TYPEDEF:
|
||||
return any_type->backend_type = llvm_get_type(c, any_type->canonical);
|
||||
case TYPE_DISTINCT:
|
||||
return any_type->backend_type = llvm_get_type(c, any_type->decl->distinct_decl.base_type);
|
||||
case TYPE_ENUM:
|
||||
return any_type->backend_type = llvm_get_type(c, any_type->decl->enums.type_info->type->canonical);
|
||||
case TYPE_ERR_UNION:
|
||||
{
|
||||
LLVMTypeRef elements[2] = { llvm_get_type(c, type_usize->canonical), llvm_get_type(c, type_usize->canonical) };
|
||||
LLVMTypeRef strukt = LLVMStructCreateNamed(c->context, "error_union");
|
||||
LLVMStructSetBody(strukt, elements, 2, false);
|
||||
return any_type->backend_type = strukt;
|
||||
}
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_BITSTRUCT:
|
||||
return any_type->backend_type = llvm_type_from_decl(c, any_type->decl);
|
||||
case TYPE_FUNC:
|
||||
return any_type->backend_type = llvm_func_type(c, any_type);
|
||||
|
||||
@@ -59,6 +59,162 @@ static inline Expr *parse_expr_or_initializer_list(Context *context)
|
||||
return parse_expr(context);
|
||||
}
|
||||
|
||||
static inline bool next_is_try_unwrap(Context *context)
|
||||
{
|
||||
return tok_is(context, TOKEN_TRY) && context->next_tok.type != TOKEN_LPAREN;
|
||||
}
|
||||
|
||||
static inline bool next_is_catch_unwrap(Context *context)
|
||||
{
|
||||
return tok_is(context, TOKEN_CATCH) && context->next_tok.type != TOKEN_LPAREN;
|
||||
}
|
||||
|
||||
static inline Expr *parse_for_try_expr(Context *context)
|
||||
{
|
||||
return parse_precedence(context, PREC_AND + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* catch_unwrap ::= CATCH IDENT | (type? IDENT '=' (expr | '(' expr (',' expr) ')'))
|
||||
*/
|
||||
static inline Expr *parse_catch_unwrap(Context *context)
|
||||
{
|
||||
advance_and_verify(context, TOKEN_CATCH);
|
||||
Expr *expr = expr_new(EXPR_CATCH_UNWRAP, source_span_from_token_id(context->prev_tok));
|
||||
expr->catch_unwrap_expr.type = parse_next_is_decl(context) ? TRY_TYPE_OR(parse_type(context), poisoned_expr) : NULL;
|
||||
expr->catch_unwrap_expr.variable = TRY_EXPR_OR(parse_for_try_expr(context), poisoned_expr);
|
||||
if (!try_consume(context, TOKEN_EQ))
|
||||
{
|
||||
if (expr->catch_unwrap_expr.type)
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "Expected a '=' here.");
|
||||
return poisoned_expr;
|
||||
}
|
||||
vec_add(expr->catch_unwrap_expr.exprs, expr->catch_unwrap_expr.variable);
|
||||
expr->catch_unwrap_expr.variable = NULL;
|
||||
RANGE_EXTEND_PREV(expr);
|
||||
return expr;
|
||||
}
|
||||
if (try_consume(context, TOKEN_LPAREN))
|
||||
{
|
||||
do
|
||||
{
|
||||
Expr *init_expr = TRY_EXPR_OR(parse_expr(context), poisoned_expr);
|
||||
vec_add(expr->catch_unwrap_expr.exprs, init_expr);
|
||||
} while (try_consume(context, TOKEN_COMMA));
|
||||
CONSUME_OR(TOKEN_RPAREN, poisoned_expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Expr *init_expr = TRY_EXPR_OR(parse_expr(context), poisoned_expr);
|
||||
vec_add(expr->catch_unwrap_expr.exprs, init_expr);
|
||||
}
|
||||
RANGE_EXTEND_PREV(expr);
|
||||
return expr;
|
||||
}
|
||||
|
||||
/**
|
||||
* try_unwrap ::= TRY (IDENT | type? IDENT '=' non_and_expr)
|
||||
*/
|
||||
static inline Expr *parse_try_unwrap(Context *context)
|
||||
{
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_TRY_UNWRAP, context->tok);
|
||||
advance_and_verify(context, TOKEN_TRY);
|
||||
if (parse_next_is_decl(context))
|
||||
{
|
||||
expr->try_unwrap_expr.type = TRY_TYPE_OR(parse_type(context), poisoned_expr);
|
||||
}
|
||||
expr->try_unwrap_expr.variable = TRY_EXPR_OR(parse_for_try_expr(context), poisoned_expr);
|
||||
if (expr->try_unwrap_expr.type && expr->try_unwrap_expr.variable->expr_kind != EXPR_IDENTIFIER)
|
||||
{
|
||||
SEMA_ERROR(expr->try_unwrap_expr.variable, "Expected a variable name after the type.");
|
||||
return poisoned_expr;
|
||||
}
|
||||
if (try_consume(context, TOKEN_EQ))
|
||||
{
|
||||
expr->try_unwrap_expr.init = TRY_EXPR_OR(parse_for_try_expr(context), poisoned_expr);
|
||||
}
|
||||
RANGE_EXTEND_PREV(expr);
|
||||
return expr;
|
||||
}
|
||||
|
||||
/**
|
||||
* try_unwrap_chain ::= try_unwrap ('&&' (try_unwrap | non_and_expr))*
|
||||
* try_unwrap ::= TRY (IDENT | type? IDENT '=' non_and_expr)
|
||||
*/
|
||||
static inline Expr *parse_try_unwrap_chain(Context *context)
|
||||
{
|
||||
Expr **unwraps = NULL;
|
||||
Expr *first_unwrap = TRY_EXPR_OR(parse_try_unwrap(context), poisoned_expr);
|
||||
vec_add(unwraps, first_unwrap);
|
||||
while (try_consume(context, TOKEN_AND))
|
||||
{
|
||||
if (next_is_try_unwrap(context))
|
||||
{
|
||||
Expr *expr = TRY_EXPR_OR(parse_try_unwrap(context), poisoned_expr);
|
||||
vec_add(unwraps, expr);
|
||||
continue;
|
||||
}
|
||||
Expr *next_unwrap = TRY_EXPR_OR(parse_for_try_expr(context), poisoned_expr);
|
||||
vec_add(unwraps, next_unwrap);
|
||||
}
|
||||
Expr *try_unwrap_chain = EXPR_NEW_EXPR(EXPR_TRY_UNWRAP_CHAIN, first_unwrap);
|
||||
try_unwrap_chain->try_unwrap_chain_expr = unwraps;
|
||||
RANGE_EXTEND_PREV(try_unwrap_chain);
|
||||
return try_unwrap_chain;
|
||||
}
|
||||
|
||||
/**
|
||||
* cond_list ::= ((expr | decl-expr) COMMA)* (expr | decl-expr | try_unwrap_chain | catch_unwrap )
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
Expr *parse_cond(Context *context)
|
||||
{
|
||||
Expr *decl_expr = EXPR_NEW_TOKEN(EXPR_COND, context->tok);
|
||||
decl_expr->cond_expr = NULL;
|
||||
while (1)
|
||||
{
|
||||
if (next_is_try_unwrap(context))
|
||||
{
|
||||
Expr *try_unwrap = TRY_EXPR_OR(parse_try_unwrap_chain(context), poisoned_expr);
|
||||
vec_add(decl_expr->cond_expr, try_unwrap);
|
||||
if (tok_is(context, TOKEN_COMMA))
|
||||
{
|
||||
SEMA_ERROR(try_unwrap, "The 'try' must be placed last, can you change it?");
|
||||
return poisoned_expr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (next_is_catch_unwrap(context))
|
||||
{
|
||||
Expr *catch_unwrap = TRY_EXPR_OR(parse_catch_unwrap(context), poisoned_expr);
|
||||
vec_add(decl_expr->cond_expr, catch_unwrap);
|
||||
if (tok_is(context, TOKEN_COMMA))
|
||||
{
|
||||
SEMA_ERROR(catch_unwrap, "The 'catch' must be placed last, can you change it?");
|
||||
return poisoned_expr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (parse_next_is_decl(context))
|
||||
{
|
||||
Decl *decl = TRY_DECL_OR(parse_decl(context), poisoned_expr);
|
||||
Expr *expr = expr_new(EXPR_DECL, decl->span);
|
||||
expr->decl_expr = decl;
|
||||
vec_add(decl_expr->cond_expr, expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Expr *expr = TRY_EXPR_OR(parse_expr(context), poisoned_expr);
|
||||
vec_add(decl_expr->cond_expr, expr);
|
||||
}
|
||||
if (!try_consume(context, TOKEN_COMMA)) break;
|
||||
}
|
||||
RANGE_EXTEND_PREV(decl_expr);
|
||||
return decl_expr;
|
||||
}
|
||||
|
||||
inline Expr* parse_expr(Context *context)
|
||||
{
|
||||
return parse_precedence(context, PREC_ASSIGNMENT);
|
||||
@@ -654,37 +810,30 @@ static Expr *parse_identifier_starting_expression(Context *context, Expr *left)
|
||||
}
|
||||
}
|
||||
|
||||
static Expr *parse_try_old_expr(Context *context, Expr *left)
|
||||
{
|
||||
assert(!left && "Unexpected left hand side");
|
||||
Expr *try_expr = EXPR_NEW_TOKEN(TOKEN_IS(TOKEN_TRY_OLD) ? EXPR_TRY_OLD : EXPR_CATCH_OLD, context->tok);
|
||||
advance(context);
|
||||
CONSUME_OR(TOKEN_LPAREN, poisoned_expr);
|
||||
try_expr->trycatch_expr = TRY_EXPR_OR(parse_expr(context), poisoned_expr);
|
||||
CONSUME_OR(TOKEN_RPAREN, poisoned_expr);
|
||||
return try_expr;
|
||||
}
|
||||
|
||||
|
||||
static Expr *parse_try_expr(Context *context, Expr *left)
|
||||
{
|
||||
assert(!left && "Unexpected left hand side");
|
||||
bool try = TOKEN_IS(TOKEN_TRY);
|
||||
Expr *try_expr = EXPR_NEW_TOKEN(EXPR_TRY, context->tok);
|
||||
bool is_try = TOKEN_IS(TOKEN_TRY);
|
||||
advance(context);
|
||||
Expr *expr = TRY_EXPR_OR(parse_precedence(context, PREC_UNARY), poisoned_expr);
|
||||
if (try_consume(context, TOKEN_EQ))
|
||||
Expr *try_expr = expr_new(EXPR_TRY, source_span_from_token_id(context->prev_tok));
|
||||
if (!try_consume(context, TOKEN_LPAREN))
|
||||
{
|
||||
Expr *init = TRY_EXPR_OR(parse_precedence(context, PREC_ASSIGNMENT), poisoned_expr);
|
||||
try_expr->expr_kind = EXPR_TRY_ASSIGN;
|
||||
try_expr->try_assign_expr.expr = expr;
|
||||
try_expr->try_assign_expr.is_try = try;
|
||||
try_expr->try_assign_expr.init = init;
|
||||
}
|
||||
else
|
||||
{
|
||||
try_expr->try_expr.expr = expr;
|
||||
try_expr->try_expr.is_try = try;
|
||||
if (is_try)
|
||||
{
|
||||
SEMA_ERROR(try_expr, "An unwrapping 'try' can only occur as the last element of a conditional, did you want 'try(expr)'?");
|
||||
return poisoned_expr;
|
||||
}
|
||||
else
|
||||
{
|
||||
SEMA_ERROR(try_expr, "An unwrapping 'catch' can only occur as the last element of a conditional, did you want 'catch(expr)'?");
|
||||
return poisoned_expr;
|
||||
}
|
||||
}
|
||||
try_expr->try_expr.expr = TRY_EXPR_OR(parse_expr(context), poisoned_expr);
|
||||
try_expr->try_expr.is_try = is_try;
|
||||
CONSUME_OR(TOKEN_RPAREN, poisoned_expr);
|
||||
RANGE_EXTEND_PREV(try_expr);
|
||||
return try_expr;
|
||||
}
|
||||
@@ -1108,8 +1257,6 @@ ParseRule rules[TOKEN_EOF + 1] = {
|
||||
[TOKEN_LBRAPIPE] = { parse_expr_block, NULL, PREC_NONE },
|
||||
[TOKEN_TRY] = { parse_try_expr, NULL, PREC_NONE },
|
||||
[TOKEN_CATCH] = { parse_try_expr, NULL, PREC_NONE },
|
||||
[TOKEN_TRY_OLD] = { parse_try_old_expr, NULL, PREC_NONE },
|
||||
[TOKEN_CATCH_OLD] = { parse_try_old_expr, NULL, PREC_NONE },
|
||||
[TOKEN_BANGBANG] = { NULL, parse_bangbang_expr, PREC_CALL },
|
||||
[TOKEN_LBRACKET] = { NULL, parse_subscript_expr, PREC_CALL },
|
||||
[TOKEN_MINUS] = { parse_unary_expr, parse_binary, PREC_ADDITIVE },
|
||||
|
||||
@@ -82,6 +82,7 @@ void recover_top_level(Context *context)
|
||||
case TOKEN_ATTRIBUTE:
|
||||
case TOKEN_DEFINE:
|
||||
case TOKEN_ERRTYPE:
|
||||
case TOKEN_BITSTRUCT:
|
||||
return;
|
||||
case TOKEN_IDENT: // Incr arrays only
|
||||
case TOKEN_CONST:
|
||||
@@ -425,12 +426,17 @@ static inline bool parse_specified_import(Context *context, Path *path)
|
||||
}
|
||||
|
||||
|
||||
static inline bool consume_ident(Context *context, const char* name)
|
||||
bool consume_ident(Context *context, const char* name)
|
||||
{
|
||||
if (try_consume(context, TOKEN_IDENT)) return true;
|
||||
if (TOKEN_IS(TOKEN_TYPE_IDENT) || TOKEN_IS(TOKEN_CONST_IDENT))
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "A %s cannot start with a capital letter.", name);
|
||||
SEMA_TOKEN_ERROR(context->tok, "A %s must start with a lower case letter.", name);
|
||||
return false;
|
||||
}
|
||||
if (token_is_keyword(context->tok.type))
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "This is a reserved keyword, did you accidentally use it?");
|
||||
return false;
|
||||
}
|
||||
SEMA_TOKEN_ERROR(context->tok, "A %s was expected.", name);
|
||||
@@ -439,7 +445,7 @@ static inline bool consume_ident(Context *context, const char* name)
|
||||
|
||||
static bool consume_type_name(Context *context, const char* type)
|
||||
{
|
||||
if (TOKEN_IS(TOKEN_IDENT))
|
||||
if (TOKEN_IS(TOKEN_IDENT) || token_is_keyword(context->tok.type))
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "Names of %ss must start with an upper case letter.", type);
|
||||
return false;
|
||||
@@ -856,39 +862,6 @@ static inline Decl *parse_incremental_array(Context *context)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* decl_expr_list
|
||||
* : expression
|
||||
* | declaration
|
||||
* | decl_expr_list ',' expression
|
||||
* | decl_expr_list ',' declaration
|
||||
* ;
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
Expr *parse_decl_expr_list(Context *context)
|
||||
{
|
||||
Expr *decl_expr = EXPR_NEW_TOKEN(EXPR_DECL_LIST, context->tok);
|
||||
decl_expr->dexpr_list_expr = NULL;
|
||||
while (1)
|
||||
{
|
||||
if (parse_next_is_decl(context))
|
||||
{
|
||||
Decl *decl = TRY_DECL_OR(parse_decl(context), poisoned_expr);
|
||||
Expr *expr = expr_new(EXPR_DECL, decl->span);
|
||||
expr->decl_expr = decl;
|
||||
vec_add(decl_expr->dexpr_list_expr, expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Expr *expr = TRY_EXPR_OR(parse_expr(context), poisoned_expr);
|
||||
vec_add(decl_expr->dexpr_list_expr, expr);
|
||||
}
|
||||
if (!try_consume(context, TOKEN_COMMA)) break;
|
||||
}
|
||||
RANGE_EXTEND_PREV(decl_expr);
|
||||
return decl_expr;
|
||||
}
|
||||
|
||||
|
||||
bool parse_next_is_decl(Context *context)
|
||||
@@ -897,8 +870,7 @@ bool parse_next_is_decl(Context *context)
|
||||
switch (context->tok.type)
|
||||
{
|
||||
case TYPELIKE_TOKENS:
|
||||
return (next_tok == TOKEN_BANG) | (next_tok == TOKEN_STAR) | (next_tok == TOKEN_LBRACKET) | (next_tok == TOKEN_IDENT)
|
||||
| (next_tok == TOKEN_CONST_IDENT);
|
||||
return next_tok != TOKEN_DOT && next_tok != TOKEN_LPAREN && next_tok != TOKEN_LBRACE;
|
||||
case TOKEN_IDENT:
|
||||
if (next_tok != TOKEN_SCOPE) return false;
|
||||
return context_next_is_type_with_path_prefix(context);
|
||||
@@ -1362,6 +1334,70 @@ static inline Decl *parse_struct_declaration(Context *context, Visibility visibi
|
||||
return decl;
|
||||
}
|
||||
|
||||
/**
|
||||
* body ::= '{' (TYPE IDENT ':' expr '..' expr EOS)* '}'
|
||||
* @param context
|
||||
* @param decl
|
||||
* @return
|
||||
*/
|
||||
static inline bool parse_bitstruct_body(Context *context, Decl *decl)
|
||||
{
|
||||
CONSUME_OR(TOKEN_LBRACE, false);
|
||||
|
||||
while (!try_consume(context, TOKEN_RBRACE))
|
||||
{
|
||||
TypeInfo *type = TRY_TYPE_OR(parse_type(context), false);
|
||||
|
||||
if (!try_consume(context, TOKEN_IDENT))
|
||||
{
|
||||
if (try_consume(context, TOKEN_CONST_IDENT) || try_consume(context, TOKEN_TYPE_IDENT))
|
||||
{
|
||||
SEMA_TOKID_ERROR(context->prev_tok, "Expected a field name with an initial lower case.");
|
||||
return false;
|
||||
}
|
||||
SEMA_TOKEN_ERROR(context->tok, "Expected a field name at this position.");
|
||||
return false;
|
||||
}
|
||||
Decl *member_decl = decl_new_var(context->prev_tok, type, VARDECL_MEMBER, VISIBLE_LOCAL);
|
||||
CONSUME_OR(TOKEN_COLON, false);
|
||||
member_decl->var.start = TRY_EXPR_OR(parse_constant_expr(context), false);
|
||||
CONSUME_OR(TOKEN_DOTDOT, false);
|
||||
member_decl->var.end = TRY_EXPR_OR(parse_constant_expr(context), false);
|
||||
CONSUME_OR(TOKEN_EOS, false);
|
||||
vec_add(decl->bitstruct.members, member_decl);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* bitstruct_declaration = 'bitstruct' IDENT ':' type bitstruct_body
|
||||
*/
|
||||
static inline Decl *parse_bitstruct_declaration(Context *context, Visibility visibility)
|
||||
{
|
||||
advance_and_verify(context, TOKEN_BITSTRUCT);
|
||||
|
||||
TokenId name = context->tok.id;
|
||||
|
||||
if (!consume_type_name(context, "bitstruct")) return poisoned_decl;
|
||||
Decl *decl = decl_new_with_type(name, DECL_BITSTRUCT, visibility);
|
||||
|
||||
CONSUME_OR(TOKEN_COLON, poisoned_decl);
|
||||
|
||||
decl->bitstruct.base_type = TRY_TYPE_OR(parse_type(context), poisoned_decl);
|
||||
|
||||
if (!parse_attributes(context, &decl->attributes))
|
||||
{
|
||||
return poisoned_decl;
|
||||
}
|
||||
|
||||
if (!parse_bitstruct_body(context, decl))
|
||||
{
|
||||
return poisoned_decl;
|
||||
}
|
||||
|
||||
return decl;
|
||||
|
||||
}
|
||||
|
||||
static inline Decl *parse_top_level_const_declaration(Context *context, Visibility visibility)
|
||||
{
|
||||
@@ -1710,29 +1746,53 @@ static inline Decl *parse_error_declaration(Context *context, Visibility visibil
|
||||
{
|
||||
advance_and_verify(context, TOKEN_ERRTYPE);
|
||||
|
||||
Decl *err_decl = decl_new_with_type(context->tok.id, DECL_ERR, visibility);
|
||||
Decl *decl = decl_new_with_type(context->tok.id, DECL_ERRTYPE, visibility);
|
||||
|
||||
if (!consume_type_name(context, "error type")) return poisoned_decl;
|
||||
|
||||
if (try_consume(context, TOKEN_LBRACE))
|
||||
TypeInfo *type = NULL;
|
||||
|
||||
CONSUME_OR(TOKEN_LBRACE, poisoned_decl);
|
||||
|
||||
decl->enums.type_info = type_info_new_base(type_iptr->canonical, decl->span);
|
||||
while (!try_consume(context, TOKEN_RBRACE))
|
||||
{
|
||||
while (!try_consume(context, TOKEN_RBRACE))
|
||||
Decl *enum_const = DECL_NEW(DECL_ERRVALUE, decl->visibility);
|
||||
const char *name = TOKSTR(context->tok);
|
||||
VECEACH(decl->enums.values, i)
|
||||
{
|
||||
TypeInfo *type = TRY_TYPE_OR(parse_type(context), poisoned_decl);
|
||||
if (!TOKEN_IS(TOKEN_IDENT))
|
||||
Decl *other_constant = decl->enums.values[i];
|
||||
if (other_constant->name == name)
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "Expected an identifier here.");
|
||||
return poisoned_decl;
|
||||
SEMA_TOKEN_ERROR(context->tok, "This enum constant is declared twice.");
|
||||
SEMA_PREV(other_constant, "The previous declaration was here.");
|
||||
decl_poison(enum_const);
|
||||
break;
|
||||
}
|
||||
Decl *member = decl_new_var(context->tok.id, type, VARDECL_MEMBER, visibility);
|
||||
advance(context);
|
||||
vec_add(err_decl->strukt.members, member);
|
||||
TRY_CONSUME_EOS_OR(poisoned_decl);
|
||||
}
|
||||
return err_decl;
|
||||
if (!consume_const_name(context, "enum constant"))
|
||||
{
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (try_consume(context, TOKEN_LPAREN))
|
||||
{
|
||||
Expr **result = NULL;
|
||||
if (!parse_arg_list(context, &result, TOKEN_RPAREN, NULL)) return poisoned_decl;
|
||||
enum_const->enum_constant.args = result;
|
||||
CONSUME_OR(TOKEN_RPAREN, poisoned_decl);
|
||||
}
|
||||
if (try_consume(context, TOKEN_EQ))
|
||||
{
|
||||
enum_const->enum_constant.expr = TRY_EXPR_OR(parse_expr(context), poisoned_decl);
|
||||
}
|
||||
vec_add(decl->enums.values, enum_const);
|
||||
// Allow trailing ','
|
||||
if (!try_consume(context, TOKEN_COMMA))
|
||||
{
|
||||
EXPECT_OR(TOKEN_RBRACE, poisoned_decl);
|
||||
}
|
||||
}
|
||||
TRY_CONSUME_EOS_OR(poisoned_decl);
|
||||
return err_decl;
|
||||
return decl;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1797,7 +1857,7 @@ static inline Decl *parse_enum_declaration(Context *context, Visibility visibili
|
||||
if (!parse_enum_spec(context, &type, &decl->enums.parameters, visibility)) return poisoned_decl;
|
||||
}
|
||||
|
||||
CONSUME_OR(TOKEN_LBRACE, false);
|
||||
CONSUME_OR(TOKEN_LBRACE, poisoned_decl);
|
||||
|
||||
decl->enums.type_info = type ? type : type_info_new_base(type_int, decl->span);
|
||||
while (!try_consume(context, TOKEN_RBRACE))
|
||||
@@ -2056,7 +2116,7 @@ static inline bool parse_doc_errors(Context *context, Ast *docs)
|
||||
|
||||
static inline bool parse_doc_contract(Context *context, Ast *docs)
|
||||
{
|
||||
docs->doc_directive.contract.decl_exprs = TRY_EXPR_OR(parse_decl_expr_list(context), false);
|
||||
docs->doc_directive.contract.decl_exprs = TRY_EXPR_OR(parse_cond(context), false);
|
||||
if (try_consume(context, TOKEN_COLON))
|
||||
{
|
||||
docs->doc_directive.contract.comment = TRY_EXPR_OR(parse_expr(context), false);
|
||||
@@ -2211,6 +2271,9 @@ Decl *parse_top_level_statement(Context *context)
|
||||
return poisoned_decl;
|
||||
}
|
||||
break;
|
||||
case TOKEN_BITSTRUCT:
|
||||
decl = TRY_DECL_OR(parse_bitstruct_declaration(context, visibility), poisoned_decl);
|
||||
break;
|
||||
case TOKEN_CONST:
|
||||
decl = TRY_DECL_OR(parse_top_level_const_declaration(context, visibility), poisoned_decl);
|
||||
break;
|
||||
|
||||
@@ -277,7 +277,7 @@ static inline Ast* parse_while_stmt(Context *context)
|
||||
while_ast->while_stmt.flow.label = TRY_DECL_OR(parse_optional_label(context, while_ast), poisoned_ast);
|
||||
|
||||
CONSUME_OR(TOKEN_LPAREN, poisoned_ast);
|
||||
while_ast->while_stmt.cond = TRY_EXPR_OR(parse_decl_expr_list(context), poisoned_ast);
|
||||
while_ast->while_stmt.cond = TRY_EXPR_OR(parse_cond(context), poisoned_ast);
|
||||
CONSUME_OR(TOKEN_RPAREN, poisoned_ast);
|
||||
while_ast->while_stmt.body = TRY_AST(parse_stmt(context));
|
||||
return while_ast;
|
||||
@@ -308,7 +308,7 @@ static inline Ast* parse_if_stmt(Context *context)
|
||||
advance_and_verify(context, TOKEN_IF);
|
||||
if_ast->if_stmt.flow.label = TRY_DECL_OR(parse_optional_label(context, if_ast), poisoned_ast);
|
||||
CONSUME_OR(TOKEN_LPAREN, poisoned_ast);
|
||||
if_ast->if_stmt.cond = TRY_EXPR_OR(parse_decl_expr_list(context), poisoned_ast);
|
||||
if_ast->if_stmt.cond = TRY_EXPR_OR(parse_cond(context), poisoned_ast);
|
||||
CONSUME_OR(TOKEN_RPAREN, poisoned_ast);
|
||||
Ast *stmt = TRY_AST(parse_stmt(context));
|
||||
if_ast->if_stmt.then_body = stmt;
|
||||
@@ -436,7 +436,7 @@ static inline Ast* parse_switch_stmt(Context *context)
|
||||
advance_and_verify(context, TOKEN_SWITCH);
|
||||
switch_ast->switch_stmt.flow.label = TRY_DECL_OR(parse_optional_label(context, switch_ast), poisoned_ast);
|
||||
CONSUME_OR(TOKEN_LPAREN, poisoned_ast);
|
||||
switch_ast->switch_stmt.cond = TRY_EXPR_OR(parse_decl_expr_list(context), poisoned_ast);
|
||||
switch_ast->switch_stmt.cond = TRY_EXPR_OR(parse_cond(context), poisoned_ast);
|
||||
CONSUME_OR(TOKEN_RPAREN, poisoned_ast);
|
||||
|
||||
if (!parse_switch_body(context, &switch_ast->switch_stmt.cases, TOKEN_CASE, TOKEN_DEFAULT, false)) return poisoned_ast;
|
||||
@@ -463,7 +463,7 @@ static inline Ast* parse_for_stmt(Context *context)
|
||||
|
||||
if (!TOKEN_IS(TOKEN_EOS))
|
||||
{
|
||||
ast->for_stmt.init = TRY_EXPR_OR(parse_decl_expr_list(context), poisoned_ast);
|
||||
ast->for_stmt.init = TRY_EXPR_OR(parse_cond(context), poisoned_ast);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -645,7 +645,7 @@ static inline Ast *parse_try_stmt(Context *context)
|
||||
Ast *stmt = AST_NEW_TOKEN(AST_TRY_STMT, context->tok);
|
||||
advance_and_verify(context, TOKEN_TRY_OLD);
|
||||
TRY_CONSUME(TOKEN_LPAREN, "Expected a '(' after 'try'.");
|
||||
stmt->try_old_stmt.decl_expr = TRY_EXPR_OR(parse_decl_expr_list(context), poisoned_ast);
|
||||
stmt->try_old_stmt.decl_expr = TRY_EXPR_OR(parse_cond(context), poisoned_ast);
|
||||
TRY_CONSUME(TOKEN_RPAREN, "Expected a ')' after 'try'.");
|
||||
stmt->try_old_stmt.body = TRY_AST(parse_stmt(context));
|
||||
return stmt;
|
||||
@@ -1148,6 +1148,7 @@ Ast *parse_stmt(Context *context)
|
||||
case TOKEN_UNDERSCORE:
|
||||
case TOKEN_PRIVATE:
|
||||
case TOKEN_PLACEHOLDER:
|
||||
case TOKEN_BITSTRUCT:
|
||||
SEMA_TOKEN_ERROR(context->tok, "Unexpected '%s' found when expecting a statement.", token_type_to_string(context->tok.type));
|
||||
advance(context);
|
||||
return poisoned_ast;
|
||||
|
||||
@@ -35,6 +35,8 @@ Ast *parse_stmt(Context *context);
|
||||
Path *parse_path_prefix(Context *context, bool *had_error);
|
||||
Expr *parse_type_expression_with_path(Context *context, Path *path);
|
||||
Expr *parse_expr(Context *context);
|
||||
bool consume_ident(Context *context, const char* name);
|
||||
Expr *parse_try_expr_after_try(Context *context, bool is_try);
|
||||
TypeInfo *parse_type(Context *context);
|
||||
TypeInfo *parse_type_with_base(Context *context, TypeInfo *type_info);
|
||||
Expr* parse_constant_expr(Context *context);
|
||||
@@ -43,7 +45,7 @@ Expr *parse_initializer(Context *context);
|
||||
void parse_imports(Context *context);
|
||||
Decl *parse_decl(Context *context);
|
||||
void recover_top_level(Context *context);
|
||||
Expr *parse_decl_expr_list(Context *context);
|
||||
Expr *parse_cond(Context *context);
|
||||
Ast* parse_compound_stmt(Context *context);
|
||||
Ast *parse_jump_stmt_no_eos(Context *context);
|
||||
bool parse_attributes(Context *context, Attr ***attributes_ref);
|
||||
|
||||
@@ -383,7 +383,7 @@ CastKind cast_to_bool_kind(Type *type)
|
||||
return CAST_VRBOOL;
|
||||
case TYPE_BOOL:
|
||||
return CAST_BOOLBOOL;
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_ANYERR:
|
||||
return CAST_EUBOOL;
|
||||
case TYPE_SUBARRAY:
|
||||
return CAST_SABOOL;
|
||||
@@ -393,18 +393,20 @@ CastKind cast_to_bool_kind(Type *type)
|
||||
return CAST_FPBOOL;
|
||||
case TYPE_POINTER:
|
||||
return CAST_PTRBOOL;
|
||||
case TYPE_ERRTYPE:
|
||||
return CAST_ERBOOL;
|
||||
case TYPE_POISONED:
|
||||
case TYPE_VOID:
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_STRLIT:
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_ENUM:
|
||||
case TYPE_FUNC:
|
||||
case TYPE_ARRAY:
|
||||
case TYPE_TYPEID:
|
||||
case TYPE_TYPEINFO:
|
||||
case TYPE_VECTOR:
|
||||
case TYPE_BITSTRUCT:
|
||||
return CAST_ERROR;
|
||||
}
|
||||
UNREACHABLE
|
||||
@@ -436,9 +438,11 @@ bool cast_may_explicit(Type *from_type, Type *to_type)
|
||||
case TYPE_BOOL:
|
||||
// May convert to any integer / distinct integer / float, no enums
|
||||
return type_is_integer(to) || type_is_float(to);
|
||||
case TYPE_ERR_UNION:
|
||||
// May convert to a bool, or an error type.
|
||||
return to == type_bool || to_kind == TYPE_ERRTYPE;
|
||||
case TYPE_BITSTRUCT:
|
||||
return false;
|
||||
case TYPE_ANYERR:
|
||||
// May convert to a bool, an error type or an integer
|
||||
return to == type_bool || to_kind == TYPE_ERRTYPE || type_is_integer(to);
|
||||
case TYPE_IXX:
|
||||
case ALL_SIGNED_INTS:
|
||||
case ALL_UNSIGNED_INTS:
|
||||
@@ -461,8 +465,8 @@ bool cast_may_explicit(Type *from_type, Type *to_type)
|
||||
case TYPE_VIRTUAL:
|
||||
return to_kind == TYPE_POINTER;
|
||||
case TYPE_ERRTYPE:
|
||||
// Allow only MyError.A -> error
|
||||
return to->type_kind == TYPE_ERR_UNION;
|
||||
// Allow MyError.A -> error, to an integer or to bool
|
||||
return to->type_kind == TYPE_ANYERR || type_is_any_integer(to) || to == type_bool;
|
||||
case TYPE_ARRAY:
|
||||
if (to_kind == TYPE_VECTOR)
|
||||
{
|
||||
@@ -552,6 +556,8 @@ bool cast_may_implicit(Type *from_type, Type *to_type)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (to == type_anyerr && from->type_kind == TYPE_ERRTYPE) return true;
|
||||
|
||||
// 3. Handle ints
|
||||
if (type_is_integer(to))
|
||||
{
|
||||
@@ -780,14 +786,17 @@ bool cast(Expr *expr, Type *to_type)
|
||||
case TYPE_FUNC:
|
||||
case TYPE_TYPEDEF:
|
||||
UNREACHABLE
|
||||
case TYPE_BITSTRUCT:
|
||||
UNREACHABLE
|
||||
case TYPE_BOOL:
|
||||
// Bool may convert into integers and floats but only explicitly.
|
||||
if (type_is_integer(canonical)) return bool_to_int(expr, canonical, to_type);
|
||||
if (type_is_float(canonical)) return bool_to_float(expr, canonical, to_type);
|
||||
break;
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_ANYERR:
|
||||
if (canonical->type_kind == TYPE_BOOL) return insert_cast(expr, CAST_EUBOOL, to_type);
|
||||
if (canonical->type_kind == TYPE_ERRTYPE) return insert_cast(expr, CAST_EUER, to_type);
|
||||
if (type_is_integer(canonical)) return insert_cast(expr, CAST_EUINT, to_type);
|
||||
break;
|
||||
case TYPE_IXX:
|
||||
if (type_is_integer(canonical)) return int_literal_to_int(expr, canonical, to_type);
|
||||
@@ -833,7 +842,9 @@ bool cast(Expr *expr, Type *to_type)
|
||||
if (canonical->type_kind == TYPE_POINTER) return enum_to_pointer(expr, from_type, to_type);
|
||||
break;
|
||||
case TYPE_ERRTYPE:
|
||||
if (canonical->type_kind == TYPE_ERR_UNION) return insert_cast(expr, CAST_EREU, to_type);
|
||||
if (canonical->type_kind == TYPE_ANYERR) return insert_cast(expr, CAST_EREU, to_type);
|
||||
if (canonical == type_bool) return insert_cast(expr, CAST_ERBOOL, to_type);
|
||||
if (type_is_integer(to_type)) return insert_cast(expr, CAST_ERINT, to_type);
|
||||
break;
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
|
||||
@@ -279,7 +279,7 @@ static bool sema_analyse_struct_union(Context *context, Decl *decl)
|
||||
case DECL_UNION:
|
||||
domain = ATTR_UNION;
|
||||
break;
|
||||
case DECL_ERR:
|
||||
case DECL_ERRTYPE:
|
||||
domain = ATTR_ERROR;
|
||||
break;
|
||||
default:
|
||||
@@ -359,6 +359,75 @@ static bool sema_analyse_struct_union(Context *context, Decl *decl)
|
||||
return decl_ok(decl);
|
||||
}
|
||||
|
||||
static bool sema_analyse_bitstruct(Context *context, Decl *decl)
|
||||
{
|
||||
VECEACH(decl->attributes, i)
|
||||
{
|
||||
Attr *attr = decl->attributes[i];
|
||||
|
||||
AttributeType attribute = sema_analyse_attribute(context, attr, ATTR_BITSTRUCT);
|
||||
if (attribute == ATTRIBUTE_NONE) return decl_poison(decl);
|
||||
|
||||
bool had = false;
|
||||
int overlap = -1;
|
||||
#define SET_ATTR(_X) had = decl->func_decl._X; decl->func_decl._X = true; break
|
||||
switch (attribute)
|
||||
{
|
||||
case ATTRIBUTE_OVERLAP:
|
||||
had = overlap != -1;
|
||||
overlap = 1;
|
||||
break;
|
||||
case ATTRIBUTE_OPAQUE:
|
||||
had = decl->is_opaque;
|
||||
decl->is_opaque = true;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
#undef SET_ATTR
|
||||
if (had)
|
||||
{
|
||||
SEMA_TOKID_ERROR(attr->name, "Attribute occurred twice, please remove one.");
|
||||
return decl_poison(decl);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_LOG("Beginning analysis of %s.", decl->name ? decl->name : "anon");
|
||||
if (!sema_resolve_type_info(context, decl->bitstruct.base_type)) return false;
|
||||
Type *type = decl->bitstruct.base_type->type->canonical;
|
||||
Type *base_type = type->type_kind == TYPE_ARRAY ? type->array.base : type;
|
||||
if (!type_is_integer(base_type))
|
||||
{
|
||||
SEMA_ERROR(decl->bitstruct.base_type, "The type of the bitstruct cannot be %s but must be an integer or an array of integers.",
|
||||
type_quoted_error_string(decl->bitstruct.base_type->type));
|
||||
return false;
|
||||
}
|
||||
Decl **members = decl->bitstruct.members;
|
||||
bool success = true;
|
||||
SCOPE_START
|
||||
VECEACH(members, i)
|
||||
{
|
||||
Decl *member = members[i];
|
||||
if (!sema_resolve_type_info(context, member->var.type_info))
|
||||
{
|
||||
success = false;
|
||||
continue;
|
||||
}
|
||||
Type *member_type = type_flatten_for_bitstruct(member->var.type_info->type);
|
||||
if (!type_is_integer(member_type) && member_type != type_bool)
|
||||
{
|
||||
SEMA_ERROR(member->var.type_info, "%s is not supported in a bitstruct, only enums, integer and boolean values may be used.",
|
||||
type_quoted_error_string(member->var.type_info->type));
|
||||
success = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
SCOPE_END;
|
||||
if (!success) return decl_poison(decl);
|
||||
TODO
|
||||
return decl_ok(decl);
|
||||
}
|
||||
|
||||
|
||||
static inline bool sema_analyse_function_param(Context *context, Decl *param, bool is_function, bool *has_default)
|
||||
{
|
||||
@@ -495,9 +564,9 @@ static inline bool sema_analyse_distinct(Context *context, Decl *decl)
|
||||
SEMA_ERROR(decl, "You cannot create a distinct type from a virtual type.");
|
||||
return false;
|
||||
case TYPE_ERRTYPE:
|
||||
SEMA_ERROR(decl, "You cannot create a distinct type from an error.");
|
||||
SEMA_ERROR(decl, "You cannot create a distinct type from an error type.");
|
||||
return false;
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_ANYERR:
|
||||
SEMA_ERROR(decl, "You cannot create a distinct type from an error union.");
|
||||
return false;
|
||||
case TYPE_VOID:
|
||||
@@ -509,6 +578,7 @@ static inline bool sema_analyse_distinct(Context *context, Decl *decl)
|
||||
case ALL_REAL_FLOATS:
|
||||
case TYPE_POINTER:
|
||||
case TYPE_ENUM:
|
||||
case TYPE_BITSTRUCT:
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_ARRAY:
|
||||
@@ -601,6 +671,29 @@ static inline bool sema_analyse_enum(Context *context, Decl *decl)
|
||||
return success;
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_error(Context *context, Decl *decl)
|
||||
{
|
||||
bool success = true;
|
||||
unsigned enums = vec_size(decl->enums.values);
|
||||
|
||||
for (unsigned i = 0; i < enums; i++)
|
||||
{
|
||||
Decl *enum_value = decl->enums.values[i];
|
||||
enum_value->type = decl->type;
|
||||
DEBUG_LOG("* Checking error value %s.", enum_value->name);
|
||||
enum_value->enum_constant.ordinal = i;
|
||||
DEBUG_LOG("* Ordinal: %d", i);
|
||||
assert(enum_value->resolve_status == RESOLVE_NOT_DONE);
|
||||
assert(enum_value->decl_kind == DECL_ERRVALUE);
|
||||
|
||||
// Start evaluating the constant
|
||||
enum_value->resolve_status = RESOLVE_RUNNING;
|
||||
enum_value->enum_constant.expr = NULL;
|
||||
enum_value->resolve_status = RESOLVE_DONE;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
static inline const char *name_by_decl(Decl *method_like)
|
||||
{
|
||||
switch (method_like->decl_kind)
|
||||
@@ -692,6 +785,8 @@ static const char *attribute_domain_to_string(AttributeDomain domain)
|
||||
{
|
||||
switch (domain)
|
||||
{
|
||||
case ATTR_BITSTRUCT:
|
||||
return "bitstruct";
|
||||
case ATTR_INTERFACE:
|
||||
return "interface";
|
||||
case ATTR_MEMBER:
|
||||
@@ -729,7 +824,7 @@ AttributeType sema_analyse_attribute(Context *context, Attr *attr, AttributeDoma
|
||||
[ATTRIBUTE_WEAK] = ATTR_FUNC | ATTR_CONST | ATTR_VAR,
|
||||
[ATTRIBUTE_EXTNAME] = ~ATTR_CALL,
|
||||
[ATTRIBUTE_SECTION] = ATTR_FUNC | ATTR_CONST | ATTR_VAR,
|
||||
[ATTRIBUTE_PACKED] = ATTR_STRUCT | ATTR_UNION | ATTR_ERROR,
|
||||
[ATTRIBUTE_PACKED] = ATTR_STRUCT | ATTR_UNION,
|
||||
[ATTRIBUTE_NORETURN] = ATTR_FUNC,
|
||||
[ATTRIBUTE_ALIGN] = ATTR_FUNC | ATTR_CONST | ATTR_VAR | ATTR_STRUCT | ATTR_UNION | ATTR_MEMBER,
|
||||
[ATTRIBUTE_INLINE] = ATTR_FUNC | ATTR_CALL,
|
||||
@@ -743,6 +838,7 @@ AttributeType sema_analyse_attribute(Context *context, Attr *attr, AttributeDoma
|
||||
[ATTRIBUTE_VECCALL] = ATTR_FUNC,
|
||||
[ATTRIBUTE_REGCALL] = ATTR_FUNC,
|
||||
[ATTRIBUTE_FASTCALL] = ATTR_FUNC,
|
||||
[ATTRIBUTE_OVERLAP] = ATTR_BITSTRUCT
|
||||
};
|
||||
|
||||
if ((attribute_domain[type] & domain) != domain)
|
||||
@@ -1048,7 +1144,9 @@ static inline bool sema_analyse_macro(Context *context, Decl *decl)
|
||||
case VARDECL_MEMBER:
|
||||
case VARDECL_LOCAL_CT:
|
||||
case VARDECL_LOCAL_CT_TYPE:
|
||||
case VARDECL_ALIAS:
|
||||
case VARDECL_UNWRAPPED:
|
||||
case VARDECL_REWRAPPED:
|
||||
case VARDECL_ERASE:
|
||||
UNREACHABLE
|
||||
}
|
||||
param->resolve_status = RESOLVE_DONE;
|
||||
@@ -1080,7 +1178,9 @@ static inline bool sema_analyse_macro(Context *context, Decl *decl)
|
||||
case VARDECL_MEMBER:
|
||||
case VARDECL_LOCAL_CT:
|
||||
case VARDECL_LOCAL_CT_TYPE:
|
||||
case VARDECL_ALIAS:
|
||||
case VARDECL_UNWRAPPED:
|
||||
case VARDECL_REWRAPPED:
|
||||
case VARDECL_ERASE:
|
||||
UNREACHABLE
|
||||
}
|
||||
param->resolve_status = RESOLVE_DONE;
|
||||
@@ -1359,31 +1459,6 @@ static inline bool sema_analyse_define(Context *c, Decl *decl)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Semantic analysis on an error first checks the internals as if it was
|
||||
* a struct, then checks that the size is not exceeded and adds padding.
|
||||
*/
|
||||
static inline bool sema_analyse_error(Context *context, Decl *decl)
|
||||
{
|
||||
// 1. Step one is to analyze the error as it it was a regular struct.
|
||||
if (!sema_analyse_struct_union(context, decl)) return false;
|
||||
|
||||
// 2. Because an error is always pointer sized, we check so that it isn't exceeded.
|
||||
ByteSize error_full_size = type_size(type_uptr);
|
||||
if (decl->strukt.size > error_full_size)
|
||||
{
|
||||
SEMA_ERROR(decl, "Error type may not exceed pointer size (%d bytes) it was %d bytes.", error_full_size, decl->strukt.size);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. If the size is smaller than than pointer sized, we add padding.
|
||||
if (decl->strukt.size < error_full_size)
|
||||
{
|
||||
decl->strukt.padding = error_full_size - decl->strukt.size;
|
||||
decl->strukt.size = error_full_size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool sema_analyse_decl(Context *context, Decl *decl)
|
||||
@@ -1404,6 +1479,10 @@ bool sema_analyse_decl(Context *context, Decl *decl)
|
||||
{
|
||||
case DECL_INTERFACE:
|
||||
TODO
|
||||
case DECL_BITSTRUCT:
|
||||
if (!sema_analyse_bitstruct(context, decl)) return decl_poison(decl);
|
||||
decl_set_external_name(decl);
|
||||
break;
|
||||
case DECL_STRUCT:
|
||||
case DECL_UNION:
|
||||
if (!sema_analyse_struct_union(context, decl)) return decl_poison(decl);
|
||||
@@ -1431,7 +1510,7 @@ bool sema_analyse_decl(Context *context, Decl *decl)
|
||||
if (!sema_analyse_enum(context, decl)) return decl_poison(decl);
|
||||
decl_set_external_name(decl);
|
||||
break;
|
||||
case DECL_ERR:
|
||||
case DECL_ERRTYPE:
|
||||
if (!sema_analyse_error(context, decl)) return decl_poison(decl);
|
||||
decl_set_external_name(decl);
|
||||
break;
|
||||
@@ -1451,6 +1530,7 @@ bool sema_analyse_decl(Context *context, Decl *decl)
|
||||
case DECL_CT_CASE:
|
||||
case DECL_CT_IF:
|
||||
case DECL_CT_ASSERT:
|
||||
case DECL_ERRVALUE:
|
||||
UNREACHABLE
|
||||
}
|
||||
decl->resolve_status = RESOLVE_DONE;
|
||||
|
||||
@@ -44,7 +44,6 @@ static Expr *expr_access_inline_member(Expr *parent, Decl *parent_decl)
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_binary(Context *context, Type *to, Expr *expr);
|
||||
static inline bool sema_analyse_expr_value(Context *context, Type *to, Expr *expr);
|
||||
static inline bool expr_const_int_valid(Expr *expr, Type *type)
|
||||
{
|
||||
if (expr_const_int_overflowed(&expr->const_expr))
|
||||
@@ -190,7 +189,7 @@ int sema_check_comp_time_bool(Context *context, Expr *expr)
|
||||
return expr->const_expr.b;
|
||||
}
|
||||
|
||||
static bool expr_is_ltype(Expr *expr)
|
||||
bool expr_is_ltype(Expr *expr)
|
||||
{
|
||||
switch (expr->expr_kind)
|
||||
{
|
||||
@@ -213,8 +212,15 @@ static bool expr_is_ltype(Expr *expr)
|
||||
case VARDECL_PARAM_REF:
|
||||
return true;
|
||||
case VARDECL_CONST:
|
||||
default:
|
||||
case VARDECL_MEMBER:
|
||||
case VARDECL_PARAM_CT:
|
||||
case VARDECL_PARAM_CT_TYPE:
|
||||
case VARDECL_PARAM_EXPR:
|
||||
return false;
|
||||
case VARDECL_UNWRAPPED:
|
||||
case VARDECL_ERASE:
|
||||
case VARDECL_REWRAPPED:
|
||||
UNREACHABLE
|
||||
}
|
||||
}
|
||||
case EXPR_UNARY:
|
||||
@@ -248,6 +254,9 @@ static inline bool sema_cast_ident_rvalue(Context *context, Type *to, Expr *expr
|
||||
case DECL_GENERIC:
|
||||
SEMA_ERROR(expr, "Expected generic followed by (...) or prefixed by '&'.");
|
||||
return expr_poison(expr);
|
||||
case DECL_ERRVALUE:
|
||||
SEMA_ERROR(expr, "Did you forget a '!' after '%s'?", decl->name);
|
||||
return expr_poison(expr);
|
||||
case DECL_ENUM_CONSTANT:
|
||||
expr_replace(expr, decl->enum_constant.expr);
|
||||
return true;
|
||||
@@ -264,6 +273,9 @@ static inline bool sema_cast_ident_rvalue(Context *context, Type *to, Expr *expr
|
||||
case DECL_INTERFACE:
|
||||
SEMA_ERROR(expr, "Expected interface followed by '.'.");
|
||||
return expr_poison(expr);
|
||||
case DECL_BITSTRUCT:
|
||||
SEMA_ERROR(expr, "Expected bitstruct followed by (...) or '.'.");
|
||||
return expr_poison(expr);
|
||||
case DECL_STRUCT:
|
||||
SEMA_ERROR(expr, "Expected struct followed by (...) or '.'.");
|
||||
return expr_poison(expr);
|
||||
@@ -273,8 +285,8 @@ static inline bool sema_cast_ident_rvalue(Context *context, Type *to, Expr *expr
|
||||
case DECL_ENUM:
|
||||
SEMA_ERROR(expr, "Expected enum name followed by '.' and an enum value.");
|
||||
return expr_poison(expr);
|
||||
case DECL_ERR:
|
||||
SEMA_ERROR(expr, "Did you forget a '!' after '%s'?", decl->name);
|
||||
case DECL_ERRTYPE:
|
||||
SEMA_ERROR(expr, "Expected errtype name followed by '.' and an error value.");
|
||||
return expr_poison(expr);
|
||||
case DECL_ARRAY_VALUE:
|
||||
UNREACHABLE
|
||||
@@ -307,7 +319,7 @@ static inline bool sema_cast_ident_rvalue(Context *context, Type *to, Expr *expr
|
||||
case VARDECL_PARAM:
|
||||
case VARDECL_GLOBAL:
|
||||
case VARDECL_LOCAL:
|
||||
case VARDECL_ALIAS:
|
||||
case VARDECL_UNWRAPPED:
|
||||
break;
|
||||
case VARDECL_MEMBER:
|
||||
SEMA_ERROR(expr, "Expected '%s' followed by a method call or property.", decl->name);
|
||||
@@ -321,6 +333,9 @@ static inline bool sema_cast_ident_rvalue(Context *context, Type *to, Expr *expr
|
||||
case VARDECL_LOCAL_CT_TYPE:
|
||||
TODO
|
||||
break;
|
||||
case VARDECL_ERASE:
|
||||
case VARDECL_REWRAPPED:
|
||||
UNREACHABLE
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -330,7 +345,7 @@ static ExprFailableStatus expr_is_failable(Expr *expr)
|
||||
if (expr->expr_kind != EXPR_IDENTIFIER) return FAILABLE_NO;
|
||||
Decl *decl = expr->identifier_expr.decl;
|
||||
if (decl->decl_kind != DECL_VAR) return FAILABLE_NO;
|
||||
if (decl->var.kind == VARDECL_ALIAS && decl->var.alias->var.failable) return FAILABLE_UNWRAPPED;
|
||||
if (decl->var.kind == VARDECL_UNWRAPPED && decl->var.alias->var.failable) return FAILABLE_UNWRAPPED;
|
||||
return decl->var.failable ? FAILABLE_YES : FAILABLE_NO;
|
||||
}
|
||||
|
||||
@@ -478,6 +493,7 @@ static inline bool find_possible_inferred_identifier(Type *to, Expr *expr)
|
||||
switch (parent_decl->decl_kind)
|
||||
{
|
||||
case DECL_ENUM:
|
||||
case DECL_ERRTYPE:
|
||||
return sema_expr_analyse_enum_constant(expr, expr->identifier_expr.identifier, parent_decl);
|
||||
case DECL_UNION:
|
||||
case DECL_STRUCT:
|
||||
@@ -1146,7 +1162,9 @@ static inline bool sema_expr_analyse_call_invocation(Context *context, Expr *cal
|
||||
case VARDECL_MEMBER:
|
||||
case VARDECL_LOCAL_CT:
|
||||
case VARDECL_LOCAL_CT_TYPE:
|
||||
case VARDECL_ALIAS:
|
||||
case VARDECL_UNWRAPPED:
|
||||
case VARDECL_REWRAPPED:
|
||||
case VARDECL_ERASE:
|
||||
UNREACHABLE
|
||||
}
|
||||
if (param->type)
|
||||
@@ -2280,7 +2298,44 @@ static inline bool sema_expr_analyse_type_access(Expr *expr, TypeInfo *parent, b
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case DECL_ERR:
|
||||
case DECL_ERRTYPE:
|
||||
if (type == TOKEN_CONST_IDENT)
|
||||
{
|
||||
if (!sema_expr_analyse_enum_constant(expr, identifier_token, decl))
|
||||
{
|
||||
SEMA_ERROR(expr, "'%s' has no error value '%s'.", decl->name, name);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (name == kw_elements)
|
||||
{
|
||||
expr_rewrite_to_int_const(expr, type_compint, vec_size(decl->enums.values));
|
||||
return true;
|
||||
}
|
||||
if (name == kw_max)
|
||||
{
|
||||
Expr *max = enum_minmax_value(decl, BINARYOP_GT);
|
||||
if (!max)
|
||||
{
|
||||
expr_rewrite_to_int_const(expr, decl->enums.type_info->type->canonical, 0);
|
||||
return true;
|
||||
}
|
||||
expr_replace(expr, max);
|
||||
return true;
|
||||
}
|
||||
if (name == kw_min)
|
||||
{
|
||||
Expr *min = enum_minmax_value(decl, BINARYOP_LT);
|
||||
if (!min)
|
||||
{
|
||||
expr_rewrite_to_int_const(expr, decl->enums.type_info->type->canonical, 0);
|
||||
return true;
|
||||
}
|
||||
expr_replace(expr, min);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case DECL_UNION:
|
||||
case DECL_STRUCT:
|
||||
case DECL_DISTINCT:
|
||||
@@ -2336,7 +2391,7 @@ static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr,
|
||||
}
|
||||
if (name == kw_ordinal && !is_macro)
|
||||
{
|
||||
if (ref->decl_kind == DECL_ENUM_CONSTANT)
|
||||
if (ref->decl_kind == DECL_ENUM_CONSTANT || ref->decl_kind == DECL_ERRVALUE)
|
||||
{
|
||||
expr_rewrite_to_int_const(expr, type_compint, ref->enum_constant.ordinal);
|
||||
return true;
|
||||
@@ -2398,7 +2453,6 @@ static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr,
|
||||
{
|
||||
case DECL_STRUCT:
|
||||
case DECL_UNION:
|
||||
case DECL_ERR:
|
||||
VECEACH(flat_ref->strukt.members, i)
|
||||
{
|
||||
Decl *member = ref->strukt.members[i];
|
||||
@@ -2976,7 +3030,6 @@ static inline void sema_update_const_initializer_with_designator(
|
||||
switch (const_init->type->type_kind)
|
||||
{
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_ERRTYPE:
|
||||
sema_update_const_initializer_with_designator_struct(const_init, curr, end, value);
|
||||
return;
|
||||
case TYPE_UNION:
|
||||
@@ -3337,7 +3390,6 @@ static inline bool sema_expr_analyse_initializer_list(Context *context, Type *to
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_ARRAY:
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
return sema_expr_analyse_initializer(context, to, assigned, expr);
|
||||
default:
|
||||
@@ -3477,7 +3529,7 @@ static inline bool sema_expr_analyse_ct_identifier_lvalue(Context *context, Expr
|
||||
|
||||
if (!decl)
|
||||
{
|
||||
SEMA_ERROR(expr, "The compile time variable '%s' was not defined in this scope.", expr->ct_ident_expr.identifier);
|
||||
SEMA_ERROR(expr, "The compile time variable '%s' was not defined in this scope.", TOKSTR(expr->ct_ident_expr.identifier));
|
||||
return expr_poison(expr);
|
||||
}
|
||||
|
||||
@@ -3565,16 +3617,6 @@ static bool sema_expr_analyse_assign(Context *context, Expr *expr, Expr *left, E
|
||||
|
||||
if (!sema_analyse_expr_value(context, NULL, left)) return false;
|
||||
|
||||
if (left->expr_kind == EXPR_TRY)
|
||||
{
|
||||
if (expr_is_ltype(left->try_expr.expr))
|
||||
{
|
||||
SEMA_ERROR(left, "This part will be evaluated to a boolean, so if you want to test an assignment, "
|
||||
"you need to use () around the assignment, like this: '%s (variable = expression)'.",
|
||||
left->expr_kind == EXPR_TRY ? "try" : "catch");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Check assignability
|
||||
if (!expr_is_ltype(left))
|
||||
@@ -4479,13 +4521,14 @@ static bool sema_expr_analyse_comp(Context *context, Expr *expr, Expr *left, Exp
|
||||
case TYPE_FUNC:
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_ANYERR:
|
||||
case TYPE_STRLIT:
|
||||
case TYPE_ARRAY:
|
||||
case TYPE_SUBARRAY:
|
||||
case TYPE_TYPEID:
|
||||
case TYPE_VIRTUAL_ANY:
|
||||
case TYPE_VIRTUAL:
|
||||
case TYPE_BITSTRUCT:
|
||||
// Only != and == allowed.
|
||||
goto ERR;
|
||||
case ALL_INTS:
|
||||
@@ -4590,7 +4633,9 @@ static inline bool sema_take_addr_of_var(Expr *expr, Decl *decl, bool *is_consta
|
||||
// May not be reached due to EXPR_CT_IDENT being handled elsewhere.
|
||||
UNREACHABLE;
|
||||
case VARDECL_MEMBER:
|
||||
case VARDECL_ALIAS:
|
||||
case VARDECL_UNWRAPPED:
|
||||
case VARDECL_REWRAPPED:
|
||||
case VARDECL_ERASE:
|
||||
UNREACHABLE
|
||||
}
|
||||
UNREACHABLE
|
||||
@@ -4808,9 +4853,10 @@ static bool sema_expr_analyse_not(Expr *expr, Expr *inner)
|
||||
case TYPE_IXX:
|
||||
case TYPE_FXX:
|
||||
case TYPE_TYPEDEF:
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_ANYERR:
|
||||
case TYPE_DISTINCT:
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
case TYPE_BITSTRUCT:
|
||||
UNREACHABLE
|
||||
case TYPE_FUNC:
|
||||
case TYPE_ARRAY:
|
||||
@@ -5048,21 +5094,6 @@ static inline bool sema_expr_analyse_post_unary(Context *context, Type *to, Expr
|
||||
}
|
||||
|
||||
|
||||
static inline bool sema_expr_analyse_try_old(Context *context, Expr *expr)
|
||||
{
|
||||
Expr *inner = expr->trycatch_expr;
|
||||
bool success = sema_analyse_expr(context, NULL, inner);
|
||||
expr->pure = inner->pure;
|
||||
expr->constant = false;
|
||||
if (!success) return false;
|
||||
if (!inner->failable)
|
||||
{
|
||||
SEMA_ERROR(expr->trycatch_expr, "Expected a failable expression to 'try'.");
|
||||
return false;
|
||||
}
|
||||
expr_set_type(expr, type_bool);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_try_assign(Context *context, Expr *expr, bool implicitly_create_variable)
|
||||
{
|
||||
@@ -5152,27 +5183,10 @@ static inline bool sema_expr_analyse_try(Context *context, Expr *expr)
|
||||
SEMA_ERROR(expr->try_expr.expr, "Expected a failable expression to '%s'.", expr->expr_kind == EXPR_TRY ? "try" : "catch");
|
||||
return false;
|
||||
}
|
||||
expr_set_type(expr, type_bool);
|
||||
expr_set_type(expr, expr->try_expr.is_try ? type_bool : type_anyerr);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_catch_old(Context *context, Expr *expr)
|
||||
{
|
||||
Expr *inner = expr->trycatch_expr;
|
||||
bool success = sema_analyse_expr(context, NULL, inner);
|
||||
expr->pure = inner->pure;
|
||||
expr->constant = false;
|
||||
if (!success) return false;
|
||||
if (!inner->failable)
|
||||
{
|
||||
SEMA_ERROR(expr->trycatch_expr, "Expected a failable expression to 'catch'.");
|
||||
return false;
|
||||
}
|
||||
expr_set_type(expr, type_bool);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static inline bool sema_expr_analyse_else(Context *context, Type *to, Expr *expr)
|
||||
{
|
||||
Expr *inner = expr->else_expr.expr;
|
||||
@@ -5335,16 +5349,6 @@ static inline bool sema_expr_analyse_failable(Context *context, Type *to, Expr *
|
||||
{
|
||||
Expr *inner = expr->failable_expr;
|
||||
|
||||
// Syntactic sugar: Foo! => Foo({})!
|
||||
if (inner->expr_kind == EXPR_TYPEINFO)
|
||||
{
|
||||
TypeInfo *type = inner->type_expr;
|
||||
*inner = (Expr) { .expr_kind = EXPR_COMPOUND_LITERAL, .span = inner->span };
|
||||
inner->expr_compound_literal.type_info = type;
|
||||
Expr *initializer_list = expr_new(EXPR_INITIALIZER_LIST, inner->span);
|
||||
initializer_list->initializer_expr.init_type = INITIALIZER_UNKNOWN;
|
||||
inner->expr_compound_literal.initializer = initializer_list;
|
||||
}
|
||||
|
||||
if (!sema_analyse_expr(context, NULL, inner)) return false;
|
||||
expr->pure = inner->pure;
|
||||
@@ -5359,7 +5363,7 @@ static inline bool sema_expr_analyse_failable(Context *context, Type *to, Expr *
|
||||
SEMA_ERROR(inner, "It looks like you added one too many '!' after the error.");
|
||||
return false;
|
||||
}
|
||||
if (type->type_kind != TYPE_ERRTYPE && type->type_kind != TYPE_ERR_UNION)
|
||||
if (type->type_kind != TYPE_ERRTYPE && type->type_kind != TYPE_ANYERR)
|
||||
{
|
||||
SEMA_ERROR(inner, "You cannot use the '!' operator on expressions of type '%s'", type_to_error_string(type));
|
||||
return false;
|
||||
@@ -5770,7 +5774,7 @@ static inline bool sema_analyse_ct_call_parameters(Context *context, Expr *expr)
|
||||
{
|
||||
case DECL_DISTINCT:
|
||||
case DECL_ENUM:
|
||||
case DECL_ERR:
|
||||
case DECL_ERRTYPE:
|
||||
case DECL_FUNC:
|
||||
case DECL_STRUCT:
|
||||
case DECL_TYPEDEF:
|
||||
@@ -6056,7 +6060,7 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *
|
||||
{
|
||||
switch (expr->expr_kind)
|
||||
{
|
||||
case EXPR_DECL_LIST:
|
||||
case EXPR_COND:
|
||||
case EXPR_UNDEF:
|
||||
case EXPR_ENUM_CONSTANT:
|
||||
case EXPR_MEMBER_ACCESS:
|
||||
@@ -6064,7 +6068,12 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *
|
||||
case EXPR_MACRO_BODY_EXPANSION:
|
||||
case EXPR_FLATPATH:
|
||||
case EXPR_NOP:
|
||||
case EXPR_TRY_UNWRAP_CHAIN:
|
||||
case EXPR_TRY_UNWRAP:
|
||||
case EXPR_CATCH_UNWRAP:
|
||||
UNREACHABLE
|
||||
case EXPR_TRY_DECL:
|
||||
TODO
|
||||
case EXPR_DECL:
|
||||
return sema_expr_analyse_decl(context, to, expr);
|
||||
case EXPR_CT_CALL:
|
||||
@@ -6094,10 +6103,6 @@ static inline bool sema_analyse_expr_dispatch(Context *context, Type *to, Expr *
|
||||
return sema_expr_analyse_try(context, expr);
|
||||
case EXPR_TRY_ASSIGN:
|
||||
return sema_expr_analyse_try_assign(context, expr, false);
|
||||
case EXPR_CATCH_OLD:
|
||||
return sema_expr_analyse_catch_old(context, expr);
|
||||
case EXPR_TRY_OLD:
|
||||
return sema_expr_analyse_try_old(context, expr);
|
||||
case EXPR_TYPEOF:
|
||||
return sema_expr_analyse_typeof(context, expr);
|
||||
case EXPR_ELSE:
|
||||
@@ -6199,15 +6204,21 @@ static inline bool sema_cast_rvalue(Context *context, Type *to, Expr *expr)
|
||||
}
|
||||
break;
|
||||
case EXPR_MEMBER_ACCESS:
|
||||
if (expr->access_expr.ref->decl_kind == DECL_ENUM_CONSTANT)
|
||||
switch (expr->access_expr.ref->decl_kind)
|
||||
{
|
||||
Type *original_type = expr->access_expr.ref->type;
|
||||
expr_replace(expr, expr->access_expr.ref->enum_constant.expr);
|
||||
expr->original_type = original_type;
|
||||
return true;
|
||||
case DECL_ERRVALUE:
|
||||
return true;
|
||||
case DECL_ENUM_CONSTANT:
|
||||
{
|
||||
Type *original_type = expr->access_expr.ref->type;
|
||||
expr_replace(expr, expr->access_expr.ref->enum_constant.expr);
|
||||
expr->original_type = original_type;
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
SEMA_ERROR(expr, "A member must be followed by '.' plus a property like 'sizeof'.");
|
||||
return false;
|
||||
}
|
||||
SEMA_ERROR(expr, "A member must be followed by '.' plus a property like 'sizeof'.");
|
||||
return false;
|
||||
case EXPR_LEN:
|
||||
if (expr->type != type_void) return true;
|
||||
SEMA_ERROR(expr, "Expected () after 'len' for subarrays.");
|
||||
|
||||
@@ -53,3 +53,6 @@ void context_change_scope_with_flags(Context *context, ScopeFlags flags);
|
||||
|
||||
void c_abi_func_create(FunctionSignature *signature);
|
||||
AttributeType sema_analyse_attribute(Context *context, Attr *attr, AttributeDomain domain);
|
||||
bool expr_is_ltype(Expr *expr);
|
||||
bool sema_analyse_expr_value(Context *context, Type *to, Expr *expr);
|
||||
|
||||
|
||||
@@ -123,10 +123,23 @@ static Decl *sema_resolve_no_path_symbol(Context *context, const char *symbol,
|
||||
}
|
||||
while (current >= first)
|
||||
{
|
||||
if (current[0]->name == symbol) return current[0];
|
||||
if (current[0]->name == symbol)
|
||||
{
|
||||
// We patch special behaviour here.
|
||||
if (current[0]->decl_kind == DECL_VAR)
|
||||
{
|
||||
VarDeclKind kind = current[0]->var.kind;
|
||||
|
||||
// In this case, we erase the value from parent scopes, so it isn't visible here.
|
||||
if (kind == VARDECL_ERASE) goto JUMP_ERASED;
|
||||
if (kind == VARDECL_REWRAPPED) return current[0]->var.alias;
|
||||
}
|
||||
return current[0];
|
||||
}
|
||||
current--;
|
||||
}
|
||||
}
|
||||
JUMP_ERASED:
|
||||
|
||||
// Search in file scope.
|
||||
decl = stable_get(&context->local_symbols, symbol);
|
||||
@@ -449,7 +462,7 @@ bool sema_add_local(Context *context, Decl *decl)
|
||||
bool sema_unwrap_var(Context *context, Decl *decl)
|
||||
{
|
||||
Decl *alias = decl_copy(decl);
|
||||
alias->var.kind = VARDECL_ALIAS;
|
||||
alias->var.kind = VARDECL_UNWRAPPED;
|
||||
alias->var.alias = decl;
|
||||
alias->var.failable = false;
|
||||
alias->resolve_status = RESOLVE_DONE;
|
||||
@@ -458,8 +471,26 @@ bool sema_unwrap_var(Context *context, Decl *decl)
|
||||
|
||||
bool sema_rewrap_var(Context *context, Decl *decl)
|
||||
{
|
||||
assert(decl->decl_kind == DECL_VAR && decl->var.kind == VARDECL_ALIAS && decl->var.alias->var.failable);
|
||||
assert(decl->decl_kind == DECL_VAR && decl->var.kind == VARDECL_UNWRAPPED && decl->var.alias->var.failable);
|
||||
return sema_append_local(context, decl->var.alias);
|
||||
}
|
||||
|
||||
bool sema_erase_var(Context *context, Decl *decl)
|
||||
{
|
||||
Decl *erased = decl_copy(decl);
|
||||
erased->var.kind = VARDECL_ERASE;
|
||||
erased->resolve_status = RESOLVE_DONE;
|
||||
return sema_append_local(context, erased);
|
||||
}
|
||||
|
||||
|
||||
bool sema_erase_unwrapped(Context *context, Decl *decl)
|
||||
{
|
||||
assert(decl->var.failable);
|
||||
Decl *rewrapped = decl_copy(decl);
|
||||
rewrapped->var.kind = VARDECL_REWRAPPED;
|
||||
rewrapped->var.alias = decl;
|
||||
rewrapped->var.failable = true;
|
||||
rewrapped->resolve_status = RESOLVE_DONE;
|
||||
return sema_append_local(context, rewrapped);
|
||||
}
|
||||
|
||||
@@ -6,73 +6,40 @@
|
||||
|
||||
#pragma mark --- Helper functions
|
||||
|
||||
static void sema_add_unwraps_from_try(Context *c, Expr *last_expr)
|
||||
|
||||
|
||||
static void sema_unwrappable_from_catch_in_else(Context *c, Expr *cond)
|
||||
{
|
||||
if (last_expr->expr_kind == EXPR_DECL_LIST)
|
||||
assert(cond->expr_kind == EXPR_COND);
|
||||
|
||||
Expr *last = VECLAST(cond->cond_expr);
|
||||
while (last->expr_kind == EXPR_CAST)
|
||||
{
|
||||
unsigned elements = vec_size(last_expr->dexpr_list_expr);
|
||||
if (!elements) return;
|
||||
last_expr = last_expr->dexpr_list_expr[elements - 1];
|
||||
last = last->cast_expr.expr;
|
||||
}
|
||||
// Flatten group.
|
||||
while (last_expr->expr_kind == EXPR_GROUP) last_expr = last_expr->group_expr;
|
||||
if (last_expr->expr_kind == EXPR_TRY && last_expr->try_expr.is_try &&
|
||||
last_expr->try_expr.expr->expr_kind == EXPR_IDENTIFIER)
|
||||
if (!last || last->expr_kind != EXPR_CATCH_UNWRAP) return;
|
||||
|
||||
Expr **unwrapped = last->catch_unwrap_expr.exprs;
|
||||
|
||||
VECEACH(unwrapped, i)
|
||||
{
|
||||
Decl *var = last_expr->try_expr.expr->identifier_expr.decl;
|
||||
if (var->decl_kind != DECL_VAR || !var->var.failable) return;
|
||||
sema_unwrap_var(c, var);
|
||||
return;
|
||||
}
|
||||
if (last_expr->expr_kind != EXPR_BINARY || last_expr->binary_expr.operator != BINARYOP_AND) return;
|
||||
sema_add_unwraps_from_try(c, last_expr->binary_expr.left);
|
||||
sema_add_unwraps_from_try(c, last_expr->binary_expr.right);
|
||||
}
|
||||
Expr *expr = unwrapped[i];
|
||||
if (expr->expr_kind != EXPR_IDENTIFIER) continue;
|
||||
Decl *decl = expr->identifier_expr.decl;
|
||||
if (decl->decl_kind != DECL_VAR) continue;
|
||||
assert(decl->var.failable && "The variable should always be failable at this point.");
|
||||
|
||||
static Decl *sema_find_unwrappable_from_catch(Context *c, Expr *last_expr)
|
||||
{
|
||||
// 1. Flatten a decl list.
|
||||
if (last_expr->expr_kind == EXPR_DECL_LIST)
|
||||
{
|
||||
unsigned elements = vec_size(last_expr->dexpr_list_expr);
|
||||
if (!elements) return NULL;
|
||||
last_expr = last_expr->dexpr_list_expr[elements - 1];
|
||||
}
|
||||
// 5. Locals and globals may be unwrapped
|
||||
switch (decl->var.kind)
|
||||
{
|
||||
case VARDECL_LOCAL:
|
||||
case VARDECL_GLOBAL:
|
||||
sema_unwrap_var(c, decl);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
// Flatten groups on top.
|
||||
while (last_expr->expr_kind == EXPR_GROUP) last_expr = last_expr->group_expr;
|
||||
|
||||
Expr *variable = NULL;
|
||||
|
||||
// 1. Get the variable in "if (check x)"
|
||||
if (last_expr->expr_kind == EXPR_TRY && !last_expr->try_expr.is_try)
|
||||
{
|
||||
variable = last_expr->try_expr.expr;
|
||||
}
|
||||
// 2. Get the variable in "if (check err = x)"
|
||||
if (last_expr->expr_kind == EXPR_TRY_ASSIGN && !last_expr->try_assign_expr.is_try)
|
||||
{
|
||||
variable = last_expr->try_assign_expr.init;
|
||||
}
|
||||
|
||||
// 3. Not found or not identifier -> exit
|
||||
if (!variable || variable->expr_kind != EXPR_IDENTIFIER) return NULL;
|
||||
|
||||
Decl *decl = variable->identifier_expr.decl;
|
||||
|
||||
// 4. Not a var declaration, when could this happen...? Possibly redundant check.
|
||||
if (decl->decl_kind != DECL_VAR) return NULL;
|
||||
|
||||
assert(decl->var.failable && "The variable should always be failable at this point.");
|
||||
|
||||
// 5. Locals and globals may be unwrapped
|
||||
switch (decl->var.kind)
|
||||
{
|
||||
case VARDECL_LOCAL:
|
||||
case VARDECL_GLOBAL:
|
||||
return decl;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,6 +116,297 @@ static inline bool sema_analyse_unreachable_stmt(Context *context)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_try_unwrap(Context *context, Expr *expr)
|
||||
{
|
||||
assert(expr->expr_kind == EXPR_TRY_UNWRAP);
|
||||
Expr *ident = expr->try_unwrap_expr.variable;
|
||||
Expr *failable = expr->try_unwrap_expr.init;
|
||||
|
||||
// Case A. Unwrapping a single variable.
|
||||
if (!failable)
|
||||
{
|
||||
if (!sema_analyse_expr(context, NULL, ident)) return false;
|
||||
if (ident->expr_kind != EXPR_IDENTIFIER)
|
||||
{
|
||||
SEMA_ERROR(ident, "Only single identifiers may be unwrapped using 'try var', maybe you wanted 'try (expr)' instead?");
|
||||
return false;
|
||||
}
|
||||
Decl *decl = ident->identifier_expr.decl;
|
||||
if (decl->decl_kind != DECL_VAR)
|
||||
{
|
||||
SEMA_ERROR(ident, "Expected this to be the name of a failable variable, but it isn't. Did you mistype?");
|
||||
return false;
|
||||
}
|
||||
if (!decl->var.failable)
|
||||
{
|
||||
if (decl->var.kind == VARDECL_UNWRAPPED)
|
||||
{
|
||||
SEMA_ERROR(ident, "This variable is already unwrapped, so you cannot use 'try' on it again, please remove the 'try'.");
|
||||
return false;
|
||||
}
|
||||
SEMA_ERROR(ident, "Expected this variable to be a failable, otherwise it can't be used for unwrap, maybe you didn't intend to use 'try'?");
|
||||
return false;
|
||||
}
|
||||
expr->try_unwrap_expr.decl = decl;
|
||||
expr_set_type(expr, type_bool);
|
||||
sema_unwrap_var(context, decl);
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Case B. We are unwrapping to a variable that may or may not exist.
|
||||
bool implicit_declaration = false;
|
||||
TypeInfo *var_type = expr->try_unwrap_expr.type;
|
||||
|
||||
// 1. Check if we are doing an implicit declaration.
|
||||
if (!var_type && ident->expr_kind == EXPR_IDENTIFIER)
|
||||
{
|
||||
Decl *decl = sema_resolve_normal_symbol(context, ident->identifier_expr.identifier, NULL, false);
|
||||
if (!decl) implicit_declaration = true;
|
||||
}
|
||||
|
||||
// 2. If we have a type for the variable, resolve it.
|
||||
if (var_type && !sema_resolve_type_info(context, var_type)) return false;
|
||||
|
||||
// 3. We interpret this as an assignment to an existing variable.
|
||||
if (!var_type && !implicit_declaration)
|
||||
{
|
||||
// 3a. Resolve the identifier.
|
||||
if (!sema_analyse_expr_value(context, NULL, ident)) return false;
|
||||
|
||||
// 3b. Make sure it's assignable
|
||||
if (!expr_is_ltype(ident))
|
||||
{
|
||||
SEMA_ERROR(ident, "'try' expected an assignable variable or expression here, did you make a mistake?");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3c. It can't be failable either.
|
||||
if (ident->failable)
|
||||
{
|
||||
if (ident->expr_kind == EXPR_IDENTIFIER)
|
||||
{
|
||||
SEMA_ERROR(ident, "This is a failable variable, you should only have non-failable variables on the left side unless you use 'try' without '='.");
|
||||
}
|
||||
else
|
||||
{
|
||||
SEMA_ERROR(ident, "This is a failable expression, it can't go on the left hand side of a 'try'.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3d. We can now analyse the expression using the variable type.
|
||||
if (!sema_analyse_expr_of_required_type(context, ident->type, failable, true)) return false;
|
||||
|
||||
expr->try_unwrap_expr.assign_existing = true;
|
||||
expr->try_unwrap_expr.lhs = ident;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4. We are creating a new variable
|
||||
|
||||
// 4a. If we had a variable type, then our expression must be an identifier.
|
||||
if (ident->expr_kind != EXPR_IDENTIFIER)
|
||||
{
|
||||
SEMA_ERROR(ident, "A variable name was expected here.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ident->identifier_expr.path)
|
||||
{
|
||||
sema_error_range(ident->identifier_expr.path->span, "The variable may not have a path.");
|
||||
return false;
|
||||
}
|
||||
|
||||
TokenId ident_token = ident->identifier_expr.identifier;
|
||||
|
||||
if (TOKTYPE(ident_token) != TOKEN_IDENT)
|
||||
{
|
||||
SEMA_ERROR(ident, "Expected a variable starting with a lower case letter.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4a. Type may be assigned or inferred.
|
||||
Type *type = var_type ? var_type->type : NULL;
|
||||
|
||||
// 4b. Evaluate the expression
|
||||
if (!sema_analyse_expr_of_required_type(context, type, failable, true)) return false;
|
||||
|
||||
// 4c. Create a type_info if needed.
|
||||
if (!var_type)
|
||||
{
|
||||
var_type = type_info_new_base(failable->type, failable->span);
|
||||
}
|
||||
|
||||
// 4d. A new declaration is created.
|
||||
Decl *decl = decl_new_var(ident_token, var_type, VARDECL_LOCAL, VISIBLE_LOCAL);
|
||||
|
||||
// 4e. Analyse it
|
||||
if (!sema_analyse_local_decl(context, decl)) return false;
|
||||
|
||||
expr->try_unwrap_expr.decl = decl;
|
||||
}
|
||||
|
||||
if (!failable->failable)
|
||||
{
|
||||
SEMA_ERROR(failable, "Expected a failable expression to 'try' here. If it isn't a failable, remove 'try'.");
|
||||
return false;
|
||||
}
|
||||
|
||||
expr->try_unwrap_expr.failable = failable;
|
||||
expr_set_type(expr, type_bool);
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
return true;
|
||||
}
|
||||
static inline bool sema_analyse_try_unwrap_chain(Context *context, Expr *expr)
|
||||
{
|
||||
assert(expr->expr_kind == EXPR_TRY_UNWRAP_CHAIN);
|
||||
VECEACH(expr->try_unwrap_chain_expr, i)
|
||||
{
|
||||
Expr *chain = expr->try_unwrap_chain_expr[i];
|
||||
if (chain->expr_kind == EXPR_TRY_UNWRAP)
|
||||
{
|
||||
if (!sema_analyse_try_unwrap(context, chain)) return false;
|
||||
continue;
|
||||
}
|
||||
if (!sema_analyse_expr_of_required_type(context, type_bool, chain, false)) return false;
|
||||
}
|
||||
expr_set_type(expr, type_bool);
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
return true;
|
||||
}
|
||||
static inline bool sema_analyse_catch_unwrap(Context *context, Expr *expr)
|
||||
{
|
||||
Expr *ident = expr->catch_unwrap_expr.variable;
|
||||
|
||||
bool implicit_declaration = false;
|
||||
TypeInfo *type = expr->catch_unwrap_expr.type;
|
||||
|
||||
if (!type && !ident)
|
||||
{
|
||||
expr->catch_unwrap_expr.lhs = NULL;
|
||||
expr->catch_unwrap_expr.decl = NULL;
|
||||
goto RESOLVE_EXPRS;
|
||||
}
|
||||
if (!type && ident->expr_kind == EXPR_IDENTIFIER)
|
||||
{
|
||||
Decl *decl = sema_resolve_normal_symbol(context, ident->identifier_expr.identifier, NULL, false);
|
||||
if (!decl) implicit_declaration = true;
|
||||
}
|
||||
|
||||
if (!type && !implicit_declaration)
|
||||
{
|
||||
if (!sema_analyse_expr_value(context, NULL, ident)) return false;
|
||||
|
||||
if (!expr_is_ltype(ident))
|
||||
{
|
||||
SEMA_ERROR(ident, "'catch' expected an assignable variable or expression here, did you make a mistake?");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ident->type->canonical != type_anyerr)
|
||||
{
|
||||
SEMA_ERROR(ident, "Expected the variable to have the type %s, not %s.", type_quoted_error_string(type_anyerr),
|
||||
type_quoted_error_string(type->type));
|
||||
return false;
|
||||
}
|
||||
|
||||
expr->catch_unwrap_expr.lhs = ident;
|
||||
expr->catch_unwrap_expr.decl = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = type ?: type_info_new_base(type_anyerr, expr->span);
|
||||
|
||||
if (!sema_resolve_type_info(context, type)) return false;
|
||||
|
||||
if (type->type->canonical != type_anyerr)
|
||||
{
|
||||
SEMA_ERROR(type, "Expected the type to be %s, not %s.", type_quoted_error_string(type_anyerr),
|
||||
type_quoted_error_string(type->type));
|
||||
return false;
|
||||
}
|
||||
if (ident->expr_kind != EXPR_IDENTIFIER)
|
||||
{
|
||||
SEMA_ERROR(ident, "A variable name was expected here.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ident->identifier_expr.path)
|
||||
{
|
||||
sema_error_range(ident->identifier_expr.path->span, "The variable may not have a path.");
|
||||
return false;
|
||||
}
|
||||
|
||||
TokenId ident_token = ident->identifier_expr.identifier;
|
||||
|
||||
if (TOKTYPE(ident_token) != TOKEN_IDENT)
|
||||
{
|
||||
SEMA_ERROR(ident, "Expected a variable starting with a lower case letter.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4d. A new declaration is created.
|
||||
Decl *decl = decl_new_var(ident_token, type, VARDECL_LOCAL, VISIBLE_LOCAL);
|
||||
decl->var.init_expr = expr_new(EXPR_UNDEF, decl->span);
|
||||
|
||||
// 4e. Analyse it
|
||||
if (!sema_analyse_local_decl(context, decl)) return false;
|
||||
|
||||
expr->catch_unwrap_expr.decl = decl;
|
||||
expr->catch_unwrap_expr.lhs = NULL;
|
||||
}
|
||||
RESOLVE_EXPRS:;
|
||||
Expr **exprs = expr->catch_unwrap_expr.exprs;
|
||||
VECEACH(exprs, i)
|
||||
{
|
||||
Expr *fail = exprs[i];
|
||||
if (!sema_analyse_expr(context, NULL, fail)) return false;
|
||||
if (!fail->failable)
|
||||
{
|
||||
SEMA_ERROR(fail, "This expression is not failable, did you add it by mistake?");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
expr_set_type(expr, type_anyerr);
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void sema_remove_unwraps_from_try(Context *c, Expr *cond)
|
||||
{
|
||||
assert(cond->expr_kind == EXPR_COND);
|
||||
Expr *last = VECLAST(cond->cond_expr);
|
||||
if (!last || last->expr_kind != EXPR_TRY_UNWRAP_CHAIN) return;
|
||||
Expr **chain = last->try_unwrap_chain_expr;
|
||||
VECEACH(chain, i)
|
||||
{
|
||||
Expr *expr = chain[i];
|
||||
if (expr->expr_kind != EXPR_TRY_UNWRAP) continue;
|
||||
if (expr->try_unwrap_expr.assign_existing) continue;
|
||||
if (expr->try_unwrap_expr.failable)
|
||||
{
|
||||
sema_erase_var(c, expr->try_unwrap_expr.decl);
|
||||
}
|
||||
else
|
||||
{
|
||||
sema_erase_unwrapped(c, expr->try_unwrap_expr.decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_last_cond(Context *context, Expr *expr)
|
||||
{
|
||||
switch (expr->expr_kind)
|
||||
{
|
||||
case EXPR_TRY_UNWRAP_CHAIN:
|
||||
return sema_analyse_try_unwrap_chain(context, expr);
|
||||
case EXPR_CATCH_UNWRAP:
|
||||
return sema_analyse_catch_unwrap(context, expr);
|
||||
default:
|
||||
return sema_analyse_expr(context, NULL, expr);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* An decl-expr-list is a list of a mixture of declarations and expressions.
|
||||
* The last declaration or expression is propagated. So for example:
|
||||
@@ -157,11 +415,11 @@ static inline bool sema_analyse_unreachable_stmt(Context *context)
|
||||
*
|
||||
* In this case the final value is 4.0 and the type is float.
|
||||
*/
|
||||
static inline bool sema_analyse_decl_expr_list(Context *context, Expr *expr)
|
||||
static inline bool sema_analyse_cond_list(Context *context, Expr *expr, bool may_unwrap)
|
||||
{
|
||||
assert(expr->expr_kind == EXPR_DECL_LIST);
|
||||
assert(expr->expr_kind == EXPR_COND);
|
||||
|
||||
Expr **dexprs = expr->dexpr_list_expr;
|
||||
Expr **dexprs = expr->cond_expr;
|
||||
unsigned entries = vec_size(dexprs);
|
||||
|
||||
// 1. Special case, there are no entries, so the type is void
|
||||
@@ -172,12 +430,15 @@ static inline bool sema_analyse_decl_expr_list(Context *context, Expr *expr)
|
||||
}
|
||||
|
||||
// 2. Walk through each of our declarations / expressions as if they were regular expressions.
|
||||
for (unsigned i = 0; i < entries; i++)
|
||||
for (unsigned i = 0; i < entries - 1; i++)
|
||||
{
|
||||
if (!sema_analyse_expr(context, NULL, dexprs[i])) return false;
|
||||
}
|
||||
|
||||
if (!sema_analyse_last_cond(context, dexprs[entries - 1])) return false;
|
||||
|
||||
expr_set_type(expr, dexprs[entries - 1]->type);
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -195,10 +456,10 @@ static inline bool sema_analyse_decl_expr_list(Context *context, Expr *expr)
|
||||
*/
|
||||
static inline bool sema_analyse_cond(Context *context, Expr *expr, bool cast_to_bool)
|
||||
{
|
||||
assert(expr->expr_kind == EXPR_DECL_LIST && "Conditional expressions should always be of type EXPR_DECL_LIST");
|
||||
assert(expr->expr_kind == EXPR_COND && "Conditional expressions should always be of type EXPR_DECL_LIST");
|
||||
|
||||
// 1. Analyse the declaration list.
|
||||
if (!sema_analyse_decl_expr_list(context, expr)) return false;
|
||||
if (!sema_analyse_cond_list(context, expr, true)) return false;
|
||||
|
||||
// 2. If we get "void", either through a void call or an empty list,
|
||||
// signal that.
|
||||
@@ -210,7 +471,7 @@ static inline bool sema_analyse_cond(Context *context, Expr *expr, bool cast_to_
|
||||
|
||||
// 3. We look at the last element (which is guaranteed to exist because
|
||||
// the type was not void.
|
||||
Expr *last = VECLAST(expr->dexpr_list_expr);
|
||||
Expr *last = VECLAST(expr->cond_expr);
|
||||
|
||||
if (last->expr_kind == EXPR_DECL)
|
||||
{
|
||||
@@ -285,9 +546,6 @@ static inline bool sema_analyse_while_stmt(Context *context, Ast *statement)
|
||||
// 4. Push break / continue - which is independent of the scope.
|
||||
PUSH_BREAKCONT(statement);
|
||||
|
||||
// 5. Add any try unwraps.
|
||||
sema_add_unwraps_from_try(context, cond);
|
||||
|
||||
// 6. Analyse the statement
|
||||
success = sema_analyse_statement(context, body);
|
||||
|
||||
@@ -583,7 +841,7 @@ static inline bool sema_analyse_for_stmt(Context *context, Ast *statement)
|
||||
is_infinite = statement->for_stmt.cond == NULL;
|
||||
if (statement->for_stmt.init)
|
||||
{
|
||||
success = sema_analyse_decl_expr_list(context, statement->for_stmt.init);
|
||||
success = sema_analyse_cond_list(context, statement->for_stmt.init, false);
|
||||
}
|
||||
|
||||
if (success && statement->for_stmt.cond)
|
||||
@@ -808,13 +1066,13 @@ static bool sema_rewrite_foreach_to_for(Context *context, Ast *statement, Expr *
|
||||
iterator->var.init_expr = enumerator;
|
||||
|
||||
// Generate Foo *value, FooIterator ".iterator" = foo.iterator();
|
||||
Expr *init_expr = expr_new(EXPR_DECL_LIST, enumerator->span);
|
||||
Expr *init_expr = expr_new(EXPR_COND, enumerator->span);
|
||||
Expr *expr = expr_new(EXPR_DECL, value->span);
|
||||
expr->decl_expr = value;
|
||||
vec_add(init_expr->dexpr_list_expr, expr);
|
||||
vec_add(init_expr->cond_expr, expr);
|
||||
expr = expr_new(EXPR_DECL, enumerator->span);
|
||||
expr->decl_expr = iterator;
|
||||
vec_add(init_expr->dexpr_list_expr, expr);
|
||||
vec_add(init_expr->cond_expr, expr);
|
||||
init_expr->resolve_status = RESOLVE_DONE;
|
||||
expr_set_type(init_expr, iterator->type);
|
||||
|
||||
@@ -1095,8 +1353,6 @@ static inline bool sema_analyse_if_stmt(Context *context, Ast *statement)
|
||||
}
|
||||
|
||||
SCOPE_START_WITH_LABEL(statement->if_stmt.flow.label);
|
||||
|
||||
sema_add_unwraps_from_try(context, statement->if_stmt.cond);
|
||||
success = success && sema_analyse_statement(context, statement->if_stmt.then_body);
|
||||
then_jump = context->active_scope.jump_end;
|
||||
|
||||
@@ -1106,8 +1362,8 @@ static inline bool sema_analyse_if_stmt(Context *context, Ast *statement)
|
||||
if (statement->if_stmt.else_body)
|
||||
{
|
||||
SCOPE_START_WITH_LABEL(statement->if_stmt.flow.label);
|
||||
Decl *possible_unwrap = sema_find_unwrappable_from_catch(context, statement->if_stmt.cond);
|
||||
if (possible_unwrap) sema_unwrap_var(context, possible_unwrap);
|
||||
sema_remove_unwraps_from_try(context, statement->if_stmt.cond);
|
||||
sema_unwrappable_from_catch_in_else(context, statement->if_stmt.cond);
|
||||
success = success && sema_analyse_statement(context, statement->if_stmt.else_body);
|
||||
else_jump = context->active_scope.jump_end;
|
||||
SCOPE_END;
|
||||
@@ -1118,8 +1374,7 @@ static inline bool sema_analyse_if_stmt(Context *context, Ast *statement)
|
||||
SCOPE_OUTER_END;
|
||||
if (then_jump)
|
||||
{
|
||||
Decl *possible_unwrap = sema_find_unwrappable_from_catch(context, statement->if_stmt.cond);
|
||||
if (possible_unwrap) sema_unwrap_var(context, possible_unwrap);
|
||||
sema_unwrappable_from_catch_in_else(context, statement->if_stmt.cond);
|
||||
}
|
||||
if (then_jump && else_jump && !statement->flow.has_break)
|
||||
{
|
||||
@@ -1551,7 +1806,7 @@ static bool sema_analyse_switch_body(Context *context, Ast *statement, SourceSpa
|
||||
switch (switch_type_flattened->type_kind)
|
||||
{
|
||||
case TYPE_TYPEID:
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_ANYERR:
|
||||
use_type_id = true;
|
||||
break;
|
||||
case ALL_INTS:
|
||||
@@ -1735,7 +1990,7 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
|
||||
if (!sema_analyse_cond(context, cond, false)) return false;
|
||||
|
||||
|
||||
Type *switch_type = VECLAST(cond->dexpr_list_expr)->type->canonical;
|
||||
Type *switch_type = VECLAST(cond->cond_expr)->type->canonical;
|
||||
statement->switch_stmt.defer = context->active_scope.defer_last;
|
||||
if (!sema_analyse_switch_body(context, statement, cond->span,
|
||||
switch_type->canonical,
|
||||
@@ -1806,7 +2061,7 @@ static bool sema_analyse_catch_stmt(Context *context, Ast *statement)
|
||||
const char *error_type = type_to_error_string(error_expr->type);
|
||||
if (error_expr->expr_kind == EXPR_IDENTIFIER
|
||||
&& error_expr->identifier_expr.decl->decl_kind == DECL_VAR
|
||||
&& error_expr->identifier_expr.decl->var.kind == VARDECL_ALIAS)
|
||||
&& error_expr->identifier_expr.decl->var.kind == VARDECL_UNWRAPPED)
|
||||
{
|
||||
SEMA_ERROR(error_expr,
|
||||
"'%s' is unwrapped to '%s' here, so it cannot be caught.",
|
||||
@@ -1853,7 +2108,7 @@ static bool sema_analyse_catch_stmt(Context *context, Ast *statement)
|
||||
if (unwrapped && !statement->flow.has_break && statement->flow.no_exit)
|
||||
{
|
||||
Decl *decl = decl_copy(unwrapped);
|
||||
decl->var.kind = VARDECL_ALIAS;
|
||||
decl->var.kind = VARDECL_UNWRAPPED;
|
||||
decl->var.alias = unwrapped;
|
||||
decl->var.failable = false;
|
||||
sema_unwrap_var(context, decl);
|
||||
@@ -1864,9 +2119,9 @@ static bool sema_analyse_catch_stmt(Context *context, Ast *statement)
|
||||
|
||||
static bool sema_analyse_try_stmt(Context *context, Ast *stmt)
|
||||
{
|
||||
assert(stmt->try_old_stmt.decl_expr->expr_kind == EXPR_DECL_LIST);
|
||||
assert(stmt->try_old_stmt.decl_expr->expr_kind == EXPR_COND);
|
||||
|
||||
Expr **dexprs = stmt->try_old_stmt.decl_expr->dexpr_list_expr;
|
||||
Expr **dexprs = stmt->try_old_stmt.decl_expr->cond_expr;
|
||||
TODO
|
||||
/*TODO
|
||||
SCOPE_START
|
||||
@@ -2109,11 +2364,11 @@ static bool sema_analyse_requires(Context *context, Ast *docs, Ast ***asserts)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
assert(declexpr->expr_kind == EXPR_DECL_LIST);
|
||||
assert(declexpr->expr_kind == EXPR_COND);
|
||||
|
||||
VECEACH(declexpr->dexpr_list_expr, j)
|
||||
VECEACH(declexpr->cond_expr, j)
|
||||
{
|
||||
Expr *expr = declexpr->dexpr_list_expr[j];
|
||||
Expr *expr = declexpr->cond_expr[j];
|
||||
if (expr->expr_kind == EXPR_DECL)
|
||||
{
|
||||
SEMA_ERROR(expr, "Only expressions are allowed.");
|
||||
|
||||
@@ -92,8 +92,9 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
|
||||
switch (decl->decl_kind)
|
||||
{
|
||||
case DECL_STRUCT:
|
||||
case DECL_BITSTRUCT:
|
||||
case DECL_UNION:
|
||||
case DECL_ERR:
|
||||
case DECL_ERRTYPE:
|
||||
case DECL_ENUM:
|
||||
case DECL_TYPEDEF:
|
||||
case DECL_DISTINCT:
|
||||
@@ -115,6 +116,7 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
|
||||
}
|
||||
FALLTHROUGH;
|
||||
case DECL_FUNC:
|
||||
case DECL_ERRVALUE:
|
||||
case DECL_ENUM_CONSTANT:
|
||||
case DECL_ARRAY_VALUE:
|
||||
case DECL_IMPORT:
|
||||
@@ -150,18 +152,19 @@ bool sema_resolve_type(Context *context, Type *type)
|
||||
case TYPE_BOOL:
|
||||
case TYPE_TYPEID:
|
||||
case TYPE_VIRTUAL_ANY:
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_ANYERR:
|
||||
case TYPE_STRLIT:
|
||||
case TYPE_VECTOR:
|
||||
return true;
|
||||
case TYPE_POINTER:
|
||||
return sema_resolve_type(context, type->pointer);
|
||||
case TYPE_BITSTRUCT:
|
||||
case TYPE_DISTINCT:
|
||||
case TYPE_ENUM:
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_FUNC:
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_DISTINCT:
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
case TYPE_SUBARRAY:
|
||||
|
||||
@@ -149,6 +149,7 @@ void symtab_init(uint32_t capacity)
|
||||
attribute_list[ATTRIBUTE_VECCALL] = KW_DEF("veccall");
|
||||
attribute_list[ATTRIBUTE_REGCALL] = KW_DEF("regcall");
|
||||
attribute_list[ATTRIBUTE_FASTCALL] = KW_DEF("fastcall");
|
||||
attribute_list[ATTRIBUTE_OVERLAP] = KW_DEF("overlap");
|
||||
}
|
||||
|
||||
static inline SymEntry *entry_find(const char *key, uint32_t key_len, uint32_t hash)
|
||||
|
||||
@@ -9,8 +9,8 @@ static ArchType arch_from_llvm_string(StringSlice string);
|
||||
static EnvironmentType environment_type_from_llvm_string(StringSlice string);
|
||||
static bool arch_is_supported(ArchType arch);
|
||||
static unsigned os_target_c_type_bits(OsType os, ArchType arch, CType type);
|
||||
static unsigned os_target_alignment_of_int(OsType os, ArchType arch, int bits);
|
||||
static unsigned os_target_alignment_of_float(OsType os, ArchType arch, int bits);
|
||||
static AlignData os_target_alignment_of_int(OsType os, ArchType arch, int bits);
|
||||
static AlignData os_target_alignment_of_float(OsType os, ArchType arch, int bits);
|
||||
static OsType os_from_llvm_string(StringSlice string);
|
||||
static VendorType vendor_from_llvm_string(StringSlice string);
|
||||
static ObjectFormatType object_format_from_os(OsType os);
|
||||
@@ -208,20 +208,60 @@ static inline bool os_is_apple(OsType os_type)
|
||||
os_type == OS_TYPE_MACOSX || os_type == OS_TYPE_IOS;
|
||||
}
|
||||
|
||||
static AlignSize os_arch_max_alignment_of_vector(OsType os, ArchType arch)
|
||||
static AlignSize os_arch_max_alignment_of_vector(OsType os, ArchType arch, EnvironmentType type, ARMVariant variant)
|
||||
{
|
||||
switch (arch)
|
||||
{
|
||||
case ARCH_TYPE_AARCH64:
|
||||
return 128 / 8;
|
||||
// aarch64 uses 128 bits.
|
||||
// See Clang: AArch64TargetInfo::AArch64TargetInfo
|
||||
return 16;
|
||||
case ARCH_TYPE_ARM:
|
||||
case ARCH_TYPE_ARMB:
|
||||
// Only if aapcs and not android
|
||||
REMINDER("Check if AAPCS");
|
||||
return 64 / 8;
|
||||
if (type == ENV_TYPE_ANDROID) return 0;
|
||||
switch (variant)
|
||||
{
|
||||
case ARM_AAPCS:
|
||||
case ARM_AAPCS_LINUX:
|
||||
return 8; // AAPCS (not AAPCS16!) uses 64 bits
|
||||
case ARM_AAPCS16:
|
||||
case ARM_APCS_GNU:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ARCH_TYPE_X86:
|
||||
if (os == OS_TYPE_WIN32) /* COFF */
|
||||
{
|
||||
return 8192;
|
||||
}
|
||||
if (os_is_apple(os))
|
||||
{
|
||||
// With AVX512 - 512, AVX - 256 otherwise AVX - 128
|
||||
return 256;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
// No max alignment default.
|
||||
return 0;
|
||||
}
|
||||
|
||||
static AlignSize os_arch_max_alignment_of_tls(OsType os, ArchType arch, EnvironmentType type)
|
||||
{
|
||||
switch (arch)
|
||||
{
|
||||
case ARCH_TYPE_X86:
|
||||
if (os == OS_TYPE_WIN32) /* COFF */
|
||||
{
|
||||
return 8192;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// No max alignment default.
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool os_target_signed_c_char_type(OsType os, ArchType arch)
|
||||
@@ -398,6 +438,18 @@ static inline void target_setup_x64_abi(BuildTarget *target)
|
||||
{
|
||||
platform_target.x64.pass_int128_vector_in_mem = true;
|
||||
}
|
||||
switch (platform_target.x64.avx_level)
|
||||
{
|
||||
case AVX_NONE:
|
||||
platform_target.x64.align_simd_default = 128;
|
||||
break;
|
||||
case AVX:
|
||||
platform_target.x64.align_simd_default = 256;
|
||||
break;
|
||||
case AVX_512:
|
||||
platform_target.x64.align_simd_default = 512;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static char *arch_to_target_triple[ARCH_OS_TARGET_LAST + 1] = {
|
||||
@@ -684,7 +736,10 @@ static unsigned os_target_supports_float16(OsType os, ArchType arch)
|
||||
{
|
||||
case ARCH_TYPE_AARCH64:
|
||||
return true;
|
||||
case ARCH_TYPE_ARM:
|
||||
// Supported on fullfp16 and mve.fp in Clang
|
||||
default:
|
||||
// Supported by AMDGPU
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -845,7 +900,17 @@ static unsigned os_target_c_type_bits(OsType os, ArchType arch, CType type)
|
||||
|
||||
}
|
||||
|
||||
static unsigned os_target_alignment_of_int(OsType os, ArchType arch, int bits)
|
||||
typedef enum {
|
||||
MACHO_MANGLING,
|
||||
ELF_MANGLING,
|
||||
MIPS_MANGLING,
|
||||
WIN86_MANGLING,
|
||||
WIN_MANGLING,
|
||||
XCOFF_MANGLING
|
||||
} Mangling;
|
||||
|
||||
|
||||
static AlignData os_target_alignment_of_int(OsType os, ArchType arch, int bits)
|
||||
{
|
||||
switch (arch)
|
||||
{
|
||||
@@ -854,36 +919,34 @@ static unsigned os_target_alignment_of_int(OsType os, ArchType arch, int bits)
|
||||
UNREACHABLE
|
||||
case ARCH_TYPE_ARM:
|
||||
case ARCH_TYPE_THUMB:
|
||||
if ((os_is_apple(os) || os == OS_TYPE_NETBSD) && bits > 32) return 4;
|
||||
return bits > 64 ? 8 : bits / 8;
|
||||
case ARCH_TYPE_ARMB:
|
||||
case ARCH_TYPE_THUMBEB:
|
||||
if (os == OS_TYPE_NETBSD && bits > 32) return 4;
|
||||
return bits > 64 ? 8 : bits / 8;
|
||||
if ((os_is_apple(os) || os == OS_TYPE_NETBSD) && bits > 32) return (AlignData) { 32, MIN(64, bits) };
|
||||
return (AlignData) { MIN(64, bits), MIN(64, bits) };
|
||||
case ARCH_TYPE_PPC64:
|
||||
case ARCH_TYPE_PPC:
|
||||
case ARCH_TYPE_PPC64LE:
|
||||
case ARCH_TYPE_RISCV32:
|
||||
case ARCH_TYPE_X86_64:
|
||||
case ARCH_TYPE_WASM32:
|
||||
case ARCH_TYPE_WASM64:
|
||||
return bits > 64 ? 8 : bits / 8;
|
||||
return bits > 32 ? 4 : bits / 8;
|
||||
case ARCH_TYPE_RISCV32:
|
||||
case ARCH_TYPE_WASM32:
|
||||
return (AlignData) { MIN(64, bits), MIN(64, bits) };
|
||||
case ARCH_TYPE_RISCV64:
|
||||
return (AlignData) { bits, bits };
|
||||
case ARCH_TYPE_AARCH64:
|
||||
case ARCH_TYPE_AARCH64_BE:
|
||||
case ARCH_TYPE_RISCV64:
|
||||
return bits / 8;
|
||||
if (bits < 32 && !os_is_apple(os) && os != OS_TYPE_WIN32) return (AlignData){ bits, 32 };
|
||||
return (AlignData) { bits, bits };
|
||||
case ARCH_TYPE_X86:
|
||||
if (bits >= 64)
|
||||
{
|
||||
return (os == OS_TYPE_WIN32 || os == OS_TYPE_NACL) ? 8 : 4;
|
||||
}
|
||||
return bits / 8;
|
||||
if (bits < 32) return (AlignData) { bits, bits };
|
||||
if (os == OS_TYPE_ELFIAMCU) return (AlignData) { 32, 32 };
|
||||
if (os == OS_TYPE_WIN32 || os == OS_TYPE_NACL) return (AlignData) { 64, 64 };
|
||||
return (AlignData) { 32, 64 };
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
static unsigned arch_little_endian(ArchType arch)
|
||||
static unsigned arch_big_endian(ArchType arch)
|
||||
{
|
||||
switch (arch)
|
||||
{
|
||||
@@ -898,53 +961,21 @@ static unsigned arch_little_endian(ArchType arch)
|
||||
case ARCH_TYPE_RISCV64:
|
||||
case ARCH_TYPE_WASM32:
|
||||
case ARCH_TYPE_WASM64:
|
||||
return true;
|
||||
case ARCH_TYPE_ARMB:
|
||||
case ARCH_TYPE_THUMBEB:
|
||||
case ARCH_TYPE_AARCH64_BE:
|
||||
case ARCH_TYPE_PPC64:
|
||||
case ARCH_TYPE_PPC:
|
||||
return false;
|
||||
case ARCH_UNSUPPORTED:
|
||||
UNREACHABLE
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
static unsigned os_target_pref_alignment_of_int(OsType os, ArchType arch, int bits)
|
||||
{
|
||||
switch (arch)
|
||||
{
|
||||
case ARCH_TYPE_UNKNOWN:
|
||||
case ARCH_UNSUPPORTED:
|
||||
UNREACHABLE
|
||||
case ARCH_TYPE_X86:
|
||||
if (os == OS_TYPE_ELFIAMCU && bits > 32) return 4;
|
||||
return bits > 64 ? 8 : bits / 8;
|
||||
case ARCH_TYPE_AARCH64:
|
||||
if (bits < 32 && !os_is_apple(os) && os != OS_TYPE_WIN32) return 4;
|
||||
return bits / 8;
|
||||
case ARCH_TYPE_AARCH64_BE:
|
||||
return bits < 32 ? 4 : bits / 8;
|
||||
case ARCH_TYPE_ARM:
|
||||
case ARCH_TYPE_ARMB:
|
||||
case ARCH_TYPE_PPC:
|
||||
case ARCH_TYPE_PPC64LE:
|
||||
case ARCH_TYPE_PPC64:
|
||||
case ARCH_TYPE_RISCV32:
|
||||
case ARCH_TYPE_THUMB:
|
||||
case ARCH_TYPE_THUMBEB:
|
||||
case ARCH_TYPE_X86_64:
|
||||
case ARCH_TYPE_WASM32:
|
||||
case ARCH_TYPE_WASM64:
|
||||
return bits < 64 ? bits / 8 : 8;
|
||||
case ARCH_TYPE_RISCV64:
|
||||
return bits / 8;
|
||||
case ARCH_TYPE_AARCH64_BE:
|
||||
case ARCH_TYPE_PPC64:
|
||||
case ARCH_TYPE_PPC:
|
||||
return true;
|
||||
case ARCH_UNSUPPORTED:
|
||||
UNREACHABLE
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
static unsigned os_target_alignment_of_float(OsType os, ArchType arch, int bits)
|
||||
|
||||
static AlignData os_target_alignment_of_float(OsType os, ArchType arch, int bits)
|
||||
{
|
||||
switch (arch)
|
||||
{
|
||||
@@ -952,12 +983,12 @@ static unsigned os_target_alignment_of_float(OsType os, ArchType arch, int bits)
|
||||
case ARCH_UNSUPPORTED:
|
||||
UNREACHABLE
|
||||
case ARCH_TYPE_X86:
|
||||
if (os == OS_TYPE_ELFIAMCU && bits >= 32) return 4;
|
||||
if (os == OS_TYPE_ELFIAMCU && bits >= 32) return (AlignData) { 32, 32 };
|
||||
if (os == OS_TYPE_WIN32 || os == OS_TYPE_NACL)
|
||||
{
|
||||
return bits / 8;
|
||||
return (AlignData) { bits, bits };
|
||||
}
|
||||
return bits == 64 ? 4 : bits / 8;
|
||||
return (AlignData) { MIN(32, bits), bits };
|
||||
case ARCH_TYPE_AARCH64:
|
||||
case ARCH_TYPE_AARCH64_BE:
|
||||
case ARCH_TYPE_PPC64:
|
||||
@@ -967,24 +998,19 @@ static unsigned os_target_alignment_of_float(OsType os, ArchType arch, int bits)
|
||||
case ARCH_TYPE_RISCV64:
|
||||
case ARCH_TYPE_WASM32:
|
||||
case ARCH_TYPE_WASM64:
|
||||
return bits / 8;
|
||||
return (AlignData) { bits , bits };
|
||||
case ARCH_TYPE_ARM:
|
||||
case ARCH_TYPE_THUMB:
|
||||
if ((os_is_apple(os) || os == OS_TYPE_NETBSD) && bits == 64)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
return bits / 8;
|
||||
case ARCH_TYPE_THUMBEB:
|
||||
case ARCH_TYPE_ARMB:
|
||||
if (os == OS_TYPE_NETBSD && bits == 64)
|
||||
if ((os_is_apple(os) || os == OS_TYPE_NETBSD) && bits == 64)
|
||||
{
|
||||
return 4;
|
||||
return (AlignData) { 32, bits };
|
||||
}
|
||||
return bits / 8;
|
||||
return (AlignData) { bits , bits };
|
||||
case ARCH_TYPE_X86_64:
|
||||
if (bits == 128 && os == OS_TYPE_ELFIAMCU) return 4;
|
||||
return bits / 8;
|
||||
if (bits == 128 && os == OS_TYPE_ELFIAMCU) return (AlignData) { 32, 32 };
|
||||
return (AlignData) { bits , bits };
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
@@ -1101,6 +1127,7 @@ static unsigned os_target_pref_alignment_of_float(OsType os, ArchType arch, int
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
|
||||
void *llvm_target_machine_create(void)
|
||||
{
|
||||
char *err = NULL;
|
||||
@@ -1218,29 +1245,14 @@ void target_setup(BuildTarget *target)
|
||||
platform_target.environment_type = environment_type_from_llvm_string(target_triple_string);
|
||||
|
||||
platform_target.float_abi = false;
|
||||
platform_target.little_endian = arch_little_endian(platform_target.arch);
|
||||
// TLS should not be supported for:
|
||||
// ARM Cygwin
|
||||
// NVPTX
|
||||
platform_target.tls_supported = true;
|
||||
platform_target.big_endian = arch_big_endian(platform_target.arch);
|
||||
platform_target.width_pointer = arch_pointer_bit_width(platform_target.os, platform_target.arch);
|
||||
platform_target.alloca_address_space = 0;
|
||||
|
||||
// Todo PIC or no PIC depending on architecture.
|
||||
switch (platform_target.arch)
|
||||
{
|
||||
case ARCH_TYPE_X86_64:
|
||||
case ARCH_TYPE_X86:
|
||||
case ARCH_TYPE_PPC64LE:
|
||||
case ARCH_TYPE_ARM:
|
||||
case ARCH_TYPE_RISCV32:
|
||||
case ARCH_TYPE_RISCV64:
|
||||
case ARCH_TYPE_AARCH64:
|
||||
platform_target.max_size_for_return = platform_target.width_pointer * 2 / 8;
|
||||
break;
|
||||
case ARCH_TYPE_PPC64:
|
||||
platform_target.max_size_for_return = 0;
|
||||
break;
|
||||
default:
|
||||
FATAL_ERROR("Unsupported architecture.");
|
||||
}
|
||||
|
||||
platform_target.object_format = object_format_from_os(platform_target.os);
|
||||
|
||||
platform_target.int128 = os_target_supports_int128(platform_target.os, platform_target.arch);
|
||||
@@ -1250,23 +1262,20 @@ void target_setup(BuildTarget *target)
|
||||
platform_target.vec64i = os_target_supports_vec(platform_target.os, platform_target.arch, 64, true);
|
||||
platform_target.float128 = os_target_supports_float128(platform_target.os, platform_target.arch);
|
||||
platform_target.float16 = os_target_supports_float16(platform_target.os, platform_target.arch);
|
||||
platform_target.align_byte = os_target_alignment_of_int(platform_target.os, platform_target.arch, 8);
|
||||
platform_target.align_short = os_target_alignment_of_int(platform_target.os, platform_target.arch, 16);
|
||||
platform_target.align_int = os_target_alignment_of_int(platform_target.os, platform_target.arch, 32);
|
||||
platform_target.align_long = os_target_alignment_of_int(platform_target.os, platform_target.arch, 64);
|
||||
platform_target.align_i128 = os_target_alignment_of_int(platform_target.os, platform_target.arch, 128);
|
||||
platform_target.align_half = os_target_alignment_of_float(platform_target.os, platform_target.arch, 16);
|
||||
platform_target.align_float = os_target_alignment_of_float(platform_target.os, platform_target.arch, 32);
|
||||
platform_target.align_double = os_target_alignment_of_float(platform_target.os, platform_target.arch, 64);
|
||||
platform_target.align_f128 = os_target_alignment_of_float(platform_target.os, platform_target.arch, 128);
|
||||
platform_target.align_int = os_target_alignment_of_int(platform_target.os, platform_target.arch, 32);
|
||||
platform_target.align_pointer = platform_target.width_pointer / 8;
|
||||
for (BitSizes i = BITS8; i < BITSIZES_LEN; i++)
|
||||
{
|
||||
unsigned bits = 8 << (i - 1);
|
||||
platform_target.integers[i] = os_target_alignment_of_int(platform_target.os, platform_target.arch, bits);
|
||||
platform_target.floats[i] = os_target_alignment_of_float(platform_target.os, platform_target.arch, bits);
|
||||
}
|
||||
platform_target.integers[BIT1] = platform_target.integers[BITS8];
|
||||
|
||||
platform_target.align_pointer = (AlignData) { platform_target.width_pointer, platform_target.width_pointer };
|
||||
platform_target.width_c_short = os_target_c_type_bits(platform_target.os, platform_target.arch, CTYPE_SHORT);
|
||||
platform_target.width_c_int = os_target_c_type_bits(platform_target.os, platform_target.arch, CTYPE_INT);
|
||||
platform_target.width_c_long = os_target_c_type_bits(platform_target.os, platform_target.arch, CTYPE_LONG);
|
||||
platform_target.width_c_long_long = os_target_c_type_bits(platform_target.os, platform_target.arch, CTYPE_LONG_LONG);
|
||||
platform_target.signed_c_char = os_target_signed_c_char_type(platform_target.os, platform_target.arch);
|
||||
platform_target.align_max_vector = os_arch_max_alignment_of_vector(platform_target.os, platform_target.arch);
|
||||
/**
|
||||
* x86-64: CMOV, CMPXCHG8B, FPU, FXSR, MMX, FXSR, SCE, SSE, SSE2
|
||||
* x86-64-v2: (close to Nehalem) CMPXCHG16B, LAHF-SAHF, POPCNT, SSE3, SSE4.1, SSE4.2, SSSE3
|
||||
@@ -1336,7 +1345,10 @@ void target_setup(BuildTarget *target)
|
||||
platform_target.abi = ABI_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
platform_target.align_max_vector = os_arch_max_alignment_of_vector(platform_target.os, platform_target.arch, platform_target.environment_type, platform_target.arm.variant);
|
||||
platform_target.align_max_tls = os_arch_max_alignment_of_tls(platform_target.os,
|
||||
platform_target.arch,
|
||||
platform_target.environment_type);
|
||||
platform_target.pic = arch_os_pic_default(platform_target.arch, platform_target.os);
|
||||
platform_target.pie = arch_os_pie_default(platform_target.arch, platform_target.os, platform_target.environment_type);
|
||||
platform_target.pic_required = arch_os_pic_default_forced(platform_target.arch, platform_target.os);
|
||||
|
||||
@@ -234,6 +234,24 @@ typedef enum
|
||||
ARM_ABI_AAPCS_VFP,
|
||||
} ARMABIVariant;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned align;
|
||||
unsigned pref_align;
|
||||
} AlignData;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
BIT1,
|
||||
BITS8,
|
||||
BITS16,
|
||||
BITS32,
|
||||
BITS64,
|
||||
BITS128,
|
||||
BITS256,
|
||||
BITSIZES_LEN
|
||||
} BitSizes;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *target_triple;
|
||||
@@ -247,6 +265,8 @@ typedef struct
|
||||
ObjectFormatType object_format;
|
||||
int alloca_address_space;
|
||||
ABI abi;
|
||||
AlignData integers[BITSIZES_LEN];
|
||||
AlignData floats[BITSIZES_LEN];
|
||||
PicGeneration pic : 3;
|
||||
PieGeneration pie : 3;
|
||||
bool pic_required : 1;
|
||||
@@ -266,6 +286,7 @@ typedef struct
|
||||
} x86;
|
||||
struct
|
||||
{
|
||||
unsigned align_simd_default : 16;
|
||||
AVXLevel avx_level : 3;
|
||||
bool no_mmx : 1;
|
||||
bool no_sse : 1;
|
||||
@@ -314,7 +335,7 @@ typedef struct
|
||||
bool has_vector : 1;
|
||||
} systemz;
|
||||
};
|
||||
bool little_endian;
|
||||
bool big_endian;
|
||||
bool tls_supported;
|
||||
bool asm_supported;
|
||||
bool float128;
|
||||
@@ -324,34 +345,9 @@ typedef struct
|
||||
bool vec128f;
|
||||
bool vec64f;
|
||||
bool int128;
|
||||
unsigned align_pref_pointer;
|
||||
unsigned align_pref_byte;
|
||||
unsigned align_pref_short;
|
||||
unsigned align_pref_int;
|
||||
unsigned align_pref_long;
|
||||
unsigned align_pref_i128;
|
||||
unsigned align_pref_half;
|
||||
unsigned align_pref_float;
|
||||
unsigned align_pref_double;
|
||||
unsigned align_pref_f128;
|
||||
unsigned align_pointer;
|
||||
unsigned align_byte;
|
||||
unsigned align_short;
|
||||
unsigned align_int;
|
||||
unsigned align_long;
|
||||
unsigned align_i128;
|
||||
unsigned align_half;
|
||||
unsigned align_float;
|
||||
unsigned align_double;
|
||||
unsigned align_f128;
|
||||
unsigned align_c_long_double;
|
||||
unsigned align_c_int;
|
||||
unsigned align_c_long;
|
||||
unsigned align_c_long_long;
|
||||
unsigned align_simd_default;
|
||||
AlignData align_pointer;
|
||||
unsigned align_max_vector;
|
||||
unsigned align_global_min;
|
||||
unsigned align_new;
|
||||
unsigned align_max_tls;
|
||||
unsigned align_large_array;
|
||||
unsigned width_pointer;
|
||||
unsigned width_c_short;
|
||||
@@ -366,8 +362,8 @@ typedef struct
|
||||
unsigned sse_reg_param_max;
|
||||
unsigned builtin_ms_valist;
|
||||
unsigned aarch64sve_types;
|
||||
unsigned max_size_for_return;
|
||||
char *platform_name;
|
||||
// MinGlobalAlign is used by Clang for SystemZ and Lanai targets.
|
||||
|
||||
} PlatformTarget;
|
||||
|
||||
|
||||
@@ -186,6 +186,8 @@ const char *token_type_to_string(TokenType type)
|
||||
return "assert";
|
||||
case TOKEN_ATTRIBUTE:
|
||||
return "attribute";
|
||||
case TOKEN_BITSTRUCT:
|
||||
return "bitstruct";
|
||||
case TOKEN_BREAK:
|
||||
return "break";
|
||||
case TOKEN_CASE:
|
||||
@@ -386,3 +388,9 @@ bool token_is_any_type(TokenType type)
|
||||
{
|
||||
return (type >= TOKEN_VOID && type <= TOKEN_TYPEID) || type == TOKEN_CT_TYPE_IDENT || type == TOKEN_TYPE_IDENT || type == TOKEN_VIRTUAL;
|
||||
}
|
||||
|
||||
bool token_is_ident_keyword(TokenType type)
|
||||
{
|
||||
if (token_is_type(type)) return true;
|
||||
return type >= TOKEN_ALIAS && type <= TOKEN_WHILE;
|
||||
}
|
||||
|
||||
@@ -114,6 +114,7 @@ const char *type_to_error_string(Type *type)
|
||||
case TYPE_POISONED:
|
||||
return "poisoned";
|
||||
case TYPE_ENUM:
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_TYPEDEF:
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_VOID:
|
||||
@@ -121,10 +122,11 @@ const char *type_to_error_string(Type *type)
|
||||
case ALL_INTS:
|
||||
case ALL_FLOATS:
|
||||
case TYPE_UNION:
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_DISTINCT:
|
||||
case TYPE_BITSTRUCT:
|
||||
case TYPE_VIRTUAL_ANY:
|
||||
case TYPE_VIRTUAL:
|
||||
case TYPE_ANYERR:
|
||||
return type->name;
|
||||
case TYPE_FUNC:
|
||||
return strcat_arena("func ", type->func.mangled_function_signature);
|
||||
@@ -153,8 +155,6 @@ const char *type_to_error_string(Type *type)
|
||||
case TYPE_SUBARRAY:
|
||||
asprintf(&buffer, "%s[]", type_to_error_string(type->array.base));
|
||||
return buffer;
|
||||
case TYPE_ERR_UNION:
|
||||
return "error";
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
@@ -189,6 +189,8 @@ ByteSize type_size(Type *type)
|
||||
{
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_BITSTRUCT:
|
||||
return type_size(type->decl->bitstruct.base_type->type);
|
||||
case TYPE_DISTINCT:
|
||||
return type_size(type->decl->distinct_decl.base_type);
|
||||
case TYPE_VECTOR:
|
||||
@@ -207,10 +209,10 @@ ByteSize type_size(Type *type)
|
||||
UNREACHABLE;
|
||||
case TYPE_TYPEDEF:
|
||||
return type_size(type->canonical);
|
||||
case TYPE_ENUM:
|
||||
return type->decl->enums.type_info->type->canonical->builtin.bytesize;
|
||||
case TYPE_ERRTYPE:
|
||||
return type_size(type_usize->canonical);
|
||||
case TYPE_ENUM:
|
||||
return type->decl->enums.type_info->type->canonical->builtin.bytesize;
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
assert(type->decl->resolve_status == RESOLVE_DONE);
|
||||
@@ -221,7 +223,7 @@ ByteSize type_size(Type *type)
|
||||
case TYPE_TYPEID:
|
||||
case ALL_INTS:
|
||||
case ALL_FLOATS:
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_ANYERR:
|
||||
case TYPE_VIRTUAL_ANY:
|
||||
return type->builtin.bytesize;
|
||||
case TYPE_VIRTUAL:
|
||||
@@ -340,6 +342,8 @@ bool type_is_abi_aggregate(Type *type)
|
||||
return type_is_abi_aggregate(type->decl->distinct_decl.base_type);
|
||||
case TYPE_TYPEDEF:
|
||||
return type_is_abi_aggregate(type->canonical);
|
||||
case TYPE_BITSTRUCT:
|
||||
return type_is_abi_aggregate(type->decl->bitstruct.base_type->type);
|
||||
case ALL_FLOATS:
|
||||
case TYPE_VOID:
|
||||
case ALL_INTS:
|
||||
@@ -350,13 +354,13 @@ bool type_is_abi_aggregate(Type *type)
|
||||
case TYPE_FUNC:
|
||||
case TYPE_STRLIT:
|
||||
case TYPE_VECTOR:
|
||||
return false;
|
||||
case TYPE_ANYERR:
|
||||
case TYPE_ERRTYPE:
|
||||
return false;
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_SUBARRAY:
|
||||
case TYPE_ARRAY:
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_VIRTUAL:
|
||||
case TYPE_VIRTUAL_ANY:
|
||||
return true;
|
||||
@@ -495,6 +499,9 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements)
|
||||
case TYPE_DISTINCT:
|
||||
type = type->decl->distinct_decl.base_type;
|
||||
goto RETRY;
|
||||
case TYPE_BITSTRUCT:
|
||||
type = type->decl->bitstruct.base_type->type;
|
||||
goto RETRY;
|
||||
case TYPE_FXX:
|
||||
case TYPE_POISONED:
|
||||
case TYPE_IXX:
|
||||
@@ -506,18 +513,15 @@ bool type_is_homogenous_aggregate(Type *type, Type **base, unsigned *elements)
|
||||
case TYPE_SUBARRAY:
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
return false;
|
||||
case TYPE_ERR_UNION:
|
||||
DEBUG_LOG("Should error be passed as homogenous aggregate?");
|
||||
FALLTHROUGH;
|
||||
case TYPE_VIRTUAL:
|
||||
case TYPE_VIRTUAL_ANY:
|
||||
*base = type_iptr->canonical;
|
||||
*elements = 2;
|
||||
return true;
|
||||
case TYPE_ANYERR:
|
||||
case TYPE_ERRTYPE:
|
||||
*base = type_iptr->canonical;
|
||||
*elements = 1;
|
||||
return true;
|
||||
type = type_iptr;
|
||||
goto RETRY;
|
||||
case TYPE_TYPEDEF:
|
||||
type = type->canonical;
|
||||
goto RETRY;
|
||||
@@ -653,6 +657,8 @@ AlignSize type_abi_alignment(Type *type)
|
||||
case TYPE_TYPEINFO:
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
UNREACHABLE;
|
||||
case TYPE_BITSTRUCT:
|
||||
return type_abi_alignment(type->decl->bitstruct.base_type->type);
|
||||
case TYPE_VECTOR:
|
||||
{
|
||||
ByteSize width = type_size(type->vector.base) * type->vector.len;
|
||||
@@ -673,7 +679,7 @@ AlignSize type_abi_alignment(Type *type)
|
||||
case TYPE_ENUM:
|
||||
return type->decl->enums.type_info->type->canonical->builtin.abi_alignment;
|
||||
case TYPE_ERRTYPE:
|
||||
return t.usz.canonical->builtin.abi_alignment;
|
||||
return t.iptr.canonical->builtin.abi_alignment;
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
return type->decl->alignment;
|
||||
@@ -682,15 +688,15 @@ AlignSize type_abi_alignment(Type *type)
|
||||
case TYPE_BOOL:
|
||||
case ALL_INTS:
|
||||
case ALL_FLOATS:
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_VIRTUAL_ANY:
|
||||
case TYPE_ANYERR:
|
||||
return type->builtin.abi_alignment;
|
||||
case TYPE_VIRTUAL:
|
||||
return type_virtual_generic->builtin.abi_alignment;
|
||||
case TYPE_FUNC:
|
||||
case TYPE_POINTER:
|
||||
case TYPE_STRLIT:
|
||||
return t.usz.canonical->builtin.abi_alignment;
|
||||
return t.iptr.canonical->builtin.abi_alignment;
|
||||
case TYPE_ARRAY:
|
||||
return type_abi_alignment(type->array.base);
|
||||
case TYPE_SUBARRAY:
|
||||
@@ -997,9 +1003,11 @@ Type *type_get_vector(Type *vector_type, unsigned len)
|
||||
static void type_create(const char *name, Type *location, TypeKind kind, unsigned bitsize,
|
||||
unsigned align, unsigned pref_align)
|
||||
{
|
||||
assert(align);
|
||||
unsigned byte_size = (bitsize + 7) / 8;
|
||||
*location = (Type) {
|
||||
.type_kind = kind,
|
||||
.builtin.bytesize = (bitsize + 7) / 8,
|
||||
.builtin.bytesize = byte_size,
|
||||
.builtin.bitsize = bitsize,
|
||||
.builtin.abi_alignment = align,
|
||||
.builtin.pref_alignment = pref_align ?: align,
|
||||
@@ -1011,6 +1019,24 @@ static void type_create(const char *name, Type *location, TypeKind kind, unsigne
|
||||
global_context_add_type(location);
|
||||
}
|
||||
|
||||
static void type_init(const char *name, Type *location, TypeKind kind, unsigned bitsize, AlignData align)
|
||||
{
|
||||
assert(align.align);
|
||||
unsigned byte_size = (bitsize + 7) / 8;
|
||||
*location = (Type) {
|
||||
.type_kind = kind,
|
||||
.builtin.bytesize = byte_size,
|
||||
.builtin.bitsize = bitsize,
|
||||
.builtin.abi_alignment = align.align / 8,
|
||||
.builtin.pref_alignment = (align.pref_align ?: align.align) / 8,
|
||||
.name = name,
|
||||
.canonical = location,
|
||||
};
|
||||
location->name = name;
|
||||
location->canonical = location;
|
||||
global_context_add_type(location);
|
||||
}
|
||||
|
||||
static void type_create_alias(const char *name, Type *location, Type *canonical)
|
||||
{
|
||||
*location = (Type) {
|
||||
@@ -1035,6 +1061,7 @@ static void type_append_name_to_scratch(Type *type)
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_DISTINCT:
|
||||
case TYPE_BITSTRUCT:
|
||||
scratch_buffer_append(type->decl->external_name);
|
||||
break;
|
||||
case TYPE_POINTER:
|
||||
@@ -1061,7 +1088,7 @@ static void type_append_name_to_scratch(Type *type)
|
||||
case TYPE_F64:
|
||||
case TYPE_F128:
|
||||
case TYPE_TYPEID:
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_ANYERR:
|
||||
case TYPE_VIRTUAL_ANY:
|
||||
case TYPE_VECTOR:
|
||||
scratch_buffer_append(type->name);
|
||||
@@ -1121,51 +1148,59 @@ Type *type_find_function_type(FunctionSignature *signature)
|
||||
return func_type;
|
||||
}
|
||||
|
||||
static inline void type_init_int(const char *name, Type *type, TypeKind kind, BitSizes bits)
|
||||
{
|
||||
int actual_bits = bits ? 8 << (bits - 1) : 1;
|
||||
type_init(name, type, kind, actual_bits, platform_target.integers[bits]);
|
||||
}
|
||||
|
||||
static inline void type_create_float(const char *name, Type *type, TypeKind kind, BitSizes bits)
|
||||
{
|
||||
int actual_bits = bits ? 8 << (bits - 1) : 1;
|
||||
type_init(name, type, kind, actual_bits, platform_target.floats[bits]);
|
||||
}
|
||||
|
||||
void type_setup(PlatformTarget *target)
|
||||
{
|
||||
stable_init(&function_types, 0x1000);
|
||||
max_alignment_vector = target->align_max_vector;
|
||||
/*TODO
|
||||
* decl_string = (Decl) { .decl_kind = DECL_BUILTIN, .name.string = "string" };
|
||||
create_type(&decl_string, &type_string);
|
||||
type_string.type_kind = TYPE_STRING;
|
||||
*/
|
||||
#define DEF_TYPE(name_, shortname_, type_, bits_, aligned_) \
|
||||
type_create(#name_, &(shortname_), type_, bits_, target->align_ ## aligned_, target->align_pref_ ## aligned_)
|
||||
|
||||
DEF_TYPE(bool, t.u1, TYPE_BOOL, 1, byte);
|
||||
DEF_TYPE(float, t.f32, TYPE_F32, 32, float);
|
||||
DEF_TYPE(double, t.f64, TYPE_F64, 64, double);
|
||||
type_create_float("float16", &t.f16, TYPE_F16, BITS16);
|
||||
type_create_float("float", &t.f32, TYPE_F32, BITS32);
|
||||
type_create_float("double", &t.f64, TYPE_F64, BITS64);
|
||||
type_create_float("float128", &t.f128, TYPE_F128, BITS128);
|
||||
|
||||
DEF_TYPE(ichar, t.i8, TYPE_I8, 8, byte);
|
||||
DEF_TYPE(short, t.i16, TYPE_I16, 16, short);
|
||||
DEF_TYPE(int, t.i32, TYPE_I32, 32, int);
|
||||
DEF_TYPE(long, t.i64, TYPE_I64, 64, long);
|
||||
DEF_TYPE(i128, t.i128, TYPE_I128, 128, i128);
|
||||
|
||||
DEF_TYPE(char, t.u8, TYPE_U8, 8, byte);
|
||||
DEF_TYPE(ushort, t.u16, TYPE_U16, 16, short);
|
||||
DEF_TYPE(uint, t.u32, TYPE_U32, 32, int);
|
||||
DEF_TYPE(ulong, t.u64, TYPE_U64, 64, long);
|
||||
DEF_TYPE(u128, t.u128, TYPE_U128, 128, i128);
|
||||
type_init_int("ichar", &t.i8, TYPE_I8, BITS8);
|
||||
type_init_int("short", &t.i16, TYPE_I16, BITS16);
|
||||
type_init_int("int", &t.i32, TYPE_I32, BITS32);
|
||||
type_init_int("long", &t.i64, TYPE_I64, BITS64);
|
||||
type_init_int("int128", &t.i128, TYPE_I128, BITS128);
|
||||
|
||||
DEF_TYPE(void, t.u0, TYPE_VOID, 8, byte);
|
||||
DEF_TYPE(string, t.str, TYPE_STRLIT, target->width_pointer, pointer);
|
||||
type_init_int("bool", &t.u1, TYPE_BOOL, BITS8);
|
||||
type_init_int("char", &t.u8, TYPE_U8, BITS8);
|
||||
type_init_int("ushort", &t.u16, TYPE_U16, BITS16);
|
||||
type_init_int("uint", &t.u32, TYPE_U32, BITS32);
|
||||
type_init_int("ulong", &t.u64, TYPE_U64, BITS64);
|
||||
type_init_int("uint128", &t.u128, TYPE_U128, BITS128);
|
||||
|
||||
#undef DEF_TYPE
|
||||
type_init_int("void", &t.u0, TYPE_VOID, BITS8);
|
||||
|
||||
type_create("typeinfo", &t.typeinfo, TYPE_TYPEINFO, 0, 0, 0);
|
||||
type_create("typeid", &t.typeid, TYPE_TYPEID, target->width_pointer, target->align_pointer, target->align_pref_pointer);
|
||||
type_create("void*", &t.voidstar, TYPE_POINTER, target->width_pointer, target->align_pointer, target->align_pref_pointer);
|
||||
type_init("string", &t.str, TYPE_STRLIT, target->width_pointer, target->align_pointer);
|
||||
|
||||
|
||||
type_create("typeinfo", &t.typeinfo, TYPE_TYPEINFO, 1, 1, 1);
|
||||
type_init("typeid", &t.typeid, TYPE_TYPEID, target->width_pointer, target->align_pointer);
|
||||
|
||||
type_init("void*", &t.voidstar, TYPE_POINTER, target->width_pointer, target->align_pointer);
|
||||
create_type_cache(type_void);
|
||||
type_void->type_cache[0] = &t.voidstar;
|
||||
t.voidstar.pointer = type_void;
|
||||
type_create("virtual*", &t.virtual, TYPE_VIRTUAL_ANY, target->width_pointer * 2, target->align_pointer, target->align_pref_pointer);
|
||||
type_create("virtual_generic", &t.virtual_generic, TYPE_VIRTUAL, target->width_pointer * 2, target->align_pointer, target->align_pref_pointer);
|
||||
type_init("virtual*", &t.virtual, TYPE_VIRTUAL_ANY, target->width_pointer * 2, target->align_pointer);
|
||||
type_init("virtual_generic", &t.virtual_generic, TYPE_VIRTUAL, target->width_pointer * 2, target->align_pointer);
|
||||
|
||||
type_create("compint", &t.ixx, TYPE_IXX, 0, 0, 0);
|
||||
type_create("compfloat", &t.fxx, TYPE_FXX, 0, 0, 0);
|
||||
type_create("compint", &t.ixx, TYPE_IXX, 1, 1, 1);
|
||||
type_create("compfloat", &t.fxx, TYPE_FXX, 1, 1, 1);
|
||||
|
||||
type_create_alias("usize", &t.usz, type_int_unsigned_by_bitsize(target->width_pointer));
|
||||
type_create_alias("isize", &t.isz, type_int_signed_by_bitsize(target->width_pointer));
|
||||
@@ -1178,7 +1213,7 @@ type_create(#name_, &(shortname_), type_, bits_, target->align_ ## aligned_, tar
|
||||
|
||||
alignment_subarray = MAX(type_abi_alignment(&t.voidstar), type_abi_alignment(t.usz.canonical));
|
||||
size_subarray = alignment_subarray * 2;
|
||||
type_create("anyerr", &t.anyerr, TYPE_ERR_UNION, target->width_pointer * 2, target->align_pointer, target->align_pref_pointer);
|
||||
type_init("anyerr", &t.anyerr, TYPE_ANYERR, target->width_pointer, target->align_pointer);
|
||||
}
|
||||
|
||||
bool type_is_scalar(Type *type)
|
||||
@@ -1206,10 +1241,13 @@ bool type_is_scalar(Type *type)
|
||||
case TYPE_POINTER:
|
||||
case TYPE_ENUM:
|
||||
case TYPE_ERRTYPE:
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_ANYERR:
|
||||
case TYPE_VIRTUAL:
|
||||
case TYPE_VIRTUAL_ANY:
|
||||
return true;
|
||||
case TYPE_BITSTRUCT:
|
||||
type = type->decl->bitstruct.base_type->type;
|
||||
goto RETRY;
|
||||
case TYPE_DISTINCT:
|
||||
type = type->decl->distinct_decl.base_type;
|
||||
goto RETRY;
|
||||
@@ -1442,6 +1480,7 @@ Type *type_find_max_type(Type *type, Type *other)
|
||||
case TYPE_TYPEINFO:
|
||||
case TYPE_VIRTUAL:
|
||||
case TYPE_VIRTUAL_ANY:
|
||||
case TYPE_BITSTRUCT:
|
||||
return NULL;
|
||||
case TYPE_IXX:
|
||||
if (other->type_kind == TYPE_DISTINCT && type_is_numeric(other->decl->distinct_decl.base_type)) return other;
|
||||
@@ -1466,7 +1505,7 @@ Type *type_find_max_type(Type *type, Type *other)
|
||||
return NULL;
|
||||
case TYPE_FUNC:
|
||||
case TYPE_UNION:
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_ANYERR:
|
||||
case TYPE_TYPEID:
|
||||
case TYPE_STRUCT:
|
||||
TODO
|
||||
|
||||
@@ -27,7 +27,7 @@ void error_exit(const char *format, ...) __attribute__((noreturn));
|
||||
|
||||
#define ASSERT(_condition, _string, ...) while (!(_condition)) { FATAL_ERROR(_string, ##__VA_ARGS__); }
|
||||
|
||||
#define UNREACHABLE FATAL_ERROR("Cannot reach %s:%d", __func__, __LINE__);
|
||||
#define UNREACHABLE FATAL_ERROR("Should be unreachable");
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 7
|
||||
#define FALLTHROUGH __attribute__ ((fallthrough))
|
||||
|
||||
26
test/test_suite/bitstruct/invalid_bitstruct_member_types.c3
Normal file
26
test/test_suite/bitstruct/invalid_bitstruct_member_types.c3
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
bitstruct Test : int
|
||||
{
|
||||
bool x : 0..0;
|
||||
float a : 1..3; // #error: 'float' is not supported in a bitstruct, only enums, integer and boolean values may be used.
|
||||
}
|
||||
|
||||
define Baz = distinct float;
|
||||
define Foo = distinct bool;
|
||||
enum Boo
|
||||
{
|
||||
BAR
|
||||
}
|
||||
bitstruct Test2 : int
|
||||
{
|
||||
Foo x : 0..0;
|
||||
Boo y : 4..6;
|
||||
Baz a : 1..3; // #error: 'Baz' is not supported in a bitstruct, only enums, integer and boolean values may be used.
|
||||
}
|
||||
|
||||
|
||||
bitstruct Test3 : int
|
||||
{
|
||||
Foo x : 0..0;
|
||||
Brob a : 1..3; // #error: 'Brob' could not be found, did you spell it right?
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
bitstruct test : int // #error: Names of bitstructs must start with an upper case letter.
|
||||
{
|
||||
int a : 1..3;
|
||||
int b : 5..10;
|
||||
uint c : 20..20;
|
||||
}
|
||||
|
||||
bitstruct $if : int // #error: 'bitstruct' should be followed by the name of the bitstruct.
|
||||
{
|
||||
int a : 1..3;
|
||||
int b : 5..10;
|
||||
uint c : 20..20;
|
||||
}
|
||||
|
||||
bitstruct if : int // #error: Names of bitstructs must start with an upper case letter.
|
||||
{
|
||||
int a : 1..3;
|
||||
int b : 5..10;
|
||||
uint c : 20..20;
|
||||
}
|
||||
7
test/test_suite/bitstruct/invalid_bitstruct_type.c3
Normal file
7
test/test_suite/bitstruct/invalid_bitstruct_type.c3
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
bitstruct Test : float // #error: The type of the bitstruct cannot be 'float' but must be an integer or an array of integers.
|
||||
{
|
||||
int a : 1..3;
|
||||
int b : 5..10;
|
||||
uint c : 20..20;
|
||||
}
|
||||
@@ -12,125 +12,100 @@ func void test()
|
||||
|
||||
// #expect: else_checks.ll
|
||||
|
||||
define void @else_checks.test()
|
||||
; Function Attrs: nounwind
|
||||
declare i64 @testError(i32*) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @else_checks.test() #0 {
|
||||
entry:
|
||||
%x = alloca double, align 8
|
||||
%retparam = alloca i32, align 4
|
||||
%result = alloca %error_union, align 8
|
||||
%retparam1 = alloca i32, align 4
|
||||
%result2 = alloca %error_union, align 8
|
||||
%y = alloca double, align 8
|
||||
%retparam6 = alloca i32, align 4
|
||||
%result7 = alloca %error_union, align 8
|
||||
%retparam4 = alloca i32, align 4
|
||||
%z = alloca double, align 8
|
||||
%retparam15 = alloca i32, align 4
|
||||
%result16 = alloca %error_union, align 8
|
||||
%retparam11 = alloca i32, align 4
|
||||
%w = alloca double, align 8
|
||||
%retparam24 = alloca i32, align 4
|
||||
%result25 = alloca %error_union, align 8
|
||||
%retparam29 = alloca i32, align 4
|
||||
%result30 = alloca %error_union, align 8
|
||||
%0 = call { i64, i64 } @testError(i32* %retparam)
|
||||
%1 = bitcast %error_union* %result to { i64, i64 }*
|
||||
store { i64, i64 } %0, { i64, i64 }* %1, align 8
|
||||
%err_domain = getelementptr inbounds %error_union, %error_union* %result, i32 0, i32 0
|
||||
%2 = load i64, i64* %err_domain, align 8
|
||||
%not_err = icmp eq i64 %2, 0
|
||||
br i1 %not_err, label %after_check, label %else_block
|
||||
%retparam18 = alloca i32, align 4
|
||||
%retparam21 = alloca i32, align 4
|
||||
%0 = call i64 @testError(i32* %retparam)
|
||||
%not_err = icmp eq i64 %0, 0
|
||||
br i1 %not_err, label %after.errcheck, label %else_block
|
||||
|
||||
after_check:
|
||||
%3 = load i32, i32* %retparam, align 4
|
||||
%4 = call { i64, i64 } @testError(i32* %retparam1)
|
||||
%5 = bitcast %error_union* %result2 to { i64, i64 }*
|
||||
store { i64, i64 } %4, { i64, i64 }* %5, align 8
|
||||
%err_domain3 = getelementptr inbounds %error_union, %error_union* %result2, i32 0, i32 0
|
||||
%6 = load i64, i64* %err_domain3, align 8
|
||||
%not_err4 = icmp eq i64 %6, 0
|
||||
br i1 %not_err4, label %after_check5, label %else_block
|
||||
after.errcheck: ; preds = %entry
|
||||
%1 = load i32, i32* %retparam, align 4
|
||||
%2 = call i64 @testError(i32* %retparam1)
|
||||
%not_err2 = icmp eq i64 %2, 0
|
||||
br i1 %not_err2, label %after.errcheck3, label %else_block
|
||||
|
||||
after_check5:
|
||||
%7 = load i32, i32* %retparam1, align 4
|
||||
%add = add i32 %3, %7
|
||||
after.errcheck3: ; preds = %after.errcheck
|
||||
%3 = load i32, i32* %retparam1, align 4
|
||||
%add = add i32 %1, %3
|
||||
br label %phi_block
|
||||
|
||||
else_block:
|
||||
else_block: ; preds = %after.errcheck, %entry
|
||||
br label %phi_block
|
||||
|
||||
phi_block:
|
||||
%val = phi i32 [ %add, %after_check5 ], [ 100, %else_block ]
|
||||
phi_block: ; preds = %else_block, %after.errcheck3
|
||||
%val = phi i32 [ %add, %after.errcheck3 ], [ 100, %else_block ]
|
||||
%sifp = sitofp i32 %val to double
|
||||
store double %sifp, double* %x, align 8
|
||||
%8 = call { i64, i64 } @testError(i32* %retparam6)
|
||||
%9 = bitcast %error_union* %result7 to { i64, i64 }*
|
||||
store { i64, i64 } %8, { i64, i64 }* %9, align 8
|
||||
%err_domain8 = getelementptr inbounds %error_union, %error_union* %result7, i32 0, i32 0
|
||||
%10 = load i64, i64* %err_domain8, align 8
|
||||
%not_err9 = icmp eq i64 %10, 0
|
||||
br i1 %not_err9, label %after_check10, label %else_block11
|
||||
%4 = call i64 @testError(i32* %retparam4)
|
||||
%not_err5 = icmp eq i64 %4, 0
|
||||
br i1 %not_err5, label %after.errcheck6, label %else_block7
|
||||
|
||||
after_check10:
|
||||
%11 = load i32, i32* %retparam6, align 4
|
||||
%shl = shl i32 1, %11
|
||||
%12 = freeze i32 %shl
|
||||
br label %phi_block12
|
||||
after.errcheck6: ; preds = %phi_block
|
||||
%5 = load i32, i32* %retparam4, align 4
|
||||
%shl = shl i32 1, %5
|
||||
%6 = freeze i32 %shl
|
||||
br label %phi_block8
|
||||
|
||||
else_block11:
|
||||
br label %phi_block12
|
||||
else_block7: ; preds = %phi_block
|
||||
br label %phi_block8
|
||||
|
||||
phi_block12:
|
||||
%val13 = phi i32 [ %12, %after_check10 ], [ 100, %else_block11 ]
|
||||
%sifp14 = sitofp i32 %val13 to double
|
||||
store double %sifp14, double* %y, align 8
|
||||
%13 = call { i64, i64 } @testError(i32* %retparam15)
|
||||
%14 = bitcast %error_union* %result16 to { i64, i64 }*
|
||||
store { i64, i64 } %13, { i64, i64 }* %14, align 8
|
||||
%err_domain17 = getelementptr inbounds %error_union, %error_union* %result16, i32 0, i32 0
|
||||
%15 = load i64, i64* %err_domain17, align 8
|
||||
%not_err18 = icmp eq i64 %15, 0
|
||||
br i1 %not_err18, label %after_check19, label %else_block20
|
||||
phi_block8: ; preds = %else_block7, %after.errcheck6
|
||||
%val9 = phi i32 [ %6, %after.errcheck6 ], [ 100, %else_block7 ]
|
||||
%sifp10 = sitofp i32 %val9 to double
|
||||
store double %sifp10, double* %y, align 8
|
||||
%7 = call i64 @testError(i32* %retparam11)
|
||||
%not_err12 = icmp eq i64 %7, 0
|
||||
br i1 %not_err12, label %after.errcheck13, label %else_block14
|
||||
|
||||
after_check19:
|
||||
%16 = load i32, i32* %retparam15, align 4
|
||||
%ashr = ashr i32 %16, 1
|
||||
%17 = freeze i32 %ashr
|
||||
br label %phi_block21
|
||||
after.errcheck13: ; preds = %phi_block8
|
||||
%8 = load i32, i32* %retparam11, align 4
|
||||
%ashr = ashr i32 %8, 1
|
||||
%9 = freeze i32 %ashr
|
||||
br label %phi_block15
|
||||
|
||||
else_block20:
|
||||
br label %phi_block21
|
||||
else_block14: ; preds = %phi_block8
|
||||
br label %phi_block15
|
||||
|
||||
phi_block21:
|
||||
%val22 = phi i32 [ %17, %after_check19 ], [ 100, %else_block20 ]
|
||||
%sifp23 = sitofp i32 %val22 to double
|
||||
store double %sifp23, double* %z, align 8
|
||||
%18 = call { i64, i64 } @testError(i32* %retparam24)
|
||||
%19 = bitcast %error_union* %result25 to { i64, i64 }*
|
||||
store { i64, i64 } %18, { i64, i64 }* %19, align 8
|
||||
%err_domain26 = getelementptr inbounds %error_union, %error_union* %result25, i32 0, i32 0
|
||||
%20 = load i64, i64* %err_domain26, align 8
|
||||
%not_err27 = icmp eq i64 %20, 0
|
||||
br i1 %not_err27, label %after_check28, label %else_block34
|
||||
phi_block15: ; preds = %else_block14, %after.errcheck13
|
||||
%val16 = phi i32 [ %9, %after.errcheck13 ], [ 100, %else_block14 ]
|
||||
%sifp17 = sitofp i32 %val16 to double
|
||||
store double %sifp17, double* %z, align 8
|
||||
%10 = call i64 @testError(i32* %retparam18)
|
||||
%not_err19 = icmp eq i64 %10, 0
|
||||
br i1 %not_err19, label %after.errcheck20, label %else_block24
|
||||
|
||||
after_check28:
|
||||
%21 = load i32, i32* %retparam24, align 4
|
||||
%22 = call { i64, i64 } @testError(i32* %retparam29)
|
||||
%23 = bitcast %error_union* %result30 to { i64, i64 }*
|
||||
store { i64, i64 } %22, { i64, i64 }* %23, align 8
|
||||
%err_domain31 = getelementptr inbounds %error_union, %error_union* %result30, i32 0, i32 0
|
||||
%24 = load i64, i64* %err_domain31, align 8
|
||||
%not_err32 = icmp eq i64 %24, 0
|
||||
br i1 %not_err32, label %after_check33, label %else_block34
|
||||
after.errcheck20: ; preds = %phi_block15
|
||||
%11 = load i32, i32* %retparam18, align 4
|
||||
%12 = call i64 @testError(i32* %retparam21)
|
||||
%not_err22 = icmp eq i64 %12, 0
|
||||
br i1 %not_err22, label %after.errcheck23, label %else_block24
|
||||
|
||||
after_check33:
|
||||
%25 = load i32, i32* %retparam29, align 4
|
||||
%mul = mul i32 %21, %25
|
||||
br label %phi_block35
|
||||
after.errcheck23: ; preds = %after.errcheck20
|
||||
%13 = load i32, i32* %retparam21, align 4
|
||||
%mul = mul i32 %11, %13
|
||||
br label %phi_block25
|
||||
|
||||
else_block34:
|
||||
br label %phi_block35
|
||||
else_block24: ; preds = %after.errcheck20, %phi_block15
|
||||
br label %phi_block25
|
||||
|
||||
phi_block35:
|
||||
%val36 = phi i32 [ %mul, %after_check33 ], [ 100, %else_block34 ]
|
||||
%sifp37 = sitofp i32 %val36 to double
|
||||
store double %sifp37, double* %w, align 8
|
||||
phi_block25: ; preds = %else_block24, %after.errcheck23
|
||||
%val26 = phi i32 [ %mul, %after.errcheck23 ], [ 100, %else_block24 ]
|
||||
%sifp27 = sitofp i32 %val26 to double
|
||||
store double %sifp27, double* %w, align 8
|
||||
ret void
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
module foo;
|
||||
|
||||
|
||||
|
||||
errtype TheError
|
||||
{
|
||||
union // #error: A type name was expected here
|
||||
{
|
||||
int a;
|
||||
int b;
|
||||
}
|
||||
}
|
||||
@@ -2,19 +2,18 @@ module errors;
|
||||
|
||||
errtype TheError
|
||||
{
|
||||
int a;
|
||||
A
|
||||
}
|
||||
|
||||
errtype TheError2
|
||||
{
|
||||
char a;
|
||||
char b;
|
||||
A,
|
||||
B
|
||||
}
|
||||
|
||||
errtype TheError3
|
||||
{
|
||||
void *a;
|
||||
C, D
|
||||
}
|
||||
|
||||
errtype OtherError;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
errtype TooBig // #error: Error type may not exceed pointer
|
||||
errtype Repeater
|
||||
{
|
||||
usize a;
|
||||
ichar b;
|
||||
A,
|
||||
A // #error: This enum constant is declared twice.
|
||||
}
|
||||
|
||||
@@ -2,10 +2,11 @@ module foo;
|
||||
|
||||
errtype Blurg
|
||||
{
|
||||
Z
|
||||
}
|
||||
|
||||
func void main()
|
||||
{
|
||||
int! i = Blurg!;
|
||||
int! j = Blurg({})!;
|
||||
int! i = Blurg.Z!;
|
||||
int! j = Blurg.Z!;
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
module foo;
|
||||
|
||||
errtype Blurg;
|
||||
errtype Blurg
|
||||
{
|
||||
X, Y, Z
|
||||
}
|
||||
|
||||
func void main()
|
||||
{
|
||||
|
||||
147
test/test_suite/errors/general_error_regression.c3t
Normal file
147
test/test_suite/errors/general_error_regression.c3t
Normal file
@@ -0,0 +1,147 @@
|
||||
module foo;
|
||||
import std::io;
|
||||
|
||||
errtype Foo
|
||||
{
|
||||
X,
|
||||
Y,
|
||||
Z,
|
||||
W,
|
||||
W1
|
||||
|
||||
|
||||
}
|
||||
|
||||
errtype Foob
|
||||
{
|
||||
X1,
|
||||
Y2
|
||||
}
|
||||
|
||||
define Bar = distinct int;
|
||||
|
||||
enum MyEnum
|
||||
{
|
||||
A,
|
||||
B
|
||||
}
|
||||
|
||||
func void Foo.hello(Foo *f)
|
||||
{
|
||||
io::println("Hello from Foo");
|
||||
}
|
||||
|
||||
func void Bar.hello(Bar *b)
|
||||
{
|
||||
io::println("Hello from Bar");
|
||||
}
|
||||
|
||||
func void MyEnum.hello(MyEnum *myenum)
|
||||
{
|
||||
io::println("Hello from MyEnum");
|
||||
}
|
||||
func void main()
|
||||
{
|
||||
Foo f = Foo.X;
|
||||
Foo ef = Foo.Y;
|
||||
anyerr x = f;
|
||||
ulong z = (ulong)(x);
|
||||
io::printf("1: %p\n", z);
|
||||
x = ef;
|
||||
z = (ulong)(x);
|
||||
io::printf("2: %p\n", z);
|
||||
x = Foo.W;
|
||||
z = (ulong)(x);
|
||||
io::printf("21: %p\n", z);
|
||||
x = Foo.W1;
|
||||
z = (ulong)(x);
|
||||
io::printf("22: %p\n", z);
|
||||
x = Foob.X1;
|
||||
z = (ulong)(x);
|
||||
io::printf("3: %p\n", z);
|
||||
x = Foob.Y2;
|
||||
z = (ulong)(x);
|
||||
io::printf("4: %p\n", z);
|
||||
Bar b;
|
||||
MyEnum a = MyEnum.A;
|
||||
f.hello();
|
||||
b.hello();
|
||||
a.hello();
|
||||
}
|
||||
|
||||
// #expect: foo.ll
|
||||
|
||||
define void @foo.Foo__hello(i64* %0) #0 {
|
||||
entry:
|
||||
%f = alloca i64*, align 8
|
||||
store i64* %0, i64** %f, align 8
|
||||
%1 = call i32 @"std::io.println"(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.6, i32 0, i32 0)) #1
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @foo.Bar__hello(i32* %0) #0 {
|
||||
entry:
|
||||
%b = alloca i32*, align 8
|
||||
store i32* %0, i32** %b, align 8
|
||||
%1 = call i32 @"std::io.println"(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.7, i32 0, i32 0)) #1
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @foo.MyEnum__hello(i32* %0) #0 {
|
||||
entry:
|
||||
%myenum = alloca i32*, align 8
|
||||
store i32* %0, i32** %myenum, align 8
|
||||
%1 = call i32 @"std::io.println"(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.8, i32 0, i32 0)) #1
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @main() #0 {
|
||||
entry:
|
||||
%f = alloca i64, align 8
|
||||
%ef = alloca i64, align 8
|
||||
%x = alloca i64, align 8
|
||||
%z = alloca i64, align 8
|
||||
%b = alloca i32, align 4
|
||||
%a = alloca i32, align 4
|
||||
store i64 ptrtoint ([5 x i8*]* @"foo.Foo$elements" to i64), i64* %f, align 8
|
||||
store i64 ptrtoint ([5 x i8*]* getelementptr inbounds ([5 x i8*], [5 x i8*]* @"foo.Foo$elements", i64 1) to i64), i64* %ef, align 8
|
||||
%0 = load i64, i64* %f, align 8
|
||||
store i64 %0, i64* %x, align 8
|
||||
%1 = load i64, i64* %x, align 8
|
||||
store i64 %1, i64* %z, align 8
|
||||
%2 = load i64, i64* %z, align 8
|
||||
%3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str, i32 0, i32 0), i64 %2)
|
||||
%4 = load i64, i64* %ef, align 8
|
||||
store i64 %4, i64* %x, align 8
|
||||
%5 = load i64, i64* %x, align 8
|
||||
store i64 %5, i64* %z, align 8
|
||||
%6 = load i64, i64* %z, align 8
|
||||
%7 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.1, i32 0, i32 0), i64 %6)
|
||||
store i64 ptrtoint ([5 x i8*]* getelementptr inbounds ([5 x i8*], [5 x i8*]* @"foo.Foo$elements", i64 3) to i64), i64* %x, align 8
|
||||
%8 = load i64, i64* %x, align 8
|
||||
store i64 %8, i64* %z, align 8
|
||||
%9 = load i64, i64* %z, align 8
|
||||
%10 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.2, i32 0, i32 0), i64 %9)
|
||||
store i64 ptrtoint ([5 x i8*]* getelementptr inbounds ([5 x i8*], [5 x i8*]* @"foo.Foo$elements", i64 4) to i64), i64* %x, align 8
|
||||
%11 = load i64, i64* %x, align 8
|
||||
store i64 %11, i64* %z, align 8
|
||||
%12 = load i64, i64* %z, align 8
|
||||
%13 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.3, i32 0, i32 0), i64 %12)
|
||||
store i64 ptrtoint ([2 x i8*]* @"foo.Foob$elements" to i64), i64* %x, align 8
|
||||
%14 = load i64, i64* %x, align 8
|
||||
store i64 %14, i64* %z, align 8
|
||||
%15 = load i64, i64* %z, align 8
|
||||
%16 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.4, i32 0, i32 0), i64 %15)
|
||||
store i64 ptrtoint ([2 x i8*]* getelementptr inbounds ([2 x i8*], [2 x i8*]* @"foo.Foob$elements", i64 1) to i64), i64* %x, align 8
|
||||
%17 = load i64, i64* %x, align 8
|
||||
store i64 %17, i64* %z, align 8
|
||||
%18 = load i64, i64* %z, align 8
|
||||
%19 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.5, i32 0, i32 0), i64 %18)
|
||||
store i32 0, i32* %b, align 4
|
||||
store i32 0, i32* %a, align 4
|
||||
call void @foo.Foo__hello(i64* %f)
|
||||
call void @foo.Bar__hello(i32* %b)
|
||||
call void @foo.MyEnum__hello(i32* %a)
|
||||
ret void
|
||||
}
|
||||
|
||||
@@ -8,42 +8,27 @@ func void! test()
|
||||
|
||||
// #expect: rethrow.ll
|
||||
|
||||
entry:
|
||||
%i = alloca i32, align 4
|
||||
%i.f = alloca %error_union, align 8
|
||||
%error_var = alloca %error_union, align 8
|
||||
%tempcoerce = alloca { i64, i64 }, align 8
|
||||
%tempaddr = alloca %error_union, align 8
|
||||
%tempcoerce1 = alloca { i64, i64 }, align 8
|
||||
store %error_union zeroinitializer, %error_union* %i.f, align 8
|
||||
%i = alloca i32, align 4
|
||||
%i.f = alloca i64, align 8
|
||||
%error_var = alloca i64, align 8
|
||||
store i64 0, i64* %i.f, align 8
|
||||
store i32 0, i32* %i, align 4
|
||||
%err_domain = getelementptr inbounds %error_union, %error_union* %i.f, i32 0, i32 0
|
||||
%0 = load i64, i64* %err_domain, align 8
|
||||
%0 = load i64, i64* %i.f, align 8
|
||||
%not_err = icmp eq i64 %0, 0
|
||||
br i1 %not_err, label %after_check, label %error
|
||||
|
||||
error:
|
||||
%1 = bitcast %error_union* %error_var to i8*
|
||||
%2 = bitcast %error_union* %i.f to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %1, i8* align 8 %2, i32 16, i1 false)
|
||||
error: ; preds = %entry
|
||||
store i64 %0, i64* %error_var, align 8
|
||||
br label %guard_block
|
||||
|
||||
after_check:
|
||||
%3 = load i32, i32* %i, align 4
|
||||
after_check: ; preds = %entry
|
||||
%1 = load i32, i32* %i, align 4
|
||||
br label %noerr_block
|
||||
|
||||
guard_block: ; preds = %error
|
||||
%4 = bitcast { i64, i64 }* %tempcoerce to i8*
|
||||
%5 = bitcast %error_union* %error_var to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %4, i8* align 8 %5, i32 16, i1 false)
|
||||
%6 = load { i64, i64 }, { i64, i64 }* %tempcoerce, align 8
|
||||
ret { i64, i64 } %6
|
||||
%2 = load i64, i64* %error_var, align 8
|
||||
ret i64 %2
|
||||
|
||||
noerr_block: ; preds = %after_check
|
||||
store %error_union zeroinitializer, %error_union* %tempaddr, align 8
|
||||
%7 = bitcast { i64, i64 }* %tempcoerce1 to i8*
|
||||
%8 = bitcast %error_union* %tempaddr to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %7, i8* align 8 %8, i32 16, i1 false)
|
||||
%9 = load { i64, i64 }, { i64, i64 }* %tempcoerce1, align 8
|
||||
ret { i64, i64 } %9
|
||||
}
|
||||
ret i64 0
|
||||
}
|
||||
|
||||
@@ -10,35 +10,31 @@ func void! test()
|
||||
|
||||
// #expect: rethrow.ll
|
||||
|
||||
define void @rethrow.test(%error_union* sret align 8 %0)
|
||||
define i64 @rethrow.test() #0 {
|
||||
entry:
|
||||
%i = alloca i32, align 4
|
||||
%i.f = alloca %error_union, align 8
|
||||
%error_var = alloca %error_union, align 8
|
||||
store %error_union zeroinitializer, %error_union* %i.f, align 8
|
||||
%i.f = alloca i64, align 8
|
||||
%error_var = alloca i64, align 8
|
||||
store i64 0, i64* %i.f, align 8
|
||||
store i32 0, i32* %i, align 4
|
||||
%err_domain = getelementptr inbounds %error_union, %error_union* %i.f, i32 0, i32 0
|
||||
%1 = load i64, i64* %err_domain, align 8
|
||||
%not_err = icmp eq i64 %1, 0
|
||||
%0 = load i64, i64* %i.f, align 8
|
||||
%not_err = icmp eq i64 %0, 0
|
||||
br i1 %not_err, label %after_check, label %error
|
||||
|
||||
error:
|
||||
%2 = bitcast %error_union* %error_var to i8*
|
||||
%3 = bitcast %error_union* %i.f to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %2, i8* align 8 %3, i32 16, i1 false)
|
||||
error: ; preds = %entry
|
||||
store i64 %0, i64* %error_var, align 8
|
||||
br label %guard_block
|
||||
|
||||
after_check:
|
||||
%4 = load i32, i32* %i, align 4
|
||||
after_check: ; preds = %entry
|
||||
%1 = load i32, i32* %i, align 4
|
||||
br label %noerr_block
|
||||
|
||||
guard_block:
|
||||
%5 = bitcast %error_union* %0 to i8*
|
||||
%6 = bitcast %error_union* %error_var to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %5, i8* align 8 %6, i32 16, i1 false)
|
||||
ret void
|
||||
guard_block: ; preds = %error
|
||||
%2 = load i64, i64* %error_var, align 8
|
||||
ret i64 %2
|
||||
|
||||
noerr_block: ; preds = %after_check
|
||||
ret i64 0
|
||||
}
|
||||
|
||||
noerr_block:
|
||||
store %error_union zeroinitializer, %error_union* %0, align 8
|
||||
ret void
|
||||
|
||||
|
||||
@@ -2,33 +2,26 @@
|
||||
|
||||
module foo;
|
||||
|
||||
errtype Blurg;
|
||||
errtype Blurg
|
||||
{
|
||||
Y
|
||||
}
|
||||
|
||||
func void main()
|
||||
{
|
||||
static int! x = 120;
|
||||
int! i = Blurg!;
|
||||
int! i = Blurg.Y!;
|
||||
}
|
||||
|
||||
// #expect: foo.ll
|
||||
|
||||
%error_union = type { i64, i64 }
|
||||
%Blurg = type { [8 x i8] }
|
||||
|
||||
@Blurg = linkonce_odr constant i8 1
|
||||
@main.x.f = hidden global %error_union zeroinitializer, align 8
|
||||
@main.x = hidden global i32 120, align 4
|
||||
|
||||
define void @main()
|
||||
define void @main() #0 {
|
||||
entry:
|
||||
%i = alloca i32, align 4
|
||||
%i.f = alloca %error_union, align 8
|
||||
%literal = alloca %Blurg, align 8
|
||||
%0 = bitcast %Blurg* %literal to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
|
||||
%1 = load %Blurg, %Blurg* %literal, align 8
|
||||
%2 = bitcast %error_union* %i.f to %Blurg*
|
||||
store %Blurg %1, %Blurg* %2, align 1
|
||||
%i.f = alloca i64, align 8
|
||||
store i64 ptrtoint ([1 x i8*]* @"foo.Blurg$elements" to i64), i64* %i.f, align 8
|
||||
br label %after_assign
|
||||
|
||||
after_assign:
|
||||
after_assign: ; preds = %entry
|
||||
ret void
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// #target: x64-darwin
|
||||
|
||||
extern func int! err();
|
||||
errtype FooErr { int x; }
|
||||
errtype FooErr { QBERT }
|
||||
extern func int printf(char* fmt, ...);
|
||||
|
||||
func void main()
|
||||
@@ -10,7 +10,7 @@ func void main()
|
||||
int! z = 234;
|
||||
int! w;
|
||||
int gh = 1;
|
||||
if ((try x = z) && (try gh = w))
|
||||
if (try x = z && try gh = w)
|
||||
{
|
||||
printf("Success %d && %d!\n", x, gh);
|
||||
}
|
||||
@@ -27,123 +27,126 @@ func void main()
|
||||
|
||||
// #expect: try_assign.ll
|
||||
|
||||
define void @main() #0 {
|
||||
entry:
|
||||
%x = alloca i32, align 4
|
||||
%z = alloca i32, align 4
|
||||
%z.f = alloca %error_union, align 8
|
||||
%z.f = alloca i64, align 8
|
||||
%w = alloca i32, align 4
|
||||
%w.f = alloca %error_union, align 8
|
||||
%w.f = alloca i64, align 8
|
||||
%gh = alloca i32, align 4
|
||||
%e = alloca %error_union, align 8
|
||||
%e = alloca i64, align 8
|
||||
store i32 123, i32* %x, align 4
|
||||
store %error_union zeroinitializer, %error_union* %z.f, align 8
|
||||
store i64 0, i64* %z.f, align 8
|
||||
store i32 234, i32* %z, align 4
|
||||
store %error_union zeroinitializer, %error_union* %z.f, align 8
|
||||
store %error_union zeroinitializer, %error_union* %w.f, align 8
|
||||
store i64 0, i64* %z.f, align 8
|
||||
store i64 0, i64* %w.f, align 8
|
||||
store i32 0, i32* %w, align 4
|
||||
store i32 1, i32* %gh, align 4
|
||||
%err_domain = getelementptr inbounds %error_union, %error_union* %z.f, i32 0, i32 0
|
||||
%0 = load i64, i64* %err_domain, align 8
|
||||
%0 = load i64, i64* %z.f, align 8
|
||||
%not_err = icmp eq i64 %0, 0
|
||||
br i1 %not_err, label %after_check, label %catch_landing
|
||||
|
||||
after_check:
|
||||
after_check: ; preds = %entry
|
||||
%1 = load i32, i32* %z, align 4
|
||||
store i32 %1, i32* %x, align 4
|
||||
br label %phi_try_catch
|
||||
|
||||
catch_landing:
|
||||
catch_landing: ; preds = %entry
|
||||
br label %phi_try_catch
|
||||
|
||||
phi_try_catch:
|
||||
phi_try_catch: ; preds = %catch_landing, %after_check
|
||||
%val = phi i1 [ true, %after_check ], [ false, %catch_landing ]
|
||||
br i1 %val, label %and.rhs, label %and.phi
|
||||
br i1 %val, label %chain_next, label %fail_chain
|
||||
|
||||
and.rhs:
|
||||
%err_domain1 = getelementptr inbounds %error_union, %error_union* %w.f, i32 0, i32 0
|
||||
%2 = load i64, i64* %err_domain1, align 8
|
||||
%not_err2 = icmp eq i64 %2, 0
|
||||
br i1 %not_err2, label %after_check3, label %catch_landing4
|
||||
chain_next: ; preds = %phi_try_catch
|
||||
%2 = load i64, i64* %w.f, align 8
|
||||
%not_err1 = icmp eq i64 %2, 0
|
||||
br i1 %not_err1, label %after_check2, label %catch_landing3
|
||||
|
||||
after_check3:
|
||||
after_check2: ; preds = %chain_next
|
||||
%3 = load i32, i32* %w, align 4
|
||||
store i32 %3, i32* %gh, align 4
|
||||
br label %phi_try_catch5
|
||||
br label %phi_try_catch4
|
||||
|
||||
catch_landing4:
|
||||
br label %phi_try_catch5
|
||||
catch_landing3: ; preds = %chain_next
|
||||
br label %phi_try_catch4
|
||||
|
||||
phi_try_catch5:
|
||||
%val6 = phi i1 [ true, %after_check3 ], [ false, %catch_landing4 ]
|
||||
br label %and.phi
|
||||
phi_try_catch4: ; preds = %catch_landing3, %after_check2
|
||||
%val5 = phi i1 [ true, %after_check2 ], [ false, %catch_landing3 ]
|
||||
br i1 %val5, label %chain_next6, label %fail_chain
|
||||
|
||||
and.phi:
|
||||
%val7 = phi i1 [ false, %phi_try_catch ], [ %val6, %phi_try_catch5 ]
|
||||
br i1 %val7, label %if.then, label %if.exit
|
||||
chain_next6: ; preds = %phi_try_catch4
|
||||
br label %end_chain
|
||||
|
||||
if.then:
|
||||
fail_chain: ; preds = %phi_try_catch4, %phi_try_catch
|
||||
br label %end_chain
|
||||
|
||||
end_chain: ; preds = %fail_chain, %chain_next6
|
||||
%chain.phi = phi i1 [ true, %chain_next6 ], [ false, %fail_chain ]
|
||||
br i1 %chain.phi, label %if.then, label %if.exit
|
||||
|
||||
if.then: ; preds = %end_chain
|
||||
%4 = load i32, i32* %x, align 4
|
||||
%5 = load i32, i32* %gh, align 4
|
||||
%6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([19 x i8], [19 x i8]* @.str, i32 0, i32 0), i32 %4, i32 %5)
|
||||
br label %if.exit
|
||||
|
||||
if.exit:
|
||||
%err_domain8 = getelementptr inbounds %error_union, %error_union* %z.f, i32 0, i32 0
|
||||
%7 = load i64, i64* %err_domain8, align 8
|
||||
%not_err9 = icmp eq i64 %7, 0
|
||||
br i1 %not_err9, label %after_check10, label %catch_landing14
|
||||
if.exit: ; preds = %if.then, %end_chain
|
||||
%7 = load i64, i64* %z.f, align 8
|
||||
%not_err7 = icmp eq i64 %7, 0
|
||||
br i1 %not_err7, label %after_check8, label %catch_landing11
|
||||
|
||||
after_check10:
|
||||
after_check8: ; preds = %if.exit
|
||||
%8 = load i32, i32* %z, align 4
|
||||
%err_domain11 = getelementptr inbounds %error_union, %error_union* %w.f, i32 0, i32 0
|
||||
%9 = load i64, i64* %err_domain11, align 8
|
||||
%not_err12 = icmp eq i64 %9, 0
|
||||
br i1 %not_err12, label %after_check13, label %catch_landing14
|
||||
%9 = load i64, i64* %w.f, align 8
|
||||
%not_err9 = icmp eq i64 %9, 0
|
||||
br i1 %not_err9, label %after_check10, label %catch_landing11
|
||||
|
||||
after_check13:
|
||||
after_check10: ; preds = %after_check8
|
||||
%10 = load i32, i32* %w, align 4
|
||||
%add = add i32 %8, %10
|
||||
store i32 %add, i32* %x, align 4
|
||||
br label %phi_try_catch15
|
||||
br label %phi_try_catch12
|
||||
|
||||
catch_landing14:
|
||||
br label %phi_try_catch15
|
||||
catch_landing11: ; preds = %after_check8, %if.exit
|
||||
br label %phi_try_catch12
|
||||
|
||||
phi_try_catch15:
|
||||
%val16 = phi i1 [ true, %after_check13 ], [ false, %catch_landing14 ]
|
||||
br i1 %val16, label %if.then17, label %if.exit18
|
||||
phi_try_catch12: ; preds = %catch_landing11, %after_check10
|
||||
%val13 = phi i1 [ true, %after_check10 ], [ false, %catch_landing11 ]
|
||||
br i1 %val13, label %if.then14, label %if.exit15
|
||||
|
||||
if.then17:
|
||||
if.then14: ; preds = %phi_try_catch12
|
||||
%11 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0))
|
||||
br label %if.exit18
|
||||
br label %if.exit15
|
||||
|
||||
if.exit18:
|
||||
%12 = bitcast %error_union* %e to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 8 %12, i8 0, i64 16, i1 false)
|
||||
%err_domain19 = getelementptr inbounds %error_union, %error_union* %z.f, i32 0, i32 0
|
||||
%13 = load i64, i64* %err_domain19, align 8
|
||||
%not_err20 = icmp eq i64 %13, 0
|
||||
br i1 %not_err20, label %after_check21, label %error
|
||||
if.exit15: ; preds = %if.then14, %phi_try_catch12
|
||||
store i64 0, i64* %e, align 8
|
||||
br label %testblock
|
||||
|
||||
error:
|
||||
%14 = bitcast %error_union* %e to i8*
|
||||
%15 = bitcast %error_union* %z.f to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %14, i8* align 8 %15, i32 16, i1 false)
|
||||
br label %catch_landing22
|
||||
testblock: ; preds = %if.exit15
|
||||
%12 = load i64, i64* %z.f, align 8
|
||||
%not_err16 = icmp eq i64 %12, 0
|
||||
br i1 %not_err16, label %after_check17, label %error
|
||||
|
||||
after_check21:
|
||||
br label %phi_try_catch23
|
||||
error: ; preds = %testblock
|
||||
store i64 %12, i64* %e, align 8
|
||||
br label %end_block
|
||||
|
||||
catch_landing22:
|
||||
br label %phi_try_catch23
|
||||
after_check17: ; preds = %testblock
|
||||
store i64 0, i64* %e, align 8
|
||||
br label %end_block
|
||||
|
||||
phi_try_catch23:
|
||||
%val24 = phi i1 [ false, %after_check21 ], [ true, %catch_landing22 ]
|
||||
br i1 %val24, label %if.then25, label %if.exit26
|
||||
end_block: ; preds = %after_check17, %error
|
||||
%13 = load i64, i64* %e, align 8
|
||||
%intbool = icmp ne i64 %13, 0
|
||||
br i1 %intbool, label %if.then18, label %if.exit19
|
||||
|
||||
if.then25:
|
||||
%16 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.2, i32 0, i32 0))
|
||||
br label %if.exit26
|
||||
if.then18: ; preds = %end_block
|
||||
%14 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.2, i32 0, i32 0))
|
||||
br label %if.exit19
|
||||
|
||||
if.exit26:
|
||||
if.exit19: ; preds = %if.then18, %end_block
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
99
test/test_suite/errors/try_catch_if.c3t
Normal file
99
test/test_suite/errors/try_catch_if.c3t
Normal file
@@ -0,0 +1,99 @@
|
||||
// #target: x64-darwin
|
||||
|
||||
func int hello(int x)
|
||||
{
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
extern func int printf(char *c, ...);
|
||||
|
||||
func int! tester()
|
||||
{
|
||||
printf("In tester\n");
|
||||
return 222;
|
||||
}
|
||||
|
||||
errtype Foo
|
||||
{
|
||||
A
|
||||
}
|
||||
func void test1()
|
||||
{
|
||||
int! a = 123;
|
||||
if (catch err = (a, tester()))
|
||||
{
|
||||
printf("Err\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Noerr %d\n", a);
|
||||
}
|
||||
}
|
||||
func void main()
|
||||
{
|
||||
test1();
|
||||
}
|
||||
|
||||
// #expect: try_catch_if.ll
|
||||
|
||||
define i64 @try_catch_if.tester(i32* %0) #0 {
|
||||
entry:
|
||||
%reterr = alloca i64, align 8
|
||||
%1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i32 0, i32 0))
|
||||
store i32 222, i32* %0, align 4
|
||||
ret i64 0
|
||||
}
|
||||
|
||||
define void @try_catch_if.test1() #0 {
|
||||
entry:
|
||||
%a = alloca i32, align 4
|
||||
%a.f = alloca i64, align 8
|
||||
%err = alloca i64, align 8
|
||||
%retparam = alloca i32, align 4
|
||||
store i64 0, i64* %a.f, align 8
|
||||
store i32 123, i32* %a, align 4
|
||||
store i64 0, i64* %a.f, align 8
|
||||
br label %testblock
|
||||
|
||||
testblock: ; preds = %entry
|
||||
%0 = load i64, i64* %a.f, align 8
|
||||
%not_err = icmp eq i64 %0, 0
|
||||
br i1 %not_err, label %after_check, label %error
|
||||
|
||||
error: ; preds = %testblock
|
||||
store i64 %0, i64* %err, align 8
|
||||
br label %end_block
|
||||
|
||||
after_check: ; preds = %testblock
|
||||
br label %testblock1
|
||||
|
||||
testblock1: ; preds = %after_check
|
||||
%1 = call i64 @try_catch_if.tester(i32* %retparam)
|
||||
%not_err2 = icmp eq i64 %1, 0
|
||||
br i1 %not_err2, label %after.errcheck, label %error3
|
||||
|
||||
error3: ; preds = %testblock1
|
||||
store i64 %1, i64* %err, align 8
|
||||
br label %end_block
|
||||
|
||||
after.errcheck: ; preds = %testblock1
|
||||
store i64 0, i64* %err, align 8
|
||||
br label %end_block
|
||||
|
||||
end_block: ; preds = %after.errcheck, %error3, %error
|
||||
%2 = load i64, i64* %err, align 8
|
||||
%intbool = icmp ne i64 %2, 0
|
||||
br i1 %intbool, label %if.then, label %if.else
|
||||
|
||||
if.then: ; preds = %end_block
|
||||
%3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i32 0, i32 0))
|
||||
br label %if.exit
|
||||
|
||||
if.else: ; preds = %end_block
|
||||
%4 = load i32, i32* %a, align 4
|
||||
%5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.2, i32 0, i32 0), i32 %4)
|
||||
br label %if.exit
|
||||
|
||||
if.exit: ; preds = %if.else, %if.then
|
||||
ret void
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
|
||||
extern func int printf(char* fmt, ...);
|
||||
|
||||
extern func int! err();
|
||||
errtype FooErr { int x; }
|
||||
errtype FooErr
|
||||
{
|
||||
X
|
||||
}
|
||||
func void test1()
|
||||
{
|
||||
int! z = 234;
|
||||
@@ -10,35 +12,16 @@ func void test1()
|
||||
{
|
||||
int y = z;
|
||||
z = 12;
|
||||
z = FooErr({1})!; // #error: The variable is unwrapped in this context
|
||||
z = FooErr.X!; // #error: The variable is unwrapped in this context
|
||||
}
|
||||
}
|
||||
|
||||
func void test2()
|
||||
{
|
||||
int! z = 234;
|
||||
if (try z || 1)
|
||||
{
|
||||
z = 12;
|
||||
z = FooErr({1})!;
|
||||
}
|
||||
}
|
||||
func void test3()
|
||||
{
|
||||
int! z = 234;
|
||||
int! w = 123;
|
||||
if (try z || try w)
|
||||
{
|
||||
int y = z; // #error: 'int!' cannot be converted into 'int'
|
||||
y = w;
|
||||
}
|
||||
}
|
||||
|
||||
func void test4()
|
||||
{
|
||||
int! z = 234;
|
||||
int! w = 123;
|
||||
if (try z && ((try w) && 1))
|
||||
if (try z && try w && 1)
|
||||
{
|
||||
int y = z;
|
||||
y = w;
|
||||
@@ -49,7 +32,16 @@ func void test5()
|
||||
{
|
||||
int! z = 234;
|
||||
int! w = 123;
|
||||
if (try z && try z)
|
||||
if (try z && try w)
|
||||
{
|
||||
int y = z;
|
||||
}
|
||||
}
|
||||
func void test5b()
|
||||
{
|
||||
int! z = 234;
|
||||
int! w = 123;
|
||||
if (try z && try z) // #error: This variable is already unwrapped, so you cannot use 'try' on it again, please remove the 'try'.
|
||||
{
|
||||
int y = z;
|
||||
}
|
||||
@@ -83,12 +75,12 @@ func void test8()
|
||||
{
|
||||
int! z = 234;
|
||||
int! w = 123;
|
||||
if (catch z && 1)
|
||||
if (catch z)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
int y = z; // #error: 'int!' cannot be converted into 'int'
|
||||
int y = z;
|
||||
}
|
||||
}
|
||||
func void test9()
|
||||
|
||||
@@ -2,13 +2,5 @@ func void test()
|
||||
{
|
||||
int! z;
|
||||
int! w;
|
||||
try w = z; // #error: A 'try' assignment is not possible with failable on the left hand side, did you intend 'try (variable = expr)
|
||||
try w = z; // #error: An unwrapping 'try' can only occur as the last element of a conditional, did you want 'try(expr)
|
||||
}
|
||||
|
||||
func int! err();
|
||||
func void test2()
|
||||
{
|
||||
int! z;
|
||||
int! w;
|
||||
try err() = z; // #error: This expression is not assignable, did you make a mistake
|
||||
}
|
||||
@@ -23,45 +23,35 @@ entry:
|
||||
%val = alloca i32, align 4
|
||||
%retparam = alloca i32, align 4
|
||||
%retparam1 = alloca i8*, align 8
|
||||
%result = alloca %error_union, align 8
|
||||
%result2 = alloca %error_union, align 8
|
||||
store i32 0, i32* %val, align 4
|
||||
%0 = call { i64, i64 } @readLine(i8** %retparam1)
|
||||
%1 = bitcast %error_union* %result to { i64, i64 }*
|
||||
store { i64, i64 } %0, { i64, i64 }* %1, align 8
|
||||
%err_domain = getelementptr inbounds %error_union, %error_union* %result, i32 0, i32 0
|
||||
%2 = load i64, i64* %err_domain, align 8
|
||||
%not_err = icmp eq i64 %2, 0
|
||||
br i1 %not_err, label %after_check, label %catch_landing
|
||||
%0 = call i64 @readLine(i8** %retparam1)
|
||||
%not_err = icmp eq i64 %0, 0
|
||||
br i1 %not_err, label %after.errcheck, label %catch_landing
|
||||
|
||||
after_check:
|
||||
%3 = load i8*, i8** %retparam1, align 8
|
||||
%4 = call { i64, i64 } @atoi(i32* %retparam, i8* %3)
|
||||
%5 = bitcast %error_union* %result2 to { i64, i64 }*
|
||||
store { i64, i64 } %4, { i64, i64 }* %5, align 8
|
||||
%err_domain3 = getelementptr inbounds %error_union, %error_union* %result2, i32 0, i32 0
|
||||
%6 = load i64, i64* %err_domain3, align 8
|
||||
%not_err4 = icmp eq i64 %6, 0
|
||||
br i1 %not_err4, label %after_check5, label %catch_landing
|
||||
after.errcheck: ; preds = %entry
|
||||
%1 = load i8*, i8** %retparam1, align 8
|
||||
%2 = call i64 @atoi(i32* %retparam, i8* %1)
|
||||
%not_err2 = icmp eq i64 %2, 0
|
||||
br i1 %not_err2, label %after.errcheck3, label %catch_landing
|
||||
|
||||
after_check5:
|
||||
%7 = load i32, i32* %retparam, align 4
|
||||
store i32 %7, i32* %val, align 4
|
||||
after.errcheck3: ; preds = %after.errcheck
|
||||
%3 = load i32, i32* %retparam, align 4
|
||||
store i32 %3, i32* %val, align 4
|
||||
br label %phi_try_catch
|
||||
|
||||
catch_landing:
|
||||
catch_landing: ; preds = %after.errcheck, %entry
|
||||
br label %phi_try_catch
|
||||
|
||||
phi_try_catch:
|
||||
%val6 = phi i1 [ true, %after_check5 ], [ false, %catch_landing ]
|
||||
br i1 %val6, label %if.then, label %if.exit
|
||||
phi_try_catch: ; preds = %catch_landing, %after.errcheck3
|
||||
%val4 = phi i1 [ true, %after.errcheck3 ], [ false, %catch_landing ]
|
||||
br i1 %val4, label %if.then, label %if.exit
|
||||
|
||||
if.then:
|
||||
%8 = load i32, i32* %val, align 4
|
||||
%9 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @.str, i32 0, i32 0), i32 %8)
|
||||
if.then: ; preds = %phi_try_catch
|
||||
%4 = load i32, i32* %val, align 4
|
||||
%5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @.str, i32 0, i32 0), i32 %4)
|
||||
ret void
|
||||
|
||||
if.exit:
|
||||
%10 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([31 x i8], [31 x i8]* @.str.1, i32 0, i32 0))
|
||||
if.exit: ; preds = %phi_try_catch
|
||||
%6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([31 x i8], [31 x i8]* @.str.1, i32 0, i32 0))
|
||||
ret void
|
||||
}
|
||||
93
test/test_suite/errors/try_with_chained_unwrap_errors.c3
Normal file
93
test/test_suite/errors/try_with_chained_unwrap_errors.c3
Normal file
@@ -0,0 +1,93 @@
|
||||
func void test()
|
||||
{
|
||||
int! a;
|
||||
int b;
|
||||
if (try int b = a) {} // #error: 'b' would shadow a previous declaration.
|
||||
}
|
||||
func void test2()
|
||||
{
|
||||
int! a;
|
||||
int b;
|
||||
if (try b = a) {}
|
||||
if (try test2 = a) {} // #error: 'try' expected an assignable variable or expression here, did you make a mistake?
|
||||
}
|
||||
|
||||
const int BAZ = 1;
|
||||
|
||||
func void test3()
|
||||
{
|
||||
|
||||
int! a;
|
||||
int b;
|
||||
if (try BAZ = a) {} // #error: 'try' expected an assignable variable or expression here, did you make a mistake?
|
||||
}
|
||||
|
||||
|
||||
func void test4()
|
||||
{
|
||||
|
||||
int! a;
|
||||
int b;
|
||||
if (try b = 1) {} // #error: Expected a failable expression to 'try' here. If it isn't a failable, remove 'try'
|
||||
}
|
||||
|
||||
func void test5()
|
||||
{
|
||||
|
||||
int! a;
|
||||
int b;
|
||||
if (try a = a) {} // #error: This is a failable variable, you should only have non-failable variables on the left side unless you use 'try' without '='
|
||||
}
|
||||
|
||||
func void test6()
|
||||
{
|
||||
|
||||
int! a;
|
||||
int b;
|
||||
int*! x;
|
||||
if (try *x = a) {} // #error: This is a failable expression, it can't go on the left hand side of a 'try'.
|
||||
}
|
||||
|
||||
|
||||
func void test7()
|
||||
{
|
||||
int! a;
|
||||
int b;
|
||||
int*! x;
|
||||
if (try foo::z = a) {} // #error: The variable may not have a path.
|
||||
}
|
||||
|
||||
func void test8()
|
||||
{
|
||||
int! a;
|
||||
int b;
|
||||
if (b == 0, try b = a && try b = a && b > 0) {}
|
||||
if (try b = a && try b = a && b > 0) {}
|
||||
if (try c = a && try c = a) { c++; }
|
||||
}
|
||||
|
||||
func void test9()
|
||||
{
|
||||
int! a = 11;
|
||||
if (try z = a)
|
||||
{
|
||||
int g = z++;
|
||||
}
|
||||
else
|
||||
{
|
||||
z++; // #error: 'z' could not be found, did you spell it right?
|
||||
}
|
||||
}
|
||||
|
||||
func void test10()
|
||||
{
|
||||
int! a = 11;
|
||||
if (try a)
|
||||
{
|
||||
int g = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
int g = a; // #error: 'int!' cannot be converted into 'int'
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// #target: x64-darwin
|
||||
extern func char*! readLine();
|
||||
extern func int! atoi(char*);
|
||||
|
||||
@@ -21,106 +22,63 @@ func void main()
|
||||
// #expect: try_with_unwrap.ll
|
||||
|
||||
define void @main() #0 {
|
||||
entry:
|
||||
%line = alloca i8*, align 8
|
||||
%line.f = alloca %error_union, align 8
|
||||
%retparam = alloca i8*, align 8
|
||||
%result = alloca %error_union, align 8
|
||||
%val4 = alloca i32, align 4
|
||||
%val.f = alloca %error_union, align 8
|
||||
%retparam5 = alloca i32, align 4
|
||||
%result6 = alloca %error_union, align 8
|
||||
%0 = call { i64, i64 } @readLine(i8** %retparam)
|
||||
%1 = bitcast %error_union* %result to { i64, i64 }*
|
||||
store { i64, i64 } %0, { i64, i64 }* %1, align 8
|
||||
%err_domain = getelementptr inbounds %error_union, %error_union* %result, i32 0, i32 0
|
||||
%2 = load i64, i64* %err_domain, align 8
|
||||
%not_err = icmp eq i64 %2, 0
|
||||
br i1 %not_err, label %after_check, label %error
|
||||
entry:
|
||||
%line = alloca i8*, align 8
|
||||
%line.f = alloca i64, align 8
|
||||
%retparam = alloca i8*, align 8
|
||||
%val = alloca i32, align 4
|
||||
%val.f = alloca i64, align 8
|
||||
%retparam1 = alloca i32, align 4
|
||||
%0 = call i64 @readLine(i8** %retparam)
|
||||
%not_err = icmp eq i64 %0, 0
|
||||
br i1 %not_err, label %after.errcheck, label %error
|
||||
|
||||
error: ; preds = %entry
|
||||
%3 = bitcast %error_union* %line.f to i8*
|
||||
%4 = bitcast %error_union* %result to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %3, i8* align 8 %4, i32 16, i1 false)
|
||||
br label %after_assign
|
||||
error: ; preds = %entry
|
||||
store i64 %0, i64* %line.f, align 8
|
||||
br label %after_assign
|
||||
|
||||
after_check: ; preds = %entry
|
||||
%5 = load i8*, i8** %retparam, align 8
|
||||
store i8* %5, i8** %line, align 8
|
||||
store %error_union zeroinitializer, %error_union* %line.f, align 8
|
||||
br label %after_assign
|
||||
after.errcheck: ; preds = %entry
|
||||
%1 = load i8*, i8** %retparam, align 8
|
||||
store i8* %1, i8** %line, align 8
|
||||
store i64 0, i64* %line.f, align 8
|
||||
br label %after_assign
|
||||
|
||||
after_assign: ; preds = %after_check, %error
|
||||
%err_domain1 = getelementptr inbounds %error_union, %error_union* %line.f, i32 0, i32 0
|
||||
%6 = load i64, i64* %err_domain1, align 8
|
||||
%not_err2 = icmp eq i64 %6, 0
|
||||
br i1 %not_err2, label %after_check3, label %error_block
|
||||
after_assign: ; preds = %after.errcheck, %error
|
||||
%load.err = load i64, i64* %line.f, align 8
|
||||
%result = icmp eq i64 %load.err, 0
|
||||
br i1 %result, label %if.then, label %if.exit9
|
||||
|
||||
after_check3: ; preds = %after_assign
|
||||
br label %noerr_block
|
||||
if.then: ; preds = %after_assign
|
||||
%2 = load i8*, i8** %line, align 8
|
||||
%3 = call i64 @atoi(i32* %retparam1, i8* %2)
|
||||
%not_err2 = icmp eq i64 %3, 0
|
||||
br i1 %not_err2, label %after.errcheck4, label %error3
|
||||
|
||||
noerr_block: ; preds = %after_check3
|
||||
br label %phi_trycatch_block
|
||||
error3: ; preds = %if.then
|
||||
store i64 %3, i64* %val.f, align 8
|
||||
br label %after_assign5
|
||||
|
||||
error_block: ; preds = %after_assign
|
||||
br label %phi_trycatch_block
|
||||
after.errcheck4: ; preds = %if.then
|
||||
%4 = load i32, i32* %retparam1, align 4
|
||||
store i32 %4, i32* %val, align 4
|
||||
store i64 0, i64* %val.f, align 8
|
||||
br label %after_assign5
|
||||
|
||||
phi_trycatch_block: ; preds = %error_block, %noerr_block
|
||||
%val = phi i8 [ 1, %noerr_block ], [ 0, %error_block ]
|
||||
%7 = trunc i8 %val to i1
|
||||
br i1 %7, label %if.then, label %if.exit20
|
||||
after_assign5: ; preds = %after.errcheck4, %error3
|
||||
%load.err6 = load i64, i64* %val.f, align 8
|
||||
%result7 = icmp eq i64 %load.err6, 0
|
||||
br i1 %result7, label %if.then8, label %if.exit
|
||||
|
||||
if.then: ; preds = %phi_trycatch_block
|
||||
%8 = load i8*, i8** %line, align 8
|
||||
%9 = call { i64, i64 } @atoi(i32* %retparam5, i8* %8)
|
||||
%10 = bitcast %error_union* %result6 to { i64, i64 }*
|
||||
store { i64, i64 } %9, { i64, i64 }* %10, align 8
|
||||
%err_domain7 = getelementptr inbounds %error_union, %error_union* %result6, i32 0, i32 0
|
||||
%11 = load i64, i64* %err_domain7, align 8
|
||||
%not_err8 = icmp eq i64 %11, 0
|
||||
br i1 %not_err8, label %after_check10, label %error9
|
||||
if.then8: ; preds = %after_assign5
|
||||
%5 = load i32, i32* %val, align 4
|
||||
%6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @.str, i32 0, i32 0), i32 %5)
|
||||
ret void
|
||||
|
||||
error9: ; preds = %if.then
|
||||
%12 = bitcast %error_union* %val.f to i8*
|
||||
%13 = bitcast %error_union* %result6 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %12, i8* align 8 %13, i32 16, i1 false)
|
||||
br label %after_assign11
|
||||
if.exit: ; preds = %after_assign5
|
||||
br label %if.exit9
|
||||
|
||||
after_check10: ; preds = %if.then
|
||||
%14 = load i32, i32* %retparam5, align 4
|
||||
store i32 %14, i32* %val4, align 4
|
||||
store %error_union zeroinitializer, %error_union* %val.f, align 8
|
||||
br label %after_assign11
|
||||
if.exit9: ; preds = %if.exit, %after_assign
|
||||
%7 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([31 x i8], [31 x i8]* @.str.1, i32 0, i32 0))
|
||||
ret void
|
||||
}
|
||||
|
||||
after_assign11: ; preds = %after_check10, %error9
|
||||
%err_domain12 = getelementptr inbounds %error_union, %error_union* %val.f, i32 0, i32 0
|
||||
%15 = load i64, i64* %err_domain12, align 8
|
||||
%not_err13 = icmp eq i64 %15, 0
|
||||
br i1 %not_err13, label %after_check14, label %error_block16
|
||||
|
||||
after_check14: ; preds = %after_assign11
|
||||
br label %noerr_block15
|
||||
|
||||
noerr_block15: ; preds = %after_check14
|
||||
br label %phi_trycatch_block17
|
||||
|
||||
error_block16: ; preds = %after_assign11
|
||||
br label %phi_trycatch_block17
|
||||
|
||||
phi_trycatch_block17: ; preds = %error_block16, %noerr_block15
|
||||
%val18 = phi i8 [ 1, %noerr_block15 ], [ 0, %error_block16 ]
|
||||
%16 = trunc i8 %val18 to i1
|
||||
br i1 %16, label %if.then19, label %if.exit
|
||||
|
||||
if.then19: ; preds = %phi_trycatch_block17
|
||||
%17 = load i32, i32* %val4, align 4
|
||||
%18 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @.str, i32 0, i32 0), i32 %17)
|
||||
ret void
|
||||
|
||||
if.exit: ; preds = %phi_trycatch_block17
|
||||
br label %if.exit20
|
||||
|
||||
if.exit20: ; preds = %if.exit, %phi_trycatch_block
|
||||
%19 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([31 x i8], [31 x i8]* @.str.1, i32 0, i32 0))
|
||||
ret void
|
||||
}
|
||||
187
test/test_suite/errors/try_with_unwrapper.c3t
Normal file
187
test/test_suite/errors/try_with_unwrapper.c3t
Normal file
@@ -0,0 +1,187 @@
|
||||
// #target: x64-darwin
|
||||
|
||||
func int hello(int x)
|
||||
{
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
extern func int printf(char *c, ...);
|
||||
|
||||
func int! tester()
|
||||
{
|
||||
printf("In tester\n");
|
||||
return 222;
|
||||
}
|
||||
|
||||
errtype Foo
|
||||
{
|
||||
A
|
||||
}
|
||||
func void test1()
|
||||
{
|
||||
int! a = 11;
|
||||
if (try int b = a && try int c = tester())
|
||||
{
|
||||
printf("%d\n", hello(b));
|
||||
printf("%d\n", c);
|
||||
}
|
||||
}
|
||||
func void main()
|
||||
{
|
||||
test1();
|
||||
}
|
||||
|
||||
func void test2()
|
||||
{
|
||||
int! a;
|
||||
if (try int b = a && hello(b))
|
||||
{
|
||||
hello(b + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// #expect: try_with_unwrapper.ll
|
||||
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define i32 @try_with_unwrapper.hello(i32 %0) #0 {
|
||||
entry:
|
||||
%x = alloca i32, align 4
|
||||
store i32 %0, i32* %x, align 4
|
||||
%1 = load i32, i32* %x, align 4
|
||||
%add = add i32 %1, 1
|
||||
ret i32 %add
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
declare i32 @printf(i8*, ...) #0
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define i64 @try_with_unwrapper.tester(i32* %0) #0 {
|
||||
entry:
|
||||
%reterr = alloca i64, align 8
|
||||
%1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i32 0, i32 0))
|
||||
store i32 222, i32* %0, align 4
|
||||
ret i64 0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @try_with_unwrapper.test1() #0 {
|
||||
entry:
|
||||
%a = alloca i32, align 4
|
||||
%a.f = alloca i64, align 8
|
||||
%b = alloca i32, align 4
|
||||
%c = alloca i32, align 4
|
||||
%retparam = alloca i32, align 4
|
||||
store i64 0, i64* %a.f, align 8
|
||||
store i32 11, i32* %a, align 4
|
||||
store i64 0, i64* %a.f, align 8
|
||||
store i32 0, i32* %b, align 4
|
||||
%0 = load i64, i64* %a.f, align 8
|
||||
%not_err = icmp eq i64 %0, 0
|
||||
br i1 %not_err, label %after_check, label %catch_landing
|
||||
|
||||
after_check: ; preds = %entry
|
||||
%1 = load i32, i32* %a, align 4
|
||||
store i32 %1, i32* %b, align 4
|
||||
br label %phi_try_catch
|
||||
|
||||
catch_landing: ; preds = %entry
|
||||
br label %phi_try_catch
|
||||
|
||||
phi_try_catch: ; preds = %catch_landing, %after_check
|
||||
%val = phi i1 [ true, %after_check ], [ false, %catch_landing ]
|
||||
br i1 %val, label %chain_next, label %fail_chain
|
||||
|
||||
chain_next: ; preds = %phi_try_catch
|
||||
store i32 0, i32* %c, align 4
|
||||
%2 = call i64 @try_with_unwrapper.tester(i32* %retparam)
|
||||
%not_err1 = icmp eq i64 %2, 0
|
||||
br i1 %not_err1, label %after.errcheck, label %catch_landing2
|
||||
|
||||
after.errcheck: ; preds = %chain_next
|
||||
%3 = load i32, i32* %retparam, align 4
|
||||
store i32 %3, i32* %c, align 4
|
||||
br label %phi_try_catch3
|
||||
|
||||
catch_landing2: ; preds = %chain_next
|
||||
br label %phi_try_catch3
|
||||
|
||||
phi_try_catch3: ; preds = %catch_landing2, %after.errcheck
|
||||
%val4 = phi i1 [ true, %after.errcheck ], [ false, %catch_landing2 ]
|
||||
br i1 %val4, label %chain_next5, label %fail_chain
|
||||
|
||||
chain_next5: ; preds = %phi_try_catch3
|
||||
br label %end_chain
|
||||
|
||||
fail_chain: ; preds = %phi_try_catch3, %phi_try_catch
|
||||
br label %end_chain
|
||||
|
||||
end_chain: ; preds = %fail_chain, %chain_next5
|
||||
%chain.phi = phi i1 [ true, %chain_next5 ], [ false, %fail_chain ]
|
||||
br i1 %chain.phi, label %if.then, label %if.exit
|
||||
|
||||
if.then: ; preds = %end_chain
|
||||
%4 = load i32, i32* %b, align 4
|
||||
%5 = call i32 @try_with_unwrapper.hello(i32 %4)
|
||||
%6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1, i32 0, i32 0), i32 %5)
|
||||
%7 = load i32, i32* %c, align 4
|
||||
%8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i32 0, i32 0), i32 %7)
|
||||
br label %if.exit
|
||||
|
||||
if.exit: ; preds = %if.then, %end_chain
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @try_with_unwrapper.test2() #0 {
|
||||
entry:
|
||||
%a = alloca i32, align 4
|
||||
%a.f = alloca i64, align 8
|
||||
%b = alloca i32, align 4
|
||||
store i64 0, i64* %a.f, align 8
|
||||
store i32 0, i32* %a, align 4
|
||||
store i32 0, i32* %b, align 4
|
||||
%0 = load i64, i64* %a.f, align 8
|
||||
%not_err = icmp eq i64 %0, 0
|
||||
br i1 %not_err, label %after_check, label %catch_landing
|
||||
|
||||
after_check: ; preds = %entry
|
||||
%1 = load i32, i32* %a, align 4
|
||||
store i32 %1, i32* %b, align 4
|
||||
br label %phi_try_catch
|
||||
|
||||
catch_landing: ; preds = %entry
|
||||
br label %phi_try_catch
|
||||
|
||||
phi_try_catch: ; preds = %catch_landing, %after_check
|
||||
%val = phi i1 [ true, %after_check ], [ false, %catch_landing ]
|
||||
br i1 %val, label %chain_next, label %fail_chain
|
||||
|
||||
chain_next: ; preds = %phi_try_catch
|
||||
%2 = load i32, i32* %b, align 4
|
||||
%3 = call i32 @try_with_unwrapper.hello(i32 %2)
|
||||
%intbool = icmp ne i32 %3, 0
|
||||
br i1 %intbool, label %chain_next1, label %fail_chain
|
||||
|
||||
chain_next1: ; preds = %chain_next
|
||||
br label %end_chain
|
||||
|
||||
fail_chain: ; preds = %chain_next, %phi_try_catch
|
||||
br label %end_chain
|
||||
|
||||
end_chain: ; preds = %fail_chain, %chain_next1
|
||||
%chain.phi = phi i1 [ true, %chain_next1 ], [ false, %fail_chain ]
|
||||
br i1 %chain.phi, label %if.then, label %if.exit
|
||||
|
||||
if.then: ; preds = %end_chain
|
||||
%4 = load i32, i32* %b, align 4
|
||||
%add = add i32 %4, 1
|
||||
%5 = call i32 @try_with_unwrapper.hello(i32 %add)
|
||||
br label %if.exit
|
||||
|
||||
if.exit: ; preds = %if.then, %end_chain
|
||||
ret void
|
||||
}
|
||||
|
||||
16
test/test_suite/errors/try_with_weird_stuff.c3
Normal file
16
test/test_suite/errors/try_with_weird_stuff.c3
Normal file
@@ -0,0 +1,16 @@
|
||||
func void test1()
|
||||
{
|
||||
|
||||
int! a;
|
||||
int b;
|
||||
int*! x;
|
||||
if (try int &a = a) {} // #error: Expected a variable name after the type.
|
||||
}
|
||||
|
||||
func void test2()
|
||||
{
|
||||
int! a;
|
||||
int b;
|
||||
int*! x;
|
||||
if (try foo::z = a, b += 1) {} // #error: The 'try' must be placed last, can you change it?
|
||||
}
|
||||
@@ -216,7 +216,8 @@ Type argh = 234;
|
||||
|
||||
errtype MyErr
|
||||
{
|
||||
Type x;
|
||||
X,
|
||||
Y
|
||||
}
|
||||
|
||||
enum Hello : int
|
||||
|
||||
@@ -216,7 +216,8 @@ Type argh = 234;
|
||||
|
||||
errtype MyErr
|
||||
{
|
||||
Type x;
|
||||
X,
|
||||
Y
|
||||
}
|
||||
|
||||
enum Hello : int
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
module foo;
|
||||
import std::io;
|
||||
|
||||
errtype Foo;
|
||||
errtype Foo
|
||||
{
|
||||
X
|
||||
}
|
||||
|
||||
define Bar = distinct int;
|
||||
|
||||
@@ -39,9 +42,9 @@ func void main()
|
||||
|
||||
// #expect: foo.ll
|
||||
|
||||
define void @foo.Foo__hello(%Foo* %0)
|
||||
%f = alloca %Foo*, align 8
|
||||
store %Foo* %0, %Foo** %f, align 8
|
||||
define void @foo.Foo__hello(i64* %0)
|
||||
%f = alloca i64*, align 8
|
||||
store i64* %0, i64** %f, align 8
|
||||
%1 = call i32 @"std::io.println"(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str, i32 0, i32 0))
|
||||
ret void
|
||||
|
||||
@@ -59,14 +62,13 @@ define void @foo.MyEnum__hello(i32* %0)
|
||||
|
||||
define void @main()
|
||||
entry:
|
||||
%f = alloca %Foo, align 8
|
||||
%f = alloca i64, align 8
|
||||
%b = alloca i32, align 4
|
||||
%a = alloca i32, align 4
|
||||
%0 = bitcast %Foo* %f to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 8, i1 false)
|
||||
store i64 0, i64* %f, align 8
|
||||
store i32 0, i32* %b, align 4
|
||||
store i32 0, i32* %a, align 4
|
||||
call void @foo.Foo__hello(%Foo* %f)
|
||||
call void @foo.Foo__hello(i64* %f)
|
||||
call void @foo.Bar__hello(i32* %b)
|
||||
call void @foo.MyEnum__hello(i32* %a)
|
||||
ret void
|
||||
|
||||
@@ -15,16 +15,15 @@ func void test()
|
||||
|
||||
entry:
|
||||
%x = alloca [3 x i32], align 4
|
||||
%x.f = alloca %error_union, align 8
|
||||
%x.f = alloca i64, align 8
|
||||
%g = alloca i32, align 4
|
||||
%idx = alloca i64, align 8
|
||||
%z = alloca i32, align 4
|
||||
store %error_union zeroinitializer, %error_union* %x.f, align 8
|
||||
store i64 0, i64* %x.f, align 8
|
||||
%0 = bitcast [3 x i32]* %x to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 0, i64 12, i1 false)
|
||||
store i32 0, i32* %g, align 4
|
||||
%err_domain = getelementptr inbounds %error_union, %error_union* %x.f, i32 0, i32 0
|
||||
%1 = load i64, i64* %err_domain, align 8
|
||||
%1 = load i64, i64* %x.f, align 8
|
||||
%not_err = icmp eq i64 %1, 0
|
||||
br i1 %not_err, label %after_check, label %foreach.exit
|
||||
|
||||
@@ -45,12 +44,11 @@ foreach.body:
|
||||
%6 = load i32, i32* %z, align 4
|
||||
%add = add i32 %5, %6
|
||||
store i32 %add, i32* %g, align 4
|
||||
%err_domain1 = getelementptr inbounds %error_union, %error_union* %x.f, i32 0, i32 0
|
||||
%7 = load i64, i64* %err_domain1, align 8
|
||||
%not_err2 = icmp eq i64 %7, 0
|
||||
br i1 %not_err2, label %after_check3, label %voiderr
|
||||
%7 = load i64, i64* %x.f, align 8
|
||||
%not_err1 = icmp eq i64 %7, 0
|
||||
br i1 %not_err1, label %after_check2, label %voiderr
|
||||
|
||||
after_check3:
|
||||
after_check2:
|
||||
%arridx = getelementptr inbounds [3 x i32], [3 x i32]* %x, i64 0, i64 0
|
||||
store i32 1, i32* %arridx, align 4
|
||||
br label %voiderr
|
||||
|
||||
Reference in New Issue
Block a user