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:
Christoffer Lerno
2021-08-12 01:08:22 +02:00
committed by Christoffer Lerno
parent 95836e98a2
commit f180a0d44a
63 changed files with 2572 additions and 1124 deletions

View File

@@ -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};

View File

@@ -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:

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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:

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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));

View File

@@ -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;

View File

@@ -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:

View File

@@ -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

View File

@@ -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:

View File

@@ -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:

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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);

View File

@@ -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 },

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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:

View File

@@ -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;

View File

@@ -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.");

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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.");

View File

@@ -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:

View File

@@ -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)

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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))

View 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?
}

View File

@@ -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;
}

View 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;
}

View File

@@ -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
}
}

View File

@@ -1,12 +0,0 @@
module foo;
errtype TheError
{
union // #error: A type name was expected here
{
int a;
int b;
}
}

View File

@@ -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;

View File

@@ -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.
}

View File

@@ -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!;
}

View File

@@ -1,6 +1,9 @@
module foo;
errtype Blurg;
errtype Blurg
{
X, Y, Z
}
func void main()
{

View 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
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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
}

View 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
}

View File

@@ -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()

View File

@@ -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
}

View File

@@ -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
}

View 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'
}
}

View File

@@ -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
}

View 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
}

View 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?
}

View File

@@ -216,7 +216,8 @@ Type argh = 234;
errtype MyErr
{
Type x;
X,
Y
}
enum Hello : int

View File

@@ -216,7 +216,8 @@ Type argh = 234;
errtype MyErr
{
Type x;
X,
Y
}
enum Hello : int

View File

@@ -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

View File

@@ -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