mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Add @local and fix visibility issues for generic methods.
This commit is contained in:
committed by
Christoffer Lerno
parent
8184fba34b
commit
03cd56e46b
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.4.62"
|
||||
#define COMPILER_VERSION "0.4.63"
|
||||
35
test/test_suite/methods/extending_with_visibility.c3
Normal file
35
test/test_suite/methods/extending_with_visibility.c3
Normal 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;
|
||||
}
|
||||
37
test/test_suite/methods/extending_with_visibility_fail.c3
Normal file
37
test/test_suite/methods/extending_with_visibility_fail.c3
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user