Changed generic modules to internal templates.

This commit is contained in:
Christoffer Lerno
2021-05-26 22:50:27 +02:00
committed by Christoffer Lerno
parent b99f8d644b
commit 892c7e8874
41 changed files with 601 additions and 502 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1 +1 @@
#define COMPILER_VERSION "A223"
#define COMPILER_VERSION "A224"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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