mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
User defined attributes.
This commit is contained in:
committed by
Christoffer Lerno
parent
b0c55ff777
commit
e09e5c06d3
@@ -491,12 +491,11 @@ bool ast_is_not_empty(Ast *ast)
|
||||
return false;
|
||||
}
|
||||
|
||||
AttributeType attribute_by_name(Attr *attr)
|
||||
AttributeType attribute_by_name(const char *name)
|
||||
{
|
||||
const char *attribute = attr->name;
|
||||
for (unsigned i = 0; i < NUMBER_OF_ATTRIBUTES; i++)
|
||||
{
|
||||
if (attribute_list[i] == attribute) return (AttributeType)i;
|
||||
if (attribute_list[i] == name) return (AttributeType)i;
|
||||
}
|
||||
return ATTRIBUTE_NONE;
|
||||
}
|
||||
|
||||
@@ -302,12 +302,8 @@ typedef struct
|
||||
const char *name;
|
||||
SourceSpan span;
|
||||
AttributeType attr_kind : 8;
|
||||
union
|
||||
{
|
||||
Expr *expr;
|
||||
uint32_t alignment;
|
||||
OperatorOverload operator;
|
||||
};
|
||||
bool is_custom : 1;
|
||||
Expr **exprs;
|
||||
} Attr;
|
||||
|
||||
typedef struct
|
||||
@@ -447,6 +443,7 @@ typedef struct FunctionSignature_
|
||||
bool has_default : 1;
|
||||
bool use_win64 : 1;
|
||||
bool is_pure : 1;
|
||||
CallABI abi : 8;
|
||||
TypeInfoId returntype;
|
||||
Decl** params;
|
||||
} FunctionSignature;
|
||||
@@ -457,7 +454,6 @@ typedef struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
bool attr_weak : 1;
|
||||
bool attr_noreturn : 1;
|
||||
bool attr_inline : 1;
|
||||
bool attr_noinline : 1;
|
||||
@@ -472,8 +468,9 @@ typedef struct
|
||||
|
||||
typedef struct
|
||||
{
|
||||
AttributeDomain domains;
|
||||
FunctionSignature attr_signature;
|
||||
struct CompilationUnit_ *unit;
|
||||
Decl **params;
|
||||
Attr **attrs;
|
||||
} AttrDecl;
|
||||
|
||||
typedef struct
|
||||
@@ -526,7 +523,6 @@ typedef enum
|
||||
DEFINE_TYPE_GENERIC,
|
||||
DEFINE_IDENT_ALIAS,
|
||||
DEFINE_IDENT_GENERIC,
|
||||
DEFINE_ATTRIBUTE,
|
||||
} DefineType;
|
||||
|
||||
typedef struct
|
||||
@@ -534,11 +530,6 @@ typedef struct
|
||||
DefineType define_kind: 5;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
Decl **params;
|
||||
Attr **attrs;
|
||||
} attributes;
|
||||
struct
|
||||
{
|
||||
union
|
||||
@@ -588,6 +579,10 @@ typedef struct Decl_
|
||||
bool is_autoimport : 1;
|
||||
bool has_extname : 1;
|
||||
bool is_external_visible : 1;
|
||||
bool is_weak : 1;
|
||||
bool is_maybe_unused : 1;
|
||||
bool is_must_use : 1;
|
||||
bool will_reflect : 1;
|
||||
OperatorOverload operator : 4;
|
||||
union
|
||||
{
|
||||
@@ -634,7 +629,7 @@ typedef struct Decl_
|
||||
LabelDecl label;
|
||||
EnumConstantDecl enum_constant;
|
||||
FuncDecl func_decl;
|
||||
AttrDecl attr;
|
||||
AttrDecl attr_decl;
|
||||
TypedefDecl typedef_decl;
|
||||
MacroDecl macro_decl;
|
||||
GenericDecl generic_decl;
|
||||
@@ -1336,6 +1331,7 @@ typedef struct CompilationUnit_
|
||||
Decl **types;
|
||||
Decl **functions;
|
||||
Decl **enums;
|
||||
Decl **attributes;
|
||||
Decl **faulttypes;
|
||||
struct
|
||||
{
|
||||
@@ -1661,7 +1657,7 @@ typedef enum CmpRes_
|
||||
CMP_GT = 1,
|
||||
} CmpRes;
|
||||
|
||||
AttributeType attribute_by_name(Attr *attr);
|
||||
AttributeType attribute_by_name(const char *name);
|
||||
|
||||
void type_setup(PlatformTarget *target);
|
||||
Float float_add(Float op1, Float op2);
|
||||
@@ -2461,6 +2457,7 @@ Expr *expr_macro_copy(Expr *source_expr);
|
||||
Decl **decl_copy_list(Decl **decl_list);
|
||||
Ast *ast_macro_copy(Ast *source_ast);
|
||||
Ast *ast_defer_copy(Ast *source_ast);
|
||||
Decl *decl_macro_copy(Decl *source_decl);
|
||||
|
||||
Expr **copy_expr_list(CopyStruct *c, Expr **expr_list);
|
||||
Expr *copy_expr(CopyStruct *c, Expr *source_expr);
|
||||
|
||||
@@ -241,12 +241,15 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl)
|
||||
decl_set_external_name(decl);
|
||||
decl_register(decl);
|
||||
break;
|
||||
case DECL_ATTRIBUTE:
|
||||
vec_add(unit->attributes, decl);
|
||||
decl_register(decl);
|
||||
break;
|
||||
case DECL_FAULTVALUE:
|
||||
case DECL_ENUM_CONSTANT:
|
||||
case DECL_IMPORT:
|
||||
case DECL_CT_ELSE:
|
||||
case DECL_CT_ELIF:
|
||||
case DECL_ATTRIBUTE:
|
||||
case DECL_LABEL:
|
||||
case DECL_CT_CASE:
|
||||
case DECL_DECLARRAY:
|
||||
|
||||
@@ -148,6 +148,13 @@ Ast *ast_macro_copy(Ast *source_ast)
|
||||
return ast_copy_deep(©_struct, source_ast);
|
||||
}
|
||||
|
||||
Decl *decl_macro_copy(Decl *source_decl)
|
||||
{
|
||||
copy_struct.current_fixup = copy_struct.fixups;
|
||||
copy_struct.single_static = false;
|
||||
return copy_decl(©_struct, source_decl);
|
||||
}
|
||||
|
||||
Ast *ast_defer_copy(Ast *source_ast)
|
||||
{
|
||||
copy_struct.current_fixup = copy_struct.fixups;
|
||||
@@ -557,7 +564,7 @@ static Attr **copy_attributes(CopyStruct *c, Attr** attr_list)
|
||||
Attr *attribute = attr_list[i];
|
||||
Attr *copy = MALLOCS(Attr);
|
||||
*copy = *attribute;
|
||||
MACRO_COPY_EXPR(copy->expr);
|
||||
MACRO_COPY_EXPR_LIST(copy->exprs);
|
||||
vec_add(list, copy);
|
||||
}
|
||||
return list;
|
||||
@@ -691,10 +698,6 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
|
||||
break;
|
||||
case DEFINE_IDENT_ALIAS:
|
||||
break;
|
||||
case DEFINE_ATTRIBUTE:
|
||||
decl->define_decl.attributes.attrs = copy_attributes(c, decl->define_decl.attributes.attrs);
|
||||
MACRO_COPY_DECL_LIST(decl->define_decl.attributes.params);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -637,7 +637,7 @@ typedef enum
|
||||
{
|
||||
OVERLOAD_ELEMENT_AT = 1,
|
||||
OVERLOAD_ELEMENT_REF,
|
||||
OVERLOAT_ELEMENT_SET,
|
||||
OVERLOAD_ELEMENT_SET,
|
||||
OVERLOAD_LEN
|
||||
} OperatorOverload;
|
||||
|
||||
|
||||
@@ -320,9 +320,8 @@ static bool linker_setup(const char ***args_ref, const char **files_to_link, uns
|
||||
case OS_TYPE_NETBSD:
|
||||
case OS_TYPE_TVOS:
|
||||
case OS_TYPE_FREE_BSD:
|
||||
return false;
|
||||
case OS_TYPE_WASI:
|
||||
return false;
|
||||
break;
|
||||
case OS_TYPE_LINUX:
|
||||
linker_setup_linux(args_ref, linker_type);
|
||||
break;
|
||||
|
||||
@@ -651,7 +651,7 @@ void llvm_emit_function_decl(GenContext *c, Decl *decl)
|
||||
switch (visibility)
|
||||
{
|
||||
case VISIBLE_EXTERN:
|
||||
if (decl->func_decl.attr_weak)
|
||||
if (decl->is_weak)
|
||||
{
|
||||
LLVMSetLinkage(function, LLVMExternalWeakLinkage);
|
||||
llvm_set_comdat(c, function);
|
||||
@@ -668,10 +668,10 @@ void llvm_emit_function_decl(GenContext *c, Decl *decl)
|
||||
break;
|
||||
case VISIBLE_PUBLIC:
|
||||
case VISIBLE_MODULE:
|
||||
if (decl->func_decl.attr_weak) llvm_set_weak(c, function);
|
||||
if (decl->is_weak) llvm_set_weak(c, function);
|
||||
break;
|
||||
case VISIBLE_LOCAL:
|
||||
LLVMSetLinkage(function, decl->func_decl.attr_weak ? LLVMLinkerPrivateWeakLinkage : LLVMInternalLinkage);
|
||||
LLVMSetLinkage(function, decl->is_weak ? LLVMLinkerPrivateWeakLinkage : LLVMInternalLinkage);
|
||||
LLVMSetVisibility(function, LLVMDefaultVisibility);
|
||||
break;;
|
||||
}
|
||||
|
||||
@@ -699,7 +699,7 @@ static Expr *parse_call_expr(ParseContext *c, Expr *left)
|
||||
if (!parse_attribute(c, &attr)) return poisoned_expr;
|
||||
if (!attr) break;
|
||||
|
||||
AttributeType attr_type = attribute_by_name(attr);
|
||||
AttributeType attr_type = attribute_by_name(attr->name);
|
||||
int new_inline = attr_type == ATTRIBUTE_INLINE;
|
||||
switch (attr_type)
|
||||
{
|
||||
|
||||
@@ -876,14 +876,37 @@ bool parse_attribute(ParseContext *c, Attr **attribute_ref)
|
||||
attr->name = symstr(c);
|
||||
attr->span = c->span;
|
||||
attr->path = path;
|
||||
|
||||
if (tok_is(c, TOKEN_AT_IDENT))
|
||||
{
|
||||
AttributeType type = attribute_by_name(attr->name);
|
||||
if (type == ATTRIBUTE_NONE)
|
||||
{
|
||||
SEMA_ERROR_HERE("This is not a known valid attribute name.");
|
||||
return false;
|
||||
}
|
||||
attr->attr_kind = type;
|
||||
}
|
||||
else
|
||||
{
|
||||
attr->is_custom = true;
|
||||
}
|
||||
advance(c);
|
||||
|
||||
if (tok_is(c, TOKEN_LPAREN))
|
||||
Expr **list = NULL;
|
||||
|
||||
if (try_consume(c, TOKEN_LPAREN))
|
||||
{
|
||||
ASSIGN_EXPR_OR_RET(attr->expr, parse_const_paren_expr(c), false);
|
||||
while (1)
|
||||
{
|
||||
ASSIGN_EXPR_OR_RET(Expr *expr, parse_constant_expr(c), false);
|
||||
vec_add(list, expr);
|
||||
if (try_consume(c, TOKEN_RPAREN)) break;
|
||||
CONSUME_OR_RET(TOKEN_COMMA, false);
|
||||
}
|
||||
}
|
||||
|
||||
attr->exprs = list;
|
||||
|
||||
*attribute_ref = attr;
|
||||
return true;
|
||||
}
|
||||
@@ -1633,38 +1656,28 @@ static inline Decl *parse_define_attribute(ParseContext *c, Visibility visibilit
|
||||
// 1. Store the beginning of the "define".
|
||||
advance_and_verify(c, TOKEN_DEFINE);
|
||||
|
||||
advance_and_verify(c, TOKEN_AT);
|
||||
Decl *decl = decl_new(DECL_ATTRIBUTE, symstr(c), c->span, visibility);
|
||||
|
||||
TokenType alias_type = c->tok;
|
||||
if (alias_type != TOKEN_TYPE_IDENT)
|
||||
{
|
||||
if (token_is_some_ident(alias_type) || token_is_keyword(alias_type))
|
||||
{
|
||||
SEMA_ERROR_HERE("A user defined attribute must start with an uppercase character, followed by at least one lower case.");
|
||||
return false;
|
||||
}
|
||||
SEMA_ERROR_HERE("The attribute name was expected here.");
|
||||
return false;
|
||||
}
|
||||
Decl *decl = decl_new(DECL_DEFINE, symstr(c), c->span, visibility);
|
||||
advance_and_verify(c, TOKEN_TYPE_IDENT);
|
||||
advance_and_verify(c, TOKEN_AT_TYPE_IDENT);
|
||||
|
||||
Decl **parameters = NULL;
|
||||
if (try_consume(c, TOKEN_LPAREN))
|
||||
{
|
||||
if (!parse_parameters(c, visibility, ¶meters)) return false;
|
||||
if (!parse_parameters(c, visibility, &decl->attr_decl.params)) return poisoned_decl;
|
||||
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_decl);
|
||||
}
|
||||
|
||||
Attr **attributes = NULL;
|
||||
if (try_consume(c, TOKEN_EQ))
|
||||
{
|
||||
if (!parse_attributes(c, &attributes)) return false;
|
||||
while (1)
|
||||
{
|
||||
if (!parse_attributes(c, &attributes)) return poisoned_decl;
|
||||
if (tok_is(c, TOKEN_EOS)) break;
|
||||
CONSUME_OR_RET(TOKEN_COMMA, poisoned_decl);
|
||||
}
|
||||
}
|
||||
|
||||
decl->define_decl.define_kind = DEFINE_ATTRIBUTE;
|
||||
decl->define_decl.attributes.attrs = attributes;
|
||||
decl->define_decl.attributes.params = parameters;
|
||||
decl->attr_decl.attrs = attributes;
|
||||
CONSUME_EOS_OR_RET(poisoned_decl);
|
||||
return decl;
|
||||
}
|
||||
@@ -1676,8 +1689,8 @@ static inline Decl *parse_define(ParseContext *c, Visibility visibility)
|
||||
{
|
||||
switch (peek(c))
|
||||
{
|
||||
case TOKEN_AT:
|
||||
// define @foo = @inline, @noreturn
|
||||
case TOKEN_AT_TYPE_IDENT:
|
||||
// define @Foo = @inline, @noreturn
|
||||
return parse_define_attribute(c, visibility);
|
||||
case TOKEN_TYPE_IDENT:
|
||||
return parse_define_type(c, visibility);
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
|
||||
static bool sema_analyse_struct_union(SemaContext *context, Decl *decl);
|
||||
static bool sema_analyse_attributes(SemaContext *context, Decl *decl, Attr** attrs, AttributeDomain domain);
|
||||
static bool sema_analyse_attributes_for_var(SemaContext *context, Decl *decl);
|
||||
static bool sema_check_section(SemaContext *context, Decl *decl, Attr *attr)
|
||||
static bool sema_check_section(SemaContext *context, Attr *attr)
|
||||
{
|
||||
const char *section_string = attr->expr->const_expr.string.chars;
|
||||
decl->section = section_string;
|
||||
const char *section_string = attr->exprs[0]->const_expr.string.chars;
|
||||
// No restrictions except for MACH-O
|
||||
if (platform_target.object_format != OBJ_FORMAT_MACHO)
|
||||
{
|
||||
@@ -25,23 +25,23 @@ static bool sema_check_section(SemaContext *context, Decl *decl, Attr *attr)
|
||||
|
||||
if (slice.len)
|
||||
{
|
||||
SEMA_ERROR(attr->expr, "Too many parts to the Mach-o section description.");
|
||||
SEMA_ERROR(attr->exprs[0], "Too many parts to the Mach-o section description.");
|
||||
}
|
||||
slice_trim(&segment);
|
||||
if (segment.len == 0)
|
||||
{
|
||||
SEMA_ERROR(attr->expr, "The segment is missing, did you type it correctly?");
|
||||
SEMA_ERROR(attr->exprs[0], "The segment is missing, did you type it correctly?");
|
||||
return false;
|
||||
}
|
||||
slice_trim(§ion);
|
||||
if (section.len == 0)
|
||||
{
|
||||
SEMA_ERROR(attr->expr, "Mach-o requires 'segment,section' as the format, did you type it correctly?");
|
||||
SEMA_ERROR(attr->exprs[0], "Mach-o requires 'segment,section' as the format, did you type it correctly?");
|
||||
return false;
|
||||
}
|
||||
if (section.len > 16)
|
||||
{
|
||||
SEMA_ERROR(attr->expr, "Mach-o requires the section to be at the most 16 characters, can you shorten it?");
|
||||
SEMA_ERROR(attr->exprs[0], "Mach-o requires the section to be at the most 16 characters, can you shorten it?");
|
||||
return false;
|
||||
}
|
||||
// TODO improve checking
|
||||
@@ -264,17 +264,14 @@ static bool sema_analyse_struct_members(SemaContext *context, Decl *decl, Decl *
|
||||
AlignSize member_natural_alignment = type_abi_alignment(member->type);
|
||||
AlignSize member_alignment = is_packed ? 1 : member_natural_alignment;
|
||||
Attr **attributes = member->attributes;
|
||||
unsigned count = vec_size(attributes);
|
||||
for (unsigned j = 0; j < count; j++)
|
||||
|
||||
if (!sema_analyse_attributes(context, member, attributes, ATTR_MEMBER)) return decl_poison(decl);
|
||||
|
||||
if (member->alignment)
|
||||
{
|
||||
Attr *attribute = attributes[j];
|
||||
if (!sema_analyse_attribute(context, attribute, ATTR_GLOBAL)) return false;
|
||||
if (attribute->name == attribute_list[ATTRIBUTE_ALIGN])
|
||||
{
|
||||
member_alignment = attribute->alignment;
|
||||
// Update total alignment if we have a member that has bigger alignment.
|
||||
if (member_alignment > decl->alignment) decl->alignment = member_alignment;
|
||||
}
|
||||
member_alignment = member->alignment;
|
||||
// Update total alignment if we have a member that has bigger alignment.
|
||||
if (member_alignment > decl->alignment) decl->alignment = member_alignment;
|
||||
}
|
||||
|
||||
// If the member alignment is higher than the currently detected alignment,
|
||||
@@ -366,39 +363,8 @@ static bool sema_analyse_struct_union(SemaContext *context, Decl *decl)
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
VECEACH(decl->attributes, i)
|
||||
{
|
||||
Attr *attr = decl->attributes[i];
|
||||
|
||||
if (!sema_analyse_attribute(context, attr, domain)) return decl_poison(decl);
|
||||
|
||||
bool had = false;
|
||||
#define SET_ATTR(_X) had = decl->func_decl._X; decl->func_decl._X = true; break
|
||||
switch (attr->attr_kind)
|
||||
{
|
||||
case ATTRIBUTE_EXTNAME:
|
||||
had = decl->has_extname;
|
||||
decl->has_extname = true;
|
||||
decl->extname = attr->expr->const_expr.string.chars;
|
||||
break;
|
||||
case ATTRIBUTE_ALIGN:
|
||||
had = decl->alignment != 0;
|
||||
decl->alignment = attr->alignment;
|
||||
break;
|
||||
case ATTRIBUTE_PACKED:
|
||||
had = decl->is_packed;
|
||||
decl->is_packed = true;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
#undef SET_ATTR
|
||||
if (had)
|
||||
{
|
||||
sema_error_at(attr->span, "Attribute occurred twice, please remove one.");
|
||||
return decl_poison(decl);
|
||||
}
|
||||
}
|
||||
if (!sema_analyse_attributes(context, decl, decl->attributes, domain)) return decl_poison(decl);
|
||||
|
||||
DEBUG_LOG("Beginning analysis of %s.", decl->name ? decl->name : "anon");
|
||||
bool success;
|
||||
@@ -532,43 +498,7 @@ static inline bool sema_analyse_bitstruct_member(SemaContext *context, Decl *dec
|
||||
|
||||
static bool sema_analyse_bitstruct(SemaContext *context, Decl *decl)
|
||||
{
|
||||
VECEACH(decl->attributes, i)
|
||||
{
|
||||
Attr *attr = decl->attributes[i];
|
||||
|
||||
if (!sema_analyse_attribute(context, attr, ATTR_BITSTRUCT)) return decl_poison(decl);
|
||||
|
||||
bool had = false;
|
||||
#define SET_ATTR(_X) had = decl->bitstruct._X; decl->bitstruct._X = true; break
|
||||
switch (attr->attr_kind)
|
||||
{
|
||||
case ATTRIBUTE_OVERLAP:
|
||||
SET_ATTR(overlap);
|
||||
break;
|
||||
case ATTRIBUTE_BIGENDIAN:
|
||||
if (decl->bitstruct.little_endian)
|
||||
{
|
||||
sema_error_at(attr->span, "Attribute cannot be combined with @littleendian");
|
||||
return decl_poison(decl);
|
||||
}
|
||||
SET_ATTR(big_endian);
|
||||
case ATTRIBUTE_LITTLEENDIAN:
|
||||
if (decl->bitstruct.big_endian)
|
||||
{
|
||||
sema_error_at(attr->span, "Attribute cannot be combined with @bigendian");
|
||||
return decl_poison(decl);
|
||||
}
|
||||
SET_ATTR(little_endian);
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
#undef SET_ATTR
|
||||
if (had)
|
||||
{
|
||||
sema_error_at(attr->span, "Attribute occurred twice, please remove one.");
|
||||
return decl_poison(decl);
|
||||
}
|
||||
}
|
||||
if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_BITSTRUCT)) return decl_poison(decl);
|
||||
|
||||
DEBUG_LOG("Beginning analysis of %s.", decl->name ? decl->name : "anon");
|
||||
if (!sema_resolve_type_info(context, decl->bitstruct.base_type)) return false;
|
||||
@@ -1100,7 +1030,7 @@ static bool sema_check_operator_method_validity(Decl *method)
|
||||
{
|
||||
switch (method->operator)
|
||||
{
|
||||
case OVERLOAT_ELEMENT_SET:
|
||||
case OVERLOAD_ELEMENT_SET:
|
||||
return sema_analyse_operator_element_set(method);
|
||||
case OVERLOAD_ELEMENT_AT:
|
||||
case OVERLOAD_ELEMENT_REF:
|
||||
@@ -1216,21 +1146,19 @@ static const char *attribute_domain_to_string(AttributeDomain domain)
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
bool sema_analyse_attribute(SemaContext *context, Attr *attr, AttributeDomain domain)
|
||||
|
||||
static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, AttributeDomain domain)
|
||||
{
|
||||
AttributeType type = attribute_by_name(attr);
|
||||
if (type == ATTRIBUTE_NONE)
|
||||
{
|
||||
sema_error_at(attr->span, "There is no attribute with the name '%s', did you mistype?", attr->name);
|
||||
return false;
|
||||
}
|
||||
AttributeType type = attr->attr_kind;
|
||||
assert(type >= 0 && type < NUMBER_OF_ATTRIBUTES);
|
||||
static AttributeDomain attribute_domain[NUMBER_OF_ATTRIBUTES] = {
|
||||
[ATTRIBUTE_WEAK] = ATTR_FUNC | ATTR_CONST | ATTR_GLOBAL,
|
||||
[ATTRIBUTE_EXTNAME] = (AttributeDomain)~(ATTR_CALL | ATTR_BITSTRUCT | ATTR_MACRO),
|
||||
[ATTRIBUTE_SECTION] = ATTR_FUNC | ATTR_CONST | ATTR_GLOBAL,
|
||||
[ATTRIBUTE_PACKED] = ATTR_STRUCT | ATTR_UNION,
|
||||
[ATTRIBUTE_NORETURN] = ATTR_FUNC | ATTR_MACRO,
|
||||
[ATTRIBUTE_ALIGN] = ATTR_FUNC | ATTR_CONST | ATTR_LOCAL | ATTR_GLOBAL | ATTR_STRUCT | ATTR_UNION | ATTR_MEMBER,
|
||||
[ATTRIBUTE_ALIGN] = ATTR_FUNC | ATTR_CONST | ATTR_LOCAL | ATTR_GLOBAL | ATTR_STRUCT | ATTR_UNION |
|
||||
ATTR_MEMBER,
|
||||
[ATTRIBUTE_INLINE] = ATTR_FUNC | ATTR_CALL,
|
||||
[ATTRIBUTE_NOINLINE] = ATTR_FUNC | ATTR_CALL,
|
||||
[ATTRIBUTE_BIGENDIAN] = ATTR_BITSTRUCT,
|
||||
@@ -1255,79 +1183,128 @@ bool sema_analyse_attribute(SemaContext *context, Attr *attr, AttributeDomain do
|
||||
sema_error_at(attr->span, "'%s' is not a valid %s attribute.", attr->name, attribute_domain_to_string(domain));
|
||||
return false;
|
||||
}
|
||||
attr->attr_kind = type;
|
||||
unsigned args = vec_size(attr->exprs);
|
||||
if (args > 1)
|
||||
{
|
||||
SEMA_ERROR(attr->exprs[1], "Too many arguments for the attribute.");
|
||||
return false;
|
||||
}
|
||||
Expr *expr = args ? attr->exprs[0] : NULL;
|
||||
switch (type)
|
||||
{
|
||||
case ATTRIBUTE_CDECL:
|
||||
case ATTRIBUTE_FASTCALL:
|
||||
case ATTRIBUTE_STDCALL:
|
||||
decl->func_decl.function_signature.abi = CALL_C;
|
||||
break;
|
||||
case ATTRIBUTE_VECCALL:
|
||||
switch (platform_target.arch)
|
||||
{
|
||||
case ARCH_TYPE_X86_64:
|
||||
case ARCH_TYPE_X86:
|
||||
decl->func_decl.function_signature.abi = CALL_X86_VECTOR;
|
||||
break;
|
||||
case ARCH_TYPE_ARM:
|
||||
case ARCH_TYPE_ARMB:
|
||||
case ARCH_TYPE_AARCH64:
|
||||
case ARCH_TYPE_AARCH64_32:
|
||||
case ARCH_TYPE_AARCH64_BE:
|
||||
decl->func_decl.function_signature.abi = CALL_AAPCS_VFP;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ATTRIBUTE_STDCALL:
|
||||
assert(decl->decl_kind == DECL_FUNC);
|
||||
if (platform_target.arch == ARCH_TYPE_X86 || platform_target.arch == ARCH_TYPE_X86_64)
|
||||
{
|
||||
decl->func_decl.function_signature.abi = CALL_X86_STD;
|
||||
}
|
||||
else if (platform_target.arch == ARCH_TYPE_ARM || platform_target.arch == ARCH_TYPE_ARMB)
|
||||
{
|
||||
decl->func_decl.function_signature.abi = CALL_AAPCS;
|
||||
}
|
||||
break; // Check args
|
||||
case ATTRIBUTE_FASTCALL:
|
||||
if (platform_target.arch == ARCH_TYPE_X86 ||
|
||||
(platform_target.arch == ARCH_TYPE_X86_64 && platform_target.os == OS_TYPE_WIN32))
|
||||
{
|
||||
decl->func_decl.function_signature.abi = CALL_X86_FAST;
|
||||
}
|
||||
break;
|
||||
case ATTRIBUTE_REGCALL:
|
||||
return true;
|
||||
if (platform_target.arch == ARCH_TYPE_X86 ||
|
||||
(platform_target.arch == ARCH_TYPE_X86_64 && platform_target.os == OS_TYPE_WIN32))
|
||||
{
|
||||
decl->func_decl.function_signature.abi = CALL_X86_REG;
|
||||
}
|
||||
break;
|
||||
case ATTRIBUTE_OPERATOR:
|
||||
{
|
||||
Expr *expr = attr->expr;
|
||||
assert(decl->decl_kind == DECL_FUNC || decl->decl_kind == DECL_MACRO);
|
||||
if (!expr || expr->expr_kind != EXPR_IDENTIFIER) goto FAILED_OP_TYPE;
|
||||
if (expr->identifier_expr.path) goto FAILED_OP_TYPE;
|
||||
const char *kw = expr->identifier_expr.ident;
|
||||
if (kw == kw_elementat)
|
||||
{
|
||||
attr->operator = OVERLOAD_ELEMENT_AT;
|
||||
decl->operator = OVERLOAD_ELEMENT_AT;
|
||||
}
|
||||
else if (kw == kw_elementref)
|
||||
{
|
||||
attr->operator = OVERLOAD_ELEMENT_REF;
|
||||
decl->operator = OVERLOAD_ELEMENT_REF;
|
||||
}
|
||||
else if (kw == kw_elementset)
|
||||
{
|
||||
attr->operator = OVERLOAT_ELEMENT_SET;
|
||||
decl->operator = OVERLOAD_ELEMENT_SET;
|
||||
}
|
||||
else if (kw == kw_len)
|
||||
{
|
||||
attr->operator = OVERLOAD_LEN;
|
||||
decl->operator = OVERLOAD_LEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto FAILED_OP_TYPE;
|
||||
}
|
||||
return true;
|
||||
FAILED_OP_TYPE:
|
||||
SEMA_ERROR(attr, "'operator' requires an operator type argument: '%s', '%s' or '%s'.", kw_elementat, kw_elementref, kw_len);
|
||||
FAILED_OP_TYPE:
|
||||
SEMA_ERROR(attr,
|
||||
"'operator' requires an operator type argument: '%s', '%s' or '%s'.",
|
||||
kw_elementat,
|
||||
kw_elementref,
|
||||
kw_len);
|
||||
return false;
|
||||
}
|
||||
case ATTRIBUTE_ALIGN:
|
||||
if (!attr->expr)
|
||||
if (!expr)
|
||||
{
|
||||
sema_error_at(attr->span, "'align' requires an power-of-2 argument, e.g. align(8).");
|
||||
return false;
|
||||
}
|
||||
if (!sema_analyse_expr(context, attr->expr)) return false;
|
||||
if (attr->expr->expr_kind != EXPR_CONST || !type_is_integer(attr->expr->type->canonical))
|
||||
if (!sema_analyse_expr(context, expr)) return false;
|
||||
if (expr->expr_kind != EXPR_CONST || !type_is_integer(expr->type->canonical))
|
||||
{
|
||||
SEMA_ERROR(attr->expr, "Expected a constant integer value as argument.");
|
||||
SEMA_ERROR(expr, "Expected a constant integer value as argument.");
|
||||
return false;
|
||||
}
|
||||
{
|
||||
if (int_ucomp(attr->expr->const_expr.ixx, MAX_ALIGNMENT, BINARYOP_GT))
|
||||
if (int_ucomp(expr->const_expr.ixx, MAX_ALIGNMENT, BINARYOP_GT))
|
||||
{
|
||||
SEMA_ERROR(attr->expr, "Alignment must be less or equal to %ull.", MAX_ALIGNMENT);
|
||||
SEMA_ERROR(expr, "Alignment must be less or equal to %ull.", MAX_ALIGNMENT);
|
||||
return false;
|
||||
}
|
||||
if (int_ucomp(attr->expr->const_expr.ixx, 0, BINARYOP_LE))
|
||||
if (int_ucomp(expr->const_expr.ixx, 0, BINARYOP_LE))
|
||||
{
|
||||
SEMA_ERROR(attr->expr, "Alignment must be greater than zero.");
|
||||
SEMA_ERROR(expr, "Alignment must be greater than zero.");
|
||||
return false;
|
||||
}
|
||||
uint64_t align = int_to_u64(attr->expr->const_expr.ixx);
|
||||
uint64_t align = int_to_u64(expr->const_expr.ixx);
|
||||
if (!is_power_of_two(align))
|
||||
{
|
||||
SEMA_ERROR(attr->expr, "Alignment must be a power of two.");
|
||||
SEMA_ERROR(expr, "Alignment must be a power of two.");
|
||||
return false;
|
||||
}
|
||||
|
||||
attr->alignment = (AlignSize)align;
|
||||
decl->alignment = (AlignSize)align;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
case ATTRIBUTE_SECTION:
|
||||
case ATTRIBUTE_EXTNAME:
|
||||
if (context->unit->module->is_generic)
|
||||
@@ -1335,29 +1312,166 @@ bool sema_analyse_attribute(SemaContext *context, Attr *attr, AttributeDomain do
|
||||
sema_error_at(attr->span, "'extname' attributes are not allowed in generic modules.");
|
||||
return false;
|
||||
}
|
||||
if (!attr->expr)
|
||||
if (!expr)
|
||||
{
|
||||
sema_error_at(attr->span, "'%s' requires a string argument, e.g. %s(\"foo\").", attr->name, attr->name);
|
||||
return false;
|
||||
}
|
||||
if (!sema_analyse_expr(context, attr->expr)) return false;
|
||||
if (attr->expr->expr_kind != EXPR_CONST || attr->expr->const_expr.const_kind != CONST_STRING)
|
||||
if (!sema_analyse_expr(context, expr)) return false;
|
||||
if (expr->expr_kind != EXPR_CONST || expr->const_expr.const_kind != CONST_STRING)
|
||||
{
|
||||
SEMA_ERROR(attr->expr, "Expected a constant string value as argument.");
|
||||
SEMA_ERROR(expr, "Expected a constant string value as argument.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
if (attr->expr)
|
||||
if (type == ATTRIBUTE_SECTION)
|
||||
{
|
||||
SEMA_ERROR(attr->expr, "'%s' should not have any arguments.", attr->name);
|
||||
return false;
|
||||
if (!sema_check_section(context, attr)) return false;
|
||||
decl->section = expr->const_expr.string.chars;
|
||||
}
|
||||
else
|
||||
{
|
||||
decl->has_extname = true;
|
||||
decl->extname = expr->const_expr.string.chars;
|
||||
}
|
||||
return true;
|
||||
case ATTRIBUTE_NOINLINE:
|
||||
decl->func_decl.attr_noinline = true;
|
||||
decl->func_decl.attr_inline = false;
|
||||
break;
|
||||
case ATTRIBUTE_INLINE:
|
||||
decl->func_decl.attr_inline = true;
|
||||
decl->func_decl.attr_noinline = false;
|
||||
break;
|
||||
case ATTRIBUTE_NORETURN:
|
||||
if (domain == ATTR_MACRO)
|
||||
{
|
||||
decl->macro_decl.attr_noreturn = true;
|
||||
break;
|
||||
}
|
||||
assert(domain == ATTR_FUNC);
|
||||
decl->func_decl.attr_noreturn = true;
|
||||
break;
|
||||
case ATTRIBUTE_WEAK:
|
||||
decl->is_weak = true;
|
||||
break;
|
||||
case ATTRIBUTE_NAKED:
|
||||
assert(domain == ATTR_FUNC);
|
||||
decl->func_decl.attr_naked = true;
|
||||
break;
|
||||
case ATTRIBUTE_AUTOIMPORT:
|
||||
decl->is_autoimport = true;
|
||||
break;
|
||||
case ATTRIBUTE_OVERLAP:
|
||||
decl->bitstruct.overlap = true;
|
||||
break;
|
||||
case ATTRIBUTE_BIGENDIAN:
|
||||
if (decl->bitstruct.little_endian)
|
||||
{
|
||||
sema_error_at(attr->span, "Attribute cannot be combined with @littleendian");
|
||||
return decl_poison(decl);
|
||||
}
|
||||
decl->bitstruct.big_endian = true;
|
||||
break;
|
||||
case ATTRIBUTE_LITTLEENDIAN:
|
||||
if (decl->bitstruct.big_endian)
|
||||
{
|
||||
sema_error_at(attr->span, "Attribute cannot be combined with @bigendian");
|
||||
return decl_poison(decl);
|
||||
}
|
||||
decl->bitstruct.little_endian = true;
|
||||
break;
|
||||
case ATTRIBUTE_PACKED:
|
||||
decl->is_packed = true;
|
||||
break;
|
||||
case ATTRIBUTE_UNUSED:
|
||||
decl->is_maybe_unused = true;
|
||||
break;
|
||||
case ATTRIBUTE_USED:
|
||||
decl->is_must_use = true;
|
||||
break;
|
||||
case ATTRIBUTE_PURE:
|
||||
// Only used for calls.
|
||||
UNREACHABLE
|
||||
case ATTRIBUTE_REFLECT:
|
||||
decl->will_reflect = true;
|
||||
break;
|
||||
case ATTRIBUTE_NONE:
|
||||
UNREACHABLE
|
||||
}
|
||||
if (expr)
|
||||
{
|
||||
SEMA_ERROR(expr, "'%s' should not have any arguments.", attr->name);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
static bool sema_analyse_attributes(SemaContext *context, Decl *decl, Attr** attrs, AttributeDomain domain)
|
||||
{
|
||||
int count = vec_size(attrs);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Attr *attr = attrs[i];
|
||||
if (attr->is_custom)
|
||||
{
|
||||
Decl *attr_decl = sema_find_symbol(context, attr->name);
|
||||
if (!attr_decl || attr_decl->decl_kind != DECL_ATTRIBUTE)
|
||||
{
|
||||
SEMA_ERROR(attr, "The attribute '%s' could not be found.", attr->name);
|
||||
return false;
|
||||
}
|
||||
Decl **params = attr_decl->attr_decl.params;
|
||||
unsigned param_count = vec_size(params);
|
||||
Expr **args = attr->exprs;
|
||||
if (param_count != vec_size(args))
|
||||
{
|
||||
SEMA_ERROR(attr, "Expected %d parameter(s).", param_count);
|
||||
return false;
|
||||
}
|
||||
|
||||
Attr **attributes = attr_decl->attr_decl.attrs;
|
||||
if (context->current_function == attr_decl)
|
||||
{
|
||||
SEMA_ERROR(attr_decl, "Recursive declaration of attribute '%s' – it contains itself.", attr_decl->name);
|
||||
return false;
|
||||
}
|
||||
SemaContext eval_context;
|
||||
sema_context_init(&eval_context, attr_decl->attr_decl.unit);
|
||||
eval_context.compilation_unit = context->unit;
|
||||
// We need to track recursion:
|
||||
if (context->current_function && context->current_function->decl_kind == DECL_ATTRIBUTE)
|
||||
{
|
||||
eval_context.current_function = context->current_function;
|
||||
}
|
||||
else
|
||||
{
|
||||
eval_context.current_function = attr_decl;
|
||||
}
|
||||
for (int j = 0; j < param_count; j++)
|
||||
{
|
||||
if (!sema_analyse_ct_expr(context, args[j]))
|
||||
{
|
||||
sema_context_destroy(&eval_context);
|
||||
return false;
|
||||
}
|
||||
params[i]->var.init_expr = args[j];
|
||||
params[i]->var.kind = VARDECL_CONST;
|
||||
sema_add_local(&eval_context, params[i]);
|
||||
}
|
||||
if (!sema_analyse_attributes(&eval_context, decl, attributes, domain))
|
||||
{
|
||||
sema_context_destroy(&eval_context);
|
||||
return false;
|
||||
}
|
||||
sema_context_destroy(&eval_context);
|
||||
continue;
|
||||
}
|
||||
if (!sema_analyse_attribute(context, decl, attr, domain)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_doc_header(AstId doc, Decl **params, Decl **extra_params, bool *pure_ref)
|
||||
{
|
||||
while (doc)
|
||||
@@ -1567,111 +1681,9 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl)
|
||||
{
|
||||
DEBUG_LOG("----Analysing function %s", decl->name);
|
||||
|
||||
CallABI call_abi = 0;
|
||||
VECEACH(decl->attributes, i)
|
||||
{
|
||||
Attr *attr = decl->attributes[i];
|
||||
if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_FUNC)) return decl_poison(decl);
|
||||
|
||||
if (!sema_analyse_attribute(context, attr, ATTR_FUNC)) return decl_poison(decl);
|
||||
|
||||
bool had = false;
|
||||
#define SET_ATTR(_X) had = decl->func_decl._X; decl->func_decl._X = true; break
|
||||
|
||||
switch (attr->attr_kind)
|
||||
{
|
||||
case ATTRIBUTE_OPERATOR:
|
||||
had = decl->operator > 0;
|
||||
decl->operator = attr->operator;
|
||||
break;
|
||||
case ATTRIBUTE_EXTNAME:
|
||||
had = decl->has_extname;
|
||||
decl->has_extname = true;
|
||||
decl->extname = attr->expr->const_expr.string.chars;
|
||||
break;
|
||||
case ATTRIBUTE_SECTION:
|
||||
had = decl->section != NULL;
|
||||
if (!sema_check_section(context, decl, attr)) return decl_poison(decl);
|
||||
break;
|
||||
case ATTRIBUTE_ALIGN:
|
||||
had = decl->alignment != 0;
|
||||
decl->alignment = attr->alignment;
|
||||
break;
|
||||
case ATTRIBUTE_NOINLINE: SET_ATTR(attr_noinline);
|
||||
case ATTRIBUTE_STDCALL:
|
||||
if (platform_target.arch == ARCH_TYPE_X86 || platform_target.arch == ARCH_TYPE_X86_64)
|
||||
{
|
||||
had = call_abi > 0;
|
||||
call_abi = CALL_X86_STD;
|
||||
}
|
||||
else if (platform_target.arch == ARCH_TYPE_ARM || platform_target.arch == ARCH_TYPE_ARMB)
|
||||
{
|
||||
had = call_abi > 0;
|
||||
call_abi = CALL_AAPCS;
|
||||
}
|
||||
break;
|
||||
case ATTRIBUTE_CDECL:
|
||||
had = call_abi > 0;
|
||||
call_abi = CALL_C;
|
||||
break;
|
||||
case ATTRIBUTE_VECCALL:
|
||||
switch (platform_target.arch)
|
||||
{
|
||||
case ARCH_TYPE_X86_64:
|
||||
case ARCH_TYPE_X86:
|
||||
had = call_abi > 0;
|
||||
call_abi = CALL_X86_VECTOR;
|
||||
break;
|
||||
case ARCH_TYPE_ARM:
|
||||
case ARCH_TYPE_ARMB:
|
||||
case ARCH_TYPE_AARCH64:
|
||||
case ARCH_TYPE_AARCH64_32:
|
||||
case ARCH_TYPE_AARCH64_BE:
|
||||
had = call_abi > 0;
|
||||
call_abi = CALL_AAPCS_VFP;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ATTRIBUTE_FASTCALL:
|
||||
if (platform_target.arch == ARCH_TYPE_X86 || (platform_target.arch == ARCH_TYPE_X86_64 && platform_target.os == OS_TYPE_WIN32))
|
||||
{
|
||||
had = call_abi > 0;
|
||||
call_abi = CALL_X86_FAST;
|
||||
}
|
||||
break;
|
||||
case ATTRIBUTE_REGCALL:
|
||||
had = call_abi > 0;
|
||||
if (platform_target.arch == ARCH_TYPE_X86 || (platform_target.arch == ARCH_TYPE_X86_64 && platform_target.os == OS_TYPE_WIN32))
|
||||
{
|
||||
had = call_abi > 0;
|
||||
call_abi = CALL_X86_REG;
|
||||
}
|
||||
break;
|
||||
case ATTRIBUTE_NORETURN: SET_ATTR(attr_noreturn);
|
||||
case ATTRIBUTE_INLINE: SET_ATTR(attr_inline);
|
||||
case ATTRIBUTE_WEAK: SET_ATTR(attr_weak);
|
||||
case ATTRIBUTE_NAKED: SET_ATTR(attr_naked);
|
||||
case ATTRIBUTE_AUTOIMPORT:
|
||||
decl->is_autoimport = true;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
#undef SET_ATTR
|
||||
if (had)
|
||||
{
|
||||
sema_error_at(attr->span, "Attribute occurred twice, please remove one.");
|
||||
return decl_poison(decl);
|
||||
}
|
||||
if (decl->func_decl.attr_inline && decl->func_decl.attr_noinline)
|
||||
{
|
||||
sema_error_at(attr->span, "A function cannot be 'inline' and 'noinline' at the same time.");
|
||||
return decl_poison(decl);
|
||||
}
|
||||
}
|
||||
|
||||
Type *func_type = sema_analyse_function_signature(context, call_abi, &decl->func_decl.function_signature, true);
|
||||
Type *func_type = sema_analyse_function_signature(context, decl->func_decl.function_signature.abi, &decl->func_decl.function_signature, true);
|
||||
|
||||
decl->type = func_type;
|
||||
if (!func_type) return decl_poison(decl);
|
||||
@@ -1730,35 +1742,8 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl)
|
||||
{
|
||||
bool is_generic = decl->decl_kind == DECL_GENERIC;
|
||||
|
||||
VECEACH(decl->attributes, i)
|
||||
{
|
||||
Attr *attr = decl->attributes[i];
|
||||
if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_MACRO)) return decl_poison(decl);
|
||||
|
||||
if (!sema_analyse_attribute(context, attr, ATTR_MACRO)) return decl_poison(decl);
|
||||
|
||||
bool had = false;
|
||||
switch (attr->attr_kind)
|
||||
{
|
||||
case ATTRIBUTE_OPERATOR:
|
||||
had = decl->operator > 0;
|
||||
decl->operator = attr->operator;
|
||||
break;
|
||||
case ATTRIBUTE_AUTOIMPORT:
|
||||
decl->is_autoimport = true;
|
||||
break;
|
||||
case ATTRIBUTE_NORETURN:
|
||||
had = decl->macro_decl.attr_noreturn;
|
||||
decl->macro_decl.attr_noreturn = true;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
if (had)
|
||||
{
|
||||
sema_error_at(attr->span, "Attribute occurred twice, please remove one.");
|
||||
return decl_poison(decl);
|
||||
}
|
||||
}
|
||||
|
||||
TypeInfo *rtype = type_infoptr(decl->macro_decl.rtype);
|
||||
if (decl->macro_decl.rtype && !sema_resolve_type_info(context, rtype)) return decl_poison(decl);
|
||||
@@ -1885,41 +1870,7 @@ static bool sema_analyse_attributes_for_var(SemaContext *context, Decl *decl)
|
||||
domain = ATTR_LOCAL;
|
||||
break;
|
||||
}
|
||||
VECEACH(decl->attributes, i)
|
||||
{
|
||||
Attr *attr = decl->attributes[i];
|
||||
|
||||
if (!sema_analyse_attribute(context, attr, domain)) decl_poison(decl);
|
||||
|
||||
bool had = false;
|
||||
#define SET_ATTR(_X) had = decl->func_decl._X; decl->func_decl._X = true; break
|
||||
switch (attr->attr_kind)
|
||||
{
|
||||
case ATTRIBUTE_EXTNAME:
|
||||
had = decl->has_extname;
|
||||
decl->has_extname = true;
|
||||
decl->extname = attr->expr->const_expr.string.chars;
|
||||
break;
|
||||
case ATTRIBUTE_SECTION:
|
||||
had = decl->section != NULL;
|
||||
if (!sema_check_section(context, decl, attr)) return decl_poison(decl);
|
||||
break;
|
||||
case ATTRIBUTE_ALIGN:
|
||||
had = decl->alignment != 0;
|
||||
decl->alignment = attr->alignment;
|
||||
break;
|
||||
case ATTRIBUTE_WEAK:
|
||||
SET_ATTR(attr_weak);
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
#undef SET_ATTR
|
||||
if (had)
|
||||
{
|
||||
sema_error_at(attr->span, "Attribute occurred twice, please remove one.");
|
||||
return decl_poison(decl);
|
||||
}
|
||||
}
|
||||
if (!sema_analyse_attributes(context, decl, decl->attributes, domain)) return decl_poison(decl);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2195,8 +2146,6 @@ static bool sema_analyse_parameterized_define(SemaContext *c, Decl *decl)
|
||||
span = define_type->span;
|
||||
break;
|
||||
}
|
||||
case DEFINE_ATTRIBUTE:
|
||||
TODO
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
@@ -2263,13 +2212,48 @@ static bool sema_analyse_parameterized_define(SemaContext *c, Decl *decl)
|
||||
type->canonical = symbol->type->canonical;
|
||||
return true;
|
||||
}
|
||||
case DEFINE_ATTRIBUTE:
|
||||
TODO
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_attribute_decl(SemaContext *c, Decl *decl)
|
||||
{
|
||||
decl->attr_decl.unit = c->compilation_unit;
|
||||
Decl **params = decl->attr_decl.params;
|
||||
Attr **attrs = decl->attr_decl.attrs;
|
||||
unsigned param_count = vec_size(params);
|
||||
for (unsigned i = 0; i < param_count; i++)
|
||||
{
|
||||
Decl *param = params[i];
|
||||
if (param->var.kind != VARDECL_PARAM)
|
||||
{
|
||||
SEMA_ERROR(param, "Expected a simple replacement parameter e.g. 'val' here.");
|
||||
return false;
|
||||
}
|
||||
if (param->var.type_info)
|
||||
{
|
||||
SEMA_ERROR(param, "Type is not allowed on attribute parameters.");
|
||||
return false;
|
||||
}
|
||||
if (param->var.init_expr)
|
||||
{
|
||||
SEMA_ERROR(param, "Attribute parameters may not have default values.");
|
||||
return false;
|
||||
}
|
||||
param->resolve_status = RESOLVE_DONE;
|
||||
for (int j = 0; j < i; j++)
|
||||
{
|
||||
if (param[j].name == param->name)
|
||||
{
|
||||
SEMA_ERROR(param, "Duplicate parameter name.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_define(SemaContext *c, Decl *decl)
|
||||
{
|
||||
// 1. The plain define
|
||||
@@ -2325,6 +2309,9 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl)
|
||||
if (!sema_analyse_var_decl(context, decl, false)) return decl_poison(decl);
|
||||
decl_set_external_name(decl);
|
||||
break;
|
||||
case DECL_ATTRIBUTE:
|
||||
if (!sema_analyse_attribute_decl(context, decl)) return decl_poison(decl);
|
||||
break;
|
||||
case DECL_DISTINCT:
|
||||
if (!sema_analyse_distinct(context, decl)) return decl_poison(decl);
|
||||
decl_set_external_name(decl);
|
||||
@@ -2343,8 +2330,6 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl)
|
||||
case DECL_DEFINE:
|
||||
if (!sema_analyse_define(context, decl)) return decl_poison(decl);
|
||||
break;
|
||||
case DECL_ATTRIBUTE:
|
||||
TODO
|
||||
case DECL_POISONED:
|
||||
case DECL_IMPORT:
|
||||
case DECL_ENUM_CONSTANT:
|
||||
|
||||
@@ -56,7 +56,6 @@ bool splitpathref(const char *string, ArraySize len, Path **path_ref, const char
|
||||
|
||||
#define IS_CONST(_x) ((_x)->expr_kind == EXPR_CONST)
|
||||
|
||||
bool sema_analyse_attribute(SemaContext *context, Attr *attr, AttributeDomain domain);
|
||||
bool expr_is_ltype(Expr *expr);
|
||||
bool sema_expr_check_assign(SemaContext *c, Expr *expr);
|
||||
|
||||
|
||||
@@ -310,6 +310,10 @@ void sema_analysis_pass_decls(Module *module)
|
||||
.local_decl_start = 0,
|
||||
.current_local = 0,
|
||||
};
|
||||
VECEACH(unit->attributes, i)
|
||||
{
|
||||
sema_analyse_decl(&context, unit->attributes[i]);
|
||||
}
|
||||
VECEACH(unit->enums, i)
|
||||
{
|
||||
sema_analyse_decl(&context, unit->enums[i]);
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.2.2"
|
||||
#define COMPILER_VERSION "0.2.3"
|
||||
17
test/test_suite/attributes/recursive_attributes.c3
Normal file
17
test/test_suite/attributes/recursive_attributes.c3
Normal file
@@ -0,0 +1,17 @@
|
||||
module test;
|
||||
|
||||
define @Align(y) = @Align16(y / 2);
|
||||
define @Align16(x) = @align(4), @Align(8 * x); // #error: Recursive declaration of attribute
|
||||
define @Test = @noinline;
|
||||
struct Foo
|
||||
{
|
||||
int z;
|
||||
int xy @Align16(8);
|
||||
}
|
||||
|
||||
Foo f;
|
||||
|
||||
fn void testme() @Test
|
||||
{
|
||||
int x;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
fn void test()
|
||||
{
|
||||
for (int a @align(16) @align(16) = 0 ; a < 10; a++) // #error: Repeat of attribute '@align'
|
||||
{
|
||||
}
|
||||
}
|
||||
45
test/test_suite/attributes/user_defined_attributes.c3t
Normal file
45
test/test_suite/attributes/user_defined_attributes.c3t
Normal file
@@ -0,0 +1,45 @@
|
||||
// #target: macos-x64
|
||||
|
||||
module test;
|
||||
|
||||
define @Align(y) = @align(y);
|
||||
define @Align16(x) = @Align(8 * x), @align(1024);
|
||||
define @Test = @noinline;
|
||||
define @TestZero;
|
||||
struct Foo
|
||||
{
|
||||
int z;
|
||||
int xy @Align16(8);
|
||||
}
|
||||
|
||||
Foo f;
|
||||
|
||||
fn void testme() @Test
|
||||
{
|
||||
int x;
|
||||
}
|
||||
|
||||
fn void main() @TestZero
|
||||
{
|
||||
testme();
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
%Foo = type { i32, [1020 x i8], i32, [1020 x i8] }
|
||||
|
||||
@introspect.Foo = linkonce constant i8 1
|
||||
@test.f = local_unnamed_addr global %Foo zeroinitializer, align 1024
|
||||
|
||||
define void @test.testme() #0 {
|
||||
entry:
|
||||
%x = alloca i32, align 4
|
||||
store i32 0, i32* %x, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test.main() #1 {
|
||||
entry:
|
||||
call void @test.testme()
|
||||
ret void
|
||||
}
|
||||
@@ -37,7 +37,7 @@ bitstruct BitField3 : char[3]
|
||||
int d : 19..23;
|
||||
}
|
||||
|
||||
bitstruct BitField4 : char[3] @aligned
|
||||
bitstruct BitField4 : char[3] @align(8)
|
||||
{
|
||||
int a : 0..2;
|
||||
int b : 3..7;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// #target: macos-x64
|
||||
|
||||
module struct2;
|
||||
|
||||
// <{ i64, i8, [3 x i8] }>
|
||||
|
||||
Reference in New Issue
Block a user