Add @local and fix visibility issues for generic methods.

This commit is contained in:
Christoffer Lerno
2023-02-14 12:08:14 +01:00
committed by Christoffer Lerno
parent 8184fba34b
commit 03cd56e46b
20 changed files with 295 additions and 127 deletions

View File

@@ -436,6 +436,16 @@ bool ast_is_compile_time(Ast *ast)
}
}
bool decl_is_externally_visible(Decl *decl)
{
return decl->is_external_visible || decl->visibility == VISIBLE_PUBLIC || decl->is_export;
}
bool decl_is_local(Decl *decl)
{
return !decl->is_external_visible && decl->visibility != VISIBLE_PUBLIC && !decl->is_export;
}
Decl *decl_find_enum_constant(Decl *decl, const char *name)
{
VECEACH(decl->enums.values, i)

View File

@@ -659,9 +659,9 @@ typedef struct Decl_
SourceSpan span;
DeclKind decl_kind : 7;
ResolveStatus resolve_status : 3;
Visibility visibility : 3;
bool is_packed : 1;
bool is_extern : 1;
bool is_private : 1;
bool is_substruct : 1;
bool has_variable_array : 1;
bool is_value : 1;
@@ -1599,6 +1599,7 @@ struct CompilationUnit_
Decl *main_function;
HTable local_symbols;
int lambda_count;
Decl **local_method_extensions;
struct
{
void *debug_file;
@@ -2119,10 +2120,12 @@ INLINE Decl *decl_flatten(Decl *decl);
INLINE const char *decl_get_extname(Decl *decl);
static inline Decl *decl_raw(Decl *decl);
static inline DeclKind decl_from_token(TokenType type);
static inline bool decl_is_local(Decl *decl);
static inline bool decl_is_var_local(Decl *decl);
bool decl_is_ct_var(Decl *decl);
Decl *decl_find_enum_constant(Decl *decl, const char *name);
AlignSize decl_find_member_offset(Decl *decl, Decl *member);
bool decl_is_externally_visible(Decl *decl);
bool decl_is_local(Decl *decl);
// --- Expression functions
@@ -2240,7 +2243,7 @@ Decl *sema_find_decl_in_modules(Module **module_list, Path *path, const char *in
Decl *unit_resolve_parameterized_symbol(CompilationUnit *unit, NameResolve *name_resolve);
Decl *sema_resolve_type_method(CompilationUnit *unit, Type *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref);
Decl *sema_resolve_method(CompilationUnit *unit, Decl *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref);
Decl *sema_find_extension_method_in_module(Decl **extensions, Type *type, const char *method_name);
Decl *sema_find_extension_method_in_list(Decl **extensions, Type *type, const char *method_name);
bool sema_resolve_type_decl(SemaContext *context, Type *type);
Decl *sema_find_symbol(SemaContext *context, const char *symbol);
@@ -3231,7 +3234,7 @@ INLINE bool decl_var_kind_is_ct(VarDeclKind kind)
return kind >= VARDECL_FIRST_CT && kind <= VARDECL_LAST_CT;
}
static inline bool decl_is_local(Decl *decl)
static inline bool decl_is_var_local(Decl *decl)
{
if (decl->decl_kind != DECL_VAR) return false;
VarDeclKind kind = decl->var.kind;

View File

@@ -129,7 +129,7 @@ void unit_register_external_symbol(CompilationUnit *unit, Decl *decl)
void decl_register(Decl *decl)
{
if (decl->is_private) return;
if (decl->visibility > VISIBLE_PUBLIC) return;
switch (decl->decl_kind)
{
case DECL_INITIALIZE:

View File

@@ -719,15 +719,14 @@ typedef enum
VARDECL_LAST_CT = VARDECL_LOCAL_CT_TYPE,
} VarDeclKind;
typedef enum
{
VISIBLE_LOCAL,
VISIBLE_MODULE,
VISIBLE_PUBLIC,
VISIBLE_EXTERN,
VISIBLE_PRIVATE,
VISIBLE_LOCAL,
} Visibility;
typedef enum
{
ATTR_FUNC = 1 << 0,
@@ -769,6 +768,7 @@ typedef enum
ATTRIBUTE_EXTNAME,
ATTRIBUTE_INLINE,
ATTRIBUTE_LITTLEENDIAN,
ATTRIBUTE_LOCAL,
ATTRIBUTE_MAYDISCARD,
ATTRIBUTE_NAKED,
ATTRIBUTE_NODISCARD,

View File

@@ -332,7 +332,7 @@ void llvm_set_global_tls(Decl *decl)
{
if (!decl->var.is_threadlocal) return;
LLVMThreadLocalMode thread_local_mode = LLVMGeneralDynamicTLSModel;
if (!decl->var.is_addr && decl->is_private && !decl->is_external_visible)
if (!decl->var.is_addr && decl_is_local(decl))
{
thread_local_mode = LLVMLocalDynamicTLSModel;
}
@@ -411,9 +411,8 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl)
}
else
{
LLVMUnnamedAddr addr = LLVMGlobalUnnamedAddr;
if (!decl->is_private || decl->is_external_visible) addr = LLVMLocalUnnamedAddr;
LLVMSetUnnamedAddress(decl->backend_ref, addr);
LLVMSetUnnamedAddress(decl->backend_ref,
decl_is_local(decl) ? LLVMGlobalUnnamedAddr : LLVMLocalUnnamedAddr);
}
if (decl->section)
{
@@ -447,7 +446,12 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl)
LLVMSetLinkage(global_ref, LLVMExternalLinkage);
if (optional_ref) LLVMSetLinkage(optional_ref, LLVMExternalLinkage);
}
else if (decl->is_private && !decl->is_external_visible)
else if (decl_is_externally_visible(decl))
{
LLVMSetVisibility(global_ref, LLVMDefaultVisibility);
if (optional_ref) LLVMSetVisibility(optional_ref, LLVMDefaultVisibility);
}
else
{
if (decl->var.kind == VARDECL_CONST || decl->var.kind == VARDECL_GLOBAL)
{
@@ -460,11 +464,6 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl)
if (optional_ref) LLVMSetLinkage(optional_ref, LLVMInternalLinkage);
}
}
else
{
LLVMSetVisibility(global_ref, LLVMDefaultVisibility);
if (optional_ref) LLVMSetVisibility(optional_ref, LLVMDefaultVisibility);
}
decl->backend_ref = global_ref;
LLVMReplaceAllUsesWith(old, global_ref);
@@ -752,24 +751,6 @@ void llvm_set_weak(GenContext *c, LLVMValueRef global)
llvm_set_comdat(c, global);
}
void llvm_set_linkage(GenContext *c, Decl *decl, LLVMValueRef value)
{
if (decl->unit->module != c->code_module)
{
llvm_set_linkonce(c, value);
return;
}
if (decl->is_private && !decl->is_external_visible)
{
LLVMSetVisibility(value, LLVMHiddenVisibility);
LLVMSetLinkage(value, LLVMLinkerPrivateLinkage);
}
else
{
llvm_set_linkonce(c, value);
}
}
void llvm_value_set_int(GenContext *c, BEValue *value, Type *type, uint64_t i)
{
@@ -1067,8 +1048,9 @@ LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl)
case DECL_FUNC:
backend_ref = decl->backend_ref = LLVMAddFunction(c->module, decl_get_extname(decl), llvm_get_type(c, decl->type));
llvm_append_function_attributes(c, decl);
if (decl->unit->module == c->code_module && !decl->is_external_visible && decl->is_private)
if (decl_is_local(decl))
{
assert(decl->unit->module == c->code_module);
llvm_set_internal_linkage(backend_ref);
}
return backend_ref;

View File

@@ -98,7 +98,7 @@ void llvm_emit_debug_global_var(GenContext *c, Decl *global)
c->debug.file,
loc.row ? loc.row : 1,
llvm_get_debug_type(c, global->type),
global->is_private,
decl_is_local(global),
LLVMDIBuilderCreateExpression(c->debug.builder, NULL, 0),
NULL,
global->alignment);
@@ -108,13 +108,13 @@ void llvm_emit_debug_function(GenContext *c, Decl *decl)
{
LLVMDIFlags flags = LLVMDIFlagZero;
if (!decl->func_decl.body) return;
if (decl->is_private)
if (decl_is_externally_visible(decl))
{
flags |= LLVMDIFlagPrivate;
flags |= LLVMDIFlagPublic;
}
else
{
flags |= LLVMDIFlagPublic;
flags |= LLVMDIFlagPrivate;
}
flags |= LLVMDIFlagPrototyped;
if (decl->func_decl.signature.attrs.noreturn) flags |= LLVMDIFlagNoReturn;
@@ -128,7 +128,7 @@ void llvm_emit_debug_function(GenContext *c, Decl *decl)
c->debug.file,
row,
llvm_get_debug_type(c, decl->type),
decl->is_private,
decl_is_local(decl),
true,
row,
flags,

View File

@@ -634,7 +634,7 @@ void llvm_emit_function_decl(GenContext *c, Decl *decl)
LLVMSetVisibility(function, LLVMDefaultVisibility);
return;
}
if (decl->is_private && !decl->is_external_visible)
if (decl_is_local(decl))
{
LLVMSetLinkage(function, decl->is_weak ? LLVMLinkerPrivateWeakLinkage : LLVMInternalLinkage);
LLVMSetVisibility(function, LLVMDefaultVisibility);

View File

@@ -302,7 +302,6 @@ void llvm_attribute_add_int(GenContext *c, LLVMValueRef value_to_add_attribute_t
void llvm_set_linkonce(GenContext *c, LLVMValueRef global);
void llvm_set_comdat(GenContext *c, LLVMValueRef global);
void llvm_set_weak(GenContext *c, LLVMValueRef global);
void llvm_set_linkage(GenContext *c, Decl *decl, LLVMValueRef value);
void llvm_set_private_linkage(LLVMValueRef alloc);
void llvm_set_internal_linkage(LLVMValueRef alloc);
void llvm_set_global_tls(Decl *decl);

View File

@@ -342,7 +342,7 @@ static Expr *parse_lambda(ParseContext *c, Expr *left)
advance_and_verify(c, TOKEN_FN);
Decl *func = decl_calloc();
func->decl_kind = DECL_FUNC;
func->is_private = true;
func->visibility = VISIBLE_LOCAL;
func->func_decl.generated_lambda = NULL;
TypeInfo *return_type = NULL;
if (!tok_is(c, TOKEN_LPAREN))

View File

@@ -826,7 +826,7 @@ Decl *parse_local_decl(ParseContext *c)
if (tok_is(c, TOKEN_CONST))
{
ASSIGN_DECL_OR_RET(Decl *decl, parse_const_declaration(c), poisoned_decl);
decl->is_private = true;
decl->visibility = VISIBLE_LOCAL;
return decl;
}
@@ -843,7 +843,7 @@ Decl *parse_local_decl(ParseContext *c)
}
decl->var.is_static = is_static || is_threadlocal;
decl->var.is_threadlocal = is_threadlocal;
decl->is_private = true;
decl->visibility = VISIBLE_LOCAL;
return decl;
}
@@ -1045,7 +1045,28 @@ bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Decl *owner)
SEMA_ERROR(attr, "'%s' cannot be used here.");
return false;
}
owner->is_private = true;
if (owner->visibility != VISIBLE_PUBLIC)
{
SEMA_ERROR(attr, "Only a single visibility attribute may be added.");
return false;
}
owner->visibility = VISIBLE_PRIVATE;
continue;
}
if (name == attribute_list[ATTRIBUTE_LOCAL])
{
if (!owner)
{
SEMA_ERROR(attr, "'%s' cannot be used here.");
return false;
}
if (owner->visibility != VISIBLE_PUBLIC)
{
SEMA_ERROR(attr, "Only a single visibility attribute may be added.");
return false;
}
owner->visibility = VISIBLE_LOCAL;
continue;
}
FOREACH_BEGIN(Attr *other_attr, *attributes_ref)
if (other_attr->name == name)
@@ -2073,7 +2094,7 @@ static inline Decl *parse_fault_declaration(ParseContext *c, bool is_private)
// advance_and_verify(context, TOKEN_ERRTYPE);
Decl *decl = decl_new_with_type(symstr(c), c->span, DECL_FAULT);
decl->is_private = is_private;
if (is_private) decl->visibility = VISIBLE_PRIVATE;
if (!consume_type_name(c, "fault")) return poisoned_decl;
TypeInfo *type = NULL;
@@ -2085,7 +2106,7 @@ static inline Decl *parse_fault_declaration(ParseContext *c, bool is_private)
while (!try_consume(c, TOKEN_RBRACE))
{
Decl *fault_const = decl_new(DECL_FAULTVALUE, symstr(c), c->span);
fault_const->is_private = is_private;
if (is_private) decl->visibility = VISIBLE_PRIVATE;
if (!consume_const_name(c, "fault value"))
{
return poisoned_decl;
@@ -2171,7 +2192,7 @@ static inline Decl *parse_enum_declaration(ParseContext *c, bool is_private)
advance_and_verify(c, TOKEN_ENUM);
Decl *decl = decl_new_with_type(symstr(c), c->span, DECL_ENUM);
decl->is_private = is_private;
if (is_private) decl->visibility = VISIBLE_PRIVATE;
if (!consume_type_name(c, "enum")) return poisoned_decl;
TypeInfo *type = NULL;
@@ -2181,14 +2202,14 @@ static inline Decl *parse_enum_declaration(ParseContext *c, bool is_private)
}
if (!parse_attributes(c, &decl->attributes, decl)) return poisoned_decl;
Visibility visibility = decl->visibility;
CONSUME_OR_RET(TOKEN_LBRACE, poisoned_decl);
decl->enums.type_info = type ? type : type_info_new_base(type_int, decl->span);
while (!try_consume(c, TOKEN_RBRACE))
{
Decl *enum_const = decl_new(DECL_ENUM_CONSTANT, symstr(c), c->span);
enum_const->is_private = is_private;
enum_const->visibility = visibility;
const char *name = enum_const->name;
if (!consume_const_name(c, "enum constant"))
{
@@ -2373,6 +2394,11 @@ static inline bool parse_import(ParseContext *c)
Path *path = parse_module_path(c);
if (!path) return false;
unit_add_import(c->unit, path, private);
if (tok_is(c, TOKEN_COLON) && peek(c) == TOKEN_IDENT)
{
SEMA_ERROR_HERE("'::' was expected here, did you make a mistake?");
return false;
}
if (!try_consume(c, TOKEN_COMMA)) break;
}
@@ -2777,13 +2803,13 @@ AFTER_VISIBILITY:
case TOKEN_DEFINE:
{
ASSIGN_DECL_OR_RET(decl, parse_define(c), poisoned_decl);
if (is_private) decl->is_private = is_private;
if (is_private) decl->visibility = VISIBLE_PRIVATE;
break;
}
case TOKEN_FN:
{
ASSIGN_DECL_OR_RET(decl, parse_func_definition(c, docs, false), poisoned_decl);
if (is_private) decl->is_private = is_private;
if (is_private) decl->visibility = VISIBLE_PRIVATE;
break;
}
case TOKEN_STATIC:
@@ -2871,45 +2897,43 @@ AFTER_VISIBILITY:
case TOKEN_BITSTRUCT:
{
ASSIGN_DECL_OR_RET(decl, parse_bitstruct_declaration(c), poisoned_decl);
if (is_private) decl->is_private = is_private;
if (is_private) decl->visibility = VISIBLE_PRIVATE;
break;
}
case TOKEN_CONST:
{
ASSIGN_DECL_OR_RET(decl, parse_top_level_const_declaration(c), poisoned_decl);
if (is_private) decl->is_private = is_private;
if (is_private) decl->visibility = VISIBLE_PRIVATE;
break;
}
case TOKEN_STRUCT:
case TOKEN_UNION:
{
ASSIGN_DECL_OR_RET(decl, parse_struct_declaration(c), poisoned_decl);
if (is_private) decl->is_private = is_private;
if (is_private) decl->visibility = VISIBLE_PRIVATE;
break;
}
case TOKEN_GENERIC:
case TOKEN_MACRO:
{
ASSIGN_DECL_OR_RET(decl, parse_macro_declaration(c, docs), poisoned_decl);
if (is_private) decl->is_private = is_private;
if (is_private) decl->visibility = VISIBLE_PRIVATE;
break;
}
case TOKEN_ENUM:
{
ASSIGN_DECL_OR_RET(decl, parse_enum_declaration(c, is_private), poisoned_decl);
if (is_private) decl->is_private = is_private;
break;
}
case TOKEN_FAULT:
{
ASSIGN_DECL_OR_RET(decl, parse_fault_declaration(c, is_private), poisoned_decl);
if (is_private) decl->is_private = is_private;
break;
}
case TOKEN_IDENT:
{
ASSIGN_DECL_OR_RET(decl, parse_global_declaration(c), poisoned_decl);
if (is_private) decl->is_private = is_private;
if (is_private) decl->visibility = VISIBLE_PRIVATE;
break;
}
case TOKEN_EOF:
@@ -2931,7 +2955,7 @@ AFTER_VISIBILITY:
case TYPELIKE_TOKENS:
{
ASSIGN_DECL_OR_RET(decl, parse_global_declaration(c), poisoned_decl);
if (is_private) decl->is_private = is_private;
if (is_private) decl->visibility = VISIBLE_PRIVATE;
break;
}
case TOKEN_EOS:

View File

@@ -101,13 +101,13 @@ static inline Ast *parse_declaration_stmt(ParseContext *c)
{
result->declare_stmt->var.is_threadlocal = is_threadlocal;
result->declare_stmt->var.is_static = is_static || is_threadlocal;
result->declare_stmt->is_private = true;
result->declare_stmt->visibility = VISIBLE_LOCAL;
return result;
}
FOREACH_BEGIN(Decl *var, result->decls_stmt)
var->var.is_threadlocal = is_threadlocal;
var->var.is_static = is_static || is_threadlocal;
var->is_private = true;
var->visibility = VISIBLE_LOCAL;
FOREACH_END();
return result;
}

View File

@@ -1282,34 +1282,48 @@ static bool sema_check_operator_method_validity(Decl *method)
UNREACHABLE
}
static inline bool unit_add_base_extension_method(CompilationUnit *unit, Type *parent_type, Decl *method_like)
INLINE void sema_set_method_ext_name(CompilationUnit *unit, const char *parent_name, Decl *method_like)
{
if (!method_like->has_extname)
if (method_like->has_extname) return;
scratch_buffer_clear();
switch (method_like->visibility)
{
scratch_buffer_clear();
if (method_like->is_private)
{
scratch_buffer_append(parent_type->name);
scratch_buffer_append_char('$');
scratch_buffer_append(method_like->name);
}
else
{
scratch_buffer_append(parent_type->name);
case VISIBLE_PUBLIC:
scratch_buffer_append(parent_name);
scratch_buffer_append("_");
scratch_buffer_append(method_like->name);
}
method_like->extname = scratch_buffer_copy();
break;
case VISIBLE_PRIVATE:
scratch_buffer_append(parent_name);
scratch_buffer_append_char('$');
scratch_buffer_append(method_like->name);
break;
case VISIBLE_LOCAL:
scratch_buffer_append(unit->file->name);
scratch_buffer_append_char('.');
scratch_buffer_append(parent_name);
scratch_buffer_append_char('.');
scratch_buffer_append(method_like->name);
break;
}
method_like->extname = scratch_buffer_copy();
}
static inline bool unit_add_base_extension_method(CompilationUnit *unit, Type *parent_type, Decl *method_like)
{
sema_set_method_ext_name(unit, parent_type->name, method_like);
switch (method_like->visibility)
{
case VISIBLE_PUBLIC:
vec_add(global_context.method_extensions, method_like);
break;
case VISIBLE_PRIVATE:
vec_add(unit->module->private_method_extensions, method_like);
break;
case VISIBLE_LOCAL:
vec_add(unit->local_method_extensions, method_like);
break;
}
DEBUG_LOG("Method-like '%s.%s' analysed.", parent_type->name, method_like->name);
if (method_like->is_private)
{
vec_add(unit->module->private_method_extensions, method_like);
}
else
{
vec_add(global_context.method_extensions, method_like);
}
return true;
}
@@ -1317,8 +1331,9 @@ static inline bool unit_add_method_like(CompilationUnit *unit, Type *parent_type
{
assert(parent_type->canonical == parent_type);
const char *name = method_like->name;
Decl *method = sema_find_extension_method_in_module(unit->module->private_method_extensions, parent_type, name);
if (!method) sema_find_extension_method_in_module(global_context.method_extensions, parent_type, name);
Decl *method = sema_find_extension_method_in_list(unit->local_method_extensions, parent_type, name);
if (!method) sema_find_extension_method_in_list(unit->module->private_method_extensions, parent_type, name);
if (!method) sema_find_extension_method_in_list(global_context.method_extensions, parent_type, name);
if (method)
{
SEMA_ERROR(method_like, "This %s is already defined.", method_name_by_decl(method_like));
@@ -1340,31 +1355,31 @@ static inline bool unit_add_method_like(CompilationUnit *unit, Type *parent_type
}
if (method_like->operator && !sema_check_operator_method_validity(method_like)) return false;
REMINDER("Check multiple operator");
if (!method_like->has_extname)
{
scratch_buffer_clear();
if (method_like->is_private)
{
scratch_buffer_append(parent->extname);
scratch_buffer_append_char('$');
scratch_buffer_append(method_like->name);
}
else
{
scratch_buffer_append(parent->extname);
scratch_buffer_append("_");
scratch_buffer_append(method_like->name);
}
method_like->extname = scratch_buffer_copy();
}
sema_set_method_ext_name(unit, parent->extname, method_like);
DEBUG_LOG("Method-like '%s.%s' analysed.", parent->name, method_like->name);
if (parent->unit->module == unit->module || !method_like->is_private)
switch (method_like->visibility)
{
vec_add(parent->methods, method_like);
}
else
{
vec_add(unit->module->private_method_extensions, method_like);
case VISIBLE_PUBLIC:
vec_add(parent->methods, method_like);
break;
case VISIBLE_PRIVATE:
if (parent->unit->module == unit->module && parent->visibility >= VISIBLE_PRIVATE)
{
vec_add(parent->methods, method_like);
break;
}
vec_add(unit->module->private_method_extensions, method_like);
break;
case VISIBLE_LOCAL:
if (parent->unit == unit && parent->visibility >= VISIBLE_LOCAL)
{
vec_add(parent->methods, method_like);
break;
}
vec_add(unit->local_method_extensions, method_like);
break;
default:
UNREACHABLE
}
return true;
@@ -1447,6 +1462,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
[ATTRIBUTE_EXTERN] = (AttributeDomain)~(ATTR_CALL | ATTR_BITSTRUCT | ATTR_DEFINE | ATTR_MACRO | ATTR_XXLIZER),
[ATTRIBUTE_INLINE] = ATTR_FUNC | ATTR_CALL,
[ATTRIBUTE_LITTLEENDIAN] = ATTR_BITSTRUCT,
[ATTRIBUTE_LOCAL] = ATTR_FUNC | ATTR_MACRO | ATTR_GLOBAL | ATTR_CONST | USER_DEFINED_TYPES | ATTR_DEFINE,
[ATTRIBUTE_MAYDISCARD] = ATTR_FUNC | ATTR_MACRO,
[ATTRIBUTE_NAKED] = ATTR_FUNC,
[ATTRIBUTE_NODISCARD] = ATTR_FUNC | ATTR_MACRO,
@@ -1516,7 +1532,20 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
}
break;
case ATTRIBUTE_PRIVATE:
decl->is_private = true;
if (decl->visibility != VISIBLE_PUBLIC)
{
SEMA_ERROR(decl, "Multiple visibility attributes cannot be combined.");
return false;
}
decl->visibility = VISIBLE_PRIVATE;
break;
case ATTRIBUTE_LOCAL:
if (decl->visibility != VISIBLE_PUBLIC)
{
SEMA_ERROR(decl, "Multiple visibility attributes cannot be combined.");
return false;
}
decl->visibility = VISIBLE_LOCAL;
break;
case ATTRIBUTE_TEST:
decl->func_decl.attr_test = true;
@@ -2125,9 +2154,9 @@ static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl)
assert(decl != context->unit->main_function);
bool is_winmain = decl->func_decl.attr_winmain;
bool is_win32 = platform_target.os == OS_TYPE_WIN32;
if (decl->is_private)
if (decl->visibility != VISIBLE_PUBLIC)
{
SEMA_ERROR(decl, "A main function may not be private.");
SEMA_ERROR(decl, "A main function must be public.");
return false;
}
Signature *signature = &decl->func_decl.signature;
@@ -2736,7 +2765,7 @@ static CompilationUnit *unit_copy(Module *module, CompilationUnit *unit)
static Module *module_instantiate_generic(Module *module, Path *path, Expr **params)
{
Module *new_module = compiler_find_or_create_module(path, NULL, module->is_private);
new_module->is_generic = true;
new_module->is_generic = false;
CompilationUnit **units = module->units;
VECEACH(units, i)
{

View File

@@ -3655,6 +3655,10 @@ CHECK_DEEPER:
return true;
}
Decl *private = NULL;
if (strcmp(kw, "put_all_for_create") == 0)
{
int x = 123;
}
if (!member)
{
Decl *ambiguous = NULL;
@@ -6389,7 +6393,7 @@ static inline bool sema_expr_analyse_ct_nameof(SemaContext *context, Expr *expr)
expr_rewrite_to_string(expr, decl->extname);
return true;
}
if (!decl->unit || name_type == TOKEN_CT_NAMEOF || decl_is_local(decl))
if (!decl->unit || name_type == TOKEN_CT_NAMEOF || decl_is_var_local(decl))
{
expr_rewrite_to_string(expr, decl->name);
return true;

View File

@@ -150,8 +150,10 @@ static Decl *sema_find_decl_in_imports(Decl **imports, NameResolve *name_resolve
// No match, so continue
if (!found) continue;
assert(found->visibility != VISIBLE_LOCAL);
// If we found something private but we don't import privately?
if (found->is_private && !import->import.private && !decl)
if (found->visibility == VISIBLE_PRIVATE && !import->import.private && !decl)
{
// Register this as a possible private decl.
name_resolve->private_decl = found;
@@ -568,7 +570,7 @@ INLINE Decl *sema_resolve_symbol_common(SemaContext *context, NameResolve *name_
return decl;
}
Decl *sema_find_extension_method_in_module(Decl **extensions, Type *type, const char *method_name)
Decl *sema_find_extension_method_in_list(Decl **extensions, Type *type, const char *method_name)
{
VECEACH(extensions, i)
{
@@ -592,13 +594,14 @@ Decl *sema_resolve_method_in_module(Module *module, Type *actual_type, const cha
Decl **private_found, Decl **ambiguous, MethodSearchType search_type)
{
if (module->is_generic) return NULL;
Decl *found = sema_find_extension_method_in_module(module->private_method_extensions, actual_type, method_name);
Decl *found = sema_find_extension_method_in_list(module->private_method_extensions, actual_type, method_name);
// The found one might not be visible
if (found && search_type < METHOD_SEARCH_CURRENT && found->is_private)
if (found && search_type < METHOD_SEARCH_CURRENT && found->visibility == VISIBLE_PRIVATE)
{
*private_found = found;
found = NULL;
}
assert(!found || found->visibility != VISIBLE_LOCAL);
if (found && search_type == METHOD_SEARCH_CURRENT) return found;
// We are now searching submodules, so hide the private ones.
if (search_type == METHOD_SEARCH_CURRENT) search_type = METHOD_SEARCH_SUBMODULE_CURRENT;
@@ -622,7 +625,10 @@ Decl *sema_resolve_method(CompilationUnit *unit, Decl *type, const char *method_
VECEACH(type->methods, i)
{
Decl *func = type->methods[i];
if (method_name == func->name) return func;
if (method_name == func->name)
{
return func;
}
}
return sema_resolve_type_method(unit, type->type, method_name, ambiguous_ref, private_ref);
@@ -681,7 +687,8 @@ Decl *sema_resolve_type_method(CompilationUnit *unit, Type *type, const char *me
assert(type == type->canonical);
Decl *private = NULL;
Decl *ambiguous = NULL;
Decl *found = sema_resolve_method_in_module(unit->module, type, method_name, &private, &ambiguous, METHOD_SEARCH_CURRENT);
Decl *found = sema_find_extension_method_in_list(unit->local_method_extensions, type, method_name);
if (!found) found = sema_resolve_method_in_module(unit->module, type, method_name, &private, &ambiguous, METHOD_SEARCH_CURRENT);
if (ambiguous)
{
*ambiguous_ref = ambiguous;
@@ -725,7 +732,7 @@ Decl *sema_resolve_type_method(CompilationUnit *unit, Type *type, const char *me
}
if (!found)
{
found = sema_find_extension_method_in_module(global_context.method_extensions, type, method_name);
found = sema_find_extension_method_in_list(global_context.method_extensions, type, method_name);
private = NULL;
}
if (private) *private_ref = private;

View File

@@ -198,7 +198,7 @@ static void register_generic_decls(CompilationUnit *unit, Decl **decls)
break;
}
htable_set(&unit->module->symbols, (void *)decl->name, decl);
if (!decl->is_private) global_context_add_generic_decl(decl);
if (decl->visibility == VISIBLE_PUBLIC) global_context_add_generic_decl(decl);
}
}

View File

@@ -301,6 +301,7 @@ void symtab_init(uint32_t capacity)
attribute_list[ATTRIBUTE_EXTNAME] = KW_DEF("@extname");
attribute_list[ATTRIBUTE_INLINE] = KW_DEF("@inline");
attribute_list[ATTRIBUTE_LITTLEENDIAN] = KW_DEF("@littleendian");
attribute_list[ATTRIBUTE_LOCAL] = KW_DEF("@local");
attribute_list[ATTRIBUTE_MAYDISCARD] = KW_DEF("@maydiscard");
attribute_list[ATTRIBUTE_NAKED] = KW_DEF("@naked");
attribute_list[ATTRIBUTE_NODISCARD] = KW_DEF("@nodiscard");

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.62"
#define COMPILER_VERSION "0.4.63"

View File

@@ -0,0 +1,35 @@
module test;
import abc;
struct Foo
{
int x;
}
fn int Foo.get1(Foo* f) @private => f.x;
fn int Foo.get2(Foo* f) => f.x;
fn int Foo.get3(Foo* f) @local => f.x;
fn int Bar.get1(Bar* f) @private => f.x;
fn int Bar.get2(Bar* f) => f.x;
fn int Bar.get3(Bar* f) @local => f.x;
fn int main()
{
Foo x = { 1 };
x.get1();
x.get2();
x.get3();
Bar y = { 1 };
y.get1();
y.get2();
y.get3();
return 1;
}
module abc;
struct Bar
{
int x;
}

View File

@@ -0,0 +1,37 @@
module test;
import abc;
struct Foo
{
int x;
}
fn int Foo.get1(Foo* f) @private => f.x;
fn int Foo.get2(Foo* f) => f.x;
fn int Foo.get3(Foo* f) @local => f.x;
fn int Bar.get1(Bar* f) @private => f.x;
fn int Bar.get2(Bar* f) => f.x;
fn int Bar.get3(Bar* f) @local => f.x;
module abc;
import test;
struct Bar
{
int x;
}
Foo x = { 1 };
Bar y = { 1 };
fn int test()
{
x.get1(); // #error: method
x.get2();
x.get3(); // #error: method
y.get1(); // #error: method
y.get2();
y.get3(); // #error: method
return 1;
}

View File

@@ -0,0 +1,37 @@
module test;
import abc;
struct Foo
{
int x;
}
fn int Foo.get1(Foo* f) @private => f.x;
fn int Foo.get2(Foo* f) => f.x;
fn int Foo.get3(Foo* f) @local => f.x;
fn int Bar.get1(Bar* f) @private => f.x;
fn int Bar.get2(Bar* f) => f.x;
fn int Bar.get3(Bar* f) @local => f.x;
module abc;
import private test;
struct Bar
{
int x;
}
Foo x = { 1 };
Bar y = { 1 };
fn int test()
{
x.get1();
x.get2();
x.get3(); // #error: method
y.get1();
y.get2();
y.get3(); // #error: method
return 1;
}