mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Generic modules also accepts integers and booleans.
This commit is contained in:
42
releasenotes.md
Normal file
42
releasenotes.md
Normal file
@@ -0,0 +1,42 @@
|
||||
Release Notes
|
||||
|
||||
0.4.0 Change List
|
||||
|
||||
- Compatibility with LLVM 16.
|
||||
- Dropped LLVM 12 support.
|
||||
- Updated memory allocators. Added @scoped and @pool macros.
|
||||
- Various bug fixes.
|
||||
- Constant pointers may be compile time evaluated.
|
||||
- Added many new builtins.
|
||||
- Emit asm using --emit-asm.
|
||||
- Added --nostdlib and --nolibc.
|
||||
- Fixes to adding libraries at link time.
|
||||
- Various improved error messages.
|
||||
- Windows debug info fixes.
|
||||
- Add of `foreach_r`.
|
||||
- Script downloading the MSVC SDK to cross compile to windows.
|
||||
- Many standard library additions.
|
||||
- Extension methods may be added for built-in types.
|
||||
- Macros may take vector and array arguments generic over length.
|
||||
- Macro varargs with $vaarg, $vacount etc.
|
||||
- Many vector builtins added as dot methods.
|
||||
- in / out / inout doc parameters checked.
|
||||
- Initial inline asm support for aarch64 and x64.
|
||||
- Single line short function declaration.
|
||||
- Added `$checks` builtin.
|
||||
- Optional single module compilation.
|
||||
- Static initialization / finalization to have code running at start/end.
|
||||
- C3 custom printf function in the stdlib.
|
||||
- `[]=` overload now works correctly.
|
||||
- More compile time reflection added and general cleanup done.
|
||||
- usize/isize/iptrdiff/uptrdiff replaced by usz/isz.
|
||||
- Add `var` to allow type inference on regular variables.
|
||||
- LLVM codegen optimizations.
|
||||
- `??` now allows chaining another optional.
|
||||
- int128 support on all platforms.
|
||||
- `import` is now allowed anywhere at the top level.
|
||||
- `project.c3p` renamed `project.json`
|
||||
- Update to project properties, e.g. "libs" -> "dependencies" etc.
|
||||
- $$TIME, $$DATE and $$FUNCTION builtin defines added.
|
||||
- Improvements to untyped lists.
|
||||
- Various builtins added: $$prefetch, $$reverse, $$shufflevector etc.
|
||||
@@ -609,7 +609,7 @@ typedef struct
|
||||
SourceSpan span;
|
||||
};
|
||||
};
|
||||
TypeInfo **generic_params;
|
||||
Expr **generic_params;
|
||||
};
|
||||
Decl *alias;
|
||||
};
|
||||
@@ -1451,7 +1451,7 @@ typedef struct Module_
|
||||
AnalysisStage stage : 6;
|
||||
|
||||
Ast **files; // Asts
|
||||
|
||||
AstId docs;
|
||||
Decl** method_extensions;
|
||||
HTable symbols;
|
||||
struct CompilationUnit_ **units;
|
||||
|
||||
@@ -901,7 +901,7 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
|
||||
{
|
||||
case DEFINE_TYPE_GENERIC:
|
||||
case DEFINE_IDENT_GENERIC:
|
||||
MACRO_COPY_TYPE_LIST(decl->define_decl.generic_params);
|
||||
MACRO_COPY_EXPR_LIST(decl->define_decl.generic_params);
|
||||
break;
|
||||
case DEFINE_IDENT_ALIAS:
|
||||
break;
|
||||
|
||||
@@ -89,6 +89,11 @@ static Expr *parse_precedence(ParseContext *c, Precedence precedence)
|
||||
return parse_precedence_with_left_side(c, left_side, precedence);
|
||||
}
|
||||
|
||||
Expr *parse_generic_parameter(ParseContext *c)
|
||||
{
|
||||
return parse_precedence(c, PREC_ADDITIVE);
|
||||
}
|
||||
|
||||
Expr *parse_expr_or_initializer_list(ParseContext *c)
|
||||
{
|
||||
return parse_expr(c);
|
||||
|
||||
@@ -90,7 +90,7 @@ static inline bool parse_top_level_block(ParseContext *c, Decl ***decls, TokenTy
|
||||
CONSUME_OR_RET(TOKEN_COLON, false);
|
||||
while (!tok_is(c, end1) && !tok_is(c, end2) && !tok_is(c, end3) && !tok_is(c, TOKEN_EOF))
|
||||
{
|
||||
Decl *decl = parse_top_level_statement(c, false);
|
||||
Decl *decl = parse_top_level_statement(c, NULL);
|
||||
if (!decl) continue;
|
||||
assert(decl);
|
||||
if (decl_ok(decl))
|
||||
@@ -173,7 +173,7 @@ static inline Decl *parse_ct_case(ParseContext *c)
|
||||
{
|
||||
TokenType type = c->tok;
|
||||
if (type == TOKEN_CT_DEFAULT || type == TOKEN_CT_CASE || type == TOKEN_CT_ENDSWITCH) break;
|
||||
ASSIGN_DECL_OR_RET(Decl * stmt, parse_top_level_statement(c, false), poisoned_decl);
|
||||
ASSIGN_DECL_OR_RET(Decl *stmt, parse_top_level_statement(c, NULL), poisoned_decl);
|
||||
vec_add(decl->ct_case_decl.body, stmt);
|
||||
}
|
||||
return decl;
|
||||
@@ -282,12 +282,13 @@ static inline bool parse_optional_module_params(ParseContext *c, const char ***t
|
||||
switch (c->tok)
|
||||
{
|
||||
case TOKEN_TYPE_IDENT:
|
||||
case TOKEN_CONST_IDENT:
|
||||
break;
|
||||
case TOKEN_COMMA:
|
||||
SEMA_ERROR_HERE("Unexpected ','");
|
||||
return false;
|
||||
case TOKEN_IDENT:
|
||||
SEMA_ERROR_HERE("The module parameter must be a type.");
|
||||
SEMA_ERROR_HERE("The module parameter must be a type or a constant.");
|
||||
return false;
|
||||
case TOKEN_CT_IDENT:
|
||||
case TOKEN_CT_TYPE_IDENT:
|
||||
@@ -309,13 +310,8 @@ static inline bool parse_optional_module_params(ParseContext *c, const char ***t
|
||||
/**
|
||||
* module ::= MODULE module_path ('<' module_params '>')? EOS
|
||||
*/
|
||||
bool parse_module(ParseContext *c)
|
||||
bool parse_module(ParseContext *c, AstId docs)
|
||||
{
|
||||
if (!try_consume(c, TOKEN_MODULE))
|
||||
{
|
||||
return context_set_module_from_filename(c);
|
||||
}
|
||||
|
||||
bool is_private = try_consume(c, TOKEN_PRIVATE);
|
||||
|
||||
if (tok_is(c, TOKEN_STRING))
|
||||
@@ -359,11 +355,30 @@ bool parse_module(ParseContext *c)
|
||||
const char **generic_parameters = NULL;
|
||||
if (!parse_optional_module_params(c, &generic_parameters))
|
||||
{
|
||||
context_set_module(c, path, NULL, is_private);
|
||||
if (!context_set_module(c, path, NULL, is_private)) return false;
|
||||
recover_top_level(c);
|
||||
if (docs)
|
||||
{
|
||||
SEMA_ERROR(astptr(docs), "Contracts cannot be use with non-generic modules.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
context_set_module(c, path, generic_parameters, is_private);
|
||||
if (!context_set_module(c, path, generic_parameters, is_private)) return false;
|
||||
if (docs)
|
||||
{
|
||||
AstId old_docs = c->unit->module->docs;
|
||||
if (old_docs)
|
||||
{
|
||||
Ast *last = ast_last(astptr(old_docs));
|
||||
last->next = docs;
|
||||
}
|
||||
else
|
||||
{
|
||||
c->unit->module->docs = docs;
|
||||
}
|
||||
}
|
||||
|
||||
CONSUME_EOS_OR_RET(false);
|
||||
return true;
|
||||
}
|
||||
@@ -1629,24 +1644,24 @@ static bool parse_macro_arguments(ParseContext *c, Visibility visibility, Decl *
|
||||
}
|
||||
|
||||
/**
|
||||
* define_parameters ::= type (',' type)* '>'
|
||||
* define_parameters ::= expr (',' expr)* '>'
|
||||
*
|
||||
* @return NULL if parsing failed, otherwise a list of Type*
|
||||
*/
|
||||
static inline TypeInfo **parse_generic_parameters(ParseContext *c)
|
||||
static inline Expr **parse_generic_parameters(ParseContext *c)
|
||||
{
|
||||
TypeInfo **types = NULL;
|
||||
Expr **params = NULL;
|
||||
while (!try_consume(c, TOKEN_GREATER))
|
||||
{
|
||||
ASSIGN_TYPE_OR_RET(TypeInfo *type_info, parse_type(c), NULL);
|
||||
vec_add(types, type_info);
|
||||
ASSIGN_EXPR_OR_RET(Expr *arg, parse_generic_parameter(c), NULL);
|
||||
vec_add(params, arg);
|
||||
TokenType tok = c->tok;
|
||||
if (tok != TOKEN_RPAREN && tok != TOKEN_GREATER)
|
||||
{
|
||||
TRY_CONSUME_OR_RET(TOKEN_COMMA, "Expected ',' after argument.", NULL);
|
||||
}
|
||||
}
|
||||
return types;
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1693,7 +1708,7 @@ static inline Decl *parse_define_type(ParseContext *c, Visibility visibility)
|
||||
// 3. Do we have '<' if so it's a parameterized type e.g. foo::bar::Type<int, double>.
|
||||
if (try_consume(c, TOKEN_LESS))
|
||||
{
|
||||
TypeInfo **params = parse_generic_parameters(c);
|
||||
Expr **params = parse_generic_parameters(c);
|
||||
if (!params) return poisoned_decl;
|
||||
Decl *decl = decl_new(DECL_DEFINE, alias_name, name_loc, visibility);
|
||||
decl->define_decl.define_kind = DEFINE_TYPE_GENERIC;
|
||||
@@ -1796,7 +1811,7 @@ static inline Decl *parse_define_ident(ParseContext *c, Visibility visibility)
|
||||
if (try_consume(c, TOKEN_LESS))
|
||||
{
|
||||
decl->define_decl.define_kind = DEFINE_IDENT_GENERIC;
|
||||
TypeInfo **params = parse_generic_parameters(c);
|
||||
Expr **params = parse_generic_parameters(c);
|
||||
if (!params) return poisoned_decl;
|
||||
decl->define_decl.generic_params = params;
|
||||
}
|
||||
@@ -2519,7 +2534,7 @@ static bool parse_docs(ParseContext *c, AstId *docs_ref)
|
||||
* @param visibility
|
||||
* @return Decl* or a poison value if parsing failed
|
||||
*/
|
||||
Decl *parse_top_level_statement(ParseContext *c, bool allow_import)
|
||||
Decl *parse_top_level_statement(ParseContext *c, ParseContext **c_ref)
|
||||
{
|
||||
AstId docs = 0;
|
||||
if (!parse_docs(c, &docs)) return poisoned_decl;
|
||||
@@ -2539,8 +2554,35 @@ Decl *parse_top_level_statement(ParseContext *c, bool allow_import)
|
||||
|
||||
Decl *decl;
|
||||
TokenType tok = c->tok;
|
||||
if (tok != TOKEN_MODULE && !c->unit->module)
|
||||
{
|
||||
if (!context_set_module_from_filename(c)) return poisoned_decl;
|
||||
// Pass the docs to the next thing.
|
||||
}
|
||||
|
||||
switch (tok)
|
||||
{
|
||||
case TOKEN_MODULE:
|
||||
if (visibility != VISIBLE_PUBLIC)
|
||||
{
|
||||
SEMA_ERROR_HERE("Did not expect visibility before 'module'.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (!c_ref)
|
||||
{
|
||||
SEMA_ERROR_HERE("'module' cannot appear inside of conditional compilation.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
advance(c);
|
||||
if (c->unit->module)
|
||||
{
|
||||
ParseContext *new_context = CALLOCS(ParseContext);
|
||||
*new_context = *c;
|
||||
new_context->unit = unit_create(c->unit->file);
|
||||
*c_ref = c = new_context;
|
||||
}
|
||||
if (!parse_module(c, docs)) return poisoned_decl;
|
||||
return NULL;
|
||||
case TOKEN_DOCS_START:
|
||||
if (visibility != VISIBLE_PUBLIC)
|
||||
{
|
||||
@@ -2596,7 +2638,7 @@ Decl *parse_top_level_statement(ParseContext *c, bool allow_import)
|
||||
}
|
||||
case TOKEN_IMPORT:
|
||||
if (!check_no_visibility_before(c, visibility)) return poisoned_decl;
|
||||
if (!allow_import)
|
||||
if (!c_ref)
|
||||
{
|
||||
SEMA_ERROR_HERE("'import' may not appear inside a compile time statement.");
|
||||
return poisoned_decl;
|
||||
|
||||
@@ -64,19 +64,9 @@ static inline void parse_translation_unit(ParseContext *c)
|
||||
// Prime everything
|
||||
advance(c);
|
||||
advance(c);
|
||||
NEXT_CONTEXT:
|
||||
if (!parse_module(c)) return;
|
||||
while (!tok_is(c, TOKEN_EOF))
|
||||
{
|
||||
if (tok_is(c, TOKEN_MODULE))
|
||||
{
|
||||
ParseContext *new_context = CALLOCS(ParseContext);
|
||||
*new_context = *c;
|
||||
new_context->unit = unit_create(c->unit->file);
|
||||
c = new_context;
|
||||
goto NEXT_CONTEXT;
|
||||
}
|
||||
Decl *decl = parse_top_level_statement(c, true);
|
||||
Decl *decl = parse_top_level_statement(c, &c);
|
||||
if (!decl) continue;
|
||||
if (decl_ok(decl))
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#define TRY_CONSUME_AFTER(_tok, _message, _type) do { if (!try_consume(c, _tok)) { sema_error_at_after(c->prev_span, _message); return _type; } } while(0)
|
||||
#define CHECK_EXPR_OR_RET(_expr) do { if (!expr_ok(_expr)) return _expr; } while(0)
|
||||
|
||||
Decl *parse_top_level_statement(ParseContext *c, bool allow_import);
|
||||
Decl *parse_top_level_statement(ParseContext *c, ParseContext **new_context);
|
||||
Ast *parse_ct_assert_stmt(ParseContext *c);
|
||||
Ast *parse_stmt(ParseContext *c);
|
||||
Path *parse_path_prefix(ParseContext *c, bool *had_error);
|
||||
@@ -52,8 +52,8 @@ parse_parameters(ParseContext *c, Visibility visibility, Decl ***params_ref, Dec
|
||||
bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool *splat, bool vasplat);
|
||||
Expr *parse_type_compound_literal_expr_after_type(ParseContext *c, TypeInfo *type_info);
|
||||
|
||||
bool parse_module(ParseContext *c);
|
||||
|
||||
bool parse_module(ParseContext *c, AstId docs);
|
||||
Expr *parse_generic_parameter(ParseContext *c);
|
||||
bool try_consume(ParseContext *c, TokenType type);
|
||||
bool consume(ParseContext *c, TokenType type, const char *message, ...);
|
||||
bool consume_const_name(ParseContext *c, const char* type);
|
||||
|
||||
@@ -51,7 +51,7 @@ static inline bool sema_analyse_distinct(SemaContext *context, Decl *decl);
|
||||
|
||||
static CompilationUnit *unit_copy(Module *module, CompilationUnit *unit);
|
||||
static bool sema_analyse_parameterized_define(SemaContext *c, Decl *decl);
|
||||
static Module *module_instantiate_generic(Module *module, Path *path, TypeInfo **parms);
|
||||
static Module *module_instantiate_generic(Module *module, Path *path, Expr **params);
|
||||
|
||||
static inline bool sema_analyse_enum_param(SemaContext *context, Decl *param, bool *has_default);
|
||||
static inline bool sema_analyse_enum(SemaContext *context, Decl *decl);
|
||||
@@ -2500,7 +2500,6 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
|
||||
}
|
||||
|
||||
|
||||
|
||||
static CompilationUnit *unit_copy(Module *module, CompilationUnit *unit)
|
||||
{
|
||||
CompilationUnit *copy = unit_create(unit->file);
|
||||
@@ -2511,7 +2510,7 @@ static CompilationUnit *unit_copy(Module *module, CompilationUnit *unit)
|
||||
return copy;
|
||||
}
|
||||
|
||||
static Module *module_instantiate_generic(Module *module, Path *path, TypeInfo **parms)
|
||||
static Module *module_instantiate_generic(Module *module, Path *path, Expr **params)
|
||||
{
|
||||
Module *new_module = compiler_find_or_create_module(path, NULL, module->is_private);
|
||||
new_module->is_generic = true;
|
||||
@@ -2523,10 +2522,20 @@ static Module *module_instantiate_generic(Module *module, Path *path, TypeInfo *
|
||||
CompilationUnit *first_context = new_module->units[0];
|
||||
VECEACH(module->parameters, i)
|
||||
{
|
||||
const char *param = module->parameters[i];
|
||||
Decl *decl = decl_new_with_type(param, parms[i]->span, DECL_TYPEDEF, VISIBLE_PUBLIC);
|
||||
const char *param_name = module->parameters[i];
|
||||
Expr *param = params[i];
|
||||
if (param->expr_kind != EXPR_TYPEINFO)
|
||||
{
|
||||
Decl *decl = decl_new_var(param_name, param->span, NULL, VARDECL_CONST, VISIBLE_PUBLIC);
|
||||
decl->var.init_expr = param;
|
||||
decl->type = param->type;
|
||||
decl->resolve_status = RESOLVE_NOT_DONE;
|
||||
vec_add(first_context->global_decls, decl);
|
||||
continue;
|
||||
}
|
||||
Decl *decl = decl_new_with_type(param_name, params[i]->span, DECL_TYPEDEF, VISIBLE_PUBLIC);
|
||||
decl->resolve_status = RESOLVE_DONE;
|
||||
TypeInfo *type_info = parms[i];
|
||||
TypeInfo *type_info = param->type_expr;
|
||||
assert(type_info->resolve_status == RESOLVE_DONE);
|
||||
decl->typedef_decl.type_info = type_info;
|
||||
decl->type->name = decl->name;
|
||||
@@ -2576,7 +2585,7 @@ static bool sema_analyse_parameterized_define(SemaContext *c, Decl *decl)
|
||||
}
|
||||
|
||||
Module *module = alias->unit->module;
|
||||
TypeInfo **params = decl->define_decl.generic_params;
|
||||
Expr **params = decl->define_decl.generic_params;
|
||||
unsigned parameter_count = vec_size(module->parameters);
|
||||
assert(parameter_count > 0);
|
||||
if (parameter_count != vec_size(params))
|
||||
@@ -2591,10 +2600,62 @@ static bool sema_analyse_parameterized_define(SemaContext *c, Decl *decl)
|
||||
scratch_buffer_clear();
|
||||
scratch_buffer_append_len(module->name->module, module->name->len);
|
||||
scratch_buffer_append("$$");
|
||||
FOREACH_BEGIN_IDX(i, TypeInfo *type_info, decl->define_decl.generic_params)
|
||||
if (!sema_resolve_type_info(c, type_info)) return decl_poison(decl);
|
||||
FOREACH_BEGIN_IDX(i, Expr *param, decl->define_decl.generic_params)
|
||||
if (i != 0) scratch_buffer_append_char('.');
|
||||
type_mangle_introspect_name_to_buffer(type_info->type->canonical);
|
||||
if (param->expr_kind == EXPR_TYPEINFO)
|
||||
{
|
||||
TypeInfo *type = param->type_expr;
|
||||
if (!sema_resolve_type_info(c, type)) return decl_poison(decl);
|
||||
if (type->kind == TYPE_OPTIONAL)
|
||||
{
|
||||
SEMA_ERROR(type, "Expected a non-optional type.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (type_is_invalid_storage_type(type->type))
|
||||
{
|
||||
SEMA_ERROR(type, "Expected a runtime type.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
type_mangle_introspect_name_to_buffer(type->type->canonical);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!sema_analyse_ct_expr(c, param)) return decl_poison(decl);
|
||||
Type *type = param->type->canonical;
|
||||
if (!type_is_integer_or_bool_kind(type))
|
||||
{
|
||||
SEMA_ERROR(param, "Only integer and boolean types may be generic arguments.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
assert(expr_is_const(param));
|
||||
if (type == type_bool)
|
||||
{
|
||||
scratch_buffer_append_char(param->const_expr.b ? 't' : 'f');
|
||||
}
|
||||
else
|
||||
{
|
||||
char *maybe_neg = &scratch_buffer.str[scratch_buffer.len];
|
||||
if (type->type_kind == TYPE_I128 || type->type_kind == TYPE_U128)
|
||||
{
|
||||
char *str = int_to_str(param->const_expr.ixx, 10);
|
||||
|
||||
scratch_buffer_append(str);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type_is_signed(type))
|
||||
{
|
||||
scratch_buffer_append_signed_int(param->const_expr.ixx.i.low);
|
||||
}
|
||||
else
|
||||
{
|
||||
scratch_buffer_append_unsigned_int(param->const_expr.ixx.i.high);
|
||||
}
|
||||
}
|
||||
// Replace - with _
|
||||
if (maybe_neg[0] == '-') maybe_neg[0] = '_';
|
||||
}
|
||||
}
|
||||
FOREACH_END();
|
||||
TokenType ident_type = TOKEN_IDENT;
|
||||
const char *path_string = scratch_buffer_interned();
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.3.95"
|
||||
#define COMPILER_VERSION "0.3.96"
|
||||
61
test/test_suite/generic/generic_num.c3t
Normal file
61
test/test_suite/generic/generic_num.c3t
Normal file
@@ -0,0 +1,61 @@
|
||||
// #target: macos-x64
|
||||
module hello<Type, FOO>;
|
||||
|
||||
fn Type x(Type t)
|
||||
{
|
||||
return t * t + FOO;
|
||||
}
|
||||
|
||||
module test;
|
||||
import hello;
|
||||
define xint = hello::x<int, -123>;
|
||||
|
||||
import std::io;
|
||||
|
||||
fn void main()
|
||||
{
|
||||
io::printfln("%d", xint(4));
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define void @test_main() #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 ([3 x i8], [3 x i8]* @.str, i32 0, i32 0), i64 2 }, %"char[]"* %taddr, align 8
|
||||
%0 = bitcast %"char[]"* %taddr to { i8*, i64 }*
|
||||
%1 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %0, i32 0, i32 0
|
||||
%lo = load i8*, i8** %1, align 8
|
||||
%2 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %0, i32 0, i32 1
|
||||
%hi = load i64, i64* %2, align 8
|
||||
%3 = call i32 @"hello$$int._123_x"(i32 4)
|
||||
store i32 %3, 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 void
|
||||
}
|
||||
58
test/test_suite2/generic/generic_num.c3t
Normal file
58
test/test_suite2/generic/generic_num.c3t
Normal file
@@ -0,0 +1,58 @@
|
||||
// #target: macos-x64
|
||||
module hello<Type, FOO>;
|
||||
|
||||
fn Type x(Type t)
|
||||
{
|
||||
return t * t + FOO;
|
||||
}
|
||||
|
||||
module test;
|
||||
import hello;
|
||||
define xint = hello::x<int, -123>;
|
||||
|
||||
import std::io;
|
||||
|
||||
fn void main()
|
||||
{
|
||||
io::printfln("%d", xint(4));
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define void @test_main() #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 2 }, ptr %taddr, align 8
|
||||
%0 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 0
|
||||
%lo = load ptr, ptr %0, align 8
|
||||
%1 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 1
|
||||
%hi = load i64, ptr %1, align 8
|
||||
%2 = call i32 @"hello$$int._123_x"(i32 4)
|
||||
store i32 %2, 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 void
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user