mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Support varargs for macros. Bugfix member access. Support macro varargs.
This commit is contained in:
committed by
Christoffer Lerno
parent
52bcf4654a
commit
6b1370ba76
@@ -46,7 +46,9 @@ typedef struct Expr_ Expr;
|
||||
typedef struct Module_ Module;
|
||||
typedef struct Type_ Type;
|
||||
typedef Type CanonicalType;
|
||||
|
||||
typedef struct Signature_ Signature;
|
||||
typedef struct ConstInitializer_ ConstInitializer;
|
||||
typedef struct CompilationUnit_ CompilationUnit;
|
||||
typedef unsigned AstId;
|
||||
typedef unsigned ExprId;
|
||||
typedef unsigned DeclId;
|
||||
@@ -88,32 +90,32 @@ typedef enum
|
||||
|
||||
|
||||
|
||||
typedef struct ConstInitializer_
|
||||
struct ConstInitializer_
|
||||
{
|
||||
ConstInitType kind;
|
||||
// Type initialized
|
||||
Type *type;
|
||||
union
|
||||
{
|
||||
struct ConstInitializer_ **init_struct;
|
||||
ConstInitializer **init_struct;
|
||||
Expr *init_value;
|
||||
struct
|
||||
{
|
||||
struct ConstInitializer_ *element;
|
||||
ConstInitializer *element;
|
||||
MemberIndex index;
|
||||
} init_union;
|
||||
struct
|
||||
{
|
||||
struct ConstInitializer_ **elements;
|
||||
ConstInitializer **elements;
|
||||
} init_array;
|
||||
struct ConstInitializer_ **init_array_full;
|
||||
ConstInitializer **init_array_full;
|
||||
struct
|
||||
{
|
||||
struct ConstInitializer_ *element;
|
||||
ConstInitializer *element;
|
||||
MemberIndex index;
|
||||
} init_array_value;
|
||||
};
|
||||
} ConstInitializer;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -169,8 +171,6 @@ typedef union
|
||||
|
||||
static_assert(sizeof(SourceSpan) == 8, "Expected 8 bytes");
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *key;
|
||||
@@ -225,14 +225,15 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
bool nodiscard : 1;
|
||||
bool maydiscard: 1;
|
||||
} FunctionAttributes;
|
||||
bool maydiscard : 1;
|
||||
bool is_pure : 1;
|
||||
bool noreturn : 1;
|
||||
} CalleeAttributes;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
FunctionAttributes attrs;
|
||||
Module *module;
|
||||
Decl** params;
|
||||
Signature *signature;
|
||||
struct FunctionPrototype_ *prototype;
|
||||
} TypeFunction;
|
||||
|
||||
@@ -443,36 +444,53 @@ typedef enum
|
||||
|
||||
|
||||
|
||||
typedef struct FunctionSignature_
|
||||
struct Signature_
|
||||
{
|
||||
FunctionAttributes attrs;
|
||||
CalleeAttributes attrs;
|
||||
bool is_macro : 1;
|
||||
bool is_at_macro : 1;
|
||||
Variadic variadic : 3;
|
||||
unsigned vararg_index : 10;
|
||||
bool use_win64 : 1;
|
||||
bool is_pure : 1;
|
||||
CallABI abi : 8;
|
||||
TypeInfoId returntype;
|
||||
unsigned vararg_index;
|
||||
TypeInfoId rtype;
|
||||
Decl** params;
|
||||
} FunctionSignature;
|
||||
};
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
bool attr_noreturn : 1;
|
||||
bool attr_inline : 1;
|
||||
bool attr_noinline : 1;
|
||||
bool attr_extname : 1;
|
||||
bool attr_naked : 1;
|
||||
};
|
||||
TypeInfoId type_parent;
|
||||
FunctionSignature function_signature;
|
||||
Signature signature;
|
||||
AstId body;
|
||||
AstId docs;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
bool attr_inline : 1;
|
||||
bool attr_noinline : 1;
|
||||
bool attr_extname : 1;
|
||||
bool attr_naked : 1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
DeclId body_param;
|
||||
CompilationUnit *unit;
|
||||
};
|
||||
};
|
||||
} FuncDecl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
TypeInfoId type_parent; // May be 0
|
||||
Signature signature;
|
||||
AstId body;
|
||||
DeclId body_param;
|
||||
CompilationUnit *unit;
|
||||
AstId docs;
|
||||
} MacroDecl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Decl **params;
|
||||
@@ -485,7 +503,7 @@ typedef struct
|
||||
bool is_distinct : 1;
|
||||
union
|
||||
{
|
||||
FunctionSignature function_signature;
|
||||
Signature function_signature;
|
||||
TypeInfo *type_info;
|
||||
};
|
||||
} TypedefDecl;
|
||||
@@ -500,33 +518,7 @@ typedef struct
|
||||
};
|
||||
} DistinctDecl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned vararg_index : 10;
|
||||
Variadic variadic : 3;
|
||||
bool attr_noreturn : 1;
|
||||
bool attr_nodiscard : 1;
|
||||
bool attr_maydiscard : 1;
|
||||
};
|
||||
TypeInfoId type_parent; // May be 0
|
||||
TypeInfoId rtype; // May be 0
|
||||
AstId body;
|
||||
DeclId body_param;
|
||||
Decl **parameters;
|
||||
struct CompilationUnit_ *unit;
|
||||
AstId docs;
|
||||
} MacroDecl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct Ast_ **cases;
|
||||
Decl **parameters;
|
||||
Decl **body_parameters;
|
||||
TypeInfoId rtype; // May be 0!
|
||||
Path *path; // For redefinition
|
||||
} GenericDecl;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@@ -645,8 +637,6 @@ typedef struct Decl_
|
||||
FuncDecl func_decl;
|
||||
AttrDecl attr_decl;
|
||||
TypedefDecl typedef_decl;
|
||||
MacroDecl macro_decl;
|
||||
GenericDecl generic_decl;
|
||||
DefineDecl define_decl;
|
||||
CtIfDecl ct_if_decl;
|
||||
CtIfDecl ct_elif_decl;
|
||||
@@ -845,7 +835,7 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
TokenType type : 8;
|
||||
TokenType type : 16;
|
||||
ExprId arg;
|
||||
} ExprCtArg;
|
||||
|
||||
@@ -883,7 +873,6 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
AstId first_stmt;
|
||||
Expr **args;
|
||||
Decl **params;
|
||||
BlockExit **block_exit;
|
||||
} ExprMacroBlock;
|
||||
@@ -1418,7 +1407,7 @@ typedef struct
|
||||
DeclId *entries;
|
||||
} DeclTable;
|
||||
|
||||
typedef struct CompilationUnit_
|
||||
struct CompilationUnit_
|
||||
{
|
||||
Module *module;
|
||||
File* file;
|
||||
@@ -1449,7 +1438,7 @@ typedef struct CompilationUnit_
|
||||
void *debug_file;
|
||||
void *debug_compile_unit;
|
||||
} llvm;
|
||||
} CompilationUnit;
|
||||
};
|
||||
|
||||
typedef struct ParseContext_
|
||||
{
|
||||
@@ -1494,6 +1483,7 @@ typedef struct SemaContext_
|
||||
// Reusable returns cache.
|
||||
Ast **returns_cache;
|
||||
Expr **macro_varargs;
|
||||
Decl **macro_params;
|
||||
};
|
||||
Type *rtype;
|
||||
struct SemaContext_ *yield_context;
|
||||
@@ -2137,7 +2127,7 @@ void type_func_prototype_init(uint32_t capacity);
|
||||
bool type_is_subtype(Type *type, Type *possible_subtype);
|
||||
bool type_is_abi_aggregate(Type *type);
|
||||
bool type_is_int128(Type *type);
|
||||
Type *type_get_func(FunctionSignature *signature, CallABI abi);
|
||||
Type *type_get_func(Signature *signature, CallABI abi);
|
||||
Type *type_from_token(TokenType type);
|
||||
bool type_is_user_defined(Type *type);
|
||||
bool type_is_structurally_equivalent(Type *type1, Type *type);
|
||||
|
||||
@@ -175,7 +175,7 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl)
|
||||
break;
|
||||
case DECL_GENERIC:
|
||||
assert(decl->name);
|
||||
if (decl->macro_decl.type_parent)
|
||||
if (decl->func_decl.type_parent)
|
||||
{
|
||||
vec_add(unit->generic_methods, decl);
|
||||
return;
|
||||
@@ -189,7 +189,7 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl)
|
||||
break;
|
||||
case DECL_MACRO:
|
||||
assert(decl->name);
|
||||
if (decl->macro_decl.type_parent)
|
||||
if (decl->func_decl.type_parent)
|
||||
{
|
||||
vec_add(unit->macro_methods, decl);
|
||||
return;
|
||||
|
||||
@@ -545,6 +545,7 @@ TypeInfo *copy_type_info(CopyStruct *c, TypeInfo *source)
|
||||
return copy;
|
||||
case TYPE_INFO_EVALTYPE:
|
||||
case TYPE_INFO_EXPRESSION:
|
||||
case TYPE_INFO_VAARG_TYPE:
|
||||
assert(source->resolve_status == RESOLVE_NOT_DONE);
|
||||
copy->unresolved_type_expr = copy_expr(c, source->unresolved_type_expr);
|
||||
return copy;
|
||||
@@ -566,10 +567,10 @@ TypeInfo *copy_type_info(CopyStruct *c, TypeInfo *source)
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
static void copy_function_signature_deep(CopyStruct *c, FunctionSignature *signature)
|
||||
static void copy_signature_deep(CopyStruct *c, Signature *signature)
|
||||
{
|
||||
MACRO_COPY_DECL_LIST(signature->params);
|
||||
MACRO_COPY_TYPEID(signature->returntype);
|
||||
MACRO_COPY_TYPEID(signature->rtype);
|
||||
}
|
||||
void copy_decl_type(Decl *decl)
|
||||
{
|
||||
@@ -647,7 +648,7 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
|
||||
copy_decl_type(copy);
|
||||
MACRO_COPY_TYPEID(copy->func_decl.type_parent);
|
||||
MACRO_COPY_ASTID(copy->func_decl.docs);
|
||||
copy_function_signature_deep(c, ©->func_decl.function_signature);
|
||||
copy_signature_deep(c, ©->func_decl.signature);
|
||||
MACRO_COPY_ASTID(copy->func_decl.body);
|
||||
break;
|
||||
case DECL_VAR:
|
||||
@@ -673,7 +674,7 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
|
||||
copy_decl_type(copy);
|
||||
if (copy->typedef_decl.is_func)
|
||||
{
|
||||
copy_function_signature_deep(c, ©->typedef_decl.function_signature);
|
||||
copy_signature_deep(c, ©->typedef_decl.function_signature);
|
||||
break;
|
||||
}
|
||||
MACRO_COPY_TYPE(copy->typedef_decl.type_info);
|
||||
@@ -683,7 +684,7 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
|
||||
MACRO_COPY_DECL_LIST(copy->methods);
|
||||
if (copy->distinct_decl.typedef_decl.is_func)
|
||||
{
|
||||
copy_function_signature_deep(c, ©->distinct_decl.typedef_decl.function_signature);
|
||||
copy_signature_deep(c, ©->distinct_decl.typedef_decl.function_signature);
|
||||
break;
|
||||
}
|
||||
MACRO_COPY_TYPE(copy->distinct_decl.typedef_decl.type_info);
|
||||
@@ -708,12 +709,11 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
|
||||
break;
|
||||
case DECL_GENERIC:
|
||||
case DECL_MACRO:
|
||||
MACRO_COPY_ASTID(copy->macro_decl.docs);
|
||||
MACRO_COPY_TYPEID(decl->macro_decl.type_parent);
|
||||
MACRO_COPY_DECL_LIST(decl->macro_decl.parameters);
|
||||
MACRO_COPY_ASTID(decl->macro_decl.body);
|
||||
MACRO_COPY_TYPEID(decl->macro_decl.rtype);
|
||||
MACRO_COPY_DECLID(decl->macro_decl.body_param);
|
||||
MACRO_COPY_ASTID(copy->func_decl.docs);
|
||||
MACRO_COPY_TYPEID(decl->func_decl.type_parent);
|
||||
copy_signature_deep(c, ©->func_decl.signature);
|
||||
MACRO_COPY_ASTID(decl->func_decl.body);
|
||||
MACRO_COPY_DECLID(decl->func_decl.body_param);
|
||||
break;
|
||||
case DECL_CT_SWITCH:
|
||||
MACRO_COPY_DECL_LIST(decl->ct_switch_decl.cases);
|
||||
|
||||
@@ -324,6 +324,7 @@ typedef enum
|
||||
TYPE_INFO_IDENTIFIER,
|
||||
TYPE_INFO_CT_IDENTIFIER,
|
||||
TYPE_INFO_EXPRESSION,
|
||||
TYPE_INFO_VAARG_TYPE,
|
||||
TYPE_INFO_EVALTYPE,
|
||||
TYPE_INFO_ARRAY,
|
||||
TYPE_INFO_VECTOR,
|
||||
@@ -554,7 +555,8 @@ typedef enum
|
||||
case TOKEN_FLOAT128: case TOKEN_TYPEID: case TOKEN_ANYERR: case TOKEN_VARIANT
|
||||
#define TYPE_TOKENS NON_VOID_TYPE_TOKENS: case TOKEN_VOID
|
||||
#define TYPELIKE_TOKENS TYPE_TOKENS: case TOKEN_TYPE_IDENT: \
|
||||
case TOKEN_CT_TYPE_IDENT: case TOKEN_CT_TYPEOF
|
||||
case TOKEN_CT_TYPE_IDENT: case TOKEN_CT_TYPEOF: case TOKEN_CT_EVALTYPE: \
|
||||
case TOKEN_CT_VAARG_GET_TYPE
|
||||
|
||||
// Note that ordering matters here. If ordering is changed,
|
||||
// So must type_find_max_type and friends.
|
||||
|
||||
@@ -321,10 +321,11 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl)
|
||||
LLVMValueRef init_value;
|
||||
|
||||
Type *var_type = type_lowering(decl->type);
|
||||
AlignSize alignment = type_alloca_alignment(var_type);
|
||||
|
||||
Expr *init_expr = decl->var.init_expr;
|
||||
if (init_expr && init_expr->expr_kind == EXPR_IDENTIFIER && init_expr->identifier_expr.is_const)
|
||||
while (init_expr && init_expr->expr_kind == EXPR_IDENTIFIER
|
||||
&& init_expr->identifier_expr.decl->decl_kind == DECL_VAR
|
||||
&& init_expr->identifier_expr.decl->var.kind == VARDECL_CONST)
|
||||
{
|
||||
init_expr = init_expr->identifier_expr.decl->var.init_expr;
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ void llvm_emit_debug_function(GenContext *c, Decl *decl)
|
||||
UNREACHABLE
|
||||
}
|
||||
flags |= LLVMDIFlagPrototyped;
|
||||
if (decl->func_decl.attr_noreturn) flags |= LLVMDIFlagNoReturn;
|
||||
if (decl->func_decl.signature.attrs.noreturn) flags |= LLVMDIFlagNoReturn;
|
||||
|
||||
uint32_t row = decl->span.row;
|
||||
if (!row) row = 1;
|
||||
|
||||
@@ -5163,11 +5163,12 @@ static inline void llvm_emit_expr_block(GenContext *context, BEValue *be_value,
|
||||
|
||||
static inline void llvm_emit_macro_block(GenContext *context, BEValue *be_value, Expr *expr)
|
||||
{
|
||||
VECEACH(expr->macro_block.params, i)
|
||||
foreach(Decl *, expr->macro_block.params)
|
||||
{
|
||||
// Skip vararg
|
||||
if (!val) continue;
|
||||
// In case we have a constant, we never do an emit. The value is already folded.
|
||||
Decl *decl = expr->macro_block.params[i];
|
||||
switch (decl->var.kind)
|
||||
switch (val->var.kind)
|
||||
{
|
||||
case VARDECL_CONST:
|
||||
case VARDECL_GLOBAL:
|
||||
@@ -5183,8 +5184,8 @@ static inline void llvm_emit_macro_block(GenContext *context, BEValue *be_value,
|
||||
case VARDECL_PARAM_REF:
|
||||
{
|
||||
BEValue addr;
|
||||
llvm_emit_expr(context, &addr, decl->var.init_expr);
|
||||
decl->backend_ref = addr.value;
|
||||
llvm_emit_expr(context, &addr, val->var.init_expr);
|
||||
val->backend_ref = addr.value;
|
||||
continue;
|
||||
}
|
||||
case VARDECL_PARAM_CT:
|
||||
@@ -5194,11 +5195,11 @@ static inline void llvm_emit_macro_block(GenContext *context, BEValue *be_value,
|
||||
case VARDECL_PARAM:
|
||||
break;
|
||||
}
|
||||
llvm_emit_and_set_decl_alloca(context, decl);
|
||||
llvm_emit_and_set_decl_alloca(context, val);
|
||||
BEValue value;
|
||||
|
||||
llvm_emit_expr(context, &value, expr->macro_block.args[i]);
|
||||
llvm_store_decl(context, decl, &value);
|
||||
llvm_emit_expr(context, &value, val->var.init_expr);
|
||||
llvm_store_decl(context, val, &value);
|
||||
}
|
||||
|
||||
llvm_emit_return_block(context, be_value, expr->type, expr->macro_block.first_stmt, expr->macro_block.block_exit);
|
||||
|
||||
@@ -506,9 +506,9 @@ void llvm_emit_function_body(GenContext *c, Decl *decl)
|
||||
if (!decl->func_decl.attr_naked)
|
||||
{
|
||||
// Generate LLVMValueRef's for all parameters, so we can use them as local vars in code
|
||||
VECEACH(decl->func_decl.function_signature.params, i)
|
||||
VECEACH(decl->func_decl.signature.params, i)
|
||||
{
|
||||
llvm_emit_parameter(c, decl->func_decl.function_signature.params[i], prototype->abi_args[i], &arg, i);
|
||||
llvm_emit_parameter(c, decl->func_decl.signature.params[i], prototype->abi_args[i], &arg, i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -633,7 +633,7 @@ void llvm_emit_function_decl(GenContext *c, Decl *decl)
|
||||
{
|
||||
llvm_attribute_add(c, function, attribute_id.noinline, -1);
|
||||
}
|
||||
if (decl->func_decl.attr_noreturn)
|
||||
if (decl->func_decl.signature.attrs.noreturn)
|
||||
{
|
||||
llvm_attribute_add(c, function, attribute_id.noreturn, -1);
|
||||
}
|
||||
|
||||
@@ -912,11 +912,13 @@ static Expr *parse_ct_call(ParseContext *c, Expr *left)
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
||||
static Expr *parse_ct_arg(ParseContext *c, Expr *left)
|
||||
{
|
||||
assert(!left && "Unexpected left hand side");
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_CT_ARG);
|
||||
TokenType type = expr->ct_arg_expr.type = c->tok;
|
||||
assert(type != TOKEN_CT_VAARG_GET_TYPE);
|
||||
advance(c);
|
||||
CONSUME_OR_RET(TOKEN_LPAREN, poisoned_expr);
|
||||
if (type != TOKEN_CT_VAARG_COUNT)
|
||||
@@ -1753,5 +1755,10 @@ ParseRule rules[TOKEN_EOF + 1] = {
|
||||
[TOKEN_CT_CONVERTIBLE] = { parse_ct_conv, NULL, PREC_NONE },
|
||||
[TOKEN_CT_CASTABLE] = { parse_ct_conv, NULL, PREC_NONE },
|
||||
[TOKEN_LBRACE] = { parse_initializer_list, NULL, PREC_NONE },
|
||||
[TOKEN_CT_VAARG_COUNT] = { parse_ct_arg, NULL, PREC_NONE }
|
||||
[TOKEN_CT_VAARG_COUNT] = { parse_ct_arg, NULL, PREC_NONE },
|
||||
[TOKEN_CT_VAARG_GET_ARG] = { parse_ct_arg, NULL, PREC_NONE },
|
||||
[TOKEN_CT_VAARG_GET_REF] = { parse_ct_arg, NULL, PREC_NONE },
|
||||
[TOKEN_CT_VAARG_GET_TYPE] = { parse_type_expr, NULL, PREC_NONE },
|
||||
[TOKEN_CT_VAARG_GET_EXPR] = { parse_ct_arg, NULL, PREC_NONE },
|
||||
[TOKEN_CT_VAARG_GET_CONST] = { parse_ct_arg, NULL, PREC_NONE },
|
||||
};
|
||||
|
||||
@@ -491,6 +491,15 @@ static inline TypeInfo *parse_base_type(ParseContext *c)
|
||||
RANGE_EXTEND_PREV(type_info);
|
||||
return type_info;
|
||||
}
|
||||
if (try_consume(c, TOKEN_CT_VAARG_GET_TYPE))
|
||||
{
|
||||
TypeInfo *type_info = type_info_new(TYPE_INFO_VAARG_TYPE, c->prev_span);
|
||||
CONSUME_OR_RET(TOKEN_LPAREN, poisoned_type_info);
|
||||
ASSIGN_EXPR_OR_RET(type_info->unresolved_type_expr, parse_expr(c), poisoned_type_info);
|
||||
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_type_info);
|
||||
RANGE_EXTEND_PREV(type_info);
|
||||
return type_info;
|
||||
}
|
||||
if (try_consume(c, TOKEN_CT_EVALTYPE))
|
||||
{
|
||||
TypeInfo *type_info = type_info_new(TYPE_INFO_EVALTYPE, c->prev_span);
|
||||
@@ -1066,11 +1075,10 @@ INLINE bool is_end_of_param_list(ParseContext *c)
|
||||
* | ELLIPSIS (CT_TYPE_IDENT | non_type_ident ('=' expr)?)?
|
||||
*/
|
||||
bool parse_parameters(ParseContext *c, Visibility visibility, Decl ***params_ref, Decl **body_params,
|
||||
Variadic *variadic, unsigned *vararg_index_ref)
|
||||
Variadic *variadic, int *vararg_index_ref)
|
||||
{
|
||||
Decl** params = NULL;
|
||||
bool var_arg_found = false;
|
||||
|
||||
while (!is_end_of_param_list(c))
|
||||
{
|
||||
bool ellipsis = try_consume(c, TOKEN_ELLIPSIS);
|
||||
@@ -1280,16 +1288,15 @@ bool parse_parameters(ParseContext *c, Visibility visibility, Decl ***params_ref
|
||||
*
|
||||
* parameter_type_list ::= '(' parameters ')'
|
||||
*/
|
||||
static inline bool parse_fn_parameter_list(ParseContext *c, Visibility parent_visibility, FunctionSignature *signature, bool is_interface)
|
||||
static inline bool parse_fn_parameter_list(ParseContext *c, Visibility parent_visibility, Signature *signature, bool is_interface)
|
||||
{
|
||||
Decl **decls = NULL;
|
||||
CONSUME_OR_RET(TOKEN_LPAREN, false);
|
||||
Variadic variadic = VARIADIC_NONE;
|
||||
unsigned vararg_index = 0;
|
||||
int vararg_index = -1;
|
||||
if (!parse_parameters(c, parent_visibility, &decls, NULL, &variadic, &vararg_index)) return false;
|
||||
CONSUME_OR_RET(TOKEN_RPAREN, false);
|
||||
|
||||
signature->vararg_index = vararg_index;
|
||||
signature->vararg_index = vararg_index < 0 ? vec_size(decls) : vararg_index;
|
||||
signature->params = decls;
|
||||
signature->variadic = variadic;
|
||||
|
||||
@@ -1529,12 +1536,12 @@ static bool parse_macro_arguments(ParseContext *c, Visibility visibility, Decl *
|
||||
|
||||
// Parse the regular parameters.
|
||||
Variadic variadic = VARIADIC_NONE;
|
||||
unsigned vararg_index = 0;
|
||||
int vararg_index = -1;
|
||||
Decl **params = NULL;
|
||||
if (!parse_parameters(c, visibility, ¶ms, NULL, &variadic, &vararg_index)) return false;
|
||||
macro->macro_decl.parameters = params;
|
||||
macro->macro_decl.vararg_index = vararg_index;
|
||||
macro->macro_decl.variadic = variadic;
|
||||
macro->func_decl.signature.params = params;
|
||||
macro->func_decl.signature.vararg_index = vararg_index < 0 ? vec_size(params) : vararg_index;
|
||||
macro->func_decl.signature.variadic = variadic;
|
||||
|
||||
// Do we have trailing block parameters?
|
||||
if (try_consume(c, TOKEN_EOS))
|
||||
@@ -1547,11 +1554,11 @@ static bool parse_macro_arguments(ParseContext *c, Visibility visibility, Decl *
|
||||
if (!parse_parameters(c, visibility, &body_param->body_params, NULL, NULL, NULL)) return false;
|
||||
CONSUME_OR_RET(TOKEN_RPAREN, false);
|
||||
}
|
||||
macro->macro_decl.body_param = declid(body_param);
|
||||
macro->func_decl.body_param = declid(body_param);
|
||||
}
|
||||
else
|
||||
{
|
||||
macro->macro_decl.body_param = 0;
|
||||
macro->func_decl.body_param = 0;
|
||||
}
|
||||
CONSUME_OR_RET(TOKEN_RPAREN, false);
|
||||
return true;
|
||||
@@ -1606,7 +1613,7 @@ static inline Decl *parse_define_type(ParseContext *c, Visibility visibility)
|
||||
decl->typedef_decl.is_func = true;
|
||||
decl->typedef_decl.is_distinct = distinct;
|
||||
ASSIGN_TYPE_OR_RET(TypeInfo *type_info, parse_optional_type(c), poisoned_decl);
|
||||
decl->typedef_decl.function_signature.returntype = type_infoid(type_info);
|
||||
decl->typedef_decl.function_signature.rtype = type_infoid(type_info);
|
||||
if (!parse_fn_parameter_list(c, decl->visibility, &(decl->typedef_decl.function_signature), true))
|
||||
{
|
||||
return poisoned_decl;
|
||||
@@ -1794,13 +1801,13 @@ static inline bool parse_is_macro_name(ParseContext *c)
|
||||
* func_header ::= type '!'? (type '.')? (IDENT | MACRO_IDENT)
|
||||
* macro_header ::= (type '!'?)? (type '.')? (IDENT | MACRO_IDENT)
|
||||
*/
|
||||
static inline bool parse_func_macro_header(ParseContext *c, bool is_macro,
|
||||
TypeInfoId *rtype_ref, TypeInfoId *method_type_ref,
|
||||
const char **name_ref, SourceSpan *name_span)
|
||||
static inline bool parse_func_macro_header(ParseContext *c, Decl *decl)
|
||||
{
|
||||
TypeInfo *rtype = NULL;
|
||||
TypeInfo *method_type = NULL;
|
||||
|
||||
bool is_macro = decl->decl_kind == DECL_MACRO;
|
||||
|
||||
// 1. If we have a macro and see the name, we're done.
|
||||
if (is_macro && parse_is_macro_name(c))
|
||||
{
|
||||
@@ -1839,8 +1846,8 @@ static inline bool parse_func_macro_header(ParseContext *c, bool is_macro,
|
||||
return false;
|
||||
}
|
||||
RESULT:
|
||||
*name_ref = symstr(c);
|
||||
*name_span = c->span;
|
||||
decl->name = symstr(c);
|
||||
decl->span = c->span;
|
||||
if (is_macro && c->tok != TOKEN_IDENT && c->tok != TOKEN_AT_IDENT)
|
||||
{
|
||||
sema_error_at(c->span, "Expected a macro name here, e.g. '@someName' or 'someName'.");
|
||||
@@ -1852,8 +1859,10 @@ static inline bool parse_func_macro_header(ParseContext *c, bool is_macro,
|
||||
return false;
|
||||
}
|
||||
advance(c);
|
||||
*rtype_ref = rtype ? type_infoid(rtype) : 0;
|
||||
*method_type_ref = method_type ? type_infoid(method_type) : 0;
|
||||
decl->func_decl.signature.rtype = rtype ? type_infoid(rtype) : 0;
|
||||
decl->func_decl.signature.is_macro = is_macro;
|
||||
decl->func_decl.signature.is_at_macro = decl->name[0] == '@';
|
||||
decl->func_decl.type_parent = method_type ? type_infoid(method_type) : 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1869,15 +1878,13 @@ static inline Decl *parse_macro_declaration(ParseContext *c, Visibility visibili
|
||||
Decl *decl = decl_calloc();
|
||||
decl->decl_kind = kind;
|
||||
decl->visibility = visibility;
|
||||
decl->macro_decl.docs = docs;
|
||||
TypeInfoId *rtype_ref = &decl->macro_decl.rtype;
|
||||
TypeInfoId *method_type_ref = &decl->macro_decl.type_parent;
|
||||
if (!parse_func_macro_header(c, true, rtype_ref, method_type_ref, &decl->name, &decl->span)) return poisoned_decl;
|
||||
decl->func_decl.docs = docs;
|
||||
if (!parse_func_macro_header(c, decl)) return poisoned_decl;
|
||||
const char *block_parameter = NULL;
|
||||
if (!parse_macro_arguments(c, visibility, decl)) return poisoned_decl;
|
||||
|
||||
if (!parse_attributes(c, &decl->attributes)) return poisoned_decl;
|
||||
ASSIGN_ASTID_OR_RET(decl->macro_decl.body, parse_stmt(c), poisoned_decl);
|
||||
ASSIGN_ASTID_OR_RET(decl->func_decl.body, parse_stmt(c), poisoned_decl);
|
||||
return decl;
|
||||
}
|
||||
|
||||
@@ -2073,15 +2080,13 @@ static inline Decl *parse_func_definition(ParseContext *c, Visibility visibility
|
||||
func->decl_kind = DECL_FUNC;
|
||||
func->visibility = visibility;
|
||||
func->func_decl.docs = docs;
|
||||
TypeInfoId *rtype_id_ref = &func->func_decl.function_signature.returntype;
|
||||
TypeInfoId *method_type_ref = &func->func_decl.type_parent;
|
||||
if (!parse_func_macro_header(c, false, rtype_id_ref, method_type_ref, &func->name, &func->span)) return poisoned_decl;
|
||||
if (!parse_func_macro_header(c, func)) return poisoned_decl;
|
||||
if (func->name[0] == '@')
|
||||
{
|
||||
SEMA_ERROR(func, "Function names may not use '@'.");
|
||||
return false;
|
||||
}
|
||||
if (!parse_fn_parameter_list(c, visibility, &(func->func_decl.function_signature), is_interface)) return poisoned_decl;
|
||||
if (!parse_fn_parameter_list(c, visibility, &(func->func_decl.signature), is_interface)) return poisoned_decl;
|
||||
if (!parse_attributes(c, &func->attributes)) return poisoned_decl;
|
||||
|
||||
// TODO remove
|
||||
|
||||
@@ -856,7 +856,6 @@ Ast *parse_stmt(ParseContext *c)
|
||||
case TOKEN_HASH_IDENT:
|
||||
case TOKEN_IDENT:
|
||||
case TOKEN_CONST_IDENT:
|
||||
case TOKEN_CT_EVALTYPE:
|
||||
return parse_decl_or_expr_stmt(c);
|
||||
case TOKEN_VAR:
|
||||
return parse_var_stmt(c);
|
||||
@@ -964,7 +963,6 @@ Ast *parse_stmt(ParseContext *c)
|
||||
case TOKEN_CT_VAARG_GET_EXPR:
|
||||
case TOKEN_CT_VAARG_GET_CONST:
|
||||
case TOKEN_CT_VAARG_GET_REF:
|
||||
case TOKEN_CT_VAARG_GET_TYPE:
|
||||
return parse_expr_stmt(c);
|
||||
case TOKEN_ASSERT:
|
||||
return parse_assert_stmt(c);
|
||||
|
||||
@@ -46,7 +46,7 @@ Decl *parse_var_decl(ParseContext *c);
|
||||
|
||||
bool
|
||||
parse_parameters(ParseContext *c, Visibility visibility, Decl ***params_ref, Decl **body_params, Variadic *variadic,
|
||||
unsigned *vararg_index_ref);
|
||||
int *vararg_index_ref);
|
||||
bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool *splat);
|
||||
Expr *parse_type_compound_literal_expr_after_type(ParseContext *c, TypeInfo *type_info);
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ static inline bool sema_check_param_uniqueness_and_type(Decl **decls, Decl *curr
|
||||
{
|
||||
if (name == decls[i]->name)
|
||||
{
|
||||
SEMA_ERROR(current, "Duplicate parameter name %s.", name);
|
||||
SEMA_ERROR(current, "Duplicate parameter name '%s'.", name);
|
||||
SEMA_NOTE(decls[i], "Previous use of the name was here.");
|
||||
decl_poison(decls[i]);
|
||||
decl_poison(current);
|
||||
@@ -581,51 +581,40 @@ static bool sema_analyse_bitstruct(SemaContext *context, Decl *decl)
|
||||
}
|
||||
|
||||
|
||||
static inline bool sema_analyse_function_param(SemaContext *context, Decl *param)
|
||||
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig)
|
||||
{
|
||||
param->unit = context->unit;
|
||||
assert(param->decl_kind == DECL_VAR);
|
||||
// We need to check that the parameters are not typeless nor are of any macro parameter kind.
|
||||
if (param->var.kind != VARDECL_PARAM)
|
||||
{
|
||||
SEMA_ERROR(param, "Only regular parameters are allowed for functions.");
|
||||
return false;
|
||||
}
|
||||
Variadic variadic_type = sig->variadic;
|
||||
Decl **params = sig->params;
|
||||
unsigned param_count = vec_size(params);
|
||||
unsigned vararg_index = sig->vararg_index;
|
||||
bool is_fn = !sig->is_macro;
|
||||
bool is_macro_at_name = sig->is_at_macro;
|
||||
|
||||
if (!sema_analyse_attributes_for_var(context, param)) return false;
|
||||
if (!param->var.type_info)
|
||||
// Check return type
|
||||
assert(sig->rtype || sig->is_macro);
|
||||
Type *rtype = NULL;
|
||||
if (sig->rtype)
|
||||
{
|
||||
SEMA_ERROR(param, "Only typed parameters are allowed for functions.");
|
||||
return false;
|
||||
}
|
||||
if (!sema_resolve_type_info(context, param->var.type_info)) return false;
|
||||
|
||||
if (param->var.vararg)
|
||||
{
|
||||
param->var.type_info->type = type_get_subarray(param->var.type_info->type);
|
||||
}
|
||||
param->type = param->var.type_info->type;
|
||||
if (param->var.init_expr)
|
||||
{
|
||||
Expr *expr = param->var.init_expr;
|
||||
|
||||
if (expr->expr_kind == EXPR_CONST)
|
||||
TypeInfo *rtype_info = type_infoptr(sig->rtype);
|
||||
if (!sema_resolve_type_info(context, type_infoptr(sig->rtype))) return false;
|
||||
rtype = rtype_info->type;
|
||||
if (sig->attrs.nodiscard)
|
||||
{
|
||||
if (!sema_analyse_expr_rhs(context, param->type, expr, true)) return false;
|
||||
if (rtype == type_void)
|
||||
{
|
||||
SEMA_ERROR(rtype_info, "@nodiscard cannot be used on %s returning 'void'.", is_fn ? "functions" : "macros");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (sig->attrs.maydiscard)
|
||||
{
|
||||
if (!type_is_optional(rtype))
|
||||
{
|
||||
SEMA_ERROR(rtype_info, "@maydiscard can only be used on %s returning optional values.", is_fn ? "functions" : "macros");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
param->alignment = type_abi_alignment(param->type);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline Type *sema_analyse_function_signature(SemaContext *context, Decl *parent, CallABI abi, FunctionSignature *signature, bool is_real_function)
|
||||
{
|
||||
// Get param count and variadic type
|
||||
Variadic variadic_type = signature->variadic;
|
||||
Decl **params = signature->params;
|
||||
unsigned param_count = vec_size(params);
|
||||
|
||||
bool all_ok = sema_resolve_type_info(context, type_infoptr(signature->returntype));
|
||||
|
||||
// We don't support more than MAX_PARAMS number of params. This makes everything sane.
|
||||
if (param_count > MAX_PARAMS)
|
||||
@@ -633,39 +622,28 @@ static inline Type *sema_analyse_function_signature(SemaContext *context, Decl *
|
||||
if (variadic_type != VARIADIC_NONE)
|
||||
{
|
||||
SEMA_ERROR(params[MAX_PARAMS], "The number of params exceeded the max of %d.", MAX_PARAMS);
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
SEMA_ERROR(params[MAX_PARAMS], "The number of params exceeded the max of %d. To accept more arguments, consider using varargs.", MAX_PARAMS);
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
Type **types = NULL;
|
||||
int vararg_index = -1;
|
||||
// Check parameters
|
||||
for (unsigned i = 0; i < param_count; i++)
|
||||
{
|
||||
Decl *param = params[i];
|
||||
// We might run into a raw vararg
|
||||
if (!param)
|
||||
{
|
||||
assert(variadic_type == VARIADIC_RAW);
|
||||
vararg_index = i;
|
||||
assert(i == vararg_index);
|
||||
continue;
|
||||
}
|
||||
assert(param->resolve_status == RESOLVE_NOT_DONE && "The param shouldn't have been resolved yet.");
|
||||
param->resolve_status = RESOLVE_RUNNING;
|
||||
// Analyse the param
|
||||
if (!sema_analyse_function_param(context, param))
|
||||
if (vararg_index < i)
|
||||
{
|
||||
decl_poison(param);
|
||||
all_ok = false;
|
||||
continue;
|
||||
}
|
||||
if (vararg_index > -1)
|
||||
{
|
||||
if (variadic_type == VARIADIC_RAW)
|
||||
if (is_fn && variadic_type == VARIADIC_RAW)
|
||||
{
|
||||
SEMA_ERROR(param, "C-style varargs cannot be followed by regular parameters.");
|
||||
return NULL;
|
||||
return decl_poison(param);
|
||||
}
|
||||
|
||||
// If we already reached a vararg (as a previous argument) and we have a
|
||||
@@ -673,48 +651,149 @@ static inline Type *sema_analyse_function_signature(SemaContext *context, Decl *
|
||||
if (!param->name)
|
||||
{
|
||||
SEMA_ERROR(param, "A parameter name was expected, as parameters after varargs must always be named.");
|
||||
decl_poison(param);
|
||||
all_ok = false;
|
||||
continue;
|
||||
return decl_poison(param);
|
||||
}
|
||||
}
|
||||
// Disallow "void" args and repeating the same parameter name.
|
||||
// This must be done after checking raw varargs
|
||||
if (!sema_check_param_uniqueness_and_type(params, param, i, param_count))
|
||||
|
||||
assert(param->resolve_status == RESOLVE_NOT_DONE && "The param shouldn't have been resolved yet.");
|
||||
param->resolve_status = RESOLVE_RUNNING;
|
||||
param->unit = context->unit;
|
||||
assert(param->decl_kind == DECL_VAR);
|
||||
VarDeclKind var_kind = param->var.kind;
|
||||
switch (var_kind)
|
||||
{
|
||||
all_ok = false;
|
||||
case VARDECL_PARAM_EXPR:
|
||||
case VARDECL_PARAM_REF:
|
||||
if (is_fn)
|
||||
{
|
||||
SEMA_ERROR(param, "Only regular parameters are allowed for functions.");
|
||||
return decl_poison(param);
|
||||
}
|
||||
if (!is_macro_at_name)
|
||||
{
|
||||
SEMA_ERROR(param, "Ref and expression parameters are not allowed in function-like macros. Prefix the macro name with '@'.");
|
||||
return decl_poison(param);
|
||||
}
|
||||
FALLTHROUGH;
|
||||
case VARDECL_PARAM_CT:
|
||||
if (is_fn)
|
||||
{
|
||||
SEMA_ERROR(param, "Only regular parameters are allowed for functions.");
|
||||
return decl_poison(param);
|
||||
}
|
||||
FALLTHROUGH;
|
||||
case VARDECL_PARAM:
|
||||
if (param->var.type_info)
|
||||
{
|
||||
if (!sema_resolve_type_info(context, param->var.type_info)) return decl_poison(param);
|
||||
param->type = param->var.type_info->type;
|
||||
}
|
||||
else if (is_fn)
|
||||
{
|
||||
SEMA_ERROR(param, "Only typed parameters are allowed for functions.");
|
||||
return false;
|
||||
}
|
||||
if (!sema_analyse_attributes_for_var(context, param)) return false;
|
||||
break;
|
||||
case VARDECL_PARAM_CT_TYPE:
|
||||
if (is_fn)
|
||||
{
|
||||
SEMA_ERROR(param, "Only regular parameters are allowed for functions.");
|
||||
return decl_poison(param);
|
||||
}
|
||||
if (param->var.type_info)
|
||||
{
|
||||
SEMA_ERROR(param->var.type_info, "A compile time type parameter cannot have a type itself.");
|
||||
return decl_poison(param);
|
||||
}
|
||||
break;
|
||||
case VARDECL_CONST:
|
||||
case VARDECL_GLOBAL:
|
||||
case VARDECL_LOCAL:
|
||||
case VARDECL_MEMBER:
|
||||
case VARDECL_BITMEMBER:
|
||||
case VARDECL_LOCAL_CT:
|
||||
case VARDECL_LOCAL_CT_TYPE:
|
||||
case VARDECL_UNWRAPPED:
|
||||
case VARDECL_REWRAPPED:
|
||||
case VARDECL_ERASE:
|
||||
UNREACHABLE
|
||||
}
|
||||
// Update whether this was a vararg, and update "default" for the signature.
|
||||
if (param->var.vararg)
|
||||
{
|
||||
if (vararg_index > -1)
|
||||
if (var_kind != VARDECL_PARAM)
|
||||
{
|
||||
SEMA_ERROR(param, "A function may not have more than one vararg.");
|
||||
all_ok = false;
|
||||
SEMA_ERROR(param, "Only regular parameters may be vararg.");
|
||||
return decl_poison(param);
|
||||
}
|
||||
vararg_index = i;
|
||||
if (!param->var.type_info)
|
||||
{
|
||||
SEMA_ERROR(param, "Only typed parameters may be vararg.");
|
||||
return decl_poison(param);
|
||||
}
|
||||
// Update whether this was a vararg, and update "default" for the signature.
|
||||
if (param->var.vararg)
|
||||
{
|
||||
if (vararg_index != i)
|
||||
{
|
||||
SEMA_ERROR(param, "A %s may not have more than one vararg.", is_fn ? "function" : "macro");
|
||||
return decl_poison(param);
|
||||
}
|
||||
}
|
||||
param->var.type_info->type = type_get_subarray(param->var.type_info->type);
|
||||
}
|
||||
// Resolution is done.
|
||||
|
||||
if (param->var.type_info)
|
||||
{
|
||||
param->type = param->var.type_info->type;
|
||||
param->alignment = type_abi_alignment(param->type);
|
||||
}
|
||||
if (param->var.init_expr)
|
||||
{
|
||||
Expr *expr = param->var.init_expr;
|
||||
if (expr->expr_kind == EXPR_CONST)
|
||||
{
|
||||
if (!sema_analyse_expr_rhs(context, param->type, expr, true)) return decl_poison(param);
|
||||
}
|
||||
}
|
||||
if (!sema_check_param_uniqueness_and_type(params, param, i, param_count)) return decl_poison(param);
|
||||
param->resolve_status = RESOLVE_DONE;
|
||||
// Add it to the type for the type signature.
|
||||
vec_add(types, param->type);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static inline Type *sema_analyse_function_signature(SemaContext *context, Decl *parent, CallABI abi, Signature *signature, bool is_real_function)
|
||||
{
|
||||
// Get param count and variadic type
|
||||
Decl **params = signature->params;
|
||||
|
||||
if (!sema_analyse_signature(context, signature)) return NULL;
|
||||
|
||||
Variadic variadic_type = signature->variadic;
|
||||
// Remove the last empty value.
|
||||
if (variadic_type == VARIADIC_RAW)
|
||||
{
|
||||
assert(vararg_index >= 0);
|
||||
assert(!params[vararg_index] && "The last parameter must have been a raw variadic.");
|
||||
assert(vararg_index == param_count - 1);
|
||||
assert(!params[signature->vararg_index] && "The last parameter must have been a raw variadic.");
|
||||
assert(signature->vararg_index == vec_size(params) - 1);
|
||||
vec_pop(params);
|
||||
}
|
||||
|
||||
Type **types = NULL;
|
||||
bool all_ok = true;
|
||||
unsigned param_count = vec_size(params);
|
||||
|
||||
for (unsigned i = 0; i < param_count; i++)
|
||||
{
|
||||
vec_add(types, params[i]->type);
|
||||
}
|
||||
|
||||
if (!all_ok) return NULL;
|
||||
Type *raw_type = type_get_func(signature, abi);
|
||||
Type *type = type_new(TYPE_FUNC, parent->name);
|
||||
type->canonical = type;
|
||||
type->function.attrs = signature->attrs;
|
||||
type->function.signature = signature;
|
||||
type->function.module = parent->unit->module;
|
||||
type->function.params = signature->params;
|
||||
type->function.prototype = raw_type->function.prototype;
|
||||
return type;
|
||||
}
|
||||
@@ -1007,33 +1086,11 @@ static inline const char *name_by_decl(Decl *method_like)
|
||||
}
|
||||
|
||||
|
||||
static inline void find_operator_parameters(Decl *method, TypeInfoId *rtype_ptr, Decl ***params_ptr)
|
||||
{
|
||||
switch (method->decl_kind)
|
||||
{
|
||||
case DECL_GENERIC:
|
||||
*params_ptr = method->generic_decl.parameters;
|
||||
*rtype_ptr = method->generic_decl.rtype;
|
||||
break;
|
||||
case DECL_MACRO:
|
||||
*params_ptr = method->macro_decl.parameters;
|
||||
*rtype_ptr = method->macro_decl.rtype;
|
||||
break;
|
||||
case DECL_FUNC:
|
||||
*params_ptr = method->func_decl.function_signature.params;
|
||||
*rtype_ptr = method->func_decl.function_signature.returntype;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool sema_analyse_operator_common(Decl *method, TypeInfo **rtype_ptr, Decl ***params_ptr, uint32_t parameters)
|
||||
{
|
||||
TypeInfoId rtype_id;
|
||||
find_operator_parameters(method, &rtype_id, params_ptr);
|
||||
Decl **params = *params_ptr;
|
||||
Signature *signature = &method->func_decl.signature;
|
||||
Decl **params = *params_ptr = signature->params;
|
||||
uint32_t param_count = vec_size(params);
|
||||
if (param_count > parameters)
|
||||
{
|
||||
@@ -1046,7 +1103,7 @@ static bool sema_analyse_operator_common(Decl *method, TypeInfo **rtype_ptr, Dec
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!rtype_id)
|
||||
if (!signature->rtype)
|
||||
{
|
||||
SEMA_ERROR(method, "The return value must be explicitly typed for '%s'.", method->name);
|
||||
return false;
|
||||
@@ -1060,7 +1117,7 @@ static bool sema_analyse_operator_common(Decl *method, TypeInfo **rtype_ptr, Dec
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*rtype_ptr = type_infoptr(rtype_id);
|
||||
*rtype_ptr = type_infoptr(signature->rtype);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1233,7 +1290,7 @@ static inline bool sema_analyse_method(SemaContext *context, Decl *decl)
|
||||
type_to_error_string(parent_type->type));
|
||||
return false;
|
||||
}
|
||||
Decl **params = decl->func_decl.function_signature.params;
|
||||
Decl **params = decl->func_decl.signature.params;
|
||||
if (!vec_size(params))
|
||||
{
|
||||
SEMA_ERROR(decl, "A method must start with a parameter of type %s or %s.",
|
||||
@@ -1330,21 +1387,21 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
|
||||
switch (type)
|
||||
{
|
||||
case ATTRIBUTE_CDECL:
|
||||
decl->func_decl.function_signature.abi = CALL_C;
|
||||
decl->func_decl.signature.abi = CALL_C;
|
||||
break;
|
||||
case ATTRIBUTE_VECCALL:
|
||||
switch (platform_target.arch)
|
||||
{
|
||||
case ARCH_TYPE_X86_64:
|
||||
case ARCH_TYPE_X86:
|
||||
decl->func_decl.function_signature.abi = CALL_X86_VECTOR;
|
||||
decl->func_decl.signature.abi = CALL_X86_VECTOR;
|
||||
break;
|
||||
case ARCH_TYPE_ARM:
|
||||
case ARCH_TYPE_ARMB:
|
||||
case ARCH_TYPE_AARCH64:
|
||||
case ARCH_TYPE_AARCH64_32:
|
||||
case ARCH_TYPE_AARCH64_BE:
|
||||
decl->func_decl.function_signature.abi = CALL_AAPCS_VFP;
|
||||
decl->func_decl.signature.abi = CALL_AAPCS_VFP;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -1354,25 +1411,25 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
|
||||
assert(decl->decl_kind == DECL_FUNC);
|
||||
if (platform_target.arch == ARCH_TYPE_X86 || platform_target.arch == ARCH_TYPE_X86_64)
|
||||
{
|
||||
decl->func_decl.function_signature.abi = CALL_X86_STD;
|
||||
decl->func_decl.signature.abi = CALL_X86_STD;
|
||||
}
|
||||
else if (platform_target.arch == ARCH_TYPE_ARM || platform_target.arch == ARCH_TYPE_ARMB)
|
||||
{
|
||||
decl->func_decl.function_signature.abi = CALL_AAPCS;
|
||||
decl->func_decl.signature.abi = CALL_AAPCS;
|
||||
}
|
||||
break; // Check args
|
||||
case ATTRIBUTE_FASTCALL:
|
||||
if (platform_target.arch == ARCH_TYPE_X86 ||
|
||||
(platform_target.arch == ARCH_TYPE_X86_64 && platform_target.os == OS_TYPE_WIN32))
|
||||
{
|
||||
decl->func_decl.function_signature.abi = CALL_X86_FAST;
|
||||
decl->func_decl.signature.abi = CALL_X86_FAST;
|
||||
}
|
||||
break;
|
||||
case ATTRIBUTE_REGCALL:
|
||||
if (platform_target.arch == ARCH_TYPE_X86 ||
|
||||
(platform_target.arch == ARCH_TYPE_X86_64 && platform_target.os == OS_TYPE_WIN32))
|
||||
{
|
||||
decl->func_decl.function_signature.abi = CALL_X86_REG;
|
||||
decl->func_decl.signature.abi = CALL_X86_REG;
|
||||
}
|
||||
break;
|
||||
case ATTRIBUTE_OPERATOR:
|
||||
@@ -1476,33 +1533,17 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
|
||||
decl->func_decl.attr_inline = false;
|
||||
break;
|
||||
case ATTRIBUTE_NODISCARD:
|
||||
if (domain == ATTR_MACRO)
|
||||
{
|
||||
decl->macro_decl.attr_nodiscard = true;
|
||||
break;
|
||||
}
|
||||
decl->func_decl.function_signature.attrs.nodiscard = true;
|
||||
decl->func_decl.signature.attrs.nodiscard = true;
|
||||
break;
|
||||
case ATTRIBUTE_MAYDISCARD:
|
||||
if (domain == ATTR_MACRO)
|
||||
{
|
||||
decl->macro_decl.attr_maydiscard = true;
|
||||
break;
|
||||
}
|
||||
decl->func_decl.function_signature.attrs.maydiscard = true;
|
||||
decl->func_decl.signature.attrs.maydiscard = true;
|
||||
break;
|
||||
case ATTRIBUTE_INLINE:
|
||||
decl->func_decl.attr_inline = true;
|
||||
decl->func_decl.attr_noinline = false;
|
||||
break;
|
||||
case ATTRIBUTE_NORETURN:
|
||||
if (domain == ATTR_MACRO)
|
||||
{
|
||||
decl->macro_decl.attr_noreturn = true;
|
||||
break;
|
||||
}
|
||||
assert(domain == ATTR_FUNC);
|
||||
decl->func_decl.attr_noreturn = true;
|
||||
decl->func_decl.signature.attrs.noreturn = true;
|
||||
break;
|
||||
case ATTRIBUTE_WEAK:
|
||||
decl->is_weak = true;
|
||||
@@ -1736,8 +1777,8 @@ static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl)
|
||||
SEMA_ERROR(decl, "A main function may not have local visibility.");
|
||||
return false;
|
||||
}
|
||||
FunctionSignature *signature = &decl->func_decl.function_signature;
|
||||
TypeInfo *rtype_info = type_infoptr(signature->returntype);
|
||||
Signature *signature = &decl->func_decl.signature;
|
||||
TypeInfo *rtype_info = type_infoptr(signature->rtype);
|
||||
Type *rtype = type_flatten_distinct(rtype_info->type);
|
||||
bool is_int_return = true;
|
||||
bool is_err_return = false;
|
||||
@@ -1807,13 +1848,14 @@ static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl)
|
||||
function->unit = decl->unit;
|
||||
function->extname = kw_main;
|
||||
function->has_extname = true;
|
||||
function->func_decl.function_signature.returntype = type_infoid(type_info_new_base(type_cint, decl->span));
|
||||
function->func_decl.signature.rtype = type_infoid(type_info_new_base(type_cint, decl->span));
|
||||
function->func_decl.signature.vararg_index = 2;
|
||||
Decl *param1 = decl_new_generated_var(type_cint, VARDECL_PARAM, decl->span);
|
||||
Decl *param2 = decl_new_generated_var(type_get_ptr(type_get_ptr(type_char)), VARDECL_PARAM, decl->span);
|
||||
Decl **main_params = NULL;
|
||||
vec_add(main_params, param1);
|
||||
vec_add(main_params, param2);
|
||||
function->func_decl.function_signature.params = main_params;
|
||||
function->func_decl.signature.params = main_params;
|
||||
Ast *body = new_ast(AST_COMPOUND_STMT, decl->span);
|
||||
AstId *next = &body->compound_stmt.first_stmt;
|
||||
Ast *ret_stmt = new_ast(AST_RETURN_STMT, decl->span);
|
||||
@@ -1877,19 +1919,24 @@ REGISTER_MAIN:
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_func_macro(SemaContext *context, Decl *decl, bool is_func)
|
||||
{
|
||||
if (!sema_analyse_attributes(context, decl, decl->attributes, is_func ? ATTR_FUNC : ATTR_MACRO)) return decl_poison(decl);
|
||||
return true;
|
||||
}
|
||||
static inline bool sema_analyse_func(SemaContext *context, Decl *decl)
|
||||
{
|
||||
DEBUG_LOG("----Analysing function %s", decl->name);
|
||||
|
||||
if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_FUNC)) return decl_poison(decl);
|
||||
if (!sema_analyse_func_macro(context, decl, true)) return false;
|
||||
|
||||
Type *func_type = sema_analyse_function_signature(context, decl, decl->func_decl.function_signature.abi, &decl->func_decl.function_signature, true);
|
||||
Type *func_type = sema_analyse_function_signature(context, decl, decl->func_decl.signature.abi, &decl->func_decl.signature, true);
|
||||
decl->type = func_type;
|
||||
if (!func_type) return decl_poison(decl);
|
||||
TypeInfo *rtype_info = type_infoptr(decl->func_decl.function_signature.returntype);
|
||||
TypeInfo *rtype_info = type_infoptr(decl->func_decl.signature.rtype);
|
||||
assert(rtype_info);
|
||||
Type *rtype = rtype_info->type->canonical;
|
||||
if (decl->func_decl.function_signature.attrs.nodiscard)
|
||||
if (decl->func_decl.signature.attrs.nodiscard)
|
||||
{
|
||||
if (rtype == type_void)
|
||||
{
|
||||
@@ -1897,7 +1944,7 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl)
|
||||
return decl_poison(decl);
|
||||
}
|
||||
}
|
||||
if (decl->func_decl.function_signature.attrs.maydiscard)
|
||||
if (decl->func_decl.signature.attrs.maydiscard)
|
||||
{
|
||||
if (!type_is_optional(rtype))
|
||||
{
|
||||
@@ -1918,8 +1965,8 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl)
|
||||
decl_set_external_name(decl);
|
||||
}
|
||||
bool pure = false;
|
||||
if (!sema_analyse_doc_header(decl->func_decl.docs, decl->func_decl.function_signature.params, NULL, &pure)) return decl_poison(decl);
|
||||
decl->func_decl.function_signature.is_pure = pure;
|
||||
if (!sema_analyse_doc_header(decl->func_decl.docs, decl->func_decl.signature.params, NULL, &pure)) return decl_poison(decl);
|
||||
decl->func_decl.signature.attrs.is_pure = pure;
|
||||
decl->alignment = type_alloca_alignment(decl->type);
|
||||
DEBUG_LOG("Function analysis done.");
|
||||
return true;
|
||||
@@ -1945,7 +1992,7 @@ ERROR:
|
||||
|
||||
static bool sema_analyse_macro_method(SemaContext *context, Decl *decl)
|
||||
{
|
||||
TypeInfo *parent_type_info = type_infoptr(decl->macro_decl.type_parent);
|
||||
TypeInfo *parent_type_info = type_infoptr(decl->func_decl.type_parent);
|
||||
if (!sema_resolve_type_info(context, parent_type_info)) return false;
|
||||
Type *parent_type = parent_type_info->type;
|
||||
if (!type_may_have_sub_elements(parent_type))
|
||||
@@ -1955,12 +2002,12 @@ static bool sema_analyse_macro_method(SemaContext *context, Decl *decl)
|
||||
type_to_error_string(parent_type));
|
||||
return false;
|
||||
}
|
||||
if (!vec_size(decl->macro_decl.parameters))
|
||||
if (!vec_size(decl->func_decl.signature.params))
|
||||
{
|
||||
SEMA_ERROR(decl, "Expected at least one parameter - of type %s.", type_to_error_string(parent_type));
|
||||
return false;
|
||||
}
|
||||
Decl *first_param = decl->macro_decl.parameters[0];
|
||||
Decl *first_param = decl->func_decl.signature.params[0];
|
||||
|
||||
if (!sema_is_valid_method_param(context, first_param, parent_type->canonical)) return false;
|
||||
|
||||
@@ -1975,91 +2022,21 @@ static bool sema_analyse_macro_method(SemaContext *context, Decl *decl)
|
||||
static inline bool sema_analyse_macro(SemaContext *context, Decl *decl)
|
||||
{
|
||||
bool is_generic = decl->decl_kind == DECL_GENERIC;
|
||||
decl->func_decl.unit = context->unit;
|
||||
|
||||
if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_MACRO)) return decl_poison(decl);
|
||||
if (!sema_analyse_func_macro(context, decl, false)) return false;
|
||||
if (!sema_analyse_signature(context, &decl->func_decl.signature)) return decl_poison(decl);
|
||||
|
||||
if (decl->macro_decl.rtype)
|
||||
if (!decl->func_decl.signature.is_at_macro && decl->func_decl.body_param)
|
||||
{
|
||||
TypeInfo *rtype_info = type_infoptr(decl->macro_decl.rtype);
|
||||
if (!sema_resolve_type_info(context, rtype_info)) return decl_poison(decl);
|
||||
Type *rtype = rtype_info->type;
|
||||
if (decl->macro_decl.attr_nodiscard)
|
||||
{
|
||||
if (rtype == type_void)
|
||||
{
|
||||
SEMA_ERROR(rtype_info, "@nodiscard cannot be used on macros returning 'void'.");
|
||||
return decl_poison(decl);
|
||||
}
|
||||
}
|
||||
if (decl->macro_decl.attr_maydiscard)
|
||||
{
|
||||
if (!type_is_optional(rtype))
|
||||
{
|
||||
SEMA_ERROR(rtype_info, "@maydiscard can only be used on macros returning optional values.");
|
||||
return decl_poison(decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
decl->macro_decl.unit = context->unit;
|
||||
Decl **parameters = decl->macro_decl.parameters;
|
||||
unsigned param_count = vec_size(parameters);
|
||||
bool is_function_like = true;
|
||||
for (unsigned i = 0; i < param_count; i++)
|
||||
{
|
||||
Decl *param = parameters[i];
|
||||
param->unit = context->unit;
|
||||
param->resolve_status = RESOLVE_RUNNING;
|
||||
assert(param->decl_kind == DECL_VAR);
|
||||
switch (param->var.kind)
|
||||
{
|
||||
case VARDECL_PARAM_EXPR:
|
||||
case VARDECL_PARAM_REF:
|
||||
is_function_like = false;
|
||||
FALLTHROUGH;
|
||||
case VARDECL_PARAM_CT:
|
||||
if (is_generic)
|
||||
{
|
||||
SEMA_ERROR(param, "Only regular parameters and type parameters are allowed for generic functions.");
|
||||
return decl_poison(decl);
|
||||
}
|
||||
FALLTHROUGH;
|
||||
case VARDECL_PARAM:
|
||||
if (param->var.type_info)
|
||||
{
|
||||
if (!sema_resolve_type_info(context, param->var.type_info)) return decl_poison(decl);
|
||||
param->type = param->var.type_info->type;
|
||||
}
|
||||
break;
|
||||
case VARDECL_PARAM_CT_TYPE:
|
||||
if (param->var.type_info)
|
||||
{
|
||||
SEMA_ERROR(param->var.type_info, "A compile time type parameter cannot have a type itself.");
|
||||
return decl_poison(decl);
|
||||
}
|
||||
break;
|
||||
case VARDECL_CONST:
|
||||
case VARDECL_GLOBAL:
|
||||
case VARDECL_LOCAL:
|
||||
case VARDECL_MEMBER:
|
||||
case VARDECL_BITMEMBER:
|
||||
case VARDECL_LOCAL_CT:
|
||||
case VARDECL_LOCAL_CT_TYPE:
|
||||
case VARDECL_UNWRAPPED:
|
||||
case VARDECL_REWRAPPED:
|
||||
case VARDECL_ERASE:
|
||||
UNREACHABLE
|
||||
}
|
||||
if (!sema_check_param_uniqueness_and_type(parameters, param, i, param_count)) return decl_poison(decl);
|
||||
param->resolve_status = RESOLVE_DONE;
|
||||
}
|
||||
DeclId body_param = decl->macro_decl.body_param;
|
||||
if (body_param) is_function_like = false;
|
||||
if (is_generic && body_param)
|
||||
{
|
||||
SEMA_ERROR(declptr(body_param), "Trailing block syntax is not allowed for generic functions.");
|
||||
SEMA_ERROR(decl, "Names of macros with a trailing body must start with '@'.");
|
||||
return decl_poison(decl);
|
||||
}
|
||||
|
||||
Decl **parameters = decl->func_decl.signature.params;
|
||||
unsigned param_count = vec_size(parameters);
|
||||
DeclId body_param = decl->func_decl.body_param;
|
||||
|
||||
Decl **body_parameters = body_param ? declptr(body_param)->body_params : NULL;
|
||||
unsigned body_param_count = vec_size(body_parameters);
|
||||
for (unsigned i = 0; i < body_param_count; i++)
|
||||
@@ -2094,13 +2071,9 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl)
|
||||
param->resolve_status = RESOLVE_DONE;
|
||||
}
|
||||
bool pure = false;
|
||||
if (!sema_analyse_doc_header(decl->macro_decl.docs, decl->macro_decl.parameters, body_parameters, &pure)) return decl_poison(decl);
|
||||
if (decl->name[0] != '@' && !is_function_like)
|
||||
{
|
||||
SEMA_ERROR(decl, "Names of non-function like macros (i.e. a macro with a trailing body, ref or expression parameters, must start with '@'.");
|
||||
return false;
|
||||
}
|
||||
if (decl->macro_decl.type_parent)
|
||||
if (!sema_analyse_doc_header(decl->func_decl.docs, decl->func_decl.signature.params, body_parameters, &pure)) return decl_poison(decl);
|
||||
|
||||
if (decl->func_decl.type_parent)
|
||||
{
|
||||
if (!sema_analyse_macro_method(context, decl)) return decl_poison(decl);
|
||||
}
|
||||
@@ -2520,7 +2493,7 @@ static inline bool sema_analyse_attribute_decl(SemaContext *c, Decl *decl)
|
||||
{
|
||||
if (param[j].name == param->name)
|
||||
{
|
||||
SEMA_ERROR(param, "Duplicate parameter name.");
|
||||
SEMA_ERROR(param, "Duplicate parameter name '%s'.", param->name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,37 @@ void expr_rewrite_to_builtin_access(SemaContext *context, Expr *expr, Expr *pare
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
}
|
||||
|
||||
Expr *sema_expr_analyse_ct_arg_index(SemaContext *context, Expr *index_expr)
|
||||
{
|
||||
unsigned args = vec_size(context->macro_varargs);
|
||||
uint64_t index;
|
||||
Decl *param = NULL;
|
||||
if (!sema_analyse_expr(context, index_expr)) return poisoned_expr;
|
||||
if (!type_is_integer(index_expr->type))
|
||||
{
|
||||
SEMA_ERROR(index_expr, "Expected the argument index here, but found a value of type %s.", type_quoted_error_string(index_expr->type));
|
||||
return poisoned_expr;
|
||||
}
|
||||
if (!expr_is_const(index_expr))
|
||||
{
|
||||
SEMA_ERROR(index_expr, "Vararg functions need a constant argument, but this is a runtime value.");
|
||||
return poisoned_expr;
|
||||
}
|
||||
Int index_val = index_expr->const_expr.ixx;
|
||||
if (int_is_neg(index_val))
|
||||
{
|
||||
SEMA_ERROR(index_expr, "The index cannot be negative.");
|
||||
return poisoned_expr;
|
||||
}
|
||||
Int int_max = { .i = { .low = args }, .type = TYPE_U32 };
|
||||
if (int_comp(index_val, int_max, BINARYOP_GE))
|
||||
{
|
||||
SEMA_ERROR(index_expr, "Only %u vararg%s exist.", args, args == 1 ? "" : "s");
|
||||
return poisoned_expr;
|
||||
}
|
||||
return context->macro_varargs[(size_t)index_val.i.low];
|
||||
}
|
||||
|
||||
const char *ct_eval_expr(SemaContext *c, const char *expr_type, Expr *inner, TokenType *type, Path **path_ref, bool report_missing)
|
||||
{
|
||||
if (!sema_analyse_expr(c, inner)) return false;
|
||||
@@ -149,7 +180,7 @@ void expr_insert_addr(Expr *original)
|
||||
original->expr_kind = EXPR_UNARY;
|
||||
Type *inner_type = inner->type;
|
||||
bool failable = type_is_optional(inner->type);
|
||||
original->type = type_add_optional(type_get_ptr(type_no_optional(inner->type)), failable);
|
||||
original->type = type_add_optional(type_get_ptr(type_no_optional(inner_type)), failable);
|
||||
original->unary_expr.operator = UNARYOP_ADDR;
|
||||
original->unary_expr.expr = inner;
|
||||
}
|
||||
@@ -380,7 +411,7 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
|
||||
return false;
|
||||
case EXPR_IDENTIFIER:
|
||||
if (expr->identifier_expr.decl->decl_kind != DECL_VAR) return true;
|
||||
if (expr->identifier_expr.is_const)
|
||||
if (expr->identifier_expr.decl->var.kind == VARDECL_CONST)
|
||||
{
|
||||
expr = expr->identifier_expr.decl->var.init_expr;
|
||||
goto RETRY;
|
||||
@@ -570,17 +601,17 @@ static bool sema_check_expr_lvalue(Expr *top_expr, Expr *expr)
|
||||
return true;
|
||||
case EXPR_IDENTIFIER:
|
||||
{
|
||||
if (expr->identifier_expr.is_const)
|
||||
{
|
||||
SEMA_ERROR(top_expr, "You cannot assign to a constant.");
|
||||
return false;
|
||||
}
|
||||
Decl *decl = expr->identifier_expr.decl;
|
||||
if (decl->decl_kind != DECL_VAR)
|
||||
{
|
||||
SEMA_ERROR(top_expr, "You cannot assign a value to %s.", decl_to_a_name(decl));
|
||||
return false;
|
||||
}
|
||||
if (decl->var.kind == VARDECL_CONST)
|
||||
{
|
||||
SEMA_ERROR(top_expr, "You cannot assign to a constant.");
|
||||
return false;
|
||||
}
|
||||
decl = decl_raw(decl);
|
||||
switch (decl->var.kind)
|
||||
{
|
||||
@@ -1100,8 +1131,9 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to,
|
||||
assert(expr && expr->identifier_expr.ident);
|
||||
DEBUG_LOG("Resolving identifier '%s'", expr->identifier_expr.ident);
|
||||
|
||||
assert(expr->resolve_status != RESOLVE_DONE);
|
||||
DeclId body_param;
|
||||
if (!expr->identifier_expr.path && context->current_macro && (body_param = context->current_macro->macro_decl.body_param))
|
||||
if (!expr->identifier_expr.path && context->current_macro && (body_param = context->current_macro->func_decl.body_param))
|
||||
{
|
||||
if (expr->identifier_expr.ident == declptr(body_param)->name)
|
||||
{
|
||||
@@ -1375,15 +1407,11 @@ static inline bool expr_may_splat_as_vararg(Expr *expr, Type *variadic_base_type
|
||||
typedef struct
|
||||
{
|
||||
bool macro;
|
||||
bool func_pointer;
|
||||
const char *name;
|
||||
const char *block_parameter;
|
||||
Decl **params;
|
||||
Type **param_types;
|
||||
Expr *struct_var;
|
||||
unsigned param_count;
|
||||
Variadic variadic;
|
||||
unsigned vararg_index;
|
||||
Signature *signature;
|
||||
} CalledDecl;
|
||||
|
||||
static inline bool expr_promote_vararg(SemaContext *context, Expr *arg)
|
||||
@@ -1463,7 +1491,6 @@ INLINE bool sema_expand_call_arguments(SemaContext *context, CalledDecl *callee,
|
||||
{
|
||||
unsigned num_args = vec_size(args);
|
||||
Decl **params = callee->params;
|
||||
bool is_func_ptr = callee->func_pointer;
|
||||
|
||||
Expr **actual_args = VECNEW(Expr*, func_param_count);
|
||||
for (unsigned i = 0; i < func_param_count; i++) vec_add(actual_args, NULL);
|
||||
@@ -1628,8 +1655,10 @@ static inline bool sema_expr_analyse_call_invocation(SemaContext *context, Expr
|
||||
|
||||
// 2. Pick out all the arguments and parameters.
|
||||
Expr **args = call->call_expr.arguments;
|
||||
Signature *sig = callee.signature;
|
||||
unsigned vararg_index = sig->vararg_index;
|
||||
Variadic variadic = sig->variadic;
|
||||
Decl **decl_params = callee.params;
|
||||
Type **param_types = callee.param_types;
|
||||
unsigned num_args = vec_size(args);
|
||||
|
||||
// 3. If this is a type call, then we have an implicit first argument.
|
||||
@@ -1655,7 +1684,7 @@ static inline bool sema_expr_analyse_call_invocation(SemaContext *context, Expr
|
||||
if (splat)
|
||||
{
|
||||
// 4a. Is this *not* a variadic function/macro? - Then that's an error.
|
||||
if (callee.variadic == VARIADIC_NONE)
|
||||
if (variadic == VARIADIC_NONE)
|
||||
{
|
||||
SEMA_ERROR(call->call_expr.arguments[num_args - 1],
|
||||
"Using the splat operator is only allowed on vararg parameters.");
|
||||
@@ -1664,15 +1693,15 @@ static inline bool sema_expr_analyse_call_invocation(SemaContext *context, Expr
|
||||
}
|
||||
|
||||
// 5. Zero out all argument slots.
|
||||
unsigned func_param_count = callee.param_count;
|
||||
unsigned param_count = vec_size(decl_params);
|
||||
|
||||
// 6. We might have a typed variadic call e.g. foo(int, double...)
|
||||
// get that type.
|
||||
Type *variadic_type = NULL;
|
||||
if (callee.variadic == VARIADIC_TYPED || callee.variadic == VARIADIC_ANY)
|
||||
if (variadic == VARIADIC_TYPED || variadic == VARIADIC_ANY)
|
||||
{
|
||||
// 7a. The parameter type is <type>[], so we get the <type>
|
||||
Type *vararg_slot_type = callee.macro ? callee.params[callee.vararg_index]->type : callee.param_types[callee.vararg_index];
|
||||
Type *vararg_slot_type = decl_params[vararg_index]->type;
|
||||
assert(vararg_slot_type->type_kind == TYPE_SUBARRAY);
|
||||
variadic_type = vararg_slot_type->array.base;
|
||||
}
|
||||
@@ -1683,9 +1712,9 @@ static inline bool sema_expr_analyse_call_invocation(SemaContext *context, Expr
|
||||
&callee,
|
||||
call,
|
||||
args,
|
||||
func_param_count,
|
||||
callee.variadic,
|
||||
callee.vararg_index,
|
||||
param_count,
|
||||
variadic,
|
||||
vararg_index,
|
||||
failable, &varargs, &vararg_splat)) return false;
|
||||
|
||||
args = call->call_expr.arguments;
|
||||
@@ -1694,18 +1723,22 @@ static inline bool sema_expr_analyse_call_invocation(SemaContext *context, Expr
|
||||
call->call_expr.varargs = NULL;
|
||||
if (varargs)
|
||||
{
|
||||
if (callee.variadic == VARIADIC_RAW)
|
||||
if (variadic == VARIADIC_RAW)
|
||||
{
|
||||
foreach(Expr*, varargs)
|
||||
{
|
||||
// 12a. Analyse the expression.
|
||||
if (!sema_analyse_expr(context, val)) return false;
|
||||
|
||||
// 12b. In the case of a compile time variable non macros we cast to c_int / double.
|
||||
if (!callee.macro)
|
||||
if (callee.macro)
|
||||
{
|
||||
// Just keep as lvalues
|
||||
if (!sema_analyse_expr_lvalue_fold_const(context, val)) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sema_analyse_expr(context, val)) return false;
|
||||
if (!expr_promote_vararg(context, val)) return false;
|
||||
}
|
||||
|
||||
// Set the argument at the location.
|
||||
*failable |= IS_OPTIONAL(val);
|
||||
}
|
||||
@@ -1746,27 +1779,15 @@ static inline bool sema_expr_analyse_call_invocation(SemaContext *context, Expr
|
||||
|
||||
// 10. If we exceed the function parameter count (remember we reduced this by one
|
||||
// in the case of typed vararg) we're now in a variadic list.
|
||||
if (i == callee.vararg_index && callee.variadic != VARIADIC_NONE)
|
||||
if (i == vararg_index && variadic != VARIADIC_NONE)
|
||||
{
|
||||
assert(arg == NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
Decl *param;
|
||||
VarDeclKind kind;
|
||||
Type *type;
|
||||
if (decl_params)
|
||||
{
|
||||
param = decl_params[i];
|
||||
kind = param->var.kind;
|
||||
type = param->type;
|
||||
}
|
||||
else
|
||||
{
|
||||
param = NULL;
|
||||
kind = VARDECL_PARAM;
|
||||
type = param_types[i];
|
||||
}
|
||||
Decl *param = decl_params[i];
|
||||
VarDeclKind kind = param->var.kind;
|
||||
Type *type = param->type;
|
||||
|
||||
// 16. Analyse a regular argument.
|
||||
switch (kind)
|
||||
@@ -1801,8 +1822,9 @@ static inline bool sema_expr_analyse_call_invocation(SemaContext *context, Expr
|
||||
SEMA_ERROR(arg, "An untyped list can only be passed as a compile time parameter.");
|
||||
return false;
|
||||
}
|
||||
if (param && !param->alignment)
|
||||
if (!param->alignment)
|
||||
{
|
||||
assert(callee.macro && "Only in the macro case should we need to insert the alignment.");
|
||||
param->alignment = type_alloca_alignment(arg->type);
|
||||
}
|
||||
break;
|
||||
@@ -1846,23 +1868,19 @@ static inline bool sema_expr_analyse_call_invocation(SemaContext *context, Expr
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static inline bool sema_expr_analyse_func_invocation(SemaContext *context, Type *type,
|
||||
FunctionSignature *sig, Expr *expr, Decl *decl,
|
||||
Expr *struct_var, bool failable, const char *name)
|
||||
static inline bool sema_expr_analyse_func_invocation(SemaContext *context, Type *type, Expr *expr, Expr *struct_var,
|
||||
bool failable, const char *name)
|
||||
{
|
||||
Signature *sig = type->function.signature;
|
||||
CalledDecl callee = {
|
||||
.macro = false,
|
||||
.name = name,
|
||||
.func_pointer = sig ? 0 : 1,
|
||||
.block_parameter = NULL,
|
||||
.struct_var = struct_var,
|
||||
.params = type->function.params,
|
||||
.param_types = type->function.prototype->param_types,
|
||||
.param_count = vec_size(type->function.prototype->param_types),
|
||||
.variadic = type->function.prototype->variadic,
|
||||
.vararg_index = type->function.prototype->vararg_index
|
||||
.params = sig->params,
|
||||
.signature = sig,
|
||||
};
|
||||
if (context->current_function_pure && (!sig || !sig->is_pure) && !expr->call_expr.attr_pure)
|
||||
if (context->current_function_pure && !sig->attrs.is_pure && !expr->call_expr.attr_pure)
|
||||
{
|
||||
SEMA_ERROR(expr, "Only '@pure' functions may be called, you can override this with an attribute.");
|
||||
return false;
|
||||
@@ -1873,16 +1891,16 @@ static inline bool sema_expr_analyse_func_invocation(SemaContext *context, Type
|
||||
|
||||
Type *rtype = type->function.prototype->rtype;
|
||||
|
||||
if (is_unused && rtype != type_void && decl && decl->decl_kind == DECL_FUNC)
|
||||
if (is_unused && rtype != type_void)
|
||||
{
|
||||
if (decl->func_decl.function_signature.attrs.nodiscard)
|
||||
if (sig->attrs.nodiscard)
|
||||
{
|
||||
SEMA_ERROR(expr, "The result of the function must be used.");
|
||||
return false;
|
||||
}
|
||||
if (type_is_optional(rtype) && !decl->func_decl.function_signature.attrs.maydiscard)
|
||||
if (type_is_optional(rtype) && !sig->attrs.maydiscard)
|
||||
{
|
||||
SEMA_ERROR(expr, "The optional result of the macro must be used.");
|
||||
SEMA_ERROR(expr, "The optional result of the function must be used.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1895,20 +1913,14 @@ static inline bool sema_expr_analyse_func_invocation(SemaContext *context, Type
|
||||
static inline bool sema_expr_analyse_var_call(SemaContext *context, Expr *expr, Type *func_ptr_type, bool failable)
|
||||
{
|
||||
Decl *decl = NULL;
|
||||
if (func_ptr_type->type_kind != TYPE_POINTER || func_ptr_type->pointer->type_kind != TYPE_FUNC) goto ERR;
|
||||
if (func_ptr_type->type_kind != TYPE_POINTER || func_ptr_type->pointer->type_kind != TYPE_FUNC)
|
||||
{
|
||||
SEMA_ERROR(expr, "Only macros, functions and function pointers maybe invoked, this is of type '%s'.", type_to_error_string(func_ptr_type));
|
||||
return false;
|
||||
}
|
||||
Type *pointee = func_ptr_type->pointer;
|
||||
expr->call_expr.is_pointer_call = true;
|
||||
return sema_expr_analyse_func_invocation(context,
|
||||
pointee,
|
||||
NULL,
|
||||
expr,
|
||||
decl,
|
||||
NULL,
|
||||
failable,
|
||||
func_ptr_type->pointer->name);
|
||||
ERR:
|
||||
SEMA_ERROR(expr, "Only macros, functions and function pointers maybe invoked, this is of type '%s'.", type_to_error_string(func_ptr_type));
|
||||
return false;
|
||||
return sema_expr_analyse_func_invocation(context, pointee, expr, NULL, failable, func_ptr_type->pointer->name);
|
||||
}
|
||||
|
||||
// Unify returns in a macro or expression block.
|
||||
@@ -2008,9 +2020,7 @@ static inline bool sema_expr_analyse_func_call(SemaContext *context, Expr *expr,
|
||||
expr->call_expr.is_pointer_call = false;
|
||||
return sema_expr_analyse_func_invocation(context,
|
||||
decl->type,
|
||||
&decl->func_decl.function_signature,
|
||||
expr,
|
||||
decl,
|
||||
expr,
|
||||
struct_var,
|
||||
failable,
|
||||
decl->name);
|
||||
@@ -2068,24 +2078,43 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
||||
{
|
||||
assert(decl->decl_kind == DECL_MACRO);
|
||||
|
||||
Decl **params = decl_copy_list(decl->macro_decl.parameters);
|
||||
Decl **params = decl_copy_list(decl->func_decl.signature.params);
|
||||
CalledDecl callee = {
|
||||
.macro = true,
|
||||
.name = decl->name,
|
||||
.block_parameter = decl->macro_decl.body_param ? declptr(decl->macro_decl.body_param)->name : NULL,
|
||||
.params = params,
|
||||
.variadic = decl->macro_decl.variadic,
|
||||
.vararg_index = decl->macro_decl.vararg_index,
|
||||
.param_count = vec_size(params),
|
||||
.block_parameter = decl->func_decl.body_param ? declptr(decl->func_decl.body_param)->name : NULL,
|
||||
.signature = &decl->func_decl.signature,
|
||||
.struct_var = struct_var
|
||||
};
|
||||
|
||||
if (!sema_expr_analyse_call_invocation(context, call_expr, callee, &failable)) return false;
|
||||
|
||||
unsigned vararg_index = decl->func_decl.signature.vararg_index;
|
||||
Expr **args = call_expr->call_expr.arguments;
|
||||
VECEACH(params, i)
|
||||
{
|
||||
Decl *param = params[i];
|
||||
if (i == vararg_index)
|
||||
{
|
||||
if (!param) continue;
|
||||
// Splat? That's the simple case.
|
||||
if (call_expr->call_expr.splat_vararg)
|
||||
{
|
||||
|
||||
if (!sema_analyse_expr(context, args[i] = call_expr->call_expr.splat)) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Expr **exprs = call_expr->call_expr.varargs;
|
||||
Expr *literal = expr_new(EXPR_COMPOUND_LITERAL, exprs ? exprs[0]->span : param->span);
|
||||
Expr *initializer_list = expr_new_expr(EXPR_INITIALIZER_LIST, literal);
|
||||
initializer_list->initializer_list = exprs;
|
||||
literal->expr_compound_literal.type_info = param->var.type_info;
|
||||
literal->expr_compound_literal.initializer = initializer_list;
|
||||
if (!sema_analyse_expr(context, args[i] = literal)) return false;
|
||||
}
|
||||
}
|
||||
param->var.init_expr = args[i];
|
||||
VarDeclKind kind = param->var.kind;
|
||||
if (kind == VARDECL_PARAM_CT_TYPE || kind == VARDECL_PARAM_CT)
|
||||
@@ -2096,7 +2125,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
||||
|
||||
Decl **body_params = call_expr->call_expr.body_arguments;
|
||||
unsigned body_params_count = vec_size(body_params);
|
||||
Decl **macro_body_params = decl->macro_decl.body_param ? declptr(decl->macro_decl.body_param)->body_params : NULL;
|
||||
Decl **macro_body_params = decl->func_decl.body_param ? declptr(decl->func_decl.body_param)->body_params : NULL;
|
||||
unsigned expected_body_params = vec_size(macro_body_params);
|
||||
if (expected_body_params > body_params_count)
|
||||
{
|
||||
@@ -2134,7 +2163,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
||||
if (!body_arg->alignment) body_arg->alignment = type_alloca_alignment(body_arg->type);
|
||||
}
|
||||
|
||||
Ast *body = ast_macro_copy(astptr(decl->macro_decl.body));
|
||||
Ast *body = ast_macro_copy(astptr(decl->func_decl.body));
|
||||
|
||||
DynamicScope old_scope = context->active_scope;
|
||||
context_change_scope_with_flags(context, SCOPE_NONE);
|
||||
@@ -2142,10 +2171,10 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
||||
SemaContext macro_context;
|
||||
|
||||
Type *rtype = NULL;
|
||||
sema_context_init(¯o_context, decl->macro_decl.unit);
|
||||
sema_context_init(¯o_context, decl->unit);
|
||||
macro_context.compilation_unit = context->unit;
|
||||
macro_context.current_function = context->current_function;
|
||||
rtype = decl->macro_decl.rtype ? type_infoptr(decl->macro_decl.rtype)->type : NULL;
|
||||
rtype = decl->func_decl.signature.rtype ? type_infoptr(decl->func_decl.signature.rtype)->type : NULL;
|
||||
macro_context.expected_block_type = rtype;
|
||||
bool may_failable = true;
|
||||
if (rtype)
|
||||
@@ -2170,26 +2199,30 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
||||
macro_context.yield_body = body_id ? astptr(body_id) : NULL;
|
||||
macro_context.yield_params = body_params;
|
||||
macro_context.yield_context = context;
|
||||
macro_context.macro_varargs = call_expr->call_expr.varargs;
|
||||
macro_context.original_inline_line = context->original_inline_line ? context->original_inline_line : call_expr->span.row;
|
||||
|
||||
macro_context.macro_params = params;
|
||||
BlockExit** block_exit_ref = MALLOCS(BlockExit*);
|
||||
macro_context.block_exit_ref = block_exit_ref;
|
||||
|
||||
VECEACH(params, i)
|
||||
{
|
||||
Decl *param = params[i];
|
||||
// Skip raw vararg
|
||||
if (!param) continue;
|
||||
if (!sema_add_local(¯o_context, param)) goto EXIT_FAIL;
|
||||
}
|
||||
|
||||
AstId assert_first = 0;
|
||||
AstId* next = &assert_first;
|
||||
|
||||
if (!sema_analyse_contracts(¯o_context, decl->macro_decl.docs, &next)) return false;
|
||||
if (!sema_analyse_contracts(¯o_context, decl->func_decl.docs, &next)) return false;
|
||||
sema_append_contract_asserts(assert_first, body);
|
||||
|
||||
if (!sema_analyse_statement(¯o_context, body)) goto EXIT_FAIL;
|
||||
|
||||
bool is_no_return = decl->macro_decl.attr_noreturn;
|
||||
params = macro_context.macro_params;
|
||||
bool is_no_return = decl->func_decl.signature.attrs.noreturn;
|
||||
|
||||
if (!vec_size(macro_context.returns))
|
||||
{
|
||||
@@ -2249,12 +2282,12 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
||||
Type *type = call_expr->type;
|
||||
if (type != type_void)
|
||||
{
|
||||
if (decl->macro_decl.attr_nodiscard)
|
||||
if (decl->func_decl.signature.attrs.nodiscard)
|
||||
{
|
||||
SEMA_ERROR(call_expr, "The result of the macro must be used.");
|
||||
return SCOPE_POP_ERROR();
|
||||
}
|
||||
if (type_is_optional(type) && !decl->macro_decl.attr_maydiscard)
|
||||
if (type_is_optional(type) && !decl->func_decl.signature.attrs.maydiscard)
|
||||
{
|
||||
SEMA_ERROR(call_expr, "The optional result of the macro must be used.");
|
||||
return SCOPE_POP_ERROR();
|
||||
@@ -2285,7 +2318,6 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
||||
call_expr->expr_kind = EXPR_MACRO_BLOCK;
|
||||
call_expr->macro_block.first_stmt = body->compound_stmt.first_stmt;
|
||||
call_expr->macro_block.params = params;
|
||||
call_expr->macro_block.args = args;
|
||||
call_expr->macro_block.block_exit = block_exit_ref;
|
||||
EXIT:
|
||||
assert(context->active_scope.defer_last == context->active_scope.defer_start);
|
||||
@@ -2301,102 +2333,11 @@ static inline Decl *sema_generate_generic_function(SemaContext *context, Expr *c
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_generic_call(SemaContext *context, Expr *call_expr, Expr *struct_var, Decl *decl, bool failable)
|
||||
{
|
||||
assert(decl->decl_kind == DECL_GENERIC);
|
||||
|
||||
Expr **args = call_expr->call_expr.arguments;
|
||||
Decl **func_params = decl->macro_decl.parameters;
|
||||
|
||||
unsigned explicit_args = vec_size(args);
|
||||
unsigned total_args = explicit_args;
|
||||
|
||||
scratch_buffer_clear();
|
||||
scratch_buffer_append(decl->extname);
|
||||
|
||||
// TODO revisit name mangling
|
||||
if (struct_var)
|
||||
{
|
||||
total_args++;
|
||||
scratch_buffer_append_char('@');
|
||||
scratch_buffer_append(struct_var->type->canonical->name);
|
||||
}
|
||||
|
||||
if (total_args != vec_size(func_params))
|
||||
{
|
||||
// TODO HANDLE VARARGS
|
||||
SEMA_ERROR(call_expr, "Mismatch on number of arguments.");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned offset = total_args - explicit_args;
|
||||
for (unsigned i = 0; i < explicit_args; i++)
|
||||
{
|
||||
Expr *arg = args[i];
|
||||
Decl *param = func_params[i + offset];
|
||||
if (param->var.kind == VARDECL_PARAM_CT_TYPE)
|
||||
{
|
||||
if (!sema_analyse_expr_lvalue_fold_const(context, arg)) return false;
|
||||
if (arg->expr_kind != EXPR_TYPEINFO)
|
||||
{
|
||||
SEMA_ERROR(arg, "A type, like 'int' or 'double' was expected for the parameter '%s'.", param->name);
|
||||
return false;
|
||||
}
|
||||
scratch_buffer_append_char(',');
|
||||
scratch_buffer_append(arg->type_expr->type->canonical->name);
|
||||
continue;
|
||||
}
|
||||
if (param->var.type_info)
|
||||
{
|
||||
if (!sema_analyse_expr_rhs(context, param->var.type_info->type, arg, true)) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sema_analyse_expr(context, arg)) return false;
|
||||
}
|
||||
scratch_buffer_append_char(',');
|
||||
scratch_buffer_append(arg->type->canonical->name);
|
||||
}
|
||||
const char *mangled_name = scratch_buffer_interned();
|
||||
Decl **generic_cache = decl->unit->module->generic_cache;
|
||||
Decl *found = NULL;
|
||||
VECEACH(generic_cache, i)
|
||||
{
|
||||
TODO
|
||||
if (generic_cache[i]->extname == mangled_name)
|
||||
{
|
||||
found = generic_cache[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
found = sema_generate_generic_function(context, call_expr, struct_var, decl, mangled_name);
|
||||
}
|
||||
// Remove type parameters from call.
|
||||
for (unsigned i = 0; i < explicit_args; i++)
|
||||
{
|
||||
Decl *param = func_params[i + offset];
|
||||
if (param->var.kind == VARDECL_PARAM_CT_TYPE)
|
||||
{
|
||||
for (unsigned j = i + 1; j < explicit_args; j++)
|
||||
{
|
||||
args[j - 1] = args[j];
|
||||
}
|
||||
explicit_args--;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
vec_resize(args, explicit_args);
|
||||
// Perform the normal func call on the found declaration.
|
||||
return sema_expr_analyse_func_call(context, call_expr, found, struct_var, failable);
|
||||
}
|
||||
|
||||
static bool sema_analyse_body_expansion(SemaContext *macro_context, Expr *call)
|
||||
{
|
||||
Decl *macro = macro_context->current_macro;
|
||||
assert(macro);
|
||||
DeclId body_param = macro->macro_decl.body_param;
|
||||
DeclId body_param = macro->func_decl.body_param;
|
||||
assert(body_param);
|
||||
|
||||
ExprCall *call_expr = &call->call_expr;
|
||||
@@ -2431,7 +2372,6 @@ static bool sema_analyse_body_expansion(SemaContext *macro_context, Expr *call)
|
||||
Ast *first_defer = NULL;
|
||||
SemaContext *context = macro_context->yield_context;
|
||||
Decl **params = macro_context->yield_params;
|
||||
|
||||
Expr *func_expr = exprptr(call_expr->function);
|
||||
assert(func_expr->expr_kind == EXPR_MACRO_BODY_EXPANSION);
|
||||
expr_replace(call, func_expr);
|
||||
@@ -2499,7 +2439,7 @@ bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl
|
||||
case DECL_GENERIC:
|
||||
expr->call_expr.func_ref = declid(decl);
|
||||
expr->call_expr.is_func_ref = true;
|
||||
return sema_expr_analyse_generic_call(context, expr, struct_var, decl, failable);
|
||||
TODO // Maybe generics won't happen
|
||||
case DECL_POISONED:
|
||||
return false;
|
||||
default:
|
||||
@@ -2820,14 +2760,8 @@ static inline bool sema_expr_analyse_call(SemaContext *context, Expr *expr)
|
||||
switch (decl->decl_kind)
|
||||
{
|
||||
case DECL_MACRO:
|
||||
if (decl->macro_decl.parameters[0]->type->type_kind == TYPE_POINTER)
|
||||
{
|
||||
expr_insert_addr(func_expr->access_expr.parent);
|
||||
}
|
||||
struct_var = func_expr->access_expr.parent;
|
||||
break;
|
||||
case DECL_FUNC:
|
||||
if (decl->func_decl.function_signature.params[0]->type->type_kind == TYPE_POINTER)
|
||||
if (decl->func_decl.signature.params[0]->type->type_kind == TYPE_POINTER)
|
||||
{
|
||||
expr_insert_addr(func_expr->access_expr.parent);
|
||||
}
|
||||
@@ -3512,6 +3446,7 @@ static void add_members_to_context(SemaContext *context, Decl *decl)
|
||||
static Expr *sema_expr_resolve_access_child(SemaContext *context, Expr *child, bool *missing)
|
||||
{
|
||||
RETRY:
|
||||
assert(child->resolve_status != RESOLVE_DONE);
|
||||
switch (child->expr_kind)
|
||||
{
|
||||
case EXPR_IDENTIFIER:
|
||||
@@ -4272,15 +4207,18 @@ CHECK_DEEPER:
|
||||
return false;
|
||||
}
|
||||
|
||||
// Transform bitstruct access to expr_bitaccess.
|
||||
if (member->var.kind == VARDECL_BITMEMBER)
|
||||
if (member->decl_kind == DECL_VAR)
|
||||
{
|
||||
expr->expr_kind = EXPR_BITACCESS;
|
||||
}
|
||||
if (member->var.kind == VARDECL_MEMBER && expr_is_const_list(current_parent))
|
||||
{
|
||||
sema_expr_fold_to_member(expr, current_parent, member);
|
||||
return true;
|
||||
if (member->var.kind == VARDECL_BITMEMBER)
|
||||
{
|
||||
// Transform bitstruct access to expr_bitaccess.
|
||||
expr->expr_kind = EXPR_BITACCESS;
|
||||
}
|
||||
else if (member->var.kind == VARDECL_MEMBER && expr_is_const_list(current_parent))
|
||||
{
|
||||
sema_expr_fold_to_member(expr, current_parent, member);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// 13. Copy properties.
|
||||
expr->access_expr.parent = current_parent;
|
||||
@@ -7615,6 +7553,9 @@ RETRY:
|
||||
if (!decl_ok(decl)) return poisoned_type;
|
||||
return decl->type->canonical;
|
||||
}
|
||||
case TYPE_INFO_VAARG_TYPE:
|
||||
if (!sema_resolve_type_info(context, type_info)) return poisoned_type;
|
||||
return type_info->type->canonical;
|
||||
case TYPE_INFO_EXPRESSION:
|
||||
if (!sema_resolve_type_info(context, type_info)) return poisoned_type;
|
||||
return type_info->type;
|
||||
@@ -7771,18 +7712,104 @@ static inline bool sema_expr_analyse_variant(SemaContext *context, Expr *expr)
|
||||
|
||||
static inline bool sema_expr_analyse_ct_arg(SemaContext *context, Expr *expr)
|
||||
{
|
||||
assert(expr->resolve_status == RESOLVE_RUNNING);
|
||||
TokenType type = expr->ct_arg_expr.type;
|
||||
if (!context->current_macro)
|
||||
{
|
||||
SEMA_ERROR(expr, "'%s' can only be used inside of a macro.", token_type_to_string(expr->ct_arg_expr.type));
|
||||
SEMA_ERROR(expr, "'%s' can only be used inside of a macro.", token_type_to_string(type));
|
||||
return false;
|
||||
}
|
||||
switch (expr->ct_arg_expr.type)
|
||||
switch (type)
|
||||
{
|
||||
case TOKEN_CT_VAARG_COUNT:
|
||||
expr_rewrite_const_int(expr, type_usize, vec_size(context->macro_varargs), true);
|
||||
return true;
|
||||
case TOKEN_CT_VAARG_GET_ARG:
|
||||
{
|
||||
// A normal argument, this means we only evaluate it once.
|
||||
ASSIGN_EXPR_OR_RET(Expr *arg_expr, sema_expr_analyse_ct_arg_index(context, exprptr(expr->ct_arg_expr.arg)), false);
|
||||
|
||||
Decl *decl = NULL;
|
||||
// Try to find the original param.
|
||||
foreach(Decl*, context->macro_params)
|
||||
{
|
||||
if (!val) continue;
|
||||
if (val->var.init_expr == arg_expr)
|
||||
{
|
||||
decl = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Not found, so generate a new.
|
||||
if (!decl)
|
||||
{
|
||||
decl = decl_new_generated_var(arg_expr->type, VARDECL_PARAM, arg_expr->span);
|
||||
decl->var.init_expr = arg_expr;
|
||||
vec_add(context->macro_params, decl);
|
||||
}
|
||||
// Replace with the identifier.
|
||||
expr->expr_kind = EXPR_IDENTIFIER;
|
||||
expr->identifier_expr = (ExprIdentifier) { .decl = decl };
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
expr->type = decl->type;
|
||||
return true;
|
||||
}
|
||||
case TOKEN_CT_VAARG_GET_EXPR:
|
||||
{
|
||||
// An expr argument, this means we copy and evaluate.
|
||||
ASSIGN_EXPR_OR_RET(Expr *arg_expr, sema_expr_analyse_ct_arg_index(context, exprptr(expr->ct_arg_expr.arg)), false);
|
||||
expr_replace(expr, expr_macro_copy(arg_expr));
|
||||
return true;
|
||||
}
|
||||
case TOKEN_CT_VAARG_GET_CONST:
|
||||
{
|
||||
// An expr argument, this means we copy and evaluate.
|
||||
ASSIGN_EXPR_OR_RET(Expr *arg_expr, sema_expr_analyse_ct_arg_index(context, exprptr(expr->ct_arg_expr.arg)), false);
|
||||
arg_expr = expr_macro_copy(arg_expr);
|
||||
if (!expr_is_constant_eval(arg_expr, CONSTANT_EVAL_CONSTANT_VALUE))
|
||||
{
|
||||
SEMA_ERROR(arg_expr, "This argument needs to be a compile time constant.");
|
||||
return false;
|
||||
}
|
||||
expr_replace(expr, arg_expr);
|
||||
return true;
|
||||
}
|
||||
case TOKEN_CT_VAARG_GET_REF:
|
||||
{
|
||||
// A normal argument, this means we only evaluate it once.
|
||||
ASSIGN_EXPR_OR_RET(Expr *arg_expr, sema_expr_analyse_ct_arg_index(context, exprptr(expr->ct_arg_expr.arg)), false);
|
||||
|
||||
if (!sema_check_expr_lvalue(arg_expr, arg_expr)) return false;
|
||||
|
||||
Decl *decl = NULL;
|
||||
// Try to find the original param.
|
||||
foreach(Decl*, context->macro_params)
|
||||
{
|
||||
if (!val) continue;
|
||||
if (val->var.init_expr == arg_expr)
|
||||
{
|
||||
decl = val;
|
||||
decl->var.kind = VARDECL_PARAM_REF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Not found, so generate a new.
|
||||
if (!decl)
|
||||
{
|
||||
decl = decl_new_generated_var(arg_expr->type, VARDECL_PARAM_REF, arg_expr->span);
|
||||
decl->var.init_expr = arg_expr;
|
||||
vec_add(context->macro_params, decl);
|
||||
}
|
||||
// Replace with the identifier.
|
||||
expr->expr_kind = EXPR_IDENTIFIER;
|
||||
expr->identifier_expr = (ExprIdentifier) { .decl = decl };
|
||||
expr->resolve_status = RESOLVE_DONE;
|
||||
expr->type = decl->type;
|
||||
return true;
|
||||
}
|
||||
case TOKEN_CT_VAARG_GET_TYPE:
|
||||
default:
|
||||
TODO;
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8133,7 +8160,7 @@ static inline bool sema_cast_rvalue(SemaContext *context, Expr *expr)
|
||||
case EXPR_MACRO_BODY_EXPANSION:
|
||||
if (!expr->body_expansion_expr.ast)
|
||||
{
|
||||
SEMA_ERROR(expr, "'@%s' must be followed by ().", declptr(context->current_macro->macro_decl.body_param)->name);
|
||||
SEMA_ERROR(expr, "'@%s' must be followed by ().", declptr(context->current_macro->func_decl.body_param)->name);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -77,6 +77,7 @@ bool sema_analyse_expr_lvalue(SemaContext *context, Expr *expr);
|
||||
bool sema_analyse_expr_lvalue_fold_const(SemaContext *context, Expr *expr);
|
||||
bool sema_analyse_ct_expr(SemaContext *context, Expr *expr);
|
||||
bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *struct_var, Decl *decl, bool failable);
|
||||
Expr *sema_expr_analyse_ct_arg_index(SemaContext *context, Expr *index_expr);
|
||||
void expr_rewrite_to_string(Expr *expr_to_rewrite, const char *string);
|
||||
const char *ct_eval_expr(SemaContext *c, const char *expr_type, Expr *inner, TokenType *type, Path **path_ref, bool report_missing);
|
||||
extern const char *ct_eval_error;
|
||||
|
||||
@@ -482,18 +482,7 @@ Decl *sema_find_extension_method_in_module(Module *module, Type *type, const cha
|
||||
{
|
||||
Decl *extension = extensions[i];
|
||||
if (extension->name != method_name) continue;
|
||||
switch (extension->decl_kind)
|
||||
{
|
||||
case DECL_FUNC:
|
||||
if (type_infoptr(extension->func_decl.type_parent)->type->canonical == type) return extension;
|
||||
break;
|
||||
case DECL_MACRO:
|
||||
case DECL_GENERIC:
|
||||
if (type_infoptr(extension->macro_decl.type_parent)->type->canonical == type) return extension;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
if (type_infoptr(extension->func_decl.type_parent)->type->canonical == type) return extension;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -324,6 +324,7 @@ static inline bool sema_analyse_try_unwrap(SemaContext *context, Expr *expr)
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(ident->resolve_status != RESOLVE_DONE);
|
||||
if (ident->identifier_expr.path)
|
||||
{
|
||||
SEMA_ERROR(ident->identifier_expr.path, "The variable may not have a path.");
|
||||
@@ -445,6 +446,7 @@ static inline bool sema_analyse_catch_unwrap(SemaContext *context, Expr *expr)
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(ident->resolve_status != RESOLVE_DONE);
|
||||
if (ident->identifier_expr.path)
|
||||
{
|
||||
SEMA_ERROR(ident->identifier_expr.path, "The variable may not have a path.");
|
||||
@@ -1048,8 +1050,8 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen
|
||||
return false;
|
||||
}
|
||||
index_macro = value_by_ref ? by_ref : by_val;
|
||||
index_type = index_macro->macro_decl.parameters[1]->type;
|
||||
TypeInfoId rtype = index_macro->macro_decl.rtype;
|
||||
index_type = index_macro->func_decl.signature.params[1]->type;
|
||||
TypeInfoId rtype = index_macro->func_decl.signature.rtype;
|
||||
value_type = rtype ? type_infoptr(rtype)->type : NULL;
|
||||
}
|
||||
|
||||
@@ -2244,8 +2246,6 @@ static bool sema_analyse_compound_stmt(SemaContext *context, Ast *statement)
|
||||
static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement)
|
||||
{
|
||||
bool success = false;
|
||||
// Enter for scope
|
||||
SCOPE_OUTER_START
|
||||
|
||||
ExprId init;
|
||||
if ((init = statement->for_stmt.init))
|
||||
@@ -2262,16 +2262,16 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement
|
||||
if (decl->decl_kind != DECL_VAR || (decl->var.kind != VARDECL_LOCAL_CT && decl->var.kind != VARDECL_LOCAL_CT_TYPE))
|
||||
{
|
||||
SEMA_ERROR(expr, "Only 'var $foo' and 'var $Type' declarations are allowed in a '$for'");
|
||||
goto EXIT_ERROR;
|
||||
return false;
|
||||
}
|
||||
if (!sema_analyse_var_decl_ct(context, decl)) goto EXIT_ERROR;
|
||||
if (!sema_analyse_var_decl_ct(context, decl)) return false;
|
||||
continue;
|
||||
}
|
||||
if (!sema_analyse_expr(context, expr)) goto EXIT_ERROR;
|
||||
if (!sema_analyse_expr(context, expr)) return false;
|
||||
if (!expr_is_constant_eval(expr, CONSTANT_EVAL_CONSTANT_VALUE))
|
||||
{
|
||||
SEMA_ERROR(expr, "Only constant expressions are allowed.");
|
||||
goto EXIT_ERROR;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2284,16 +2284,16 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement
|
||||
for (int i = 0; i < MAX_MACRO_ITERATIONS; i++)
|
||||
{
|
||||
Expr *copy = expr_macro_copy(exprptr(condition));
|
||||
if (!sema_analyse_cond_expr(context, copy)) goto EXIT_ERROR;
|
||||
if (!sema_analyse_cond_expr(context, copy)) return false;
|
||||
if (copy->expr_kind != EXPR_CONST)
|
||||
{
|
||||
SEMA_ERROR(copy, "Expected a value that can be evaluated at compile time.");
|
||||
goto EXIT_ERROR;
|
||||
return false;
|
||||
}
|
||||
if (!copy->const_expr.b) break;
|
||||
|
||||
Ast *compound_stmt = ast_macro_copy(body);
|
||||
if (!sema_analyse_compound_stmt(context, compound_stmt)) goto EXIT_ERROR;
|
||||
if (!sema_analyse_compound_statement_no_scope(context, compound_stmt)) return false;
|
||||
*current = astid(compound_stmt);
|
||||
current = &compound_stmt->next;
|
||||
|
||||
@@ -2303,21 +2303,18 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement
|
||||
VECEACH(exprs, j)
|
||||
{
|
||||
copy = expr_macro_copy(exprs[j]);
|
||||
if (!sema_analyse_expr(context, copy)) goto EXIT_ERROR;
|
||||
if (!sema_analyse_expr(context, copy)) return false;
|
||||
if (copy->expr_kind != EXPR_CONST)
|
||||
{
|
||||
SEMA_ERROR(copy, "Expected a value that can be evaluated at compile time.");
|
||||
goto EXIT_ERROR;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
statement->ast_kind = AST_COMPOUND_STMT;
|
||||
statement->compound_stmt.first_stmt = start;
|
||||
success = true;
|
||||
EXIT_ERROR:
|
||||
SCOPE_OUTER_END;
|
||||
return success;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -2544,10 +2541,10 @@ bool sema_analyse_contracts(SemaContext *context, AstId doc, AstId **asserts)
|
||||
bool sema_analyse_function_body(SemaContext *context, Decl *func)
|
||||
{
|
||||
if (!decl_ok(func)) return false;
|
||||
FunctionSignature *signature = &func->func_decl.function_signature;
|
||||
Signature *signature = &func->func_decl.signature;
|
||||
FunctionPrototype *prototype = func->type->function.prototype;
|
||||
context->current_function = func;
|
||||
context->current_function_pure = func->func_decl.function_signature.is_pure;
|
||||
context->current_function_pure = func->func_decl.signature.attrs.is_pure;
|
||||
context->rtype = prototype->rtype;
|
||||
context->active_scope = (DynamicScope) {
|
||||
.scope_id = 0,
|
||||
|
||||
@@ -254,6 +254,21 @@ RETRY:
|
||||
{
|
||||
case TYPE_INFO_POISON:
|
||||
UNREACHABLE
|
||||
case TYPE_INFO_VAARG_TYPE:
|
||||
if (context->current_macro)
|
||||
{
|
||||
ASSIGN_EXPR_OR_RET(Expr *arg_expr, sema_expr_analyse_ct_arg_index(context, type_info->unresolved_type_expr), false);
|
||||
if (arg_expr->expr_kind != EXPR_TYPEINFO)
|
||||
{
|
||||
SEMA_ERROR(arg_expr, "The argument was not a type.");
|
||||
return false;
|
||||
}
|
||||
*type_info = *arg_expr->type_expr;
|
||||
assert(type_info->resolve_status == RESOLVE_DONE);
|
||||
return true;
|
||||
}
|
||||
SEMA_ERROR(type_info, "'%s' can only be used inside of a macro.", token_type_to_string(TOKEN_CT_VAARG_GET_TYPE));
|
||||
return false;
|
||||
case TYPE_INFO_CT_IDENTIFIER:
|
||||
case TYPE_INFO_IDENTIFIER:
|
||||
if (!sema_resolve_type_identifier(context, type_info)) return false;
|
||||
|
||||
@@ -321,12 +321,12 @@ void sema_analysis_run(void)
|
||||
{
|
||||
error_exit("'%s::%s' is not a function.", path->module, ident);
|
||||
}
|
||||
Decl **params = decl->func_decl.function_signature.params;
|
||||
Decl **params = decl->func_decl.signature.params;
|
||||
if (vec_size(params) != 4 || params[0]->type != type_get_ptr(type_char)
|
||||
|| params[1]->type != type_get_ptr(type_char)
|
||||
|| params[2]->type != type_get_ptr(type_char)
|
||||
|| params[3]->type != type_uint
|
||||
|| typeinfotype(decl->func_decl.function_signature.returntype) != type_void)
|
||||
|| typeinfotype(decl->func_decl.signature.rtype) != type_void)
|
||||
{
|
||||
error_exit("Expected panic function to have the signature fn void(char*, char*, uint, uint).");
|
||||
}
|
||||
|
||||
@@ -401,6 +401,6 @@ const char *token_type_to_string(TokenType type)
|
||||
|
||||
bool token_is_any_type(TokenType type)
|
||||
{
|
||||
return (type >= TOKEN_VOID && type <= TOKEN_TYPEID) || type == TOKEN_CT_TYPE_IDENT || type == TOKEN_TYPE_IDENT;
|
||||
return (type >= TOKEN_VOID && type <= TOKEN_TYPEID) || type == TOKEN_CT_TYPE_IDENT || type == TOKEN_TYPE_IDENT || type == TOKEN_CT_VAARG_GET_TYPE;
|
||||
}
|
||||
|
||||
|
||||
@@ -1080,10 +1080,10 @@ void type_func_prototype_init(uint32_t capacity)
|
||||
map.max_load = (uint32_t)(TABLE_MAX_LOAD * capacity);
|
||||
}
|
||||
|
||||
static uint32_t hash_function(FunctionSignature *sig)
|
||||
static uint32_t hash_function(Signature *sig)
|
||||
{
|
||||
uintptr_t hash = (unsigned)sig->variadic;
|
||||
hash = hash * 31 + (uintptr_t)type_infoptr(sig->returntype)->type->canonical;
|
||||
hash = hash * 31 + (uintptr_t)type_infoptr(sig->rtype)->type->canonical;
|
||||
Decl **params = sig->params;
|
||||
VECEACH(params, i)
|
||||
{
|
||||
@@ -1093,14 +1093,14 @@ static uint32_t hash_function(FunctionSignature *sig)
|
||||
return (uint32_t)((hash >> 16) ^ hash);
|
||||
}
|
||||
|
||||
static int compare_function(FunctionSignature *sig, FunctionPrototype *proto)
|
||||
static int compare_function(Signature *sig, FunctionPrototype *proto)
|
||||
{
|
||||
if (sig->variadic != proto->variadic) return -1;
|
||||
Decl **params = sig->params;
|
||||
Type **other_params = proto->param_types;
|
||||
unsigned param_count = vec_size(params);
|
||||
if (param_count != vec_size(other_params)) return -1;
|
||||
if (type_infoptr(sig->returntype)->type->canonical != proto->rtype->canonical) return -1;
|
||||
if (type_infoptr(sig->rtype)->type->canonical != proto->rtype->canonical) return -1;
|
||||
VECEACH(params, i)
|
||||
{
|
||||
Decl *param = params[i];
|
||||
@@ -1111,13 +1111,13 @@ static int compare_function(FunctionSignature *sig, FunctionPrototype *proto)
|
||||
}
|
||||
|
||||
|
||||
static inline Type *func_create_new_func_proto(FunctionSignature *sig, CallABI abi, uint32_t hash, FuncTypeEntry *entry)
|
||||
static inline Type *func_create_new_func_proto(Signature *sig, CallABI abi, uint32_t hash, FuncTypeEntry *entry)
|
||||
{
|
||||
unsigned param_count = vec_size(sig->params);
|
||||
FunctionPrototype *proto = CALLOCS(FunctionPrototype);
|
||||
proto->variadic = sig->variadic;
|
||||
proto->vararg_index = sig->vararg_index;
|
||||
Type *rtype = type_infoptr(sig->returntype)->type;
|
||||
Type *rtype = type_infoptr(sig->rtype)->type;
|
||||
proto->rtype = rtype;
|
||||
if (type_is_optional(rtype))
|
||||
{
|
||||
@@ -1163,10 +1163,14 @@ static inline Type *func_create_new_func_proto(FunctionSignature *sig, CallABI a
|
||||
}
|
||||
scratch_buffer_append_char(')');
|
||||
Type *type = type_new(TYPE_FUNC, scratch_buffer_interned());
|
||||
Signature *copy_sig = CALLOCS(Signature);
|
||||
*copy_sig = *sig;
|
||||
copy_sig->attrs = (CalleeAttributes) { .nodiscard = false };
|
||||
copy_sig->params = proto->param_copy;
|
||||
proto->raw_type = type;
|
||||
type->function.prototype = proto;
|
||||
type->function.module = NULL;
|
||||
type->function.params = proto->param_copy;
|
||||
type->function.signature = copy_sig;
|
||||
type->canonical = type;
|
||||
entry->key = hash;
|
||||
entry->value = type;
|
||||
@@ -1202,7 +1206,7 @@ static inline Type *func_create_new_func_proto(FunctionSignature *sig, CallABI a
|
||||
return type;
|
||||
}
|
||||
|
||||
Type *type_get_func(FunctionSignature *signature, CallABI abi)
|
||||
Type *type_get_func(Signature *signature, CallABI abi)
|
||||
{
|
||||
uint32_t hash = hash_function(signature);
|
||||
uint32_t mask = map.capacity - 1;
|
||||
|
||||
@@ -11,7 +11,7 @@ fn void main()
|
||||
printf("Foo %d\n", $i);
|
||||
$endfor;
|
||||
|
||||
$for (var $i = 0, var $j = 100; $i < 4;):
|
||||
$for ($i = 0, var $j = 100; $i < 4;):
|
||||
printf("Foo %d %d\n", $i++, $j--);
|
||||
$endfor;
|
||||
|
||||
|
||||
@@ -7,4 +7,6 @@ fn void foo3(bar) { } // #error: Only typed parameters are allowed for functions
|
||||
|
||||
fn void foo4($Type) { } // #error: Only regular parameters are allowed for functions.
|
||||
|
||||
fn void foo8(int &foo) {} // #error: Only regular parameters are allowed for functions.
|
||||
fn void foo8(int &foo) {} // #error: Only regular parameters are allowed for functions.
|
||||
|
||||
fn void foo9(int x, int x) {} // #error: Duplicate parameter name 'x'.
|
||||
@@ -2,10 +2,10 @@ macro foo(a, $b, $Type) {}
|
||||
|
||||
macro @foo2(a, $b, $Type) {}
|
||||
|
||||
macro bar(&x) // #error: non-function
|
||||
macro bar(&x) // #error: Ref and expression parameters
|
||||
{}
|
||||
|
||||
macro baz(#y) {} // #error: non-function
|
||||
macro baz(#y) {} // #error: Ref and expression parameters
|
||||
|
||||
macro baz2(a; @body()) {} // #error: non-function
|
||||
macro baz2(a; @body()) {} // #error: Names of macros
|
||||
|
||||
|
||||
210
test/test_suite/macros/macro_typed_varargs.c3t
Normal file
210
test/test_suite/macros/macro_typed_varargs.c3t
Normal file
@@ -0,0 +1,210 @@
|
||||
// #target: macos-x64
|
||||
|
||||
module test;
|
||||
|
||||
import std::io;
|
||||
|
||||
macro foo(int... x)
|
||||
{
|
||||
foreach (i : x)
|
||||
{
|
||||
io::printfln("%d", i);
|
||||
}
|
||||
}
|
||||
|
||||
macro foo2(x...)
|
||||
{
|
||||
foreach (i : x)
|
||||
{
|
||||
io::printfln("%d", *(int*)i);
|
||||
}
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
foo(1, -1, 3141, 999 + 1);
|
||||
foo2(1, -1, 3141, 999 + 1);
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
|
||||
define void @test_main() #0 {
|
||||
entry:
|
||||
%x = alloca %"int[]", align 8
|
||||
%literal = alloca [4 x i32], align 16
|
||||
%.anon = alloca i64, align 8
|
||||
%.anon1 = alloca i64, align 8
|
||||
%i = alloca i32, align 4
|
||||
%retparam = alloca i64, align 8
|
||||
%taddr = alloca %"char[]", align 8
|
||||
%vararg = alloca %"variant[]", align 8
|
||||
%varargslots = alloca [1 x %variant], align 16
|
||||
%x4 = alloca %"variant[]", align 8
|
||||
%literal5 = alloca [4 x %variant], align 16
|
||||
%taddr6 = alloca i32, align 4
|
||||
%taddr7 = alloca i32, align 4
|
||||
%taddr8 = alloca i32, align 4
|
||||
%taddr9 = alloca i32, align 4
|
||||
%.anon10 = alloca i64, align 8
|
||||
%.anon11 = alloca i64, align 8
|
||||
%i15 = alloca %variant, align 8
|
||||
%retparam17 = alloca i64, align 8
|
||||
%taddr18 = alloca %"char[]", align 8
|
||||
%vararg21 = alloca %"variant[]", align 8
|
||||
%varargslots22 = alloca [1 x %variant], align 16
|
||||
%0 = getelementptr inbounds [4 x i32], [4 x i32]* %literal, i64 0, i64 0
|
||||
store i32 1, i32* %0, align 4
|
||||
%1 = getelementptr inbounds [4 x i32], [4 x i32]* %literal, i64 0, i64 1
|
||||
store i32 -1, i32* %1, align 4
|
||||
%2 = getelementptr inbounds [4 x i32], [4 x i32]* %literal, i64 0, i64 2
|
||||
store i32 3141, i32* %2, align 4
|
||||
%3 = getelementptr inbounds [4 x i32], [4 x i32]* %literal, i64 0, i64 3
|
||||
store i32 1000, i32* %3, align 4
|
||||
%4 = bitcast [4 x i32]* %literal to i32*
|
||||
%5 = insertvalue %"int[]" undef, i32* %4, 0
|
||||
%6 = insertvalue %"int[]" %5, i64 4, 1
|
||||
store %"int[]" %6, %"int[]"* %x, align 8
|
||||
%7 = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 1
|
||||
%8 = load i64, i64* %7, align 8
|
||||
store i64 %8, i64* %.anon, align 8
|
||||
store i64 0, i64* %.anon1, align 8
|
||||
br label %loop.cond
|
||||
|
||||
loop.cond: ; preds = %voiderr, %entry
|
||||
%9 = load i64, i64* %.anon1, align 8
|
||||
%10 = load i64, i64* %.anon, align 8
|
||||
%lt = icmp ult i64 %9, %10
|
||||
br i1 %lt, label %loop.body, label %loop.exit
|
||||
|
||||
loop.body: ; preds = %loop.cond
|
||||
%11 = getelementptr inbounds %"int[]", %"int[]"* %x, i32 0, i32 0
|
||||
%12 = load i32*, i32** %11, align 8
|
||||
%13 = load i64, i64* %.anon1, align 8
|
||||
%ptroffset = getelementptr inbounds i32, i32* %12, i64 %13
|
||||
%14 = load i32, i32* %ptroffset, align 4
|
||||
store i32 %14, i32* %i, align 4
|
||||
store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i64 2 }, %"char[]"* %taddr, align 8
|
||||
%15 = bitcast %"char[]"* %taddr to { i8*, i64 }*
|
||||
%16 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %15, i32 0, i32 0
|
||||
%lo = load i8*, i8** %16, align 8
|
||||
%17 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %15, i32 0, i32 1
|
||||
%hi = load i64, i64* %17, align 8
|
||||
%18 = bitcast i32* %i to i8*
|
||||
%19 = insertvalue %variant undef, i8* %18, 0
|
||||
%20 = insertvalue %variant %19, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1
|
||||
%21 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots, i64 0, i64 0
|
||||
store %variant %20, %variant* %21, align 16
|
||||
%22 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 1
|
||||
store i64 1, i64* %22, align 8
|
||||
%23 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 0
|
||||
%24 = bitcast [1 x %variant]* %varargslots to %variant*
|
||||
store %variant* %24, %variant** %23, align 8
|
||||
%25 = bitcast %"variant[]"* %vararg to { i8*, i64 }*
|
||||
%26 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %25, i32 0, i32 0
|
||||
%lo2 = load i8*, i8** %26, align 8
|
||||
%27 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %25, i32 0, i32 1
|
||||
%hi3 = load i64, i64* %27, align 8
|
||||
%28 = call i64 @std_io_printfln(i64* %retparam, i8* %lo, i64 %hi, i8* %lo2, i64 %hi3)
|
||||
%not_err = icmp eq i64 %28, 0
|
||||
br i1 %not_err, label %after_check, label %voiderr
|
||||
|
||||
after_check: ; preds = %loop.body
|
||||
br label %voiderr
|
||||
|
||||
voiderr: ; preds = %after_check, %loop.body
|
||||
%29 = load i64, i64* %.anon1, align 8
|
||||
%add = add i64 %29, 1
|
||||
store i64 %add, i64* %.anon1, align 8
|
||||
br label %loop.cond
|
||||
|
||||
loop.exit: ; preds = %loop.cond
|
||||
%30 = getelementptr inbounds [4 x %variant], [4 x %variant]* %literal5, i64 0, i64 0
|
||||
store i32 1, i32* %taddr6, align 4
|
||||
%31 = bitcast i32* %taddr6 to i8*
|
||||
%32 = insertvalue %variant undef, i8* %31, 0
|
||||
%33 = insertvalue %variant %32, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1
|
||||
store %variant %33, %variant* %30, align 8
|
||||
%34 = getelementptr inbounds [4 x %variant], [4 x %variant]* %literal5, i64 0, i64 1
|
||||
store i32 -1, i32* %taddr7, align 4
|
||||
%35 = bitcast i32* %taddr7 to i8*
|
||||
%36 = insertvalue %variant undef, i8* %35, 0
|
||||
%37 = insertvalue %variant %36, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1
|
||||
store %variant %37, %variant* %34, align 8
|
||||
%38 = getelementptr inbounds [4 x %variant], [4 x %variant]* %literal5, i64 0, i64 2
|
||||
store i32 3141, i32* %taddr8, align 4
|
||||
%39 = bitcast i32* %taddr8 to i8*
|
||||
%40 = insertvalue %variant undef, i8* %39, 0
|
||||
%41 = insertvalue %variant %40, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1
|
||||
store %variant %41, %variant* %38, align 8
|
||||
%42 = getelementptr inbounds [4 x %variant], [4 x %variant]* %literal5, i64 0, i64 3
|
||||
store i32 1000, i32* %taddr9, align 4
|
||||
%43 = bitcast i32* %taddr9 to i8*
|
||||
%44 = insertvalue %variant undef, i8* %43, 0
|
||||
%45 = insertvalue %variant %44, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1
|
||||
store %variant %45, %variant* %42, align 8
|
||||
%46 = bitcast [4 x %variant]* %literal5 to %variant*
|
||||
%47 = insertvalue %"variant[]" undef, %variant* %46, 0
|
||||
%48 = insertvalue %"variant[]" %47, i64 4, 1
|
||||
store %"variant[]" %48, %"variant[]"* %x4, align 8
|
||||
%49 = getelementptr inbounds %"variant[]", %"variant[]"* %x4, i32 0, i32 1
|
||||
%50 = load i64, i64* %49, align 8
|
||||
store i64 %50, i64* %.anon10, align 8
|
||||
store i64 0, i64* %.anon11, align 8
|
||||
br label %loop.cond12
|
||||
|
||||
loop.cond12: ; preds = %voiderr27, %loop.exit
|
||||
%51 = load i64, i64* %.anon11, align 8
|
||||
%52 = load i64, i64* %.anon10, align 8
|
||||
%lt13 = icmp ult i64 %51, %52
|
||||
br i1 %lt13, label %loop.body14, label %loop.exit29
|
||||
|
||||
loop.body14: ; preds = %loop.cond12
|
||||
%53 = getelementptr inbounds %"variant[]", %"variant[]"* %x4, i32 0, i32 0
|
||||
%54 = load %variant*, %variant** %53, align 8
|
||||
%55 = load i64, i64* %.anon11, align 8
|
||||
%ptroffset16 = getelementptr inbounds %variant, %variant* %54, i64 %55
|
||||
%56 = bitcast %variant* %i15 to i8*
|
||||
%57 = bitcast %variant* %ptroffset16 to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %56, i8* align 8 %57, i32 16, i1 false)
|
||||
store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.1, i32 0, i32 0), i64 2 }, %"char[]"* %taddr18, align 8
|
||||
%58 = bitcast %"char[]"* %taddr18 to { i8*, i64 }*
|
||||
%59 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %58, i32 0, i32 0
|
||||
%lo19 = load i8*, i8** %59, align 8
|
||||
%60 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %58, i32 0, i32 1
|
||||
%hi20 = load i64, i64* %60, align 8
|
||||
%61 = getelementptr inbounds %variant, %variant* %i15, i32 0, i32 0
|
||||
%62 = bitcast i8** %61 to i32**
|
||||
%63 = load i32*, i32** %62, align 8
|
||||
%64 = bitcast i32* %63 to i8*
|
||||
%65 = insertvalue %variant undef, i8* %64, 0
|
||||
%66 = insertvalue %variant %65, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1
|
||||
%67 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots22, i64 0, i64 0
|
||||
store %variant %66, %variant* %67, align 16
|
||||
%68 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg21, i32 0, i32 1
|
||||
store i64 1, i64* %68, align 8
|
||||
%69 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg21, i32 0, i32 0
|
||||
%70 = bitcast [1 x %variant]* %varargslots22 to %variant*
|
||||
store %variant* %70, %variant** %69, align 8
|
||||
%71 = bitcast %"variant[]"* %vararg21 to { i8*, i64 }*
|
||||
%72 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %71, i32 0, i32 0
|
||||
%lo23 = load i8*, i8** %72, align 8
|
||||
%73 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %71, i32 0, i32 1
|
||||
%hi24 = load i64, i64* %73, align 8
|
||||
%74 = call i64 @std_io_printfln(i64* %retparam17, i8* %lo19, i64 %hi20, i8* %lo23, i64 %hi24)
|
||||
%not_err25 = icmp eq i64 %74, 0
|
||||
br i1 %not_err25, label %after_check26, label %voiderr27
|
||||
|
||||
after_check26: ; preds = %loop.body14
|
||||
br label %voiderr27
|
||||
|
||||
voiderr27: ; preds = %after_check26, %loop.body14
|
||||
%75 = load i64, i64* %.anon11, align 8
|
||||
%add28 = add i64 %75, 1
|
||||
store i64 %add28, i64* %.anon11, align 8
|
||||
br label %loop.cond12
|
||||
|
||||
loop.exit29: ; preds = %loop.cond12
|
||||
ret void
|
||||
}
|
||||
|
||||
25
test/test_suite/macros/macro_untyped_varargs.c3
Normal file
25
test/test_suite/macros/macro_untyped_varargs.c3
Normal file
@@ -0,0 +1,25 @@
|
||||
macro foo(...)
|
||||
{
|
||||
$vaarg_get_arg("hello"); // #error: Expected the argument index here
|
||||
int x;
|
||||
$vaarg_get_arg(x); // #error: Vararg functions need a constant argument
|
||||
$vaarg_get_arg(-1); // #error: negative
|
||||
$vaarg_get_arg(100); // #error: varargs exist
|
||||
}
|
||||
|
||||
macro foo2(...)
|
||||
{
|
||||
$vaarg_get_const(0);
|
||||
}
|
||||
|
||||
macro foo3(...)
|
||||
{
|
||||
$vaarg_get_type(0) a;
|
||||
}
|
||||
fn void main()
|
||||
{
|
||||
foo(1, -1, 3141, 999 + 1);
|
||||
int x;
|
||||
foo2(x); // #error: This argument needs to be a compile time constant
|
||||
foo3(3); // #error: The argument was not a type.
|
||||
}
|
||||
463
test/test_suite/macros/macro_untyped_varargs_2.c3t
Normal file
463
test/test_suite/macros/macro_untyped_varargs_2.c3t
Normal file
@@ -0,0 +1,463 @@
|
||||
// #target: macos-x64
|
||||
|
||||
module test;
|
||||
|
||||
import std::io;
|
||||
|
||||
macro @foo(...)
|
||||
{
|
||||
int i = $vaarg_get_arg(1) + $vaarg_get_arg(1);
|
||||
int j = $vaarg_get_expr(2) + $vaarg_get_expr(2);
|
||||
$for (var $i = 0; $i < $vaarg_count(); $i++):
|
||||
io::printfln("%d", $vaarg_get_arg($i));
|
||||
$endfor;
|
||||
}
|
||||
|
||||
macro foo2(...)
|
||||
{
|
||||
$for (var $i = 0; $i < $vaarg_count(); $i++):
|
||||
{
|
||||
$vaarg_get_type($i) x;
|
||||
}
|
||||
io::printfln("%s", $nameof($vaarg_get_type($i)));
|
||||
$endfor;
|
||||
}
|
||||
|
||||
macro foo3(...)
|
||||
{
|
||||
var $x = 0;
|
||||
$for (var $i = 0; $i < $vaarg_count(); $i++):
|
||||
$x += $vaarg_get_const($i);
|
||||
$endfor;
|
||||
return $x;
|
||||
}
|
||||
|
||||
macro @foo4(...)
|
||||
{
|
||||
$typeof($vaarg_get_ref(0)) a = $vaarg_get_ref(0);
|
||||
$vaarg_get_ref(0) = $vaarg_get_ref(1);
|
||||
$vaarg_get_ref(1) = a;
|
||||
}
|
||||
fn int ping(int val)
|
||||
{
|
||||
io::printfln("Ping[%d]", val);
|
||||
return val;
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
@foo(ping(1), ping(-1), ping(3141), ping(999 + 1));
|
||||
foo2(int, double);
|
||||
var $x = foo3(1, 4, 100);
|
||||
io::printfln("%d", $x);
|
||||
int x = 123;
|
||||
int y = 33;
|
||||
@foo4(x, y);
|
||||
io::printfln("%d, %d", x, y);
|
||||
@foo4(x, y);
|
||||
io::printfln("%d, %d", x, y);
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define i32 @test_ping(i32 %0) #0 {
|
||||
entry:
|
||||
%retparam = alloca i64, align 8
|
||||
%taddr = alloca %"char[]", align 8
|
||||
%vararg = alloca %"variant[]", align 8
|
||||
%varargslots = alloca [1 x %variant], align 16
|
||||
%taddr1 = alloca i32, align 4
|
||||
store %"char[]" { i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str, i32 0, i32 0), i64 8 }, %"char[]"* %taddr, align 8
|
||||
%1 = bitcast %"char[]"* %taddr to { i8*, i64 }*
|
||||
%2 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %1, i32 0, i32 0
|
||||
%lo = load i8*, i8** %2, align 8
|
||||
%3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %1, i32 0, i32 1
|
||||
%hi = load i64, i64* %3, align 8
|
||||
store i32 %0, i32* %taddr1, align 4
|
||||
%4 = bitcast i32* %taddr1 to i8*
|
||||
%5 = insertvalue %variant undef, i8* %4, 0
|
||||
%6 = insertvalue %variant %5, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1
|
||||
%7 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots, i64 0, i64 0
|
||||
store %variant %6, %variant* %7, align 16
|
||||
%8 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 1
|
||||
store i64 1, i64* %8, align 8
|
||||
%9 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 0
|
||||
%10 = bitcast [1 x %variant]* %varargslots to %variant*
|
||||
store %variant* %10, %variant** %9, align 8
|
||||
%11 = bitcast %"variant[]"* %vararg to { i8*, i64 }*
|
||||
%12 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %11, i32 0, i32 0
|
||||
%lo2 = load i8*, i8** %12, align 8
|
||||
%13 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %11, i32 0, i32 1
|
||||
%hi3 = load i64, i64* %13, align 8
|
||||
%14 = call i64 @std_io_printfln(i64* %retparam, i8* %lo, i64 %hi, i8* %lo2, i64 %hi3)
|
||||
%not_err = icmp eq i64 %14, 0
|
||||
br i1 %not_err, label %after_check, label %voiderr
|
||||
|
||||
after_check: ; preds = %entry
|
||||
br label %voiderr
|
||||
|
||||
voiderr: ; preds = %after_check, %entry
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
define void @test_main() #0 {
|
||||
entry:
|
||||
%.anon = alloca i32, align 4
|
||||
%.anon1 = alloca i32, align 4
|
||||
%.anon2 = alloca i32, align 4
|
||||
%.anon3 = alloca i32, align 4
|
||||
%i = alloca i32, align 4
|
||||
%j = alloca i32, align 4
|
||||
%retparam = alloca i64, align 8
|
||||
%taddr = alloca %"char[]", align 8
|
||||
%vararg = alloca %"variant[]", align 8
|
||||
%varargslots = alloca [1 x %variant], align 16
|
||||
%retparam7 = alloca i64, align 8
|
||||
%taddr8 = alloca %"char[]", align 8
|
||||
%vararg11 = alloca %"variant[]", align 8
|
||||
%varargslots12 = alloca [1 x %variant], align 16
|
||||
%retparam18 = alloca i64, align 8
|
||||
%taddr19 = alloca %"char[]", align 8
|
||||
%vararg22 = alloca %"variant[]", align 8
|
||||
%varargslots23 = alloca [1 x %variant], align 16
|
||||
%retparam29 = alloca i64, align 8
|
||||
%taddr30 = alloca %"char[]", align 8
|
||||
%vararg33 = alloca %"variant[]", align 8
|
||||
%varargslots34 = alloca [1 x %variant], align 16
|
||||
%x = alloca i32, align 4
|
||||
%retparam40 = alloca i64, align 8
|
||||
%taddr41 = alloca %"char[]", align 8
|
||||
%vararg44 = alloca %"variant[]", align 8
|
||||
%varargslots45 = alloca [1 x %variant], align 16
|
||||
%taddr46 = alloca [3 x i8]*, align 8
|
||||
%x52 = alloca double, align 8
|
||||
%retparam53 = alloca i64, align 8
|
||||
%taddr54 = alloca %"char[]", align 8
|
||||
%vararg57 = alloca %"variant[]", align 8
|
||||
%varargslots58 = alloca [1 x %variant], align 16
|
||||
%taddr59 = alloca [6 x i8]*, align 8
|
||||
%retparam65 = alloca i64, align 8
|
||||
%taddr66 = alloca %"char[]", align 8
|
||||
%vararg69 = alloca %"variant[]", align 8
|
||||
%varargslots70 = alloca [1 x %variant], align 16
|
||||
%taddr71 = alloca i32, align 4
|
||||
%x77 = alloca i32, align 4
|
||||
%y = alloca i32, align 4
|
||||
%a = alloca i32, align 4
|
||||
%retparam78 = alloca i64, align 8
|
||||
%taddr79 = alloca %"char[]", align 8
|
||||
%vararg82 = alloca %"variant[]", align 8
|
||||
%varargslots83 = alloca [2 x %variant], align 16
|
||||
%a89 = alloca i32, align 4
|
||||
%retparam90 = alloca i64, align 8
|
||||
%taddr91 = alloca %"char[]", align 8
|
||||
%vararg94 = alloca %"variant[]", align 8
|
||||
%varargslots95 = alloca [2 x %variant], align 16
|
||||
%0 = call i32 @test_ping(i32 -1)
|
||||
store i32 %0, i32* %.anon, align 4
|
||||
%1 = call i32 @test_ping(i32 1)
|
||||
store i32 %1, i32* %.anon1, align 4
|
||||
%2 = call i32 @test_ping(i32 3141)
|
||||
store i32 %2, i32* %.anon2, align 4
|
||||
%3 = call i32 @test_ping(i32 1000)
|
||||
store i32 %3, i32* %.anon3, align 4
|
||||
%4 = load i32, i32* %.anon, align 4
|
||||
%5 = load i32, i32* %.anon, align 4
|
||||
%add = add i32 %4, %5
|
||||
store i32 %add, i32* %i, align 4
|
||||
%6 = call i32 @test_ping(i32 3141)
|
||||
%7 = call i32 @test_ping(i32 3141)
|
||||
%add4 = add i32 %6, %7
|
||||
store i32 %add4, i32* %j, align 4
|
||||
store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.1, i32 0, i32 0), i64 2 }, %"char[]"* %taddr, align 8
|
||||
%8 = bitcast %"char[]"* %taddr to { i8*, i64 }*
|
||||
%9 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %8, i32 0, i32 0
|
||||
%lo = load i8*, i8** %9, align 8
|
||||
%10 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %8, i32 0, i32 1
|
||||
%hi = load i64, i64* %10, align 8
|
||||
%11 = bitcast i32* %.anon1 to i8*
|
||||
%12 = insertvalue %variant undef, i8* %11, 0
|
||||
%13 = insertvalue %variant %12, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1
|
||||
%14 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots, i64 0, i64 0
|
||||
store %variant %13, %variant* %14, align 16
|
||||
%15 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 1
|
||||
store i64 1, i64* %15, align 8
|
||||
%16 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 0
|
||||
%17 = bitcast [1 x %variant]* %varargslots to %variant*
|
||||
store %variant* %17, %variant** %16, align 8
|
||||
%18 = bitcast %"variant[]"* %vararg to { i8*, i64 }*
|
||||
%19 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %18, i32 0, i32 0
|
||||
%lo5 = load i8*, i8** %19, align 8
|
||||
%20 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %18, i32 0, i32 1
|
||||
%hi6 = load i64, i64* %20, align 8
|
||||
%21 = call i64 @std_io_printfln(i64* %retparam, i8* %lo, i64 %hi, i8* %lo5, i64 %hi6)
|
||||
%not_err = icmp eq i64 %21, 0
|
||||
br i1 %not_err, label %after_check, label %voiderr
|
||||
|
||||
after_check: ; preds = %entry
|
||||
br label %voiderr
|
||||
|
||||
voiderr: ; preds = %after_check, %entry
|
||||
store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.2, i32 0, i32 0), i64 2 }, %"char[]"* %taddr8, align 8
|
||||
%22 = bitcast %"char[]"* %taddr8 to { i8*, i64 }*
|
||||
%23 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %22, i32 0, i32 0
|
||||
%lo9 = load i8*, i8** %23, align 8
|
||||
%24 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %22, i32 0, i32 1
|
||||
%hi10 = load i64, i64* %24, align 8
|
||||
%25 = bitcast i32* %.anon to i8*
|
||||
%26 = insertvalue %variant undef, i8* %25, 0
|
||||
%27 = insertvalue %variant %26, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1
|
||||
%28 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots12, i64 0, i64 0
|
||||
store %variant %27, %variant* %28, align 16
|
||||
%29 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg11, i32 0, i32 1
|
||||
store i64 1, i64* %29, align 8
|
||||
%30 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg11, i32 0, i32 0
|
||||
%31 = bitcast [1 x %variant]* %varargslots12 to %variant*
|
||||
store %variant* %31, %variant** %30, align 8
|
||||
%32 = bitcast %"variant[]"* %vararg11 to { i8*, i64 }*
|
||||
%33 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %32, i32 0, i32 0
|
||||
%lo13 = load i8*, i8** %33, align 8
|
||||
%34 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %32, i32 0, i32 1
|
||||
%hi14 = load i64, i64* %34, align 8
|
||||
%35 = call i64 @std_io_printfln(i64* %retparam7, i8* %lo9, i64 %hi10, i8* %lo13, i64 %hi14)
|
||||
%not_err15 = icmp eq i64 %35, 0
|
||||
br i1 %not_err15, label %after_check16, label %voiderr17
|
||||
|
||||
after_check16: ; preds = %voiderr
|
||||
br label %voiderr17
|
||||
|
||||
voiderr17: ; preds = %after_check16, %voiderr
|
||||
store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.3, i32 0, i32 0), i64 2 }, %"char[]"* %taddr19, align 8
|
||||
%36 = bitcast %"char[]"* %taddr19 to { i8*, i64 }*
|
||||
%37 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %36, i32 0, i32 0
|
||||
%lo20 = load i8*, i8** %37, align 8
|
||||
%38 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %36, i32 0, i32 1
|
||||
%hi21 = load i64, i64* %38, align 8
|
||||
%39 = bitcast i32* %.anon2 to i8*
|
||||
%40 = insertvalue %variant undef, i8* %39, 0
|
||||
%41 = insertvalue %variant %40, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1
|
||||
%42 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots23, i64 0, i64 0
|
||||
store %variant %41, %variant* %42, align 16
|
||||
%43 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg22, i32 0, i32 1
|
||||
store i64 1, i64* %43, align 8
|
||||
%44 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg22, i32 0, i32 0
|
||||
%45 = bitcast [1 x %variant]* %varargslots23 to %variant*
|
||||
store %variant* %45, %variant** %44, align 8
|
||||
%46 = bitcast %"variant[]"* %vararg22 to { i8*, i64 }*
|
||||
%47 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %46, i32 0, i32 0
|
||||
%lo24 = load i8*, i8** %47, align 8
|
||||
%48 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %46, i32 0, i32 1
|
||||
%hi25 = load i64, i64* %48, align 8
|
||||
%49 = call i64 @std_io_printfln(i64* %retparam18, i8* %lo20, i64 %hi21, i8* %lo24, i64 %hi25)
|
||||
%not_err26 = icmp eq i64 %49, 0
|
||||
br i1 %not_err26, label %after_check27, label %voiderr28
|
||||
|
||||
after_check27: ; preds = %voiderr17
|
||||
br label %voiderr28
|
||||
|
||||
voiderr28: ; preds = %after_check27, %voiderr17
|
||||
store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.4, i32 0, i32 0), i64 2 }, %"char[]"* %taddr30, align 8
|
||||
%50 = bitcast %"char[]"* %taddr30 to { i8*, i64 }*
|
||||
%51 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %50, i32 0, i32 0
|
||||
%lo31 = load i8*, i8** %51, align 8
|
||||
%52 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %50, i32 0, i32 1
|
||||
%hi32 = load i64, i64* %52, align 8
|
||||
%53 = bitcast i32* %.anon3 to i8*
|
||||
%54 = insertvalue %variant undef, i8* %53, 0
|
||||
%55 = insertvalue %variant %54, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1
|
||||
%56 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots34, i64 0, i64 0
|
||||
store %variant %55, %variant* %56, align 16
|
||||
%57 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg33, i32 0, i32 1
|
||||
store i64 1, i64* %57, align 8
|
||||
%58 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg33, i32 0, i32 0
|
||||
%59 = bitcast [1 x %variant]* %varargslots34 to %variant*
|
||||
store %variant* %59, %variant** %58, align 8
|
||||
%60 = bitcast %"variant[]"* %vararg33 to { i8*, i64 }*
|
||||
%61 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %60, i32 0, i32 0
|
||||
%lo35 = load i8*, i8** %61, align 8
|
||||
%62 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %60, i32 0, i32 1
|
||||
%hi36 = load i64, i64* %62, align 8
|
||||
%63 = call i64 @std_io_printfln(i64* %retparam29, i8* %lo31, i64 %hi32, i8* %lo35, i64 %hi36)
|
||||
%not_err37 = icmp eq i64 %63, 0
|
||||
br i1 %not_err37, label %after_check38, label %voiderr39
|
||||
|
||||
after_check38: ; preds = %voiderr28
|
||||
br label %voiderr39
|
||||
|
||||
voiderr39: ; preds = %after_check38, %voiderr28
|
||||
store i32 0, i32* %x, align 4
|
||||
store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.5, i32 0, i32 0), i64 2 }, %"char[]"* %taddr41, align 8
|
||||
%64 = bitcast %"char[]"* %taddr41 to { i8*, i64 }*
|
||||
%65 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %64, i32 0, i32 0
|
||||
%lo42 = load i8*, i8** %65, align 8
|
||||
%66 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %64, i32 0, i32 1
|
||||
%hi43 = load i64, i64* %66, align 8
|
||||
store [3 x i8]* bitcast ([4 x i8]* @.str.6 to [3 x i8]*), [3 x i8]** %taddr46, align 8
|
||||
%67 = bitcast [3 x i8]** %taddr46 to i8*
|
||||
%68 = insertvalue %variant undef, i8* %67, 0
|
||||
%69 = insertvalue %variant %68, i64 ptrtoint (%.introspect* @"ct$p$a3$char" to i64), 1
|
||||
%70 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots45, i64 0, i64 0
|
||||
store %variant %69, %variant* %70, align 16
|
||||
%71 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg44, i32 0, i32 1
|
||||
store i64 1, i64* %71, align 8
|
||||
%72 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg44, i32 0, i32 0
|
||||
%73 = bitcast [1 x %variant]* %varargslots45 to %variant*
|
||||
store %variant* %73, %variant** %72, align 8
|
||||
%74 = bitcast %"variant[]"* %vararg44 to { i8*, i64 }*
|
||||
%75 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %74, i32 0, i32 0
|
||||
%lo47 = load i8*, i8** %75, align 8
|
||||
%76 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %74, i32 0, i32 1
|
||||
%hi48 = load i64, i64* %76, align 8
|
||||
%77 = call i64 @std_io_printfln(i64* %retparam40, i8* %lo42, i64 %hi43, i8* %lo47, i64 %hi48)
|
||||
%not_err49 = icmp eq i64 %77, 0
|
||||
br i1 %not_err49, label %after_check50, label %voiderr51
|
||||
|
||||
after_check50: ; preds = %voiderr39
|
||||
br label %voiderr51
|
||||
|
||||
voiderr51: ; preds = %after_check50, %voiderr39
|
||||
store double 0.000000e+00, double* %x52, align 8
|
||||
store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.7, i32 0, i32 0), i64 2 }, %"char[]"* %taddr54, align 8
|
||||
%78 = bitcast %"char[]"* %taddr54 to { i8*, i64 }*
|
||||
%79 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %78, i32 0, i32 0
|
||||
%lo55 = load i8*, i8** %79, align 8
|
||||
%80 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %78, i32 0, i32 1
|
||||
%hi56 = load i64, i64* %80, align 8
|
||||
store [6 x i8]* bitcast ([7 x i8]* @.str.8 to [6 x i8]*), [6 x i8]** %taddr59, align 8
|
||||
%81 = bitcast [6 x i8]** %taddr59 to i8*
|
||||
%82 = insertvalue %variant undef, i8* %81, 0
|
||||
%83 = insertvalue %variant %82, i64 ptrtoint (%.introspect* @"ct$p$a6$char" to i64), 1
|
||||
%84 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots58, i64 0, i64 0
|
||||
store %variant %83, %variant* %84, align 16
|
||||
%85 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg57, i32 0, i32 1
|
||||
store i64 1, i64* %85, align 8
|
||||
%86 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg57, i32 0, i32 0
|
||||
%87 = bitcast [1 x %variant]* %varargslots58 to %variant*
|
||||
store %variant* %87, %variant** %86, align 8
|
||||
%88 = bitcast %"variant[]"* %vararg57 to { i8*, i64 }*
|
||||
%89 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %88, i32 0, i32 0
|
||||
%lo60 = load i8*, i8** %89, align 8
|
||||
%90 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %88, i32 0, i32 1
|
||||
%hi61 = load i64, i64* %90, align 8
|
||||
%91 = call i64 @std_io_printfln(i64* %retparam53, i8* %lo55, i64 %hi56, i8* %lo60, i64 %hi61)
|
||||
%not_err62 = icmp eq i64 %91, 0
|
||||
br i1 %not_err62, label %after_check63, label %voiderr64
|
||||
|
||||
after_check63: ; preds = %voiderr51
|
||||
br label %voiderr64
|
||||
|
||||
voiderr64: ; preds = %after_check63, %voiderr51
|
||||
store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.9, i32 0, i32 0), i64 2 }, %"char[]"* %taddr66, align 8
|
||||
%92 = bitcast %"char[]"* %taddr66 to { i8*, i64 }*
|
||||
%93 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %92, i32 0, i32 0
|
||||
%lo67 = load i8*, i8** %93, align 8
|
||||
%94 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %92, i32 0, i32 1
|
||||
%hi68 = load i64, i64* %94, align 8
|
||||
store i32 105, i32* %taddr71, align 4
|
||||
%95 = bitcast i32* %taddr71 to i8*
|
||||
%96 = insertvalue %variant undef, i8* %95, 0
|
||||
%97 = insertvalue %variant %96, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1
|
||||
%98 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots70, i64 0, i64 0
|
||||
store %variant %97, %variant* %98, align 16
|
||||
%99 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg69, i32 0, i32 1
|
||||
store i64 1, i64* %99, align 8
|
||||
%100 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg69, i32 0, i32 0
|
||||
%101 = bitcast [1 x %variant]* %varargslots70 to %variant*
|
||||
store %variant* %101, %variant** %100, align 8
|
||||
%102 = bitcast %"variant[]"* %vararg69 to { i8*, i64 }*
|
||||
%103 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %102, i32 0, i32 0
|
||||
%lo72 = load i8*, i8** %103, align 8
|
||||
%104 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %102, i32 0, i32 1
|
||||
%hi73 = load i64, i64* %104, align 8
|
||||
%105 = call i64 @std_io_printfln(i64* %retparam65, i8* %lo67, i64 %hi68, i8* %lo72, i64 %hi73)
|
||||
%not_err74 = icmp eq i64 %105, 0
|
||||
br i1 %not_err74, label %after_check75, label %voiderr76
|
||||
|
||||
after_check75: ; preds = %voiderr64
|
||||
br label %voiderr76
|
||||
|
||||
voiderr76: ; preds = %after_check75, %voiderr64
|
||||
store i32 123, i32* %x77, align 4
|
||||
store i32 33, i32* %y, align 4
|
||||
%106 = load i32, i32* %x77, align 4
|
||||
store i32 %106, i32* %a, align 4
|
||||
%107 = load i32, i32* %y, align 4
|
||||
store i32 %107, i32* %x77, align 4
|
||||
%108 = load i32, i32* %a, align 4
|
||||
store i32 %108, i32* %y, align 4
|
||||
store %"char[]" { i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.10, i32 0, i32 0), i64 6 }, %"char[]"* %taddr79, align 8
|
||||
%109 = bitcast %"char[]"* %taddr79 to { i8*, i64 }*
|
||||
%110 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %109, i32 0, i32 0
|
||||
%lo80 = load i8*, i8** %110, align 8
|
||||
%111 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %109, i32 0, i32 1
|
||||
%hi81 = load i64, i64* %111, align 8
|
||||
%112 = bitcast i32* %x77 to i8*
|
||||
%113 = insertvalue %variant undef, i8* %112, 0
|
||||
%114 = insertvalue %variant %113, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1
|
||||
%115 = getelementptr inbounds [2 x %variant], [2 x %variant]* %varargslots83, i64 0, i64 0
|
||||
store %variant %114, %variant* %115, align 16
|
||||
%116 = bitcast i32* %y to i8*
|
||||
%117 = insertvalue %variant undef, i8* %116, 0
|
||||
%118 = insertvalue %variant %117, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1
|
||||
%119 = getelementptr inbounds [2 x %variant], [2 x %variant]* %varargslots83, i64 0, i64 1
|
||||
store %variant %118, %variant* %119, align 16
|
||||
%120 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg82, i32 0, i32 1
|
||||
store i64 2, i64* %120, align 8
|
||||
%121 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg82, i32 0, i32 0
|
||||
%122 = bitcast [2 x %variant]* %varargslots83 to %variant*
|
||||
store %variant* %122, %variant** %121, align 8
|
||||
%123 = bitcast %"variant[]"* %vararg82 to { i8*, i64 }*
|
||||
%124 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %123, i32 0, i32 0
|
||||
%lo84 = load i8*, i8** %124, align 8
|
||||
%125 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %123, i32 0, i32 1
|
||||
%hi85 = load i64, i64* %125, align 8
|
||||
%126 = call i64 @std_io_printfln(i64* %retparam78, i8* %lo80, i64 %hi81, i8* %lo84, i64 %hi85)
|
||||
%not_err86 = icmp eq i64 %126, 0
|
||||
br i1 %not_err86, label %after_check87, label %voiderr88
|
||||
|
||||
after_check87: ; preds = %voiderr76
|
||||
br label %voiderr88
|
||||
|
||||
voiderr88: ; preds = %after_check87, %voiderr76
|
||||
%127 = load i32, i32* %x77, align 4
|
||||
store i32 %127, i32* %a89, align 4
|
||||
%128 = load i32, i32* %y, align 4
|
||||
store i32 %128, i32* %x77, align 4
|
||||
%129 = load i32, i32* %a89, align 4
|
||||
store i32 %129, i32* %y, align 4
|
||||
store %"char[]" { i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.11, i32 0, i32 0), i64 6 }, %"char[]"* %taddr91, align 8
|
||||
%130 = bitcast %"char[]"* %taddr91 to { i8*, i64 }*
|
||||
%131 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %130, i32 0, i32 0
|
||||
%lo92 = load i8*, i8** %131, align 8
|
||||
%132 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %130, i32 0, i32 1
|
||||
%hi93 = load i64, i64* %132, align 8
|
||||
%133 = bitcast i32* %x77 to i8*
|
||||
%134 = insertvalue %variant undef, i8* %133, 0
|
||||
%135 = insertvalue %variant %134, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1
|
||||
%136 = getelementptr inbounds [2 x %variant], [2 x %variant]* %varargslots95, i64 0, i64 0
|
||||
store %variant %135, %variant* %136, align 16
|
||||
%137 = bitcast i32* %y to i8*
|
||||
%138 = insertvalue %variant undef, i8* %137, 0
|
||||
%139 = insertvalue %variant %138, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1
|
||||
%140 = getelementptr inbounds [2 x %variant], [2 x %variant]* %varargslots95, i64 0, i64 1
|
||||
store %variant %139, %variant* %140, align 16
|
||||
%141 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg94, i32 0, i32 1
|
||||
store i64 2, i64* %141, align 8
|
||||
%142 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg94, i32 0, i32 0
|
||||
%143 = bitcast [2 x %variant]* %varargslots95 to %variant*
|
||||
store %variant* %143, %variant** %142, align 8
|
||||
%144 = bitcast %"variant[]"* %vararg94 to { i8*, i64 }*
|
||||
%145 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %144, i32 0, i32 0
|
||||
%lo96 = load i8*, i8** %145, align 8
|
||||
%146 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %144, i32 0, i32 1
|
||||
%hi97 = load i64, i64* %146, align 8
|
||||
%147 = call i64 @std_io_printfln(i64* %retparam90, i8* %lo92, i64 %hi93, i8* %lo96, i64 %hi97)
|
||||
%not_err98 = icmp eq i64 %147, 0
|
||||
br i1 %not_err98, label %after_check99, label %voiderr100
|
||||
|
||||
after_check99: ; preds = %voiderr88
|
||||
br label %voiderr100
|
||||
|
||||
voiderr100: ; preds = %after_check99, %voiderr88
|
||||
ret void
|
||||
}
|
||||
@@ -11,7 +11,7 @@ fn void main()
|
||||
printf("Foo %d\n", $i);
|
||||
$endfor;
|
||||
|
||||
$for (var $i = 0, var $j = 100; $i < 4;):
|
||||
$for ($i = 0, var $j = 100; $i < 4;):
|
||||
printf("Foo %d %d\n", $i++, $j--);
|
||||
$endfor;
|
||||
|
||||
|
||||
@@ -7,4 +7,6 @@ fn void foo3(bar) { } // #error: Only typed parameters are allowed for functions
|
||||
|
||||
fn void foo4($Type) { } // #error: Only regular parameters are allowed for functions.
|
||||
|
||||
fn void foo8(int &foo) {} // #error: Only regular parameters are allowed for functions.
|
||||
fn void foo8(int &foo) {} // #error: Only regular parameters are allowed for functions.
|
||||
|
||||
fn void foo9(int x, int x) {} // #error: Duplicate parameter name 'x'.
|
||||
@@ -2,10 +2,10 @@ macro foo(a, $b, $Type) {}
|
||||
|
||||
macro @foo2(a, $b, $Type) {}
|
||||
|
||||
macro bar(&x) // #error: non-function
|
||||
macro bar(&x) // #error: Ref and expression parameters
|
||||
{}
|
||||
|
||||
macro baz(#y) {} // #error: non-function
|
||||
macro baz(#y) {} // #error: Ref and expression parameters
|
||||
|
||||
macro baz2(a; @body()) {} // #error: non-function
|
||||
macro baz2(a; @body()) {} // #error: Names of macros
|
||||
|
||||
|
||||
191
test/test_suite2/macros/macro_typed_varargs.c3t
Normal file
191
test/test_suite2/macros/macro_typed_varargs.c3t
Normal file
@@ -0,0 +1,191 @@
|
||||
// #target: macos-x64
|
||||
|
||||
module test;
|
||||
|
||||
import std::io;
|
||||
|
||||
macro foo(int... x)
|
||||
{
|
||||
foreach (i : x)
|
||||
{
|
||||
io::printfln("%d", i);
|
||||
}
|
||||
}
|
||||
|
||||
macro foo2(x...)
|
||||
{
|
||||
foreach (i : x)
|
||||
{
|
||||
io::printfln("%d", *(int*)i);
|
||||
}
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
foo(1, -1, 3141, 999 + 1);
|
||||
foo2(1, -1, 3141, 999 + 1);
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define void @test_main() #0 {
|
||||
entry:
|
||||
%x = alloca %"int[]", align 8
|
||||
%literal = alloca [4 x i32], align 16
|
||||
%.anon = alloca i64, align 8
|
||||
%.anon1 = alloca i64, align 8
|
||||
%i = alloca i32, align 4
|
||||
%retparam = alloca i64, align 8
|
||||
%taddr = alloca %"char[]", align 8
|
||||
%vararg = alloca %"variant[]", align 8
|
||||
%varargslots = alloca [1 x %variant], align 16
|
||||
%x4 = alloca %"variant[]", align 8
|
||||
%literal5 = alloca [4 x %variant], align 16
|
||||
%taddr6 = alloca i32, align 4
|
||||
%taddr7 = alloca i32, align 4
|
||||
%taddr8 = alloca i32, align 4
|
||||
%taddr9 = alloca i32, align 4
|
||||
%.anon10 = alloca i64, align 8
|
||||
%.anon11 = alloca i64, align 8
|
||||
%i15 = alloca %variant, align 8
|
||||
%retparam17 = alloca i64, align 8
|
||||
%taddr18 = alloca %"char[]", align 8
|
||||
%vararg21 = alloca %"variant[]", align 8
|
||||
%varargslots22 = alloca [1 x %variant], align 16
|
||||
%0 = getelementptr inbounds [4 x i32], ptr %literal, i64 0, i64 0
|
||||
store i32 1, ptr %0, align 4
|
||||
%1 = getelementptr inbounds [4 x i32], ptr %literal, i64 0, i64 1
|
||||
store i32 -1, ptr %1, align 4
|
||||
%2 = getelementptr inbounds [4 x i32], ptr %literal, i64 0, i64 2
|
||||
store i32 3141, ptr %2, align 4
|
||||
%3 = getelementptr inbounds [4 x i32], ptr %literal, i64 0, i64 3
|
||||
store i32 1000, ptr %3, align 4
|
||||
%4 = insertvalue %"int[]" undef, ptr %literal, 0
|
||||
%5 = insertvalue %"int[]" %4, i64 4, 1
|
||||
store %"int[]" %5, ptr %x, align 8
|
||||
%6 = getelementptr inbounds %"int[]", ptr %x, i32 0, i32 1
|
||||
%7 = load i64, ptr %6, align 8
|
||||
store i64 %7, ptr %.anon, align 8
|
||||
store i64 0, ptr %.anon1, align 8
|
||||
br label %loop.cond
|
||||
|
||||
loop.cond: ; preds = %voiderr, %entry
|
||||
%8 = load i64, ptr %.anon1, align 8
|
||||
%9 = load i64, ptr %.anon, align 8
|
||||
%lt = icmp ult i64 %8, %9
|
||||
br i1 %lt, label %loop.body, label %loop.exit
|
||||
|
||||
loop.body: ; preds = %loop.cond
|
||||
%10 = getelementptr inbounds %"int[]", ptr %x, i32 0, i32 0
|
||||
%11 = load ptr, ptr %10, align 8
|
||||
%12 = load i64, ptr %.anon1, align 8
|
||||
%ptroffset = getelementptr inbounds i32, ptr %11, i64 %12
|
||||
%13 = load i32, ptr %ptroffset, align 4
|
||||
store i32 %13, ptr %i, align 4
|
||||
store %"char[]" { ptr @.str, i64 2 }, ptr %taddr, align 8
|
||||
%14 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 0
|
||||
%lo = load ptr, ptr %14, align 8
|
||||
%15 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 1
|
||||
%hi = load i64, ptr %15, align 8
|
||||
%16 = insertvalue %variant undef, ptr %i, 0
|
||||
%17 = insertvalue %variant %16, i64 ptrtoint (ptr @"ct$int" to i64), 1
|
||||
%18 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0
|
||||
store %variant %17, ptr %18, align 16
|
||||
%19 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 1
|
||||
store i64 1, ptr %19, align 8
|
||||
%20 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 0
|
||||
store ptr %varargslots, ptr %20, align 8
|
||||
%21 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 0
|
||||
%lo2 = load ptr, ptr %21, align 8
|
||||
%22 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 1
|
||||
%hi3 = load i64, ptr %22, align 8
|
||||
%23 = call i64 @std_io_printfln(ptr %retparam, ptr %lo, i64 %hi, ptr %lo2, i64 %hi3)
|
||||
%not_err = icmp eq i64 %23, 0
|
||||
br i1 %not_err, label %after_check, label %voiderr
|
||||
|
||||
after_check: ; preds = %loop.body
|
||||
br label %voiderr
|
||||
|
||||
voiderr: ; preds = %after_check, %loop.body
|
||||
%24 = load i64, ptr %.anon1, align 8
|
||||
%add = add i64 %24, 1
|
||||
store i64 %add, ptr %.anon1, align 8
|
||||
br label %loop.cond
|
||||
|
||||
loop.exit: ; preds = %loop.cond
|
||||
%25 = getelementptr inbounds [4 x %variant], ptr %literal5, i64 0, i64 0
|
||||
store i32 1, ptr %taddr6, align 4
|
||||
%26 = insertvalue %variant undef, ptr %taddr6, 0
|
||||
%27 = insertvalue %variant %26, i64 ptrtoint (ptr @"ct$int" to i64), 1
|
||||
store %variant %27, ptr %25, align 8
|
||||
%28 = getelementptr inbounds [4 x %variant], ptr %literal5, i64 0, i64 1
|
||||
store i32 -1, ptr %taddr7, align 4
|
||||
%29 = insertvalue %variant undef, ptr %taddr7, 0
|
||||
%30 = insertvalue %variant %29, i64 ptrtoint (ptr @"ct$int" to i64), 1
|
||||
store %variant %30, ptr %28, align 8
|
||||
%31 = getelementptr inbounds [4 x %variant], ptr %literal5, i64 0, i64 2
|
||||
store i32 3141, ptr %taddr8, align 4
|
||||
%32 = insertvalue %variant undef, ptr %taddr8, 0
|
||||
%33 = insertvalue %variant %32, i64 ptrtoint (ptr @"ct$int" to i64), 1
|
||||
store %variant %33, ptr %31, align 8
|
||||
%34 = getelementptr inbounds [4 x %variant], ptr %literal5, i64 0, i64 3
|
||||
store i32 1000, ptr %taddr9, align 4
|
||||
%35 = insertvalue %variant undef, ptr %taddr9, 0
|
||||
%36 = insertvalue %variant %35, i64 ptrtoint (ptr @"ct$int" to i64), 1
|
||||
store %variant %36, ptr %34, align 8
|
||||
%37 = insertvalue %"variant[]" undef, ptr %literal5, 0
|
||||
%38 = insertvalue %"variant[]" %37, i64 4, 1
|
||||
store %"variant[]" %38, ptr %x4, align 8
|
||||
%39 = getelementptr inbounds %"variant[]", ptr %x4, i32 0, i32 1
|
||||
%40 = load i64, ptr %39, align 8
|
||||
store i64 %40, ptr %.anon10, align 8
|
||||
store i64 0, ptr %.anon11, align 8
|
||||
br label %loop.cond12
|
||||
|
||||
loop.cond12: ; preds = %voiderr27, %loop.exit
|
||||
%41 = load i64, ptr %.anon11, align 8
|
||||
%42 = load i64, ptr %.anon10, align 8
|
||||
%lt13 = icmp ult i64 %41, %42
|
||||
br i1 %lt13, label %loop.body14, label %loop.exit29
|
||||
|
||||
loop.body14: ; preds = %loop.cond12
|
||||
%43 = getelementptr inbounds %"variant[]", ptr %x4, i32 0, i32 0
|
||||
%44 = load ptr, ptr %43, align 8
|
||||
%45 = load i64, ptr %.anon11, align 8
|
||||
%ptroffset16 = getelementptr inbounds %variant, ptr %44, i64 %45
|
||||
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %i15, ptr align 8 %ptroffset16, i32 16, i1 false)
|
||||
store %"char[]" { ptr @.str.1, i64 2 }, ptr %taddr18, align 8
|
||||
%46 = getelementptr inbounds { ptr, i64 }, ptr %taddr18, i32 0, i32 0
|
||||
%lo19 = load ptr, ptr %46, align 8
|
||||
%47 = getelementptr inbounds { ptr, i64 }, ptr %taddr18, i32 0, i32 1
|
||||
%hi20 = load i64, ptr %47, align 8
|
||||
%48 = getelementptr inbounds %variant, ptr %i15, i32 0, i32 0
|
||||
%49 = load ptr, ptr %48, align 8
|
||||
%50 = insertvalue %variant undef, ptr %49, 0
|
||||
%51 = insertvalue %variant %50, i64 ptrtoint (ptr @"ct$int" to i64), 1
|
||||
%52 = getelementptr inbounds [1 x %variant], ptr %varargslots22, i64 0, i64 0
|
||||
store %variant %51, ptr %52, align 16
|
||||
%53 = getelementptr inbounds %"variant[]", ptr %vararg21, i32 0, i32 1
|
||||
store i64 1, ptr %53, align 8
|
||||
%54 = getelementptr inbounds %"variant[]", ptr %vararg21, i32 0, i32 0
|
||||
store ptr %varargslots22, ptr %54, align 8
|
||||
%55 = getelementptr inbounds { ptr, i64 }, ptr %vararg21, i32 0, i32 0
|
||||
%lo23 = load ptr, ptr %55, align 8
|
||||
%56 = getelementptr inbounds { ptr, i64 }, ptr %vararg21, i32 0, i32 1
|
||||
%hi24 = load i64, ptr %56, align 8
|
||||
%57 = call i64 @std_io_printfln(ptr %retparam17, ptr %lo19, i64 %hi20, ptr %lo23, i64 %hi24)
|
||||
%not_err25 = icmp eq i64 %57, 0
|
||||
br i1 %not_err25, label %after_check26, label %voiderr27
|
||||
|
||||
after_check26: ; preds = %loop.body14
|
||||
br label %voiderr27
|
||||
|
||||
voiderr27: ; preds = %after_check26, %loop.body14
|
||||
%58 = load i64, ptr %.anon11, align 8
|
||||
%add28 = add i64 %58, 1
|
||||
store i64 %add28, ptr %.anon11, align 8
|
||||
br label %loop.cond12
|
||||
|
||||
loop.exit29: ; preds = %loop.cond12
|
||||
ret void
|
||||
}
|
||||
25
test/test_suite2/macros/macro_untyped_varargs.c3
Normal file
25
test/test_suite2/macros/macro_untyped_varargs.c3
Normal file
@@ -0,0 +1,25 @@
|
||||
macro foo(...)
|
||||
{
|
||||
$vaarg_get_arg("hello"); // #error: Expected the argument index here
|
||||
int x;
|
||||
$vaarg_get_arg(x); // #error: Vararg functions need a constant argument
|
||||
$vaarg_get_arg(-1); // #error: negative
|
||||
$vaarg_get_arg(100); // #error: varargs exist
|
||||
}
|
||||
|
||||
macro foo2(...)
|
||||
{
|
||||
$vaarg_get_const(0);
|
||||
}
|
||||
|
||||
macro foo3(...)
|
||||
{
|
||||
$vaarg_get_type(0) a;
|
||||
}
|
||||
fn void main()
|
||||
{
|
||||
foo(1, -1, 3141, 999 + 1);
|
||||
int x;
|
||||
foo2(x); // #error: This argument needs to be a compile time constant
|
||||
foo3(3); // #error: The argument was not a type.
|
||||
}
|
||||
421
test/test_suite2/macros/macro_untyped_varargs_2.c3t
Normal file
421
test/test_suite2/macros/macro_untyped_varargs_2.c3t
Normal file
@@ -0,0 +1,421 @@
|
||||
// #target: macos-x64
|
||||
|
||||
module test;
|
||||
|
||||
import std::io;
|
||||
|
||||
macro @foo(...)
|
||||
{
|
||||
int i = $vaarg_get_arg(1) + $vaarg_get_arg(1);
|
||||
int j = $vaarg_get_expr(2) + $vaarg_get_expr(2);
|
||||
$for (var $i = 0; $i < $vaarg_count(); $i++):
|
||||
io::printfln("%d", $vaarg_get_arg($i));
|
||||
$endfor;
|
||||
}
|
||||
|
||||
macro foo2(...)
|
||||
{
|
||||
$for (var $i = 0; $i < $vaarg_count(); $i++):
|
||||
{
|
||||
$vaarg_get_type($i) x;
|
||||
}
|
||||
io::printfln("%s", $nameof($vaarg_get_type($i)));
|
||||
$endfor;
|
||||
}
|
||||
|
||||
macro foo3(...)
|
||||
{
|
||||
var $x = 0;
|
||||
$for (var $i = 0; $i < $vaarg_count(); $i++):
|
||||
$x += $vaarg_get_const($i);
|
||||
$endfor;
|
||||
return $x;
|
||||
}
|
||||
|
||||
macro @foo4(...)
|
||||
{
|
||||
$typeof($vaarg_get_ref(0)) a = $vaarg_get_ref(0);
|
||||
$vaarg_get_ref(0) = $vaarg_get_ref(1);
|
||||
$vaarg_get_ref(1) = a;
|
||||
}
|
||||
fn int ping(int val)
|
||||
{
|
||||
io::printfln("Ping[%d]", val);
|
||||
return val;
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
@foo(ping(1), ping(-1), ping(3141), ping(999 + 1));
|
||||
foo2(int, double);
|
||||
var $x = foo3(1, 4, 100);
|
||||
io::printfln("%d", $x);
|
||||
int x = 123;
|
||||
int y = 33;
|
||||
@foo4(x, y);
|
||||
io::printfln("%d, %d", x, y);
|
||||
@foo4(x, y);
|
||||
io::printfln("%d, %d", x, y);
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define i32 @test_ping(i32 %0) #0 {
|
||||
entry:
|
||||
%retparam = alloca i64, align 8
|
||||
%taddr = alloca %"char[]", align 8
|
||||
%vararg = alloca %"variant[]", align 8
|
||||
%varargslots = alloca [1 x %variant], align 16
|
||||
%taddr1 = alloca i32, align 4
|
||||
store %"char[]" { ptr @.str, i64 8 }, ptr %taddr, align 8
|
||||
%1 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 0
|
||||
%lo = load ptr, ptr %1, align 8
|
||||
%2 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 1
|
||||
%hi = load i64, ptr %2, align 8
|
||||
store i32 %0, ptr %taddr1, align 4
|
||||
%3 = insertvalue %variant undef, ptr %taddr1, 0
|
||||
%4 = insertvalue %variant %3, i64 ptrtoint (ptr @"ct$int" to i64), 1
|
||||
%5 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0
|
||||
store %variant %4, ptr %5, align 16
|
||||
%6 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 1
|
||||
store i64 1, ptr %6, align 8
|
||||
%7 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 0
|
||||
store ptr %varargslots, ptr %7, align 8
|
||||
%8 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 0
|
||||
%lo2 = load ptr, ptr %8, align 8
|
||||
%9 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 1
|
||||
%hi3 = load i64, ptr %9, align 8
|
||||
%10 = call i64 @std_io_printfln(ptr %retparam, ptr %lo, i64 %hi, ptr %lo2, i64 %hi3)
|
||||
%not_err = icmp eq i64 %10, 0
|
||||
br i1 %not_err, label %after_check, label %voiderr
|
||||
|
||||
after_check: ; preds = %entry
|
||||
br label %voiderr
|
||||
|
||||
voiderr: ; preds = %after_check, %entry
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
define void @test_main() #0 {
|
||||
entry:
|
||||
%.anon = alloca i32, align 4
|
||||
%.anon1 = alloca i32, align 4
|
||||
%.anon2 = alloca i32, align 4
|
||||
%.anon3 = alloca i32, align 4
|
||||
%i = alloca i32, align 4
|
||||
%j = alloca i32, align 4
|
||||
%retparam = alloca i64, align 8
|
||||
%taddr = alloca %"char[]", align 8
|
||||
%vararg = alloca %"variant[]", align 8
|
||||
%varargslots = alloca [1 x %variant], align 16
|
||||
%retparam7 = alloca i64, align 8
|
||||
%taddr8 = alloca %"char[]", align 8
|
||||
%vararg11 = alloca %"variant[]", align 8
|
||||
%varargslots12 = alloca [1 x %variant], align 16
|
||||
%retparam18 = alloca i64, align 8
|
||||
%taddr19 = alloca %"char[]", align 8
|
||||
%vararg22 = alloca %"variant[]", align 8
|
||||
%varargslots23 = alloca [1 x %variant], align 16
|
||||
%retparam29 = alloca i64, align 8
|
||||
%taddr30 = alloca %"char[]", align 8
|
||||
%vararg33 = alloca %"variant[]", align 8
|
||||
%varargslots34 = alloca [1 x %variant], align 16
|
||||
%x = alloca i32, align 4
|
||||
%retparam40 = alloca i64, align 8
|
||||
%taddr41 = alloca %"char[]", align 8
|
||||
%vararg44 = alloca %"variant[]", align 8
|
||||
%varargslots45 = alloca [1 x %variant], align 16
|
||||
%taddr46 = alloca ptr, align 8
|
||||
%x52 = alloca double, align 8
|
||||
%retparam53 = alloca i64, align 8
|
||||
%taddr54 = alloca %"char[]", align 8
|
||||
%vararg57 = alloca %"variant[]", align 8
|
||||
%varargslots58 = alloca [1 x %variant], align 16
|
||||
%taddr59 = alloca ptr, align 8
|
||||
%retparam65 = alloca i64, align 8
|
||||
%taddr66 = alloca %"char[]", align 8
|
||||
%vararg69 = alloca %"variant[]", align 8
|
||||
%varargslots70 = alloca [1 x %variant], align 16
|
||||
%taddr71 = alloca i32, align 4
|
||||
%x77 = alloca i32, align 4
|
||||
%y = alloca i32, align 4
|
||||
%a = alloca i32, align 4
|
||||
%retparam78 = alloca i64, align 8
|
||||
%taddr79 = alloca %"char[]", align 8
|
||||
%vararg82 = alloca %"variant[]", align 8
|
||||
%varargslots83 = alloca [2 x %variant], align 16
|
||||
%a89 = alloca i32, align 4
|
||||
%retparam90 = alloca i64, align 8
|
||||
%taddr91 = alloca %"char[]", align 8
|
||||
%vararg94 = alloca %"variant[]", align 8
|
||||
%varargslots95 = alloca [2 x %variant], align 16
|
||||
%0 = call i32 @test_ping(i32 -1)
|
||||
store i32 %0, ptr %.anon, align 4
|
||||
%1 = call i32 @test_ping(i32 1)
|
||||
store i32 %1, ptr %.anon1, align 4
|
||||
%2 = call i32 @test_ping(i32 3141)
|
||||
store i32 %2, ptr %.anon2, align 4
|
||||
%3 = call i32 @test_ping(i32 1000)
|
||||
store i32 %3, ptr %.anon3, align 4
|
||||
%4 = load i32, ptr %.anon, align 4
|
||||
%5 = load i32, ptr %.anon, align 4
|
||||
%add = add i32 %4, %5
|
||||
store i32 %add, ptr %i, align 4
|
||||
%6 = call i32 @test_ping(i32 3141)
|
||||
%7 = call i32 @test_ping(i32 3141)
|
||||
%add4 = add i32 %6, %7
|
||||
store i32 %add4, ptr %j, align 4
|
||||
store %"char[]" { ptr @.str.1, i64 2 }, ptr %taddr, align 8
|
||||
%8 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 0
|
||||
%lo = load ptr, ptr %8, align 8
|
||||
%9 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 1
|
||||
%hi = load i64, ptr %9, align 8
|
||||
%10 = insertvalue %variant undef, ptr %.anon1, 0
|
||||
%11 = insertvalue %variant %10, i64 ptrtoint (ptr @"ct$int" to i64), 1
|
||||
%12 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0
|
||||
store %variant %11, ptr %12, align 16
|
||||
%13 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 1
|
||||
store i64 1, ptr %13, align 8
|
||||
%14 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 0
|
||||
store ptr %varargslots, ptr %14, align 8
|
||||
%15 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 0
|
||||
%lo5 = load ptr, ptr %15, align 8
|
||||
%16 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 1
|
||||
%hi6 = load i64, ptr %16, align 8
|
||||
%17 = call i64 @std_io_printfln(ptr %retparam, ptr %lo, i64 %hi, ptr %lo5, i64 %hi6)
|
||||
%not_err = icmp eq i64 %17, 0
|
||||
br i1 %not_err, label %after_check, label %voiderr
|
||||
|
||||
after_check: ; preds = %entry
|
||||
br label %voiderr
|
||||
|
||||
voiderr: ; preds = %after_check, %entry
|
||||
store %"char[]" { ptr @.str.2, i64 2 }, ptr %taddr8, align 8
|
||||
%18 = getelementptr inbounds { ptr, i64 }, ptr %taddr8, i32 0, i32 0
|
||||
%lo9 = load ptr, ptr %18, align 8
|
||||
%19 = getelementptr inbounds { ptr, i64 }, ptr %taddr8, i32 0, i32 1
|
||||
%hi10 = load i64, ptr %19, align 8
|
||||
%20 = insertvalue %variant undef, ptr %.anon, 0
|
||||
%21 = insertvalue %variant %20, i64 ptrtoint (ptr @"ct$int" to i64), 1
|
||||
%22 = getelementptr inbounds [1 x %variant], ptr %varargslots12, i64 0, i64 0
|
||||
store %variant %21, ptr %22, align 16
|
||||
%23 = getelementptr inbounds %"variant[]", ptr %vararg11, i32 0, i32 1
|
||||
store i64 1, ptr %23, align 8
|
||||
%24 = getelementptr inbounds %"variant[]", ptr %vararg11, i32 0, i32 0
|
||||
store ptr %varargslots12, ptr %24, align 8
|
||||
%25 = getelementptr inbounds { ptr, i64 }, ptr %vararg11, i32 0, i32 0
|
||||
%lo13 = load ptr, ptr %25, align 8
|
||||
%26 = getelementptr inbounds { ptr, i64 }, ptr %vararg11, i32 0, i32 1
|
||||
%hi14 = load i64, ptr %26, align 8
|
||||
%27 = call i64 @std_io_printfln(ptr %retparam7, ptr %lo9, i64 %hi10, ptr %lo13, i64 %hi14)
|
||||
%not_err15 = icmp eq i64 %27, 0
|
||||
br i1 %not_err15, label %after_check16, label %voiderr17
|
||||
|
||||
after_check16: ; preds = %voiderr
|
||||
br label %voiderr17
|
||||
|
||||
voiderr17: ; preds = %after_check16, %voiderr
|
||||
store %"char[]" { ptr @.str.3, i64 2 }, ptr %taddr19, align 8
|
||||
%28 = getelementptr inbounds { ptr, i64 }, ptr %taddr19, i32 0, i32 0
|
||||
%lo20 = load ptr, ptr %28, align 8
|
||||
%29 = getelementptr inbounds { ptr, i64 }, ptr %taddr19, i32 0, i32 1
|
||||
%hi21 = load i64, ptr %29, align 8
|
||||
%30 = insertvalue %variant undef, ptr %.anon2, 0
|
||||
%31 = insertvalue %variant %30, i64 ptrtoint (ptr @"ct$int" to i64), 1
|
||||
%32 = getelementptr inbounds [1 x %variant], ptr %varargslots23, i64 0, i64 0
|
||||
store %variant %31, ptr %32, align 16
|
||||
%33 = getelementptr inbounds %"variant[]", ptr %vararg22, i32 0, i32 1
|
||||
store i64 1, ptr %33, align 8
|
||||
%34 = getelementptr inbounds %"variant[]", ptr %vararg22, i32 0, i32 0
|
||||
store ptr %varargslots23, ptr %34, align 8
|
||||
%35 = getelementptr inbounds { ptr, i64 }, ptr %vararg22, i32 0, i32 0
|
||||
%lo24 = load ptr, ptr %35, align 8
|
||||
%36 = getelementptr inbounds { ptr, i64 }, ptr %vararg22, i32 0, i32 1
|
||||
%hi25 = load i64, ptr %36, align 8
|
||||
%37 = call i64 @std_io_printfln(ptr %retparam18, ptr %lo20, i64 %hi21, ptr %lo24, i64 %hi25)
|
||||
%not_err26 = icmp eq i64 %37, 0
|
||||
br i1 %not_err26, label %after_check27, label %voiderr28
|
||||
|
||||
after_check27: ; preds = %voiderr17
|
||||
br label %voiderr28
|
||||
|
||||
voiderr28: ; preds = %after_check27, %voiderr17
|
||||
store %"char[]" { ptr @.str.4, i64 2 }, ptr %taddr30, align 8
|
||||
%38 = getelementptr inbounds { ptr, i64 }, ptr %taddr30, i32 0, i32 0
|
||||
%lo31 = load ptr, ptr %38, align 8
|
||||
%39 = getelementptr inbounds { ptr, i64 }, ptr %taddr30, i32 0, i32 1
|
||||
%hi32 = load i64, ptr %39, align 8
|
||||
%40 = insertvalue %variant undef, ptr %.anon3, 0
|
||||
%41 = insertvalue %variant %40, i64 ptrtoint (ptr @"ct$int" to i64), 1
|
||||
%42 = getelementptr inbounds [1 x %variant], ptr %varargslots34, i64 0, i64 0
|
||||
store %variant %41, ptr %42, align 16
|
||||
%43 = getelementptr inbounds %"variant[]", ptr %vararg33, i32 0, i32 1
|
||||
store i64 1, ptr %43, align 8
|
||||
%44 = getelementptr inbounds %"variant[]", ptr %vararg33, i32 0, i32 0
|
||||
store ptr %varargslots34, ptr %44, align 8
|
||||
%45 = getelementptr inbounds { ptr, i64 }, ptr %vararg33, i32 0, i32 0
|
||||
%lo35 = load ptr, ptr %45, align 8
|
||||
%46 = getelementptr inbounds { ptr, i64 }, ptr %vararg33, i32 0, i32 1
|
||||
%hi36 = load i64, ptr %46, align 8
|
||||
%47 = call i64 @std_io_printfln(ptr %retparam29, ptr %lo31, i64 %hi32, ptr %lo35, i64 %hi36)
|
||||
%not_err37 = icmp eq i64 %47, 0
|
||||
br i1 %not_err37, label %after_check38, label %voiderr39
|
||||
|
||||
after_check38: ; preds = %voiderr28
|
||||
br label %voiderr39
|
||||
|
||||
voiderr39: ; preds = %after_check38, %voiderr28
|
||||
store i32 0, ptr %x, align 4
|
||||
store %"char[]" { ptr @.str.5, i64 2 }, ptr %taddr41, align 8
|
||||
%48 = getelementptr inbounds { ptr, i64 }, ptr %taddr41, i32 0, i32 0
|
||||
%lo42 = load ptr, ptr %48, align 8
|
||||
%49 = getelementptr inbounds { ptr, i64 }, ptr %taddr41, i32 0, i32 1
|
||||
%hi43 = load i64, ptr %49, align 8
|
||||
store ptr @.str.6, ptr %taddr46, align 8
|
||||
%50 = insertvalue %variant undef, ptr %taddr46, 0
|
||||
%51 = insertvalue %variant %50, i64 ptrtoint (ptr @"ct$p$a3$char" to i64), 1
|
||||
%52 = getelementptr inbounds [1 x %variant], ptr %varargslots45, i64 0, i64 0
|
||||
store %variant %51, ptr %52, align 16
|
||||
%53 = getelementptr inbounds %"variant[]", ptr %vararg44, i32 0, i32 1
|
||||
store i64 1, ptr %53, align 8
|
||||
%54 = getelementptr inbounds %"variant[]", ptr %vararg44, i32 0, i32 0
|
||||
store ptr %varargslots45, ptr %54, align 8
|
||||
%55 = getelementptr inbounds { ptr, i64 }, ptr %vararg44, i32 0, i32 0
|
||||
%lo47 = load ptr, ptr %55, align 8
|
||||
%56 = getelementptr inbounds { ptr, i64 }, ptr %vararg44, i32 0, i32 1
|
||||
%hi48 = load i64, ptr %56, align 8
|
||||
%57 = call i64 @std_io_printfln(ptr %retparam40, ptr %lo42, i64 %hi43, ptr %lo47, i64 %hi48)
|
||||
%not_err49 = icmp eq i64 %57, 0
|
||||
br i1 %not_err49, label %after_check50, label %voiderr51
|
||||
|
||||
after_check50: ; preds = %voiderr39
|
||||
br label %voiderr51
|
||||
|
||||
voiderr51: ; preds = %after_check50, %voiderr39
|
||||
store double 0.000000e+00, ptr %x52, align 8
|
||||
store %"char[]" { ptr @.str.7, i64 2 }, ptr %taddr54, align 8
|
||||
%58 = getelementptr inbounds { ptr, i64 }, ptr %taddr54, i32 0, i32 0
|
||||
%lo55 = load ptr, ptr %58, align 8
|
||||
%59 = getelementptr inbounds { ptr, i64 }, ptr %taddr54, i32 0, i32 1
|
||||
%hi56 = load i64, ptr %59, align 8
|
||||
store ptr @.str.8, ptr %taddr59, align 8
|
||||
%60 = insertvalue %variant undef, ptr %taddr59, 0
|
||||
%61 = insertvalue %variant %60, i64 ptrtoint (ptr @"ct$p$a6$char" to i64), 1
|
||||
%62 = getelementptr inbounds [1 x %variant], ptr %varargslots58, i64 0, i64 0
|
||||
store %variant %61, ptr %62, align 16
|
||||
%63 = getelementptr inbounds %"variant[]", ptr %vararg57, i32 0, i32 1
|
||||
store i64 1, ptr %63, align 8
|
||||
%64 = getelementptr inbounds %"variant[]", ptr %vararg57, i32 0, i32 0
|
||||
store ptr %varargslots58, ptr %64, align 8
|
||||
%65 = getelementptr inbounds { ptr, i64 }, ptr %vararg57, i32 0, i32 0
|
||||
%lo60 = load ptr, ptr %65, align 8
|
||||
%66 = getelementptr inbounds { ptr, i64 }, ptr %vararg57, i32 0, i32 1
|
||||
%hi61 = load i64, ptr %66, align 8
|
||||
%67 = call i64 @std_io_printfln(ptr %retparam53, ptr %lo55, i64 %hi56, ptr %lo60, i64 %hi61)
|
||||
%not_err62 = icmp eq i64 %67, 0
|
||||
br i1 %not_err62, label %after_check63, label %voiderr64
|
||||
|
||||
after_check63: ; preds = %voiderr51
|
||||
br label %voiderr64
|
||||
|
||||
voiderr64: ; preds = %after_check63, %voiderr51
|
||||
store %"char[]" { ptr @.str.9, i64 2 }, ptr %taddr66, align 8
|
||||
%68 = getelementptr inbounds { ptr, i64 }, ptr %taddr66, i32 0, i32 0
|
||||
%lo67 = load ptr, ptr %68, align 8
|
||||
%69 = getelementptr inbounds { ptr, i64 }, ptr %taddr66, i32 0, i32 1
|
||||
%hi68 = load i64, ptr %69, align 8
|
||||
store i32 105, ptr %taddr71, align 4
|
||||
%70 = insertvalue %variant undef, ptr %taddr71, 0
|
||||
%71 = insertvalue %variant %70, i64 ptrtoint (ptr @"ct$int" to i64), 1
|
||||
%72 = getelementptr inbounds [1 x %variant], ptr %varargslots70, i64 0, i64 0
|
||||
store %variant %71, ptr %72, align 16
|
||||
%73 = getelementptr inbounds %"variant[]", ptr %vararg69, i32 0, i32 1
|
||||
store i64 1, ptr %73, align 8
|
||||
%74 = getelementptr inbounds %"variant[]", ptr %vararg69, i32 0, i32 0
|
||||
store ptr %varargslots70, ptr %74, align 8
|
||||
%75 = getelementptr inbounds { ptr, i64 }, ptr %vararg69, i32 0, i32 0
|
||||
%lo72 = load ptr, ptr %75, align 8
|
||||
%76 = getelementptr inbounds { ptr, i64 }, ptr %vararg69, i32 0, i32 1
|
||||
%hi73 = load i64, ptr %76, align 8
|
||||
%77 = call i64 @std_io_printfln(ptr %retparam65, ptr %lo67, i64 %hi68, ptr %lo72, i64 %hi73)
|
||||
%not_err74 = icmp eq i64 %77, 0
|
||||
br i1 %not_err74, label %after_check75, label %voiderr76
|
||||
|
||||
after_check75: ; preds = %voiderr64
|
||||
br label %voiderr76
|
||||
|
||||
voiderr76: ; preds = %after_check75, %voiderr64
|
||||
store i32 123, ptr %x77, align 4
|
||||
store i32 33, ptr %y, align 4
|
||||
%78 = load i32, ptr %x77, align 4
|
||||
store i32 %78, ptr %a, align 4
|
||||
%79 = load i32, ptr %y, align 4
|
||||
store i32 %79, ptr %x77, align 4
|
||||
%80 = load i32, ptr %a, align 4
|
||||
store i32 %80, ptr %y, align 4
|
||||
store %"char[]" { ptr @.str.10, i64 6 }, ptr %taddr79, align 8
|
||||
%81 = getelementptr inbounds { ptr, i64 }, ptr %taddr79, i32 0, i32 0
|
||||
%lo80 = load ptr, ptr %81, align 8
|
||||
%82 = getelementptr inbounds { ptr, i64 }, ptr %taddr79, i32 0, i32 1
|
||||
%hi81 = load i64, ptr %82, align 8
|
||||
%83 = insertvalue %variant undef, ptr %x77, 0
|
||||
%84 = insertvalue %variant %83, i64 ptrtoint (ptr @"ct$int" to i64), 1
|
||||
%85 = getelementptr inbounds [2 x %variant], ptr %varargslots83, i64 0, i64 0
|
||||
store %variant %84, ptr %85, align 16
|
||||
%86 = insertvalue %variant undef, ptr %y, 0
|
||||
%87 = insertvalue %variant %86, i64 ptrtoint (ptr @"ct$int" to i64), 1
|
||||
%88 = getelementptr inbounds [2 x %variant], ptr %varargslots83, i64 0, i64 1
|
||||
store %variant %87, ptr %88, align 16
|
||||
%89 = getelementptr inbounds %"variant[]", ptr %vararg82, i32 0, i32 1
|
||||
store i64 2, ptr %89, align 8
|
||||
%90 = getelementptr inbounds %"variant[]", ptr %vararg82, i32 0, i32 0
|
||||
store ptr %varargslots83, ptr %90, align 8
|
||||
%91 = getelementptr inbounds { ptr, i64 }, ptr %vararg82, i32 0, i32 0
|
||||
%lo84 = load ptr, ptr %91, align 8
|
||||
%92 = getelementptr inbounds { ptr, i64 }, ptr %vararg82, i32 0, i32 1
|
||||
%hi85 = load i64, ptr %92, align 8
|
||||
%93 = call i64 @std_io_printfln(ptr %retparam78, ptr %lo80, i64 %hi81, ptr %lo84, i64 %hi85)
|
||||
%not_err86 = icmp eq i64 %93, 0
|
||||
br i1 %not_err86, label %after_check87, label %voiderr88
|
||||
|
||||
after_check87: ; preds = %voiderr76
|
||||
br label %voiderr88
|
||||
|
||||
voiderr88: ; preds = %after_check87, %voiderr76
|
||||
%94 = load i32, ptr %x77, align 4
|
||||
store i32 %94, ptr %a89, align 4
|
||||
%95 = load i32, ptr %y, align 4
|
||||
store i32 %95, ptr %x77, align 4
|
||||
%96 = load i32, ptr %a89, align 4
|
||||
store i32 %96, ptr %y, align 4
|
||||
store %"char[]" { ptr @.str.11, i64 6 }, ptr %taddr91, align 8
|
||||
%97 = getelementptr inbounds { ptr, i64 }, ptr %taddr91, i32 0, i32 0
|
||||
%lo92 = load ptr, ptr %97, align 8
|
||||
%98 = getelementptr inbounds { ptr, i64 }, ptr %taddr91, i32 0, i32 1
|
||||
%hi93 = load i64, ptr %98, align 8
|
||||
%99 = insertvalue %variant undef, ptr %x77, 0
|
||||
%100 = insertvalue %variant %99, i64 ptrtoint (ptr @"ct$int" to i64), 1
|
||||
%101 = getelementptr inbounds [2 x %variant], ptr %varargslots95, i64 0, i64 0
|
||||
store %variant %100, ptr %101, align 16
|
||||
%102 = insertvalue %variant undef, ptr %y, 0
|
||||
%103 = insertvalue %variant %102, i64 ptrtoint (ptr @"ct$int" to i64), 1
|
||||
%104 = getelementptr inbounds [2 x %variant], ptr %varargslots95, i64 0, i64 1
|
||||
store %variant %103, ptr %104, align 16
|
||||
%105 = getelementptr inbounds %"variant[]", ptr %vararg94, i32 0, i32 1
|
||||
store i64 2, ptr %105, align 8
|
||||
%106 = getelementptr inbounds %"variant[]", ptr %vararg94, i32 0, i32 0
|
||||
store ptr %varargslots95, ptr %106, align 8
|
||||
%107 = getelementptr inbounds { ptr, i64 }, ptr %vararg94, i32 0, i32 0
|
||||
%lo96 = load ptr, ptr %107, align 8
|
||||
%108 = getelementptr inbounds { ptr, i64 }, ptr %vararg94, i32 0, i32 1
|
||||
%hi97 = load i64, ptr %108, align 8
|
||||
%109 = call i64 @std_io_printfln(ptr %retparam90, ptr %lo92, i64 %hi93, ptr %lo96, i64 %hi97)
|
||||
%not_err98 = icmp eq i64 %109, 0
|
||||
br i1 %not_err98, label %after_check99, label %voiderr100
|
||||
|
||||
after_check99: ; preds = %voiderr88
|
||||
br label %voiderr100
|
||||
|
||||
voiderr100: ; preds = %after_check99, %voiderr88
|
||||
ret void
|
||||
}
|
||||
Reference in New Issue
Block a user