mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
deprecated attribute for procedure declarations
This commit is contained in:
@@ -877,6 +877,7 @@ __cstring_len :: proc "contextless" (s: cstring) -> int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
__cstring_to_string :: proc "contextless" (s: cstring) -> string {
|
__cstring_to_string :: proc "contextless" (s: cstring) -> string {
|
||||||
|
if s == nil do return "";
|
||||||
ptr := (^byte)(s);
|
ptr := (^byte)(s);
|
||||||
n := __cstring_len(s);
|
n := __cstring_len(s);
|
||||||
return transmute(string)raw.String{ptr, n};
|
return transmute(string)raw.String{ptr, n};
|
||||||
|
|||||||
+1
-1
@@ -15,8 +15,8 @@ new_cstring :: proc(s: string) -> cstring {
|
|||||||
return cstring(&c[0]);
|
return cstring(&c[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(deprecated="Please use a standard cast for cstring to string")
|
||||||
to_odin_string :: proc(str: cstring) -> string {
|
to_odin_string :: proc(str: cstring) -> string {
|
||||||
if str == nil do return "";
|
|
||||||
return string(str);
|
return string(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -778,6 +778,20 @@ cstring_example :: proc() {
|
|||||||
// cast(cstring)string is O(N)
|
// cast(cstring)string is O(N)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deprecated_attribute :: proc() {
|
||||||
|
@(deprecated="Use foo_v2 instead")
|
||||||
|
foo_v1 :: proc(x: int) {
|
||||||
|
fmt.println("foo_v1");
|
||||||
|
}
|
||||||
|
foo_v2 :: proc(x: int) {
|
||||||
|
fmt.println("foo_v2");
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Uncomment to see the warning messages
|
||||||
|
// foo_v1(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
when true {
|
when true {
|
||||||
general_stuff();
|
general_stuff();
|
||||||
@@ -792,5 +806,6 @@ main :: proc() {
|
|||||||
explicit_procedure_overloading();
|
explicit_procedure_overloading();
|
||||||
complete_switch();
|
complete_switch();
|
||||||
cstring_example();
|
cstring_example();
|
||||||
|
deprecated_attribute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -527,6 +527,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
e->deprecated_message = ac.deprecated_message;
|
||||||
ac.link_name = handle_link_name(c, e->token, ac.link_name, ac.link_prefix);
|
ac.link_name = handle_link_name(c, e->token, ac.link_name, ac.link_prefix);
|
||||||
|
|
||||||
if (d->scope->file != nullptr && e->token.string == "main") {
|
if (d->scope->file != nullptr && e->token.string == "main") {
|
||||||
|
|||||||
@@ -4943,6 +4943,16 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE(bill): Should this be here or on the `add_entity_use`?
|
||||||
|
// if (ce->proc != nullptr) {
|
||||||
|
// Entity *e = entity_of_node(&c->info, ce->proc);
|
||||||
|
// if (e != nullptr && e->kind == Entity_Procedure) {
|
||||||
|
// String msg = e->Procedure.deprecated_message;
|
||||||
|
// if (msg.len > 0) {
|
||||||
|
// warning(call, "%.*s is deprecated: %.*s", LIT(e->token.string), LIT(msg));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
CallArgumentData data = check_call_arguments(c, operand, proc_type, call);
|
CallArgumentData data = check_call_arguments(c, operand, proc_type, call);
|
||||||
Type *result_type = data.result_type;
|
Type *result_type = data.result_type;
|
||||||
|
|||||||
@@ -708,6 +708,29 @@ bool is_entity_implicitly_imported(Entity *import_name, Entity *e) {
|
|||||||
return ptr_set_exists(&import_name->ImportName.scope->implicit, e);
|
return ptr_set_exists(&import_name->ImportName.scope->implicit, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Will return nullptr if not found
|
||||||
|
Entity *entity_of_node(CheckerInfo *i, AstNode *expr) {
|
||||||
|
expr = unparen_expr(expr);
|
||||||
|
switch (expr->kind) {
|
||||||
|
case_ast_node(ident, Ident, expr);
|
||||||
|
return entity_of_ident(i, expr);
|
||||||
|
case_end;
|
||||||
|
case_ast_node(se, SelectorExpr, expr);
|
||||||
|
AstNode *s = se->selector;
|
||||||
|
while (s->kind == AstNode_SelectorExpr) {
|
||||||
|
s = s->SelectorExpr.selector;
|
||||||
|
}
|
||||||
|
if (s->kind == AstNode_Ident) {
|
||||||
|
return entity_of_ident(i, s);
|
||||||
|
}
|
||||||
|
case_end;
|
||||||
|
case_ast_node(cc, CaseClause, expr);
|
||||||
|
return cc->implicit_entity;
|
||||||
|
case_end;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
DeclInfo *decl_info_of_entity(CheckerInfo *i, Entity *e) {
|
DeclInfo *decl_info_of_entity(CheckerInfo *i, Entity *e) {
|
||||||
if (e != nullptr) {
|
if (e != nullptr) {
|
||||||
@@ -877,6 +900,11 @@ void add_entity_use(Checker *c, AstNode *identifier, Entity *entity) {
|
|||||||
}
|
}
|
||||||
identifier->Ident.entity = entity;
|
identifier->Ident.entity = entity;
|
||||||
add_declaration_dependency(c, entity); // TODO(bill): Should this be here?
|
add_declaration_dependency(c, entity); // TODO(bill): Should this be here?
|
||||||
|
|
||||||
|
String dmsg = entity->deprecated_message;
|
||||||
|
if (dmsg.len > 0) {
|
||||||
|
warning(identifier, "%.*s is deprecated: %.*s", LIT(entity->token.string), LIT(dmsg));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1465,6 +1493,18 @@ DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
|
|||||||
error(elem, "Expected a string value for '%.*s'", LIT(name));
|
error(elem, "Expected a string value for '%.*s'", LIT(name));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
} else if (name == "deprecated") {
|
||||||
|
if (value.kind == ExactValue_String) {
|
||||||
|
String msg = value.value_string;
|
||||||
|
if (msg.len == 0) {
|
||||||
|
error(elem, "Deprecation message cannot be an empty string");
|
||||||
|
} else {
|
||||||
|
ac->deprecated_message = msg;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error(elem, "Expected a string value for '%.*s'", LIT(name));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1567,6 +1607,7 @@ void check_decl_attributes(Checker *c, Array<AstNode *> attributes, DeclAttribut
|
|||||||
if (value != nullptr) {
|
if (value != nullptr) {
|
||||||
Operand op = {};
|
Operand op = {};
|
||||||
check_expr(c, &op, value);
|
check_expr(c, &op, value);
|
||||||
|
if (op.mode )
|
||||||
if (op.mode != Addressing_Constant) {
|
if (op.mode != Addressing_Constant) {
|
||||||
error(value, "An attribute element must be constant");
|
error(value, "An attribute element must be constant");
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+4
-2
@@ -193,8 +193,6 @@ struct DeclInfo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ProcedureInfo stores the information needed for checking a procedure
|
// ProcedureInfo stores the information needed for checking a procedure
|
||||||
|
|
||||||
|
|
||||||
struct ProcedureInfo {
|
struct ProcedureInfo {
|
||||||
AstFile * file;
|
AstFile * file;
|
||||||
Token token;
|
Token token;
|
||||||
@@ -356,6 +354,9 @@ AstFile * ast_file_of_filename (CheckerInfo *i, String filename);
|
|||||||
// IMPORTANT: Only to use once checking is done
|
// IMPORTANT: Only to use once checking is done
|
||||||
isize type_info_index (CheckerInfo *i, Type * type, bool error_on_failure = true);
|
isize type_info_index (CheckerInfo *i, Type * type, bool error_on_failure = true);
|
||||||
|
|
||||||
|
// Will return nullptr if not found
|
||||||
|
Entity *entity_of_node(CheckerInfo *i, AstNode *expr);
|
||||||
|
|
||||||
|
|
||||||
Entity *current_scope_lookup_entity(Scope *s, String name);
|
Entity *current_scope_lookup_entity(Scope *s, String name);
|
||||||
Entity *scope_lookup_entity (Scope *s, String name);
|
Entity *scope_lookup_entity (Scope *s, String name);
|
||||||
@@ -389,6 +390,7 @@ struct AttributeContext {
|
|||||||
String link_prefix;
|
String link_prefix;
|
||||||
isize init_expr_list_count;
|
isize init_expr_list_count;
|
||||||
String thread_local_model;
|
String thread_local_model;
|
||||||
|
String deprecated_message;
|
||||||
};
|
};
|
||||||
|
|
||||||
AttributeContext make_attribute_context(String link_prefix) {
|
AttributeContext make_attribute_context(String link_prefix) {
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ struct Entity {
|
|||||||
AstNode * using_expr;
|
AstNode * using_expr;
|
||||||
|
|
||||||
isize order_in_src;
|
isize order_in_src;
|
||||||
|
String deprecated_message;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
|
|||||||
+12
-18
@@ -6,6 +6,7 @@
|
|||||||
struct AstNode;
|
struct AstNode;
|
||||||
struct HashKey;
|
struct HashKey;
|
||||||
struct Type;
|
struct Type;
|
||||||
|
struct Entity;
|
||||||
bool are_types_identical(Type *x, Type *y);
|
bool are_types_identical(Type *x, Type *y);
|
||||||
|
|
||||||
struct Complex128 {
|
struct Complex128 {
|
||||||
@@ -21,9 +22,9 @@ enum ExactValueKind {
|
|||||||
ExactValue_Float,
|
ExactValue_Float,
|
||||||
ExactValue_Complex,
|
ExactValue_Complex,
|
||||||
ExactValue_Pointer,
|
ExactValue_Pointer,
|
||||||
ExactValue_Compound, // TODO(bill): Is this good enough?
|
ExactValue_Compound, // TODO(bill): Is this good enough?
|
||||||
ExactValue_Procedure, // TODO(bill): Is this good enough?
|
ExactValue_Procedure, // TODO(bill): Is this good enough?
|
||||||
ExactValue_Type,
|
ExactValue_Entity, // TODO(bill): Is this good enough?
|
||||||
|
|
||||||
ExactValue_Count,
|
ExactValue_Count,
|
||||||
};
|
};
|
||||||
@@ -39,7 +40,7 @@ struct ExactValue {
|
|||||||
Complex128 value_complex;
|
Complex128 value_complex;
|
||||||
AstNode * value_compound;
|
AstNode * value_compound;
|
||||||
AstNode * value_procedure;
|
AstNode * value_procedure;
|
||||||
Type * value_type;
|
Entity * value_entity;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -67,8 +68,8 @@ HashKey hash_exact_value(ExactValue v) {
|
|||||||
return hash_pointer(v.value_compound);
|
return hash_pointer(v.value_compound);
|
||||||
case ExactValue_Procedure:
|
case ExactValue_Procedure:
|
||||||
return hash_pointer(v.value_procedure);
|
return hash_pointer(v.value_procedure);
|
||||||
case ExactValue_Type:
|
case ExactValue_Entity:
|
||||||
return hash_pointer(v.value_type);
|
return hash_pointer(v.value_entity);
|
||||||
}
|
}
|
||||||
return hashing_proc(&v, gb_size_of(ExactValue));
|
return hashing_proc(&v, gb_size_of(ExactValue));
|
||||||
|
|
||||||
@@ -125,18 +126,18 @@ ExactValue exact_value_pointer(i64 ptr) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue exact_value_type(Type *type) {
|
|
||||||
ExactValue result = {ExactValue_Type};
|
|
||||||
result.value_type = type;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExactValue exact_value_procedure(AstNode *node) {
|
ExactValue exact_value_procedure(AstNode *node) {
|
||||||
ExactValue result = {ExactValue_Procedure};
|
ExactValue result = {ExactValue_Procedure};
|
||||||
result.value_procedure = node;
|
result.value_procedure = node;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExactValue exact_value_entity(Entity *entity) {
|
||||||
|
ExactValue result = {ExactValue_Entity};
|
||||||
|
result.value_entity = entity;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ExactValue exact_value_integer_from_string(String string) {
|
ExactValue exact_value_integer_from_string(String string) {
|
||||||
u64 u = u64_from_string(string);
|
u64 u = u64_from_string(string);
|
||||||
@@ -690,13 +691,6 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ExactValue_Type:
|
|
||||||
switch (op) {
|
|
||||||
case Token_CmpEq: return are_types_identical(x.value_type, y.value_type);
|
|
||||||
case Token_NotEq: return !are_types_identical(x.value_type, y.value_type);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GB_PANIC("Invalid comparison");
|
GB_PANIC("Invalid comparison");
|
||||||
|
|||||||
+3
-3
@@ -548,17 +548,17 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
|
|||||||
break;
|
break;
|
||||||
case ExactValue_String: {
|
case ExactValue_String: {
|
||||||
String str = value.value_string;
|
String str = value.value_string;
|
||||||
if (str.len == 0) {
|
Type *t = core_type(type);
|
||||||
|
if (str.len == 0 && !is_type_cstring(t)) {
|
||||||
ir_write_str_lit(f, "zeroinitializer");
|
ir_write_str_lit(f, "zeroinitializer");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Type *t = core_type(type);
|
|
||||||
if (!is_type_string(type)) {
|
if (!is_type_string(type)) {
|
||||||
GB_ASSERT(is_type_array(type));
|
GB_ASSERT(is_type_array(type));
|
||||||
ir_write_str_lit(f, "c\"");
|
ir_write_str_lit(f, "c\"");
|
||||||
ir_print_escape_string(f, str, false, false);
|
ir_print_escape_string(f, str, false, false);
|
||||||
ir_write_str_lit(f, "\\00\"");
|
ir_write_str_lit(f, "\\00\"");
|
||||||
} else if (t == t_cstring) {
|
} else if (is_type_cstring(t)) {
|
||||||
// HACK NOTE(bill): This is a hack but it works because strings are created at the very end
|
// HACK NOTE(bill): This is a hack but it works because strings are created at the very end
|
||||||
// of the .ll file
|
// of the .ll file
|
||||||
irValue *str_array = ir_add_global_string_array(m, str);
|
irValue *str_array = ir_add_global_string_array(m, str);
|
||||||
|
|||||||
Reference in New Issue
Block a user