mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Changed generic modules to internal templates.
This commit is contained in:
committed by
Christoffer Lerno
parent
b99f8d644b
commit
892c7e8874
@@ -91,7 +91,7 @@ work on Windows. Also, parts of the code is still rough and needs to be made sol
|
||||
- [x] Expression blocks
|
||||
- [x] Do-without-while
|
||||
- [x] Foreach statement
|
||||
- [x] Generic modules
|
||||
- [x] Templates
|
||||
- [x] Distinct types
|
||||
- [x] Built-in linking
|
||||
- [x] CT only macros evaluating to constants
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
module std::array;
|
||||
|
||||
import std::mem;
|
||||
|
||||
public macro make($Type, usize elements)
|
||||
@@ -14,4 +13,42 @@ public macro make_zero($Type, usize elements)
|
||||
assert(elements > 0);
|
||||
$Type* ptr = mem::calloc($Type.sizeof, elements);
|
||||
return ptr[0..(elements - 1)];
|
||||
}
|
||||
}
|
||||
|
||||
public template vararray <Type>
|
||||
{
|
||||
public struct VarArray
|
||||
{
|
||||
usize size;
|
||||
usize capacity;
|
||||
Type *entries;
|
||||
}
|
||||
|
||||
public func void VarArray.append(VarArray *array, Type element)
|
||||
{
|
||||
if (array.capacity == array.size)
|
||||
{
|
||||
array.capacity = array.capacity ? 2 * array.capacity : 16;
|
||||
array.entries = mem::realloc(array.entries, Type.sizeof * array.capacity);
|
||||
}
|
||||
array.entries[array.size++] = element;
|
||||
}
|
||||
|
||||
public func usize VarArray.len(VarArray *array)
|
||||
{
|
||||
return array.size;
|
||||
}
|
||||
|
||||
public func Type VarArray.get(VarArray *array, usize index)
|
||||
{
|
||||
return array.entries[index];
|
||||
}
|
||||
|
||||
public func void VarArray.free(VarArray *array)
|
||||
{
|
||||
mem::free(array.entries);
|
||||
array.capacity = 0;
|
||||
array.size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -117,6 +117,7 @@ public macro malloc($Type)
|
||||
{
|
||||
return ($Type*)(mem::alloc($Type.sizeof));
|
||||
}
|
||||
|
||||
public func void* alloc(usize size, usize elements = 1) @inline
|
||||
{
|
||||
return _malloc(size * elements);
|
||||
@@ -126,6 +127,12 @@ public func void* calloc(usize size, usize elements = 1) @inline
|
||||
{
|
||||
return _calloc(size, elements);
|
||||
}
|
||||
|
||||
public func void* realloc(void *ptr, usize size) @inline
|
||||
{
|
||||
return _realloc(ptr, size);
|
||||
}
|
||||
|
||||
public func void free(void* ptr) @inline
|
||||
{
|
||||
_free(ptr);
|
||||
|
||||
@@ -106,6 +106,7 @@ Decl *decl_new_with_type(TokenId name, DeclKind decl_type, Visibility visibility
|
||||
case DECL_CT_SWITCH:
|
||||
case DECL_CT_CASE:
|
||||
case DECL_DEFINE:
|
||||
case DECL_TEMPLATE:
|
||||
UNREACHABLE
|
||||
}
|
||||
Type *type = type_new(kind, !name.index ? "anon" : TOKSTR(name));
|
||||
@@ -782,6 +783,9 @@ void fprint_decl_recursive(Context *context, FILE *file, Decl *decl, int indent)
|
||||
if (!decl) return;
|
||||
switch (decl->decl_kind)
|
||||
{
|
||||
case DECL_TEMPLATE:
|
||||
DUMPF("(template %s", decl->name);
|
||||
DUMPEND();
|
||||
case DECL_INTERFACE:
|
||||
DUMPF("(interface %s", decl->name);
|
||||
DUMPDECLS(decl->interface_decl.functions);
|
||||
|
||||
@@ -41,7 +41,6 @@ void compiler_init(const char *std_lib_dir)
|
||||
stable_init(&global_context.modules, 64);
|
||||
stable_init(&global_context.scratch_table, 32);
|
||||
global_context.module_list = NULL;
|
||||
global_context.generic_module_list = NULL;
|
||||
stable_init(&global_context.global_symbols, 0x1000);
|
||||
vmem_init(&ast_arena, 4 * 1024);
|
||||
vmem_init(&expr_arena, 4 * 1024);
|
||||
@@ -431,7 +430,7 @@ Module *global_context_find_module(const char *name)
|
||||
return stable_get(&global_context.modules, name);
|
||||
}
|
||||
|
||||
Module *compiler_find_or_create_module(Path *module_name, TokenId *parameters)
|
||||
Module *compiler_find_or_create_module(Path *module_name)
|
||||
{
|
||||
Module *module = global_context_find_module(module_name->module);
|
||||
if (module) return module;
|
||||
@@ -441,18 +440,9 @@ Module *compiler_find_or_create_module(Path *module_name, TokenId *parameters)
|
||||
module = CALLOCS(Module);
|
||||
module->name = module_name;
|
||||
module->stage = ANALYSIS_NOT_BEGUN;
|
||||
module->parameters = parameters;
|
||||
stable_init(&module->symbols, 0x10000);
|
||||
stable_set(&global_context.modules, module_name->module, module);
|
||||
if (parameters)
|
||||
{
|
||||
vec_add(global_context.generic_module_list, module);
|
||||
}
|
||||
else
|
||||
{
|
||||
vec_add(global_context.module_list, module);
|
||||
}
|
||||
|
||||
vec_add(global_context.module_list, module);
|
||||
return module;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,8 +36,8 @@ typedef struct
|
||||
#define NO_TOKEN ((Token) { .type = TOKEN_INVALID_TOKEN })
|
||||
#define INVALID_TOKEN_ID ((TokenId) { UINT32_MAX })
|
||||
#define INVALID_RANGE ((SourceSpan){ INVALID_TOKEN_ID, INVALID_TOKEN_ID })
|
||||
#define MAX_LOCALS 0xFFFF
|
||||
#define MAX_SCOPE_DEPTH 0x1000
|
||||
#define MAX_LOCALS 0xFFF
|
||||
#define MAX_SCOPE_DEPTH 0x100
|
||||
#define MAX_STRING_BUFFER 0x10000
|
||||
#define MAX_MACRO_NESTING 1024
|
||||
#define MAX_FUNCTION_SIGNATURE_SIZE 2048
|
||||
@@ -320,6 +320,13 @@ typedef struct
|
||||
Decl **body;
|
||||
} CtCaseDecl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct Context_ *parent_context;
|
||||
TokenId *params;
|
||||
Decl **body;
|
||||
} TemplateDecl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Expr *expr;
|
||||
@@ -387,6 +394,7 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
bool is_func : 1;
|
||||
bool is_distinct : 1;
|
||||
union
|
||||
{
|
||||
FunctionSignature function_signature;
|
||||
@@ -428,28 +436,32 @@ typedef struct
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DEFINE_FUNC,
|
||||
DEFINE_DISTINCT_TYPE,
|
||||
DEFINE_TYPE_ALIAS,
|
||||
DEFINE_TYPE_TEMPLATE,
|
||||
DEFINE_IDENT_ALIAS,
|
||||
DEFINE_IDENT_TEMPLATE,
|
||||
} DefineType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DefineType define_kind: 5;
|
||||
bool is_parameterized : 1;
|
||||
union
|
||||
{
|
||||
FunctionSignature function_signature;
|
||||
TypeInfo *type_info;
|
||||
struct
|
||||
{
|
||||
Path *path;
|
||||
union
|
||||
{
|
||||
Path *path;
|
||||
struct
|
||||
{
|
||||
Path *template_path;
|
||||
TokenId template_name;
|
||||
TypeInfo **template_params;
|
||||
};
|
||||
};
|
||||
TokenId identifier;
|
||||
};
|
||||
Decl *alias;
|
||||
};
|
||||
TypeInfo **params;
|
||||
} DefineDecl;
|
||||
|
||||
typedef struct
|
||||
@@ -528,6 +540,7 @@ typedef struct Decl_
|
||||
CtCaseDecl ct_case_decl;
|
||||
Decl** ct_else_decl;
|
||||
Expr *incr_array_decl;
|
||||
TemplateDecl template_decl;
|
||||
};
|
||||
} Decl;
|
||||
|
||||
@@ -1149,12 +1162,11 @@ typedef struct Ast_
|
||||
typedef struct Module_
|
||||
{
|
||||
Path *name;
|
||||
TokenId *parameters;
|
||||
|
||||
bool is_external : 1;
|
||||
bool is_c_library : 1;
|
||||
bool is_exported : 1;
|
||||
bool is_generic : 1;
|
||||
struct Context_ *template_parent_context;
|
||||
AnalysisStage stage : 6;
|
||||
|
||||
Ast **files; // Asts
|
||||
@@ -1229,6 +1241,7 @@ typedef struct Context_
|
||||
Decl **macros;
|
||||
Decl **generics;
|
||||
Decl **interfaces;
|
||||
Decl **templates;
|
||||
Decl **methods;
|
||||
Decl **vars;
|
||||
Decl **incr_array;
|
||||
@@ -1270,6 +1283,8 @@ typedef struct Context_
|
||||
STable external_symbols;
|
||||
Decl **external_symbol_list;
|
||||
};
|
||||
Decl* locals[MAX_LOCALS];
|
||||
DynamicScope scopes[MAX_SCOPE_DEPTH];
|
||||
Lexer lexer;
|
||||
Token tok;
|
||||
TokenId prev_tok;
|
||||
@@ -1284,7 +1299,6 @@ typedef struct
|
||||
{
|
||||
STable modules;
|
||||
Module **module_list;
|
||||
Module **generic_module_list;
|
||||
STable global_symbols;
|
||||
STable qualified_symbols;
|
||||
Type **type;
|
||||
@@ -1296,8 +1310,6 @@ typedef struct
|
||||
unsigned warnings_found;
|
||||
char scratch_buffer[MAX_STRING_BUFFER];
|
||||
size_t scratch_buffer_len;
|
||||
Decl* locals[MAX_LOCALS];
|
||||
DynamicScope scopes[MAX_SCOPE_DEPTH];
|
||||
STable scratch_table;
|
||||
Module std_module;
|
||||
Path std_module_path;
|
||||
@@ -1550,7 +1562,7 @@ void header_gen(Module *module);
|
||||
|
||||
void global_context_add_type(Type *type);
|
||||
Decl *compiler_find_symbol(const char *name);
|
||||
Module *compiler_find_or_create_module(Path *module_name, TokenId *parameters);
|
||||
Module *compiler_find_or_create_module(Path *module_name);
|
||||
Module *global_context_find_module(const char *name);
|
||||
void compiler_register_public_symbol(Decl *decl);
|
||||
|
||||
@@ -1559,8 +1571,10 @@ void context_register_global_decl(Context *context, Decl *decl);
|
||||
void context_register_external_symbol(Context *context, Decl *decl);
|
||||
bool context_add_import(Context *context, Path *path, Token symbol, Token alias, bool private_import);
|
||||
bool context_set_module_from_filename(Context *context);
|
||||
bool context_set_module(Context *context, Path *path, TokenId *generic_parameters);
|
||||
|
||||
bool context_set_module(Context *context, Path *path);
|
||||
void context_print_ast(Context *context, FILE *file);
|
||||
Decl **context_get_imports(Context *context);
|
||||
|
||||
#pragma mark --- Decl functions
|
||||
|
||||
@@ -1579,7 +1593,7 @@ static inline bool decl_is_struct_type(Decl *decl);
|
||||
static inline DeclKind decl_from_token(TokenType type);
|
||||
static inline Decl *decl_flatten(Decl *decl)
|
||||
{
|
||||
if (decl->decl_kind == DECL_DEFINE && decl->define_decl.define_kind == DEFINE_IDENT_ALIAS)
|
||||
if (decl->decl_kind == DECL_DEFINE && decl->define_decl.define_kind != DEFINE_TYPE_TEMPLATE)
|
||||
{
|
||||
return decl->define_decl.alias;
|
||||
}
|
||||
@@ -1671,6 +1685,7 @@ const char *resolve_status_to_string(ResolveStatus status);
|
||||
void sema_analysis_pass_process_imports(Module *module);
|
||||
void sema_analysis_pass_register_globals(Module *module);
|
||||
void sema_analysis_pass_conditional_compilation(Module *module);
|
||||
void sema_analysis_pass_templates(Module *module);
|
||||
void sema_analysis_pass_decls(Module *module);
|
||||
void sema_analysis_pass_ct_assert(Module *module);
|
||||
void sema_analysis_pass_functions(Module *module);
|
||||
@@ -1978,7 +1993,7 @@ static inline Type *type_flatten_distinct(Type *type)
|
||||
type = type->canonical;
|
||||
while (type->type_kind == TYPE_DISTINCT)
|
||||
{
|
||||
type = type->decl->define_decl.type_info->type->canonical;
|
||||
type = type->decl->distinct_decl.base_type;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -15,12 +15,12 @@ Context *context_create(File *file)
|
||||
}
|
||||
|
||||
|
||||
static inline bool create_module_or_check_name(Context *context, Path *module_name, TokenId *parameters)
|
||||
static inline bool create_module_or_check_name(Context *context, Path *module_name)
|
||||
{
|
||||
context->module_name = module_name;
|
||||
if (context->module == NULL)
|
||||
{
|
||||
context->module = compiler_find_or_create_module(module_name, parameters);
|
||||
context->module = compiler_find_or_create_module(module_name);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -55,10 +55,10 @@ bool context_set_module_from_filename(Context *context)
|
||||
path->span = INVALID_RANGE;
|
||||
path->module = module_name;
|
||||
path->len = len;
|
||||
return create_module_or_check_name(context, path, NULL);
|
||||
return create_module_or_check_name(context, path);
|
||||
}
|
||||
|
||||
bool context_set_module(Context *context, Path *path, TokenId *generic_parameters)
|
||||
bool context_set_module(Context *context, Path *path)
|
||||
{
|
||||
// Note that we allow the illegal name for now, to be able to parse further.
|
||||
context->module_name = path;
|
||||
@@ -68,7 +68,7 @@ bool context_set_module(Context *context, Path *path, TokenId *generic_parameter
|
||||
return false;
|
||||
}
|
||||
|
||||
return create_module_or_check_name(context, path, generic_parameters);
|
||||
return create_module_or_check_name(context, path);
|
||||
}
|
||||
|
||||
|
||||
@@ -91,6 +91,11 @@ void context_register_global_decl(Context *context, Decl *decl)
|
||||
{
|
||||
case DECL_POISONED:
|
||||
break;
|
||||
case DECL_TEMPLATE:
|
||||
vec_add(context->templates, decl);
|
||||
decl->template_decl.parent_context = context;
|
||||
decl_set_external_name(decl);
|
||||
break;
|
||||
case DECL_INTERFACE:
|
||||
vec_add(context->interfaces, decl);
|
||||
decl_set_external_name(decl);
|
||||
@@ -107,13 +112,11 @@ void context_register_global_decl(Context *context, Decl *decl)
|
||||
if (decl->func.type_parent)
|
||||
{
|
||||
vec_add(context->methods, decl);
|
||||
// TODO set name
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
vec_add(context->functions, decl);
|
||||
decl_set_external_name(decl);
|
||||
}
|
||||
break;
|
||||
case DECL_VAR:
|
||||
@@ -212,6 +215,13 @@ bool context_add_import(Context *context, Path *path, Token token, Token alias,
|
||||
return true;
|
||||
}
|
||||
|
||||
Decl **context_get_imports(Context *context)
|
||||
{
|
||||
Context *parent_context = context->module->template_parent_context;
|
||||
if (parent_context) return parent_context->imports;
|
||||
return context->imports;
|
||||
}
|
||||
|
||||
void context_print_ast(Context *context, FILE *file)
|
||||
{
|
||||
VECEACH(context->enums, i)
|
||||
|
||||
@@ -471,6 +471,9 @@ Decl *copy_decl(Decl *decl)
|
||||
{
|
||||
case DECL_POISONED:
|
||||
break;
|
||||
case DECL_TEMPLATE:
|
||||
MACRO_COPY_DECL_LIST(copy->template_decl.body);
|
||||
break;
|
||||
case DECL_UNION:
|
||||
case DECL_STRUCT:
|
||||
case DECL_ERR:
|
||||
@@ -559,15 +562,11 @@ Decl *copy_decl(Decl *decl)
|
||||
case DECL_ATTRIBUTE:
|
||||
TODO
|
||||
case DECL_DEFINE:
|
||||
MACRO_COPY_TYPE_LIST(decl->define_decl.params);
|
||||
switch (decl->define_decl.define_kind)
|
||||
{
|
||||
case DEFINE_FUNC:
|
||||
copy_function_signature_deep(&decl->define_decl.function_signature);
|
||||
break;
|
||||
case DEFINE_DISTINCT_TYPE:
|
||||
case DEFINE_TYPE_ALIAS:
|
||||
MACRO_COPY_TYPE(decl->define_decl.type_info);
|
||||
case DEFINE_TYPE_TEMPLATE:
|
||||
case DEFINE_IDENT_TEMPLATE:
|
||||
MACRO_COPY_TYPE_LIST(decl->define_decl.template_params);
|
||||
break;
|
||||
case DEFINE_IDENT_ALIAS:
|
||||
break;
|
||||
|
||||
@@ -136,34 +136,35 @@ typedef enum
|
||||
typedef enum
|
||||
{
|
||||
DECL_POISONED = 0,
|
||||
DECL_FUNC,
|
||||
DECL_VAR,
|
||||
DECL_LABEL,
|
||||
DECL_ENUM_CONSTANT,
|
||||
DECL_TYPEDEF,
|
||||
DECL_DISTINCT,
|
||||
DECL_STRUCT,
|
||||
DECL_UNION,
|
||||
DECL_ENUM,
|
||||
DECL_ERR,
|
||||
DECL_ARRAY_VALUE,
|
||||
DECL_IMPORT,
|
||||
DECL_MACRO,
|
||||
DECL_GENERIC,
|
||||
DECL_CT_IF,
|
||||
DECL_CT_ELSE,
|
||||
DECL_CT_ELIF,
|
||||
DECL_CT_SWITCH,
|
||||
DECL_CT_CASE,
|
||||
DECL_ATTRIBUTE,
|
||||
DECL_ARRAY_VALUE,
|
||||
DECL_CT_CASE,
|
||||
DECL_CT_ELIF,
|
||||
DECL_CT_ELSE,
|
||||
DECL_CT_IF,
|
||||
DECL_CT_SWITCH,
|
||||
DECL_DEFINE,
|
||||
DECL_DISTINCT,
|
||||
DECL_ENUM,
|
||||
DECL_ENUM_CONSTANT,
|
||||
DECL_ERR,
|
||||
DECL_FUNC,
|
||||
DECL_GENERIC,
|
||||
DECL_IMPORT,
|
||||
DECL_INTERFACE,
|
||||
DECL_LABEL,
|
||||
DECL_MACRO,
|
||||
DECL_STRUCT,
|
||||
DECL_TEMPLATE,
|
||||
DECL_TYPEDEF,
|
||||
DECL_UNION,
|
||||
DECL_VAR,
|
||||
} DeclKind;
|
||||
|
||||
#define NON_TYPE_DECLS DECL_ARRAY_VALUE: case DECL_IMPORT: case DECL_MACRO: \
|
||||
case DECL_GENERIC: case DECL_CT_IF: case DECL_CT_ELSE: case DECL_CT_ELIF: \
|
||||
case DECL_CT_SWITCH: case DECL_CT_CASE: case DECL_ATTRIBUTE: case DECL_LABEL: \
|
||||
case DECL_DEFINE
|
||||
case DECL_DEFINE: case DECL_TEMPLATE
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@@ -431,6 +432,7 @@ typedef enum
|
||||
TOKEN_STATIC,
|
||||
TOKEN_STRUCT,
|
||||
TOKEN_SWITCH,
|
||||
TOKEN_TEMPLATE,
|
||||
TOKEN_TRUE,
|
||||
TOKEN_TRY,
|
||||
TOKEN_TYPEOF,
|
||||
|
||||
@@ -230,6 +230,9 @@ static void header_gen_decl(FILE *file, int indent, Decl *decl)
|
||||
case DECL_ERR:
|
||||
header_gen_err(file, indent, decl);
|
||||
return;
|
||||
case DECL_TEMPLATE:
|
||||
// Skipped
|
||||
return;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
@@ -2624,6 +2624,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *be_value, Expr *expr)
|
||||
// 2b. Set signature, function and function type
|
||||
signature = &function_decl->func.function_signature;
|
||||
func = function_decl->backend_ref;
|
||||
assert(func);
|
||||
func_type = llvm_get_type(c, function_decl->type);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -634,10 +634,18 @@ void llvm_emit_extern_decl(GenContext *context, Decl *decl)
|
||||
case DECL_STRUCT:
|
||||
case DECL_UNION:
|
||||
case DECL_ERR:
|
||||
VECEACH(decl->methods, i)
|
||||
{
|
||||
llvm_emit_function_decl(context, decl->methods[i]);
|
||||
}
|
||||
llvm_get_type(context, decl->type);
|
||||
// TODO // Fix typeid
|
||||
break;
|
||||
case DECL_ENUM:
|
||||
VECEACH(decl->methods, i)
|
||||
{
|
||||
llvm_emit_function_decl(context, decl->methods[i]);
|
||||
}
|
||||
TODO
|
||||
case NON_TYPE_DECLS:
|
||||
case DECL_INTERFACE:
|
||||
|
||||
@@ -13,8 +13,8 @@ static inline LLVMTypeRef llvm_type_from_decl(GenContext *c, Decl *decl)
|
||||
case DECL_VAR:
|
||||
case DECL_ENUM_CONSTANT:
|
||||
case DECL_POISONED:
|
||||
case NON_TYPE_DECLS:
|
||||
case DECL_INTERFACE:
|
||||
case NON_TYPE_DECLS:
|
||||
UNREACHABLE
|
||||
case DECL_FUNC:
|
||||
{
|
||||
@@ -36,7 +36,7 @@ static inline LLVMTypeRef llvm_type_from_decl(GenContext *c, Decl *decl)
|
||||
case DECL_STRUCT:
|
||||
{
|
||||
LLVMTypeRef *types = NULL;
|
||||
LLVMTypeRef type = LLVMStructCreateNamed(c->context, decl->external_name);
|
||||
LLVMTypeRef type = LLVMStructCreateNamed(c->context, decl->name ?: "anon");
|
||||
// Avoid recursive issues.
|
||||
decl->type->backend_type = type;
|
||||
Decl **members = decl->strukt.members;
|
||||
@@ -58,7 +58,7 @@ static inline LLVMTypeRef llvm_type_from_decl(GenContext *c, Decl *decl)
|
||||
}
|
||||
case DECL_UNION:
|
||||
{
|
||||
LLVMTypeRef type = LLVMStructCreateNamed(c->context, decl->external_name);
|
||||
LLVMTypeRef type = LLVMStructCreateNamed(c->context, decl->name ?: "anon");
|
||||
// Avoid recursive issues.
|
||||
decl->type->backend_type = type;
|
||||
Decl **members = decl->strukt.members;
|
||||
@@ -87,7 +87,7 @@ static inline LLVMTypeRef llvm_type_from_decl(GenContext *c, Decl *decl)
|
||||
return llvm_get_type(c, decl->type);
|
||||
case DECL_ERR:
|
||||
{
|
||||
LLVMTypeRef err_type = LLVMStructCreateNamed(c->context, decl->external_name);
|
||||
LLVMTypeRef err_type = LLVMStructCreateNamed(c->context, decl->name);
|
||||
// Avoid recursive issues.
|
||||
decl->type->backend_type = err_type;
|
||||
LLVMTypeRef *types = NULL;
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
static Decl *parse_const_declaration(Context *context, Visibility visibility);
|
||||
static inline Decl *parse_func_definition(Context *context, Visibility visibility, bool is_interface);
|
||||
|
||||
static bool context_next_is_path_prefix_start(Context *context)
|
||||
{
|
||||
return context->tok.type == TOKEN_IDENT && context->next_tok.type == TOKEN_SCOPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk forward through the token stream to identify a type on the format: foo::bar::Type
|
||||
*
|
||||
@@ -12,7 +17,7 @@ static inline Decl *parse_func_definition(Context *context, Visibility visibilit
|
||||
static bool context_next_is_type_with_path_prefix(Context *context)
|
||||
{
|
||||
// We assume it's called after "foo::" parsing.
|
||||
assert(context->tok.type == TOKEN_IDENT && context->next_tok.type == TOKEN_SCOPE);
|
||||
if (!context_next_is_path_prefix_start(context)) return false;
|
||||
|
||||
TokenId current = context->next_tok.id;
|
||||
while (1)
|
||||
@@ -274,60 +279,7 @@ static inline Path *parse_module_path(Context *context)
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* module_param
|
||||
* : TYPE_IDENT
|
||||
* | IDENT
|
||||
* ;
|
||||
*
|
||||
* module_params
|
||||
* : module_param
|
||||
* | module_params ',' module_param
|
||||
* ;
|
||||
*/
|
||||
static inline bool parse_optional_module_params(Context *context, TokenId **tokens)
|
||||
{
|
||||
|
||||
*tokens = NULL;
|
||||
|
||||
if (!try_consume(context, TOKEN_LPAREN)) return true;
|
||||
|
||||
if (try_consume(context, TOKEN_RPAREN))
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "Generic parameter list cannot be empty.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// No params
|
||||
while (1)
|
||||
{
|
||||
switch (context->tok.type)
|
||||
{
|
||||
case TOKEN_IDENT:
|
||||
case TOKEN_TYPE_IDENT:
|
||||
break;
|
||||
case TOKEN_COMMA:
|
||||
SEMA_TOKEN_ERROR(context->tok, "Unexpected ','");
|
||||
return false;
|
||||
case TOKEN_CT_IDENT:
|
||||
case TOKEN_CT_TYPE_IDENT:
|
||||
SEMA_TOKEN_ERROR(context->tok, "The module parameter cannot be a $-prefixed name.");
|
||||
return false;
|
||||
default:
|
||||
SEMA_TOKEN_ERROR(context->tok, "Only generic parameters are allowed here as parameters to the module.");
|
||||
return false;
|
||||
}
|
||||
*tokens = VECADD(*tokens, context->tok.id);
|
||||
advance(context);
|
||||
if (!try_consume(context, TOKEN_COMMA))
|
||||
{
|
||||
return consume(context, TOKEN_RPAREN, "Expected ')'.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* module ::= MODULE module_path ('(' module_params ')')? EOS
|
||||
* module ::= MODULE module_path EOS
|
||||
*/
|
||||
bool parse_module(Context *context)
|
||||
{
|
||||
@@ -338,7 +290,7 @@ bool parse_module(Context *context)
|
||||
|
||||
if (!TOKEN_IS(TOKEN_IDENT))
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "Module statement should be followed by the name of the module to import.");
|
||||
SEMA_TOKEN_ERROR(context->tok, "Module statement should be followed by the name of the module.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -351,20 +303,12 @@ bool parse_module(Context *context)
|
||||
path->len = strlen("INVALID");
|
||||
path->module = "INVALID";
|
||||
path->span = INVALID_RANGE;
|
||||
context_set_module(context, path, NULL);
|
||||
context_set_module(context, path);
|
||||
recover_top_level(context);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Is this a generic module?
|
||||
TokenId *generic_parameters = NULL;
|
||||
if (!parse_optional_module_params(context, &generic_parameters))
|
||||
{
|
||||
context_set_module(context, path, NULL);
|
||||
recover_top_level(context);
|
||||
return true;
|
||||
}
|
||||
context_set_module(context, path, generic_parameters);
|
||||
context_set_module(context, path);
|
||||
TRY_CONSUME_EOS_OR(false);
|
||||
return true;
|
||||
}
|
||||
@@ -1499,49 +1443,44 @@ static inline TypeInfo **parse_parameterized_define(Context *context)
|
||||
return types;
|
||||
}
|
||||
|
||||
/**
|
||||
* func_define ::= failable_type opt_parameter_type_list
|
||||
*/
|
||||
static inline bool parse_func_define(Context *context, Decl *decl, Visibility visibility, TypeInfo *return_type)
|
||||
static inline bool parse_define_optional_path(Context *context, Path **path)
|
||||
{
|
||||
decl->define_decl.define_kind = DEFINE_FUNC;
|
||||
if (try_consume(context, TOKEN_BANG))
|
||||
if (context->tok.type != TOKEN_IDENT || context->next_tok.type != TOKEN_SCOPE)
|
||||
{
|
||||
decl->define_decl.function_signature.failable = true;
|
||||
}
|
||||
decl->define_decl.function_signature.rtype = return_type;
|
||||
if (!parse_opt_parameter_type_list(context, visibility, &(decl->typedef_decl.function_signature), true))
|
||||
{
|
||||
return false;
|
||||
*path = NULL;
|
||||
return true;
|
||||
}
|
||||
bool error = false;
|
||||
*path = parse_path_prefix(context, &error);
|
||||
if (error) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static inline Decl *parse_typedef_body_function_ptr(Context *context, Decl *decl)
|
||||
{
|
||||
decl->typedef_decl.is_func = true;
|
||||
assert(decl->typedef_decl.type_info);
|
||||
decl->typedef_decl.function_signature.rtype = decl->typedef_decl.type_info;
|
||||
if (try_consume(context, TOKEN_BANG))
|
||||
{
|
||||
decl->typedef_decl.function_signature.failable = true;
|
||||
}
|
||||
if (!parse_opt_parameter_type_list(context, decl->visibility, &(decl->typedef_decl.function_signature), true))
|
||||
{
|
||||
return poisoned_decl;
|
||||
}
|
||||
TRY_CONSUME_OR(TOKEN_STAR, "Function pointers must end with a '*'", poisoned_decl);
|
||||
RANGE_EXTEND_PREV(decl);
|
||||
TRY_CONSUME_EOS_OR(poisoned_decl);
|
||||
return decl;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* define_type_body ::=
|
||||
* TYPE_IDENT '=' typedef_body | generic_define (('distinct') type ('!' parameter_type_list '*')?) | (path TYPE_IDENT '(' type_list ')')
|
||||
* template ::= IDENT '<' TYPE_INDENT (',' TYPE_IDENT)* '>' '::'
|
||||
*/
|
||||
static inline bool parse_define_template(Context *context, Decl *decl)
|
||||
{
|
||||
decl->define_decl.template_name = context->tok.id;
|
||||
// These should already be checked.
|
||||
advance_and_verify(context, TOKEN_IDENT);
|
||||
advance_and_verify(context, TOKEN_LESS);
|
||||
if (TOKEN_IS(TOKEN_GREATER))
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "Expected at least one type as a parameter.");
|
||||
return false;
|
||||
}
|
||||
TypeInfo **types = parse_parameterized_define(context);
|
||||
if (!types) return false;
|
||||
decl->define_decl.template_params = types;
|
||||
TRY_CONSUME_OR(TOKEN_SCOPE, "Expected a template name.", false);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* define_type_body ::= TYPE_IDENT '=' 'distinct'? (func_typedef | type_template | type) ';'
|
||||
*
|
||||
* func_typedef ::= 'func' failable_type parameter_type_list
|
||||
* type_template ::= path? IDENT '<' TYPE_IDENT (',' TYPE_IDENT)+ '>' '::' TYPE_IDENT
|
||||
*/
|
||||
static inline Decl *parse_define_type(Context *context, Visibility visibility)
|
||||
{
|
||||
@@ -1549,6 +1488,7 @@ static inline Decl *parse_define_type(Context *context, Visibility visibility)
|
||||
advance_and_verify(context, TOKEN_DEFINE);
|
||||
|
||||
TokenId alias_name = context->tok.id;
|
||||
DEBUG_LOG("Parse define %s", TOKSTR(alias_name));
|
||||
advance_and_verify(context, TOKEN_TYPE_IDENT);
|
||||
CONSUME_OR(TOKEN_EQ, poisoned_decl);
|
||||
bool distinct = false;
|
||||
@@ -1558,14 +1498,13 @@ static inline Decl *parse_define_type(Context *context, Visibility visibility)
|
||||
advance(context);
|
||||
}
|
||||
|
||||
|
||||
// 1. Did we have `func`? In that case it's a function pointer.
|
||||
if (try_consume(context, TOKEN_FUNC))
|
||||
{
|
||||
assert(!distinct && "TODO");
|
||||
Decl *decl = decl_new_with_type(alias_name, DECL_TYPEDEF, visibility);
|
||||
decl->span.loc = start;
|
||||
decl->typedef_decl.is_func = true;
|
||||
decl->typedef_decl.is_distinct = distinct;
|
||||
TypeInfo *type_info = TRY_TYPE_OR(parse_type(context), poisoned_decl);
|
||||
decl->typedef_decl.function_signature.rtype = type_info;
|
||||
if (try_consume(context, TOKEN_BANG))
|
||||
@@ -1581,12 +1520,11 @@ static inline Decl *parse_define_type(Context *context, Visibility visibility)
|
||||
return decl;
|
||||
|
||||
}
|
||||
TypeInfo *type_info = TRY_TYPE_OR(parse_type(context), poisoned_decl);
|
||||
|
||||
// 2. define Foo = foo::bar::Type;
|
||||
// this is always a normal typedef / distinct.
|
||||
if (TOKEN_IS(TOKEN_EOS))
|
||||
// 2. Do we have a regular foo::bar::baz::Type? Then this is a regular typedef.
|
||||
if (token_is_any_type(context->tok.type) || context_next_is_type_with_path_prefix(context))
|
||||
{
|
||||
TypeInfo *type_info = TRY_TYPE_OR(parse_type(context), poisoned_decl);
|
||||
Decl *decl = decl_new_with_type(alias_name, distinct ? DECL_DISTINCT : DECL_TYPEDEF, visibility);
|
||||
decl->span.loc = start;
|
||||
decl->typedef_decl.type_info = type_info;
|
||||
@@ -1598,37 +1536,41 @@ static inline Decl *parse_define_type(Context *context, Visibility visibility)
|
||||
decl->decl_kind = DECL_DISTINCT;
|
||||
}
|
||||
RANGE_EXTEND_PREV(decl);
|
||||
advance_and_verify(context, TOKEN_EOS);
|
||||
TRY_CONSUME_EOS_OR(poisoned_decl);
|
||||
return decl;
|
||||
}
|
||||
|
||||
// 3. Assume we missed a ';' if we don't see '<'
|
||||
if (!TOKEN_IS(TOKEN_LESS))
|
||||
// 3. This must be a template, e.g. define foo::bar::template_name<int, double>::Baz;
|
||||
Decl *decl = decl_new(DECL_DEFINE, alias_name, visibility);
|
||||
if (!parse_define_optional_path(context, &decl->define_decl.template_path)) return poisoned_decl;
|
||||
if (!TOKEN_IS(TOKEN_IDENT))
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "Expected a ';' here");
|
||||
return false;
|
||||
}
|
||||
|
||||
advance(context);
|
||||
// 4. We assume parameterization
|
||||
if (TOKEN_IS(TOKEN_GREATER))
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "Expected at least one type as a parameter.");
|
||||
SEMA_TOKEN_ERROR(context->tok, "Expected a template name here.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
TypeInfo **types = parse_parameterized_define(context);
|
||||
if (!types) return poisoned_decl;
|
||||
Decl *decl = decl_new(DECL_DEFINE, alias_name, visibility);
|
||||
decl->span.loc = start;
|
||||
decl->define_decl.is_parameterized = true;
|
||||
decl->define_decl.params = types;
|
||||
decl->define_decl.define_kind = DEFINE_TYPE_ALIAS;
|
||||
decl->define_decl.type_info = type_info;
|
||||
RANGE_EXTEND_PREV(decl);
|
||||
if (context->next_tok.type != TOKEN_LESS)
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "Expected a template definition.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (!parse_define_template(context, decl)) return poisoned_decl;
|
||||
|
||||
// 4. We've now read up to the last :: so we just read the type name:
|
||||
TRY_CONSUME_OR(TOKEN_TYPE_IDENT, "Expected the templated type", poisoned_decl);
|
||||
decl->define_decl.identifier = context->prev_tok;
|
||||
decl->define_decl.define_kind = DEFINE_TYPE_TEMPLATE;
|
||||
TRY_CONSUME_EOS_OR(poisoned_decl);
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
/**
|
||||
* define_ident ::= 'define' (IDENT | CONST_IDENT) '=' (identifier_alias | template_identifier)
|
||||
*
|
||||
* identifier_alias ::= path? (IDENT | CONST_IDENT)
|
||||
* template_identifier ::= path? IDENT '<' TYPE_IDENT (',' TYPE_IDENT)+ '>' '::' (IDENT | CONST_IDENT)
|
||||
*
|
||||
*/
|
||||
static inline Decl *parse_define_ident(Context *context, Visibility visibility)
|
||||
{
|
||||
// 1. Store the beginning of the define.
|
||||
@@ -1655,14 +1597,26 @@ static inline Decl *parse_define_ident(Context *context, Visibility visibility)
|
||||
|
||||
// 5. Here we may an (optional) path, we just check if it starts
|
||||
// with IDENT '::'
|
||||
decl->define_decl.path = NULL;
|
||||
if (TOKEN_IS(TOKEN_IDENT) && context->next_tok.type == TOKEN_SCOPE)
|
||||
Path *path = NULL;
|
||||
if (context_next_is_path_prefix_start(context))
|
||||
{
|
||||
bool error;
|
||||
decl->define_decl.path = parse_path_prefix(context, &error);
|
||||
path = parse_path_prefix(context, &error);
|
||||
if (error) return poisoned_decl;
|
||||
}
|
||||
|
||||
// 6. Is the next part IDENT '<'? If so it's a template name.
|
||||
if (TOKEN_IS(TOKEN_IDENT) && context->next_tok.type == TOKEN_LESS)
|
||||
{
|
||||
decl->define_decl.template_path = path;
|
||||
decl->define_decl.define_kind = DEFINE_IDENT_TEMPLATE;
|
||||
if (!parse_define_template(context, decl)) return poisoned_decl;
|
||||
}
|
||||
else
|
||||
{
|
||||
decl->define_decl.path = path;
|
||||
}
|
||||
|
||||
// 6. Check that the token after the path is of the same type.
|
||||
if (context->tok.type != alias_type)
|
||||
{
|
||||
@@ -1681,23 +1635,8 @@ static inline Decl *parse_define_ident(Context *context, Visibility visibility)
|
||||
decl->define_decl.identifier = context->tok.id;
|
||||
advance(context);
|
||||
|
||||
// 8. Is this one parameterized? If so parse the parameters.
|
||||
if (try_consume(context, TOKEN_LESS))
|
||||
{
|
||||
if (TOKEN_IS(TOKEN_GREATER))
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "Expected at least one type as a parameter.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
TypeInfo **types = parse_parameterized_define(context);
|
||||
if (!types) return poisoned_decl;
|
||||
decl->define_decl.is_parameterized = true;
|
||||
decl->define_decl.params = types;
|
||||
}
|
||||
|
||||
RANGE_EXTEND_PREV(decl);
|
||||
TRY_CONSUME_EOS_OR(poisoned_decl);
|
||||
|
||||
return decl;
|
||||
}
|
||||
/**
|
||||
@@ -2036,6 +1975,36 @@ static inline Decl *parse_func_definition(Context *context, Visibility visibilit
|
||||
return func;
|
||||
}
|
||||
|
||||
/**
|
||||
* template_declaration ::= 'template' IDENT '<' TYPE_IDENT (',' TYPE_IDENT)* '>' template_body
|
||||
* template_body = '{' top_level* '}'
|
||||
*/
|
||||
static inline Decl *parse_template_declaration(Context *context, Visibility visibility)
|
||||
{
|
||||
advance_and_verify(context, TOKEN_TEMPLATE);
|
||||
TokenId name = context->tok.id;
|
||||
if (!consume_ident(context, "template")) return poisoned_decl;
|
||||
Decl *decl = decl_new(DECL_TEMPLATE, name, visibility);
|
||||
CONSUME_OR(TOKEN_LESS, poisoned_decl);
|
||||
TokenId *params = NULL;
|
||||
while (1)
|
||||
{
|
||||
vec_add(params, context->tok.id);
|
||||
if (!consume_type_name(context, "type")) return poisoned_decl;
|
||||
if (try_consume(context, TOKEN_GREATER)) break;
|
||||
CONSUME_OR(TOKEN_COMMA, poisoned_decl);
|
||||
}
|
||||
decl->template_decl.params = params;
|
||||
CONSUME_OR(TOKEN_LBRACE, poisoned_decl);
|
||||
Decl **body = NULL;
|
||||
while (!try_consume(context, TOKEN_RBRACE))
|
||||
{
|
||||
Decl *statement = parse_top_level_statement(context);
|
||||
vec_add(body, statement);
|
||||
}
|
||||
decl->template_decl.body = body;
|
||||
return decl;
|
||||
}
|
||||
|
||||
/**
|
||||
* interface_declaration ::= INTERFACE TYPE '{' func_decl* '}'
|
||||
@@ -2359,6 +2328,9 @@ Decl *parse_top_level_statement(Context *context)
|
||||
case TOKEN_CONST:
|
||||
decl = TRY_DECL_OR(parse_top_level_const_declaration(context, visibility), poisoned_decl);
|
||||
break;
|
||||
case TOKEN_TEMPLATE:
|
||||
decl = TRY_DECL_OR(parse_template_declaration(context, visibility), poisoned_decl);
|
||||
break;
|
||||
case TOKEN_INTERFACE:
|
||||
decl = TRY_DECL_OR(parse_interface_declaration(context, visibility), poisoned_decl);
|
||||
break;
|
||||
|
||||
@@ -1167,6 +1167,7 @@ Ast *parse_stmt(Context *context)
|
||||
case TOKEN_RBRAPIPE:
|
||||
case TOKEN_BANGBANG:
|
||||
case TOKEN_UNDERSCORE:
|
||||
case TOKEN_TEMPLATE:
|
||||
SEMA_TOKEN_ERROR(context->tok, "Unexpected '%s' found when expecting a statement.", token_type_to_string(context->tok.type));
|
||||
advance(context);
|
||||
return poisoned_ast;
|
||||
|
||||
@@ -576,8 +576,23 @@ static inline bool sema_analyse_method(Context *context, Decl *decl)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
scratch_buffer_clear();
|
||||
if (decl->visibility <= VISIBLE_MODULE)
|
||||
{
|
||||
scratch_buffer_append(parent->name);
|
||||
scratch_buffer_append_char('.');
|
||||
scratch_buffer_append(decl->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
scratch_buffer_append(parent->external_name);
|
||||
scratch_buffer_append("__");
|
||||
scratch_buffer_append(decl->name);
|
||||
}
|
||||
decl->external_name = scratch_buffer_interned();
|
||||
DEBUG_LOG("Method '%s.%s' analysed.", parent->name, decl->name);
|
||||
vec_add(parent->methods, decl);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -685,7 +700,7 @@ static AttributeType sema_analyse_attribute(Context *context, Attr *attr, Attrib
|
||||
return type;
|
||||
case ATTRIBUTE_SECTION:
|
||||
case ATTRIBUTE_CNAME:
|
||||
if (context->module->is_generic)
|
||||
if (context->module->template_parent_context)
|
||||
{
|
||||
SEMA_TOKID_ERROR(attr->name, "'cname' attributes are not allowed in generic modules.");
|
||||
return false;
|
||||
@@ -723,6 +738,19 @@ static inline bool sema_analyse_func(Context *context, Decl *decl)
|
||||
{
|
||||
if (!sema_analyse_method(context, decl)) return decl_poison(decl);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (decl->name == kw_main)
|
||||
{
|
||||
if (decl->visibility == VISIBLE_LOCAL)
|
||||
{
|
||||
SEMA_ERROR(decl, "'main' cannot have local visibility.");
|
||||
return false;
|
||||
}
|
||||
decl->visibility = VISIBLE_EXTERN;
|
||||
}
|
||||
decl_set_external_name(decl);
|
||||
}
|
||||
VECEACH(decl->attributes, i)
|
||||
{
|
||||
Attr *attr = decl->attributes[i];
|
||||
@@ -766,15 +794,6 @@ static inline bool sema_analyse_func(Context *context, Decl *decl)
|
||||
return decl_poison(decl);
|
||||
}
|
||||
}
|
||||
if (decl->name == kw_main)
|
||||
{
|
||||
if (decl->visibility == VISIBLE_LOCAL)
|
||||
{
|
||||
SEMA_ERROR(decl, "'main' cannot have local visibility.");
|
||||
return false;
|
||||
}
|
||||
decl->visibility = VISIBLE_EXTERN;
|
||||
}
|
||||
DEBUG_LOG("Function analysis done.");
|
||||
return true;
|
||||
}
|
||||
@@ -816,6 +835,25 @@ static inline bool sema_analyse_macro(Context *context, Decl *decl)
|
||||
}
|
||||
|
||||
|
||||
static inline bool sema_analyse_template(Context *context, Decl *decl)
|
||||
{
|
||||
decl->template_decl.parent_context = context;
|
||||
stable_clear(&global_context.scratch_table);
|
||||
VECEACH(decl->template_decl.params, i)
|
||||
{
|
||||
TokenId *param = &decl->template_decl.params[i];
|
||||
const char *key = TOKSTR(*param);
|
||||
TokenId *ptr = stable_set(&global_context.scratch_table, key, param);
|
||||
if (ptr)
|
||||
{
|
||||
SEMA_TOKID_ERROR(*param, "Duplicate parameter name '%s'.", TOKSTR(*param));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static inline bool sema_analyse_global(Context *context, Decl *decl)
|
||||
@@ -998,19 +1036,20 @@ static Context *copy_context(Module *module, Context *c)
|
||||
return copy;
|
||||
}
|
||||
|
||||
static Module *sema_instantiate_module(Context *context, Module *module, Path *path, TypeInfo **parms)
|
||||
static Module *sema_instantiate_template(Context *context, Decl *template, Path *path, TypeInfo **parms)
|
||||
{
|
||||
Module *new_module = compiler_find_or_create_module(path, NULL);
|
||||
new_module->is_generic = true;
|
||||
Context **contexts = module->contexts;
|
||||
VECEACH(contexts, i)
|
||||
DEBUG_LOG("Instantiate template %s", path->module);
|
||||
Module *new_module = compiler_find_or_create_module(path);
|
||||
Context *source_context = template->template_decl.parent_context;
|
||||
|
||||
Context *new_context = context_create(context->file);
|
||||
new_context->module = new_module;
|
||||
new_module->template_parent_context = source_context;
|
||||
new_context->global_decls = copy_decl_list(template->template_decl.body);
|
||||
vec_add(new_module->contexts, new_context);
|
||||
VECEACH(template->template_decl.params, i)
|
||||
{
|
||||
vec_add(new_module->contexts, copy_context(new_module, contexts[i]));
|
||||
}
|
||||
Context *first_context = new_module->contexts[0];
|
||||
VECEACH(module->parameters, i)
|
||||
{
|
||||
TokenId param = module->parameters[i];
|
||||
TokenId param = template->template_decl.params[i];
|
||||
Decl *decl = decl_new_with_type(param, DECL_TYPEDEF, VISIBLE_PUBLIC);
|
||||
decl->resolve_status = RESOLVE_DONE;
|
||||
TypeInfo *type_info = parms[i];
|
||||
@@ -1018,175 +1057,124 @@ static Module *sema_instantiate_module(Context *context, Module *module, Path *p
|
||||
decl->typedef_decl.type_info = type_info;
|
||||
decl->type->name = decl->name;
|
||||
decl->type->canonical = type_info->type->canonical;
|
||||
vec_add(first_context->global_decls, decl);
|
||||
vec_add(new_context->global_decls, decl);
|
||||
}
|
||||
return new_module;
|
||||
}
|
||||
|
||||
static Decl *sema_analyse_parameterized_define(Context *c, Decl *decl)
|
||||
{
|
||||
Path *decl_path;
|
||||
bool mismatch = false;
|
||||
const char *name;
|
||||
SourceSpan mismatch_span = INVALID_RANGE;
|
||||
switch (decl->define_decl.define_kind)
|
||||
Decl *ambiguous = NULL;
|
||||
Decl *private_decl = NULL;
|
||||
TokenId template_token = decl->define_decl.template_name;
|
||||
const char *template_name = TOKSTR(template_token);
|
||||
DEBUG_LOG("Analyse %s", decl->name);
|
||||
Decl *template_decl = sema_resolve_symbol(c, template_name, decl->define_decl.template_path, &ambiguous, &private_decl);
|
||||
if (!template_decl)
|
||||
{
|
||||
case DEFINE_IDENT_ALIAS:
|
||||
decl_path = decl->define_decl.path;
|
||||
name = TOKSTR(decl->define_decl.identifier);
|
||||
break;
|
||||
case DEFINE_TYPE_ALIAS:
|
||||
if (private_decl && private_decl->decl_kind == DECL_TEMPLATE)
|
||||
{
|
||||
TypeInfo *define_type = decl->define_decl.type_info;
|
||||
mismatch_span = define_type->span;
|
||||
decl_path = define_type->unresolved.path;
|
||||
name = TOKSTR(define_type->unresolved.name_loc);
|
||||
mismatch = define_type->kind != TYPE_INFO_IDENTIFIER;
|
||||
break;
|
||||
SEMA_TOKID_ERROR(template_token, "'%s' is a private template.", private_decl->name);
|
||||
return poisoned_decl;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
if (mismatch)
|
||||
{
|
||||
sema_error_range(mismatch_span, "A variable, type or constant was expected here.");
|
||||
if (ambiguous)
|
||||
{
|
||||
SEMA_TOKID_ERROR(template_token, "Is an ambiguous symbol, you need to add a path.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
SEMA_TOKID_ERROR(template_token, "Unknown template '%s', did you spell it right?", template_name);
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (!decl_path)
|
||||
if (template_decl->decl_kind != DECL_TEMPLATE)
|
||||
{
|
||||
sema_error_range(mismatch_span, "Parameterization requires the full path, please add it.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
Decl *import_found = NULL;
|
||||
VECEACH(c->imports, i)
|
||||
{
|
||||
Decl *import = c->imports[i];
|
||||
if (decl_path->module == import->import.path->module)
|
||||
{
|
||||
import_found = import;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!import_found)
|
||||
{
|
||||
sema_error_range(mismatch_span, "It was not possible to find a matching module, did you use the full path?");
|
||||
SEMA_TOKID_ERROR(template_token, "'%s' is not a template, did you spell it right?", template_name);
|
||||
return poisoned_decl;
|
||||
}
|
||||
|
||||
Module *module = import_found->module;
|
||||
TypeInfo **params = decl->define_decl.params;
|
||||
unsigned parameter_count = vec_size(module->parameters);
|
||||
if (!sema_analyse_decl(template_decl->template_decl.parent_context, template_decl)) return poisoned_decl;
|
||||
TypeInfo **params = decl->define_decl.template_params;
|
||||
unsigned parameter_count = vec_size(template_decl->template_decl.params);
|
||||
assert(parameter_count > 0);
|
||||
if (parameter_count != vec_size(params))
|
||||
{
|
||||
sema_error_range((SourceSpan) { params[0]->span.loc, VECLAST(params)->span.end_loc }, "The generic module expected %d arguments, but you only supplied %d, did you make a mistake?",
|
||||
parameter_count, vec_size(decl->define_decl.params));
|
||||
sema_error_range((SourceSpan) { params[0]->span.loc, VECLAST(params)->span.end_loc }, "The template expected %d arguments, but you only supplied %d, did you make a mistake?",
|
||||
parameter_count, vec_size(decl->define_decl.template_params));
|
||||
return poisoned_decl;
|
||||
}
|
||||
scratch_buffer_clear();
|
||||
scratch_buffer_append_len(module->name->module, module->name->len);
|
||||
scratch_buffer_append_char('.');
|
||||
VECEACH(decl->define_decl.params, i)
|
||||
scratch_buffer_append(template_decl->external_name);
|
||||
VECEACH(decl->define_decl.template_params, i)
|
||||
{
|
||||
TypeInfo *type_info = decl->define_decl.params[i];
|
||||
TypeInfo *type_info = decl->define_decl.template_params[i];
|
||||
if (!sema_resolve_type_info(c, type_info)) return poisoned_decl;
|
||||
if (i != 0) scratch_buffer_append_char('.');
|
||||
scratch_buffer_append_char('.');
|
||||
const char *type_name = type_info->type->canonical->name;
|
||||
scratch_buffer_append(type_name);
|
||||
}
|
||||
TokenType ident_type = TOKEN_IDENT;
|
||||
const char *path_string = scratch_buffer_interned();
|
||||
Module *instantiated_module = global_context_find_module(path_string);
|
||||
if (!instantiated_module)
|
||||
{
|
||||
Path *path = CALLOCS(Path);
|
||||
path->module = path_string;
|
||||
path->span = module->name->span;
|
||||
path->span = decl->span;
|
||||
path->len = global_context.scratch_buffer_len;
|
||||
instantiated_module = sema_instantiate_module(c, module, path, decl->define_decl.params);
|
||||
sema_analyze_stage(instantiated_module, c->module->stage - 1);
|
||||
instantiated_module = sema_instantiate_template(c, template_decl, path, decl->define_decl.template_params);
|
||||
sema_analyze_stage(instantiated_module, c->module->stage);
|
||||
}
|
||||
const char *name = TOKSTR(decl->define_decl.identifier);
|
||||
Decl *symbol = module_find_symbol(instantiated_module, name);
|
||||
if (!symbol)
|
||||
{
|
||||
SEMA_ERROR(decl, "Identifier '%s' could not be found.", name);
|
||||
SEMA_TOKID_ERROR(decl->define_decl.identifier, "Identifier '%s' could not be found.", name);
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (symbol->visibility <= VISIBLE_MODULE && !import_found->import.private)
|
||||
if (symbol->visibility <= VISIBLE_MODULE)
|
||||
{
|
||||
SEMA_TOKID_ERROR(decl->name_token, "'%s' is not visible from this module.", symbol->name);
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (!sema_analyse_decl(template_decl->template_decl.parent_context, symbol)) return poisoned_decl;
|
||||
|
||||
context_register_external_symbol(c, symbol);
|
||||
return symbol;
|
||||
}
|
||||
static void decl_define_type(Decl *decl, Type *actual_type)
|
||||
{
|
||||
Type *type = type_new(TYPE_TYPEDEF, decl->name);
|
||||
type->decl = decl;
|
||||
type->canonical = actual_type->canonical;
|
||||
decl->type = type;
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_define(Context *c, Decl *decl)
|
||||
{
|
||||
Decl *symbol;
|
||||
if (decl->define_decl.is_parameterized)
|
||||
{
|
||||
symbol = TRY_DECL_OR(sema_analyse_parameterized_define(c, decl), poisoned_decl);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (decl->define_decl.define_kind)
|
||||
{
|
||||
case DEFINE_FUNC:
|
||||
{
|
||||
Type *func_type = sema_analyse_function_signature(c, &decl->define_decl.function_signature, false);
|
||||
if (!func_type) return false;
|
||||
decl_define_type(decl, type_get_ptr(func_type));
|
||||
return true;
|
||||
}
|
||||
case DEFINE_TYPE_ALIAS:
|
||||
if (!sema_resolve_type_info(c, decl->define_decl.type_info)) return false;
|
||||
decl_define_type(decl, decl->define_decl.type_info->type);
|
||||
return true;
|
||||
case DEFINE_DISTINCT_TYPE:
|
||||
{
|
||||
if (!sema_resolve_type_info(c, decl->define_decl.type_info)) return false;
|
||||
Type *type = type_new(TYPE_DISTINCT, decl->name);
|
||||
type->decl = decl;
|
||||
type->canonical = type;
|
||||
decl->type = type;
|
||||
return true;
|
||||
}
|
||||
case DEFINE_IDENT_ALIAS:
|
||||
{
|
||||
Decl *ambiguous_decl = NULL;
|
||||
Decl *private_symbol = NULL;
|
||||
symbol = sema_resolve_symbol(c,
|
||||
TOKSTR(decl->define_decl.identifier),
|
||||
decl->define_decl.path,
|
||||
&ambiguous_decl,
|
||||
&private_symbol);
|
||||
if (!symbol) TODO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Type *type;
|
||||
switch (decl->define_decl.define_kind)
|
||||
{
|
||||
case DEFINE_FUNC:
|
||||
case DEFINE_DISTINCT_TYPE:
|
||||
UNREACHABLE
|
||||
case DEFINE_TYPE_ALIAS:
|
||||
decl_define_type(decl, symbol->type);
|
||||
break;
|
||||
case DEFINE_IDENT_ALIAS:
|
||||
case DEFINE_TYPE_TEMPLATE:
|
||||
symbol = TRY_DECL_OR(sema_analyse_parameterized_define(c, decl), false);
|
||||
type = type_new(TYPE_TYPEDEF, decl->name);
|
||||
type->decl = decl;
|
||||
type->canonical = symbol->type->canonical;
|
||||
decl->type = type;
|
||||
decl->decl_kind = DECL_TYPEDEF;
|
||||
return true;
|
||||
case DEFINE_IDENT_TEMPLATE:
|
||||
symbol = TRY_DECL_OR(sema_analyse_parameterized_define(c, decl), false);
|
||||
decl->type = symbol->type;
|
||||
decl->define_decl.alias = symbol;
|
||||
break;
|
||||
return true;
|
||||
case DEFINE_IDENT_ALIAS:
|
||||
{
|
||||
Decl *ambiguous_decl = NULL;
|
||||
Decl *private_symbol = NULL;
|
||||
symbol = sema_resolve_symbol(c,
|
||||
TOKSTR(decl->define_decl.identifier),
|
||||
decl->define_decl.path,
|
||||
&ambiguous_decl,
|
||||
&private_symbol);
|
||||
if (!symbol) TODO;
|
||||
decl->type = symbol->type;
|
||||
decl->define_decl.alias = symbol;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
|
||||
@@ -1235,6 +1223,10 @@ bool sema_analyse_decl(Context *context, Decl *decl)
|
||||
{
|
||||
case DECL_INTERFACE:
|
||||
TODO
|
||||
case DECL_TEMPLATE:
|
||||
if (!sema_analyse_template(context, decl)) return decl_poison(decl);
|
||||
decl_set_external_name(decl);
|
||||
break;
|
||||
case DECL_STRUCT:
|
||||
case DECL_UNION:
|
||||
if (!sema_analyse_struct_union(context, decl)) return decl_poison(decl);
|
||||
@@ -1242,7 +1234,6 @@ bool sema_analyse_decl(Context *context, Decl *decl)
|
||||
break;
|
||||
case DECL_FUNC:
|
||||
if (!sema_analyse_func(context, decl)) return decl_poison(decl);
|
||||
decl_set_external_name(decl);
|
||||
break;
|
||||
case DECL_MACRO:
|
||||
if (!sema_analyse_macro(context, decl)) return decl_poison(decl);
|
||||
|
||||
@@ -166,6 +166,9 @@ static inline bool sema_cast_ident_rvalue(Context *context, Type *to, Expr *expr
|
||||
|
||||
switch (decl->decl_kind)
|
||||
{
|
||||
case DECL_TEMPLATE:
|
||||
SEMA_ERROR(expr, "Templates cannot appear inside of expressions.");
|
||||
return expr_poison(expr);
|
||||
case DECL_FUNC:
|
||||
SEMA_ERROR(expr, "Expected function followed by (...) or prefixed by &.");
|
||||
return expr_poison(expr);
|
||||
|
||||
@@ -47,14 +47,12 @@ static Decl *sema_resolve_path_symbol(Context *context, const char *symbol, Path
|
||||
return module_find_symbol(context->module, symbol);
|
||||
}
|
||||
|
||||
Decl **imports = context_get_imports(context);
|
||||
printf("Looking for path: %s\n", path->module);
|
||||
// 3. Loop over imports.
|
||||
VECEACH(context->imports, i)
|
||||
VECEACH(imports, i)
|
||||
{
|
||||
Decl *import = context->imports[i];
|
||||
// 4. Don't look through parameterized modules.
|
||||
if (import->module->parameters) continue;
|
||||
|
||||
// TODO handle partial imports.
|
||||
Decl *import = imports[i];
|
||||
|
||||
// 5. Can we match a subpath?
|
||||
if (path->len > import->import.path->len) continue;
|
||||
@@ -134,7 +132,7 @@ Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl
|
||||
|
||||
if (context->current_scope)
|
||||
{
|
||||
Decl **first = &global_context.locals[0];
|
||||
Decl **first = &context->locals[0];
|
||||
if (context->macro_nesting) first = context->macro_locals_start;
|
||||
Decl **current = context->last_local - 1;
|
||||
while (current >= first)
|
||||
@@ -152,6 +150,12 @@ Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl
|
||||
// Search in the module.
|
||||
decl = module_find_symbol(context->module, symbol);
|
||||
|
||||
// Is this a template, in that case we also search the parent module.
|
||||
if (!decl && context->module->template_parent_context)
|
||||
{
|
||||
decl = module_find_symbol(context->module->template_parent_context->module, symbol);
|
||||
}
|
||||
|
||||
if (decl)
|
||||
{
|
||||
context_register_external_symbol(context, decl);
|
||||
@@ -159,9 +163,10 @@ Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl
|
||||
}
|
||||
|
||||
// Search in imports
|
||||
VECEACH(context->imports, i)
|
||||
Decl **imports = context_get_imports(context);
|
||||
VECEACH(imports, i)
|
||||
{
|
||||
Decl *import = context->imports[i];
|
||||
Decl *import = imports[i];
|
||||
if (!decl_ok(import)) continue;
|
||||
Decl *found = module_find_symbol(import->module, symbol);
|
||||
if (!found) continue;
|
||||
@@ -187,7 +192,7 @@ Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl
|
||||
|
||||
static inline bool sema_append_local(Context *context, Decl *decl)
|
||||
{
|
||||
if (context->last_local == &global_context.locals[MAX_LOCALS - 1])
|
||||
if (context->last_local == &context->locals[MAX_LOCALS - 1])
|
||||
{
|
||||
SEMA_ERROR(decl, "Reached the maximum number of locals.");
|
||||
return false;
|
||||
|
||||
@@ -190,9 +190,9 @@ void sema_analysis_pass_decls(Module *module)
|
||||
VECEACH(module->contexts, index)
|
||||
{
|
||||
Context *context = module->contexts[index];
|
||||
context->current_scope = &global_context.scopes[0];
|
||||
context->current_scope = &context->scopes[0];
|
||||
context->current_scope->scope_id = 0;
|
||||
context->last_local = &global_context.locals[0];
|
||||
context->last_local = &context->locals[0];
|
||||
VECEACH(context->enums, i)
|
||||
{
|
||||
sema_analyse_decl(context, context->enums[i]);
|
||||
@@ -201,6 +201,10 @@ void sema_analysis_pass_decls(Module *module)
|
||||
{
|
||||
sema_analyse_decl(context, context->types[i]);
|
||||
}
|
||||
VECEACH(context->templates, i)
|
||||
{
|
||||
sema_analyse_decl(context, context->templates[i]);
|
||||
}
|
||||
VECEACH(context->macros, i)
|
||||
{
|
||||
sema_analyse_decl(context, context->macros[i]);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
void context_push_scope_with_flags(Context *context, ScopeFlags flags)
|
||||
{
|
||||
if (context->current_scope == &global_context.scopes[MAX_SCOPE_DEPTH - 1])
|
||||
if (context->current_scope == &context->scopes[MAX_SCOPE_DEPTH - 1])
|
||||
{
|
||||
FATAL_ERROR("Too deeply nested scopes.");
|
||||
}
|
||||
@@ -66,7 +66,7 @@ static inline void context_pop_defers_to(Context *context, DeferList *list)
|
||||
|
||||
void context_pop_scope(Context *context)
|
||||
{
|
||||
assert(context->current_scope != &global_context.scopes[0]);
|
||||
assert(context->current_scope != &context->scopes[0]);
|
||||
context->last_local = context->current_scope->local_decl_start;
|
||||
|
||||
assert(context_start_defer(context) == context->current_scope->defer_last);
|
||||
@@ -113,7 +113,7 @@ static void context_pop_defers_and_replace_ast(Context *context, Ast *ast)
|
||||
|
||||
AstId context_start_defer(Context *context)
|
||||
{
|
||||
if (context->current_scope == global_context.scopes) return 0;
|
||||
if (context->current_scope == context->scopes) return 0;
|
||||
if (context->current_scope->in_defer != context->current_scope[-1].in_defer) return 0;
|
||||
return context->current_scope[-1].defer_last;
|
||||
}
|
||||
@@ -930,7 +930,7 @@ static DynamicScope *context_find_scope_by_id(Context *context, ScopeId scope_id
|
||||
while (1)
|
||||
{
|
||||
if (scope->scope_id == scope_id) return scope;
|
||||
assert(scope != &global_context.scopes[0]);
|
||||
assert(scope != &context->scopes[0]);
|
||||
scope--;
|
||||
}
|
||||
UNREACHABLE
|
||||
@@ -965,7 +965,7 @@ static inline Decl *sema_analyse_label(Context *context, Ast *stmt)
|
||||
|
||||
static bool context_labels_exist_in_scope(Context *context)
|
||||
{
|
||||
for (Decl **from = &global_context.locals[0]; from < context->last_local; from++)
|
||||
for (Decl **from = &context->locals[0]; from < context->last_local; from++)
|
||||
{
|
||||
if ((*from)->decl_kind == DECL_LABEL) return true;
|
||||
}
|
||||
@@ -1916,7 +1916,7 @@ bool sema_analyse_function_body(Context *context, Decl *func)
|
||||
FunctionSignature *signature = &func->func.function_signature;
|
||||
context->active_function_for_analysis = func;
|
||||
context->rtype = signature->rtype->type;
|
||||
context->current_scope = &global_context.scopes[0];
|
||||
context->current_scope = &context->scopes[0];
|
||||
context->current_scope->scope_id = 0;
|
||||
context->failable_return = signature->failable;
|
||||
|
||||
@@ -1927,7 +1927,7 @@ bool sema_analyse_function_body(Context *context, Decl *func)
|
||||
vec_resize(context->returns, 0);
|
||||
context->scope_id = 0;
|
||||
context->expected_block_type = NULL;
|
||||
context->last_local = &global_context.locals[0];
|
||||
context->last_local = &context->locals[0];
|
||||
context->in_volatile_section = 0;
|
||||
context->macro_counter = 0;
|
||||
context->macro_nesting = 0;
|
||||
@@ -1938,13 +1938,13 @@ bool sema_analyse_function_body(Context *context, Decl *func)
|
||||
func->func.annotations = CALLOCS(FuncAnnotations);
|
||||
context_push_scope(context);
|
||||
Decl **params = signature->params;
|
||||
assert(context->current_scope == &global_context.scopes[1]);
|
||||
assert(context->current_scope == &context->scopes[1]);
|
||||
VECEACH(params, i)
|
||||
{
|
||||
if (!sema_add_local(context, params[i])) return false;
|
||||
}
|
||||
if (!sema_analyse_compound_statement_no_scope(context, func->func.body)) return false;
|
||||
assert(context->current_scope == &global_context.scopes[1]);
|
||||
assert(context->current_scope == &context->scopes[1]);
|
||||
if (!context->current_scope->jump_end)
|
||||
{
|
||||
Type *canonical_rtype = signature->rtype->type->canonical;
|
||||
|
||||
@@ -141,6 +141,7 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
|
||||
case DECL_MACRO:
|
||||
case DECL_GENERIC:
|
||||
case DECL_LABEL:
|
||||
case DECL_TEMPLATE:
|
||||
SEMA_TOKID_ERROR(type_info->unresolved.name_loc, "This is not a type.");
|
||||
return type_info_poison(type_info);
|
||||
case DECL_CT_ELSE:
|
||||
|
||||
@@ -242,6 +242,8 @@ const char *token_type_to_string(TokenType type)
|
||||
return "struct";
|
||||
case TOKEN_SWITCH:
|
||||
return "switch";
|
||||
case TOKEN_TEMPLATE:
|
||||
return "template";
|
||||
case TOKEN_TRUE:
|
||||
return "true";
|
||||
case TOKEN_TRY:
|
||||
|
||||
@@ -1079,11 +1079,57 @@ static void type_append_name_to_scratch(Type *type)
|
||||
case TYPE_ENUM:
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_DISTINCT:
|
||||
scratch_buffer_append(type->decl->external_name);
|
||||
break;
|
||||
default:
|
||||
case TYPE_POINTER:
|
||||
type_append_name_to_scratch(type->pointer);
|
||||
scratch_buffer_append_char('*');
|
||||
break;
|
||||
case TYPE_SUBARRAY:
|
||||
type_append_name_to_scratch(type->pointer);
|
||||
scratch_buffer_append("[]");
|
||||
case TYPE_VOID:
|
||||
case TYPE_BOOL:
|
||||
case TYPE_I8:
|
||||
case TYPE_I16:
|
||||
case TYPE_I32:
|
||||
case TYPE_I64:
|
||||
case TYPE_I128:
|
||||
case TYPE_U8:
|
||||
case TYPE_U16:
|
||||
case TYPE_U32:
|
||||
case TYPE_U64:
|
||||
case TYPE_U128:
|
||||
case TYPE_F16:
|
||||
case TYPE_F32:
|
||||
case TYPE_F64:
|
||||
case TYPE_F128:
|
||||
case TYPE_TYPEID:
|
||||
case TYPE_ERR_UNION:
|
||||
case TYPE_VIRTUAL_ANY:
|
||||
case TYPE_COMPLEX:
|
||||
case TYPE_VECTOR:
|
||||
scratch_buffer_append(type->name);
|
||||
break;
|
||||
case TYPE_IXX:
|
||||
case TYPE_FXX:
|
||||
case TYPE_STRLIT:
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
case TYPE_TYPEINFO:
|
||||
case TYPE_MEMBER:
|
||||
UNREACHABLE
|
||||
break;
|
||||
case TYPE_FUNC:
|
||||
scratch_buffer_append(type->func.mangled_function_signature);
|
||||
break;
|
||||
case TYPE_ARRAY:
|
||||
TODO
|
||||
case TYPE_VARARRAY:
|
||||
TODO
|
||||
case TYPE_VIRTUAL:
|
||||
scratch_buffer_append("virtual ");
|
||||
scratch_buffer_append(type->decl->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "A223"
|
||||
#define COMPILER_VERSION "A224"
|
||||
@@ -17,15 +17,15 @@ func Test creator()
|
||||
|
||||
// #expect: literal_load.ll
|
||||
|
||||
%literal = alloca %literal_load.Test, align 4
|
||||
%literal1 = alloca %literal_load.Test, align 4
|
||||
%0 = bitcast %literal_load.Test* %literal to i8*
|
||||
%literal = alloca %Test, align 4
|
||||
%literal1 = alloca %Test, align 4
|
||||
%0 = bitcast %Test* %literal to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 0, i64 4, i1 false)
|
||||
%1 = bitcast %literal_load.Test* %literal to i32*
|
||||
%1 = bitcast %Test* %literal to i32*
|
||||
%coerced = load i32, i32* %1, align 4
|
||||
call void @blorg(i32 %coerced)
|
||||
%2 = bitcast %literal_load.Test* %literal1 to i8*
|
||||
%2 = bitcast %Test* %literal1 to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 4 %2, i8 0, i64 4, i1 false)
|
||||
%3 = bitcast %literal_load.Test* %literal1 to i32*
|
||||
%3 = bitcast %Test* %literal1 to i32*
|
||||
%coerced2 = load i32, i32* %3, align 4
|
||||
ret i32 %coerced2
|
||||
@@ -16,19 +16,19 @@ func void hello(Foo f)
|
||||
|
||||
// #expect: unionx64.ll
|
||||
|
||||
%unionx64.Foo = type { i64, [8 x i8] }
|
||||
%Foo = type { i64, [8 x i8] }
|
||||
|
||||
declare void @hello2(i64, i64) #0
|
||||
|
||||
define void @unionx64.hello(i64 %0, i64 %1)
|
||||
|
||||
%f = alloca %unionx64.Foo, align 8
|
||||
%pair = bitcast %unionx64.Foo* %f to { i64, i64 }*
|
||||
%f = alloca %Foo, align 8
|
||||
%pair = bitcast %Foo* %f to { i64, i64 }*
|
||||
%lo = getelementptr inbounds { i64, i64 }, { i64, i64 }* %pair, i32 0, i32 0
|
||||
store i64 %0, i64* %lo, align 8
|
||||
%hi = getelementptr inbounds { i64, i64 }, { i64, i64 }* %pair, i32 0, i32 1
|
||||
store i64 %1, i64* %hi, align 8
|
||||
%casttemp = bitcast %unionx64.Foo* %f to { i64, i64 }*
|
||||
%casttemp = bitcast %Foo* %f to { i64, i64 }*
|
||||
%lo1 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %casttemp, i32 0, i32 0
|
||||
%lo2 = load i64, i64* %lo1, align 8
|
||||
%hi3 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %casttemp, i32 0, i32 1
|
||||
|
||||
@@ -10,4 +10,4 @@ Foo[10] array;
|
||||
|
||||
// #expect: test.ll
|
||||
|
||||
@test.array = protected global [10 x %test.Foo] zeroinitializer, align 16
|
||||
@test.array = protected global [10 x %Foo] zeroinitializer, align 16
|
||||
@@ -18,4 +18,4 @@ Connection[3] link
|
||||
@.str = private constant [6 x i8] c"link1\00", align 1
|
||||
@.str.1 = private constant [6 x i8] c"link2\00", align 1
|
||||
@.str.2 = private constant [6 x i8] c"link3\00", align 1
|
||||
@test.link = protected global [3 x %test.Connection] [%test.Connection { i64 1, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i32 0, i32 0), i64 10 }, %test.Connection { i64 2, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i64 20 }, %test.Connection { i64 3, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.2, i32 0, i32 0), i64 30 }], align 16
|
||||
@test.link = protected global [3 x %Connection] [%Connection { i64 1, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i32 0, i32 0), i64 10 }, %Connection { i64 2, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i64 20 }, %Connection { i64 3, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.2, i32 0, i32 0), i64 30 }], align 16
|
||||
|
||||
@@ -3,8 +3,6 @@ error Error
|
||||
|
||||
define Foo1 = distinct Error; // #error: You cannot create a distinct type from an error
|
||||
|
||||
define Foo2 = distinct error; // #error: You cannot create a distinct type from an error union
|
||||
|
||||
define Foo3 = distinct void; // #error: create a distinct type from 'void'
|
||||
|
||||
define Foo4 = distinct typeid; // #error: create a distinct type from 'typeid'
|
||||
|
||||
@@ -37,62 +37,62 @@ func void testSimple()
|
||||
// TODO these may be wrong.
|
||||
// #expect: pointer_access.ll
|
||||
|
||||
%pointer_access.ExtraSimple = type { i32, i32, %pointer_access.c, %pointer_access.anon, %pointer_access.anon.0, i32 }
|
||||
%pointer_access.c = type { double, double, double, double, double }
|
||||
%pointer_access.anon = type { i32, i32 }
|
||||
%pointer_access.anon.0 = type { double }
|
||||
%ExtraSimple = type { i32, i32, %c, %anon, %anon.0, i32 }
|
||||
%c = type { double, double, double, double, double }
|
||||
%anon = type { i32, i32 }
|
||||
%anon.0 = type { double }
|
||||
|
||||
@ExtraSimple = linkonce_odr constant i8 1
|
||||
|
||||
entry:
|
||||
%a = alloca %pointer_access.ExtraSimple, align 8
|
||||
%0 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 0
|
||||
%a = alloca %ExtraSimple, align 8
|
||||
%0 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 0
|
||||
store i32 0, i32* %0, align 8
|
||||
%1 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 1
|
||||
%1 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 1
|
||||
store i32 0, i32* %1, align 4
|
||||
%2 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 2
|
||||
%3 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %2, i32 0, i32 0
|
||||
%2 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 2
|
||||
%3 = getelementptr inbounds %c, %c* %2, i32 0, i32 0
|
||||
store double 0.000000e+00, double* %3, align 8
|
||||
%4 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %2, i32 0, i32 1
|
||||
%4 = getelementptr inbounds %c, %c* %2, i32 0, i32 1
|
||||
store double 0.000000e+00, double* %4, align 8
|
||||
%5 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %2, i32 0, i32 2
|
||||
%5 = getelementptr inbounds %c, %c* %2, i32 0, i32 2
|
||||
store double 0.000000e+00, double* %5, align 8
|
||||
%6 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %2, i32 0, i32 3
|
||||
%6 = getelementptr inbounds %c, %c* %2, i32 0, i32 3
|
||||
store double 0.000000e+00, double* %6, align 8
|
||||
%7 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %2, i32 0, i32 4
|
||||
%7 = getelementptr inbounds %c, %c* %2, i32 0, i32 4
|
||||
store double 3.300000e+00, double* %7, align 8
|
||||
%8 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 3
|
||||
%9 = bitcast %pointer_access.anon* %8 to i8*
|
||||
%8 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 3
|
||||
%9 = bitcast %anon* %8 to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 8 %9, i8 0, i64 8, i1 false)
|
||||
%10 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 4
|
||||
%11 = bitcast %pointer_access.anon.0* %10 to i8*
|
||||
%10 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 4
|
||||
%11 = bitcast %anon.0* %10 to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 8 %11, i8 0, i64 8, i1 false)
|
||||
%12 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 5
|
||||
%12 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 5
|
||||
store i32 0, i32* %12, align 8
|
||||
%13 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 2
|
||||
%14 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %13, i32 0, i32 4
|
||||
%13 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 2
|
||||
%14 = getelementptr inbounds %c, %c* %13, i32 0, i32 4
|
||||
store double 3.400000e+00, double* %14, align 8
|
||||
%15 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 0
|
||||
%15 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 0
|
||||
%16 = load i32, i32* %15, align 8
|
||||
%17 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 2
|
||||
%18 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %17, i32 0, i32 0
|
||||
%17 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 2
|
||||
%18 = getelementptr inbounds %c, %c* %17, i32 0, i32 0
|
||||
%19 = load double, double* %18, align 8
|
||||
%20 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 2
|
||||
%21 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %20, i32 0, i32 3
|
||||
%20 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 2
|
||||
%21 = getelementptr inbounds %c, %c* %20, i32 0, i32 3
|
||||
%22 = load double, double* %21, align 8
|
||||
%23 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 2
|
||||
%24 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %23, i32 0, i32 4
|
||||
%23 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 2
|
||||
%24 = getelementptr inbounds %c, %c* %23, i32 0, i32 4
|
||||
%25 = load double, double* %24, align 8
|
||||
%26 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 5
|
||||
%26 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 5
|
||||
%27 = load i32, i32* %26, align 8
|
||||
%28 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 4
|
||||
%29 = bitcast %pointer_access.anon.0* %28 to double*
|
||||
%28 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 4
|
||||
%29 = bitcast %anon.0* %28 to double*
|
||||
%30 = load double, double* %29, align 8
|
||||
%31 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 3
|
||||
%32 = getelementptr inbounds %pointer_access.anon, %pointer_access.anon* %31, i32 0, i32 0
|
||||
%31 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 3
|
||||
%32 = getelementptr inbounds %anon, %anon* %31, i32 0, i32 0
|
||||
%33 = load i32, i32* %32, align 8
|
||||
%34 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 3
|
||||
%35 = getelementptr inbounds %pointer_access.anon, %pointer_access.anon* %34, i32 0, i32 1
|
||||
%34 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 3
|
||||
%35 = getelementptr inbounds %anon, %anon* %34, i32 0, i32 1
|
||||
%36 = load i32, i32* %35, align 4
|
||||
call void (i8*, ...) @printf(i8* getelementptr inbounds ([71 x i8], [71 x i8]* @.str, i32 0, i32 0), i32 %16, double %19, double %22, double %25, i32 %27, double %30, i32 %33, i32 %36)
|
||||
ret void
|
||||
|
||||
@@ -101,18 +101,18 @@ if.exit:
|
||||
ret i32 %add1
|
||||
|
||||
|
||||
void @test.setInternalFPFZero(%test.InternalFPF* %0)
|
||||
%dest = alloca %test.InternalFPF*, align 8
|
||||
store %test.InternalFPF* %0, %test.InternalFPF** %dest, align 8
|
||||
%1 = load %test.InternalFPF*, %test.InternalFPF** %dest, align 8
|
||||
%2 = getelementptr inbounds %test.InternalFPF, %test.InternalFPF* %1, i32 0, i32 0
|
||||
void @test.setInternalFPFZero(%InternalFPF* %0)
|
||||
%dest = alloca %InternalFPF*, align 8
|
||||
store %InternalFPF* %0, %InternalFPF** %dest, align 8
|
||||
%1 = load %InternalFPF*, %InternalFPF** %dest, align 8
|
||||
%2 = getelementptr inbounds %InternalFPF, %InternalFPF* %1, i32 0, i32 0
|
||||
store i8 0, i8* %2, align 8
|
||||
ret void
|
||||
|
||||
void @test.denormalize(%test.InternalFPF* %0)
|
||||
void @test.denormalize(%InternalFPF* %0)
|
||||
entry:
|
||||
%ptr = alloca %test.InternalFPF*, align 8
|
||||
store %test.InternalFPF* %0, %test.InternalFPF** %ptr, align 8
|
||||
%1 = load %test.InternalFPF*, %test.InternalFPF** %ptr, align 8
|
||||
call void @test.setInternalFPFZero(%test.InternalFPF* %1)
|
||||
%ptr = alloca %InternalFPF*, align 8
|
||||
store %InternalFPF* %0, %InternalFPF** %ptr, align 8
|
||||
%1 = load %InternalFPF*, %InternalFPF** %ptr, align 8
|
||||
call void @test.setInternalFPFZero(%InternalFPF* %1)
|
||||
ret void
|
||||
|
||||
@@ -23,12 +23,12 @@ func int extract_or_test_files()
|
||||
|
||||
// #expect: test.ll
|
||||
|
||||
%test.UzGlobs = type { i8, [1 x %test.MinInfo], %test.MinInfo* }
|
||||
%test.MinInfo = type { i64, i32 }
|
||||
%UzGlobs = type { i8, [1 x %MinInfo], %MinInfo* }
|
||||
%MinInfo = type { i64, i32 }
|
||||
|
||||
@g = external global %test.UzGlobs, align 8
|
||||
@g = external global %UzGlobs, align 8
|
||||
|
||||
entry:
|
||||
store %test.MinInfo* getelementptr inbounds (%test.UzGlobs, %test.UzGlobs* @g, i32 0, i32 1, i32 0), %test.MinInfo** getelementptr inbounds (%test.UzGlobs, %test.UzGlobs* @g, i32 0, i32 2), align 8
|
||||
store %MinInfo* getelementptr inbounds (%UzGlobs, %UzGlobs* @g, i32 0, i32 1, i32 0), %MinInfo** getelementptr inbounds (%UzGlobs, %UzGlobs* @g, i32 0, i32 2), align 8
|
||||
ret i32 0
|
||||
}
|
||||
@@ -10,5 +10,5 @@ struct Foo
|
||||
|
||||
// #expect: test.ll
|
||||
|
||||
%test.Foo = type { i32, double }
|
||||
@test.a = protected global %test.Foo zeroinitializer, align 8
|
||||
%Foo = type { i32, double }
|
||||
@test.a = protected global %Foo zeroinitializer, align 8
|
||||
@@ -14,11 +14,11 @@ func void test1()
|
||||
|
||||
// #expect: test.ll
|
||||
|
||||
%test.Point = type { i32, i32 }
|
||||
%Point = type { i32, i32 }
|
||||
@Point = linkonce_odr constant i8 1
|
||||
|
||||
entry:
|
||||
%p = alloca %test.Point, align 4
|
||||
%0 = bitcast %test.Point* %p to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast (%test.Point* @.__const to i8*), i32 8, i1 false)
|
||||
%p = alloca %Point, align 4
|
||||
%0 = bitcast %Point* %p to i8*
|
||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast (%Point* @.__const to i8*), i32 8, i1 false)
|
||||
|
||||
|
||||
@@ -22,18 +22,18 @@ func void test()
|
||||
|
||||
// #expect: struct_codegen_empty.ll
|
||||
|
||||
%a = alloca %struct_codegen_empty.StructA, align 4
|
||||
%a2 = alloca %struct_codegen_empty.StructA, align 4
|
||||
%b = alloca %struct_codegen_empty.StructB, align 4
|
||||
%b2 = alloca %struct_codegen_empty.StructB, align 4
|
||||
%b3 = alloca %struct_codegen_empty.StructB, align 4
|
||||
%0 = bitcast %struct_codegen_empty.StructA* %a to i8*
|
||||
%a = alloca %StructA, align 4
|
||||
%a2 = alloca %StructA, align 4
|
||||
%b = alloca %StructB, align 4
|
||||
%b2 = alloca %StructB, align 4
|
||||
%b3 = alloca %StructB, align 4
|
||||
%0 = bitcast %StructA* %a to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 0, i64 4, i1 false)
|
||||
%1 = bitcast %struct_codegen_empty.StructA* %a2 to i8*
|
||||
%1 = bitcast %StructA* %a2 to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 4 %1, i8 0, i64 4, i1 false)
|
||||
%2 = bitcast %struct_codegen_empty.StructB* %b to i8*
|
||||
%2 = bitcast %StructB* %b to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 4 %2, i8 0, i64 4, i1 false)
|
||||
%3 = bitcast %struct_codegen_empty.StructB* %b2 to i8*
|
||||
%3 = bitcast %StructB* %b2 to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 4 %3, i8 0, i64 4, i1 false)
|
||||
%4 = bitcast %struct_codegen_empty.StructB* %b3 to i8*
|
||||
%4 = bitcast %StructB* %b3 to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 4 %4, i8 0, i64 4, i1 false)
|
||||
@@ -19,15 +19,15 @@ Foo foo8 = FOO7;
|
||||
|
||||
// #expect: structo.ll
|
||||
|
||||
%structo.Foo = type { i32, i64 }
|
||||
%Foo = type { i32, i64 }
|
||||
|
||||
@Foo = linkonce_odr constant i8 1
|
||||
@structo.x = protected global i64 16, align 8
|
||||
@structo.foo1 = protected global %structo.Foo { i32 1, i64 2 }, align 8
|
||||
@structo.foo2 = protected global %structo.Foo { i32 2, i64 0 }, align 8
|
||||
@structo.foo3 = protected global %structo.Foo { i32 0, i64 3 }, align 8
|
||||
@structo.foo4 = protected global %structo.Foo { i32 4, i64 1 }, align 8
|
||||
@structo.foo5 = protected global %structo.Foo zeroinitializer, align 8
|
||||
@structo.foo6 = protected global %structo.Foo zeroinitializer, align 8
|
||||
@structo.FOO7 = protected constant %structo.Foo { i32 1, i64 2 }, align 8
|
||||
@structo.foo8 = protected global %structo.Foo { i32 1, i64 2 }, align 8
|
||||
@structo.foo1 = protected global %Foo { i32 1, i64 2 }, align 8
|
||||
@structo.foo2 = protected global %Foo { i32 2, i64 0 }, align 8
|
||||
@structo.foo3 = protected global %Foo { i32 0, i64 3 }, align 8
|
||||
@structo.foo4 = protected global %Foo { i32 4, i64 1 }, align 8
|
||||
@structo.foo5 = protected global %Foo zeroinitializer, align 8
|
||||
@structo.foo6 = protected global %Foo zeroinitializer, align 8
|
||||
@structo.FOO7 = protected constant %Foo { i32 1, i64 2 }, align 8
|
||||
@structo.foo8 = protected global %Foo { i32 1, i64 2 }, align 8
|
||||
|
||||
@@ -69,34 +69,34 @@ public Foo6 foo6 = { 1, 2, 3 };
|
||||
|
||||
// #expect: struct2.ll
|
||||
|
||||
%struct2.Foo1 = type <{ i64, i8, [3 x i8] }>
|
||||
%struct2.Foo2 = type <{ i8, i64, [3 x i8] }>
|
||||
%struct2.Foo3 = type <{ i8, i64, [7 x i8] }>
|
||||
%struct2.Foo4 = type <{ i8, i64 }>
|
||||
%struct2.Foo5 = type { i32, [12 x i8], i8, [15 x i8] }
|
||||
%struct2.Foo6 = type { i32, i16, i16 }
|
||||
%Foo1 = type <{ i64, i8, [3 x i8] }>
|
||||
%Foo2 = type <{ i8, i64, [3 x i8] }>
|
||||
%Foo3 = type <{ i8, i64, [7 x i8] }>
|
||||
%Foo4 = type <{ i8, i64 }>
|
||||
%Foo5 = type { i32, [12 x i8], i8, [15 x i8] }
|
||||
%Foo6 = type { i32, i16, i16 }
|
||||
|
||||
@struct2.foo1 = global %struct2.Foo1 <{ i64 1, i8 2, [3 x i8] undef }>, align 4
|
||||
@struct2.foo2 = global %struct2.Foo2 <{ i8 1, i64 2, [3 x i8] undef }>, align 4
|
||||
@struct2.foo3 = global %struct2.Foo3 <{ i8 1, i64 2, [7 x i8] undef }>, align 8
|
||||
@struct2.foo4 = global %struct2.Foo4 <{ i8 1, i64 2 }>, align 1
|
||||
@struct2.foo5 = global %struct2.Foo5 { i32 1, [12 x i8] undef, i8 2, [15 x i8] undef }, align 16
|
||||
@struct2.foo6 = global %struct2.Foo6 { i32 1, i16 2, i16 3 }, align 1
|
||||
@struct2.foo1 = global %Foo1 <{ i64 1, i8 2, [3 x i8] undef }>, align 4
|
||||
@struct2.foo2 = global %Foo2 <{ i8 1, i64 2, [3 x i8] undef }>, align 4
|
||||
@struct2.foo3 = global %Foo3 <{ i8 1, i64 2, [7 x i8] undef }>, align 8
|
||||
@struct2.foo4 = global %Foo4 <{ i8 1, i64 2 }>, align 1
|
||||
@struct2.foo5 = global %Foo5 { i32 1, [12 x i8] undef, i8 2, [15 x i8] undef }, align 16
|
||||
@struct2.foo6 = global %Foo6 { i32 1, i16 2, i16 3 }, align 1
|
||||
|
||||
@struct2.test5
|
||||
entry:
|
||||
%x = alloca i8, align 1
|
||||
%y = alloca %struct2.Foo5, align 16
|
||||
%y = alloca %Foo5, align 16
|
||||
store i8 %0, i8* %x, align 1
|
||||
%1 = bitcast %struct2.Foo5* %y to i8*
|
||||
%1 = bitcast %Foo5* %y to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 16 %1, i8 0, i64 32, i1 false)
|
||||
%2 = getelementptr inbounds %struct2.Foo5, %struct2.Foo5* %y, i32 0, i32 2
|
||||
%2 = getelementptr inbounds %Foo5, %Foo5* %y, i32 0, i32 2
|
||||
%3 = load i8, i8* %x, align 1
|
||||
store i8 %3, i8* %2, align 16
|
||||
%4 = getelementptr inbounds %struct2.Foo5, %struct2.Foo5* %y, i32 0, i32 2
|
||||
%4 = getelementptr inbounds %Foo5, %Foo5* %y, i32 0, i32 2
|
||||
%5 = load i8, i8* %4, align 16
|
||||
%sisiext = sext i8 %5 to i32
|
||||
%6 = getelementptr inbounds %struct2.Foo5, %struct2.Foo5* %y, i32 0, i32 0
|
||||
%6 = getelementptr inbounds %Foo5, %Foo5* %y, i32 0, i32 0
|
||||
%7 = load i32, i32* %6, align 16
|
||||
%add = add i32 %sisiext, %7
|
||||
ret i32 %add
|
||||
|
||||
@@ -14,7 +14,7 @@ Foo i = { .b = 2.3, .a = 23 };
|
||||
// #expect: test.ll
|
||||
|
||||
@test.f = protected global { i32, [4 x i8] } { i32 23, [4 x i8] undef }, align 8
|
||||
@test.g = protected global %test.Foo { double 2.300000e+00 }, align 8
|
||||
@test.h = protected global %test.Foo { double 2.300000e+00 }, align 8
|
||||
@test.g = protected global %Foo { double 2.300000e+00 }, align 8
|
||||
@test.h = protected global %Foo { double 2.300000e+00 }, align 8
|
||||
@test.i = protected global { i32, [4 x i8] } { i32 23, [4 x i8] undef }, align 8
|
||||
|
||||
|
||||
@@ -25,21 +25,21 @@ func void test()
|
||||
|
||||
// #expect: union_codegen_empty.ll
|
||||
|
||||
%a = alloca %union_codegen_empty.UnionA, align 4
|
||||
%a2 = alloca %union_codegen_empty.UnionA, align 4
|
||||
%b = alloca %union_codegen_empty.UnionB, align 8
|
||||
%b2 = alloca %union_codegen_empty.UnionB, align 8
|
||||
%b3 = alloca %union_codegen_empty.UnionB, align 8
|
||||
%b4 = alloca %union_codegen_empty.UnionB, align 8
|
||||
%0 = bitcast %union_codegen_empty.UnionA* %a to i8*
|
||||
%a = alloca %UnionA, align 4
|
||||
%a2 = alloca %UnionA, align 4
|
||||
%b = alloca %UnionB, align 8
|
||||
%b2 = alloca %UnionB, align 8
|
||||
%b3 = alloca %UnionB, align 8
|
||||
%b4 = alloca %UnionB, align 8
|
||||
%0 = bitcast %UnionA* %a to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 0, i64 4, i1 false)
|
||||
%1 = bitcast %union_codegen_empty.UnionA* %a2 to i8*
|
||||
%1 = bitcast %UnionA* %a2 to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 4 %1, i8 0, i64 4, i1 false)
|
||||
%2 = bitcast %union_codegen_empty.UnionB* %b to i8*
|
||||
%2 = bitcast %UnionB* %b to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 8 %2, i8 0, i64 8, i1 false)
|
||||
%3 = bitcast %union_codegen_empty.UnionB* %b2 to i8*
|
||||
%3 = bitcast %UnionB* %b2 to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 8 %3, i8 0, i64 8, i1 false)
|
||||
%4 = bitcast %union_codegen_empty.UnionB* %b3 to i8*
|
||||
%4 = bitcast %UnionB* %b3 to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 8 %4, i8 0, i64 8, i1 false)
|
||||
%5 = bitcast %union_codegen_empty.UnionB* %b4 to i8*
|
||||
%5 = bitcast %UnionB* %b4 to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 8 %5, i8 0, i64 8, i1 false)
|
||||
|
||||
@@ -20,12 +20,12 @@ func void test()
|
||||
// #expect: test.ll
|
||||
|
||||
entry:
|
||||
%b = alloca %test.UnionB, align 8
|
||||
%0 = bitcast %test.UnionB* %b to i32*
|
||||
%b = alloca %UnionB, align 8
|
||||
%0 = bitcast %UnionB* %b to i32*
|
||||
%1 = call i32 @bar()
|
||||
store i32 %1, i32* %0, align 4
|
||||
%2 = bitcast %test.UnionB* %b to %test.b*
|
||||
%3 = bitcast %test.b* %2 to i8*
|
||||
%2 = bitcast %UnionB* %b to %b*
|
||||
%3 = bitcast %b* %2 to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 4 %3, i8 0, i64 4, i1 false)
|
||||
ret void
|
||||
|
||||
|
||||
@@ -20,10 +20,10 @@ func void test(Blend_Map_Entry* foo)
|
||||
// #expect: test.ll
|
||||
|
||||
|
||||
%test.Blend_Map_Entry = type { %test.vals }
|
||||
%test.vals = type { [2 x double], [8 x i8] }
|
||||
%Blend_Map_Entry = type { %vals }
|
||||
%vals = type { [2 x double], [8 x i8] }
|
||||
|
||||
@test.a = protected global { { [5 x float], [4 x i8] } } { { [5 x float], [4 x i8] } { [5 x float] [float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00, float 5.000000e+00], [4 x i8] undef } }, align 8
|
||||
@test.b = protected global %test.Blend_Map_Entry { %test.vals { [2 x double] [double 6.000000e+00, double 7.000000e+00], [8 x i8] undef } }, align 8
|
||||
@test.b = protected global %Blend_Map_Entry { %vals { [2 x double] [double 6.000000e+00, double 7.000000e+00], [8 x i8] undef } }, align 8
|
||||
@test.c = protected global { { { [2 x float], float, [2 x float] }, [4 x i8] } } { { { [2 x float], float, [2 x float] }, [4 x i8] } { { [2 x float], float, [2 x float] } { [2 x float] zeroinitializer, float 1.000000e+00, [2 x float] zeroinitializer }, [4 x i8] undef } }, align 8
|
||||
@test.d = protected global { { [5 x float], [4 x i8] } } { { [5 x float], [4 x i8] } { [5 x float] [float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00, float 5.000000e+00], [4 x i8] undef } }, align 8
|
||||
|
||||
Reference in New Issue
Block a user