mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Improve error message when doing a rethrow in a function that doesn't return an optional.
Array indices are now using int64 internally.
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
- Improved error messages on missing qualifier on enum value. #2260
|
||||
- Add `--echo-prefix` to edit the prefix with `$echo` statements. Supports {FILE} and {LINE}
|
||||
- Catch accidental `foo == BAR;` where `foo = BAR;` was most likely intended. #2274
|
||||
- Improve error message when doing a rethrow in a function that doesn't return an optional.
|
||||
|
||||
### Fixes
|
||||
- mkdir/rmdir would not work properly with substring paths on non-windows platforms.
|
||||
@@ -31,6 +32,7 @@
|
||||
- Make `to_float` more tolerant to spaces.
|
||||
- Fixes to thread local pointer handling.
|
||||
- Fixes to JSON parsing and Object.
|
||||
- Array indices are now using int64 internally.
|
||||
|
||||
### Stdlib changes
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@ static bool c_emit_type_decl(GenContext *c, Type *type)
|
||||
if (prev) return false;
|
||||
c_emit_type_decl(c, type->array.base);
|
||||
int id = ++c->typename;
|
||||
PRINTF("typedef struct { %s ptr[%u]; } __c3_array%d;\n", c_type_name(c, type->array.base), type->array.len, id);
|
||||
PRINTF("typedef struct { %s ptr[%llu]; } __c3_array%d;\n", c_type_name(c, type->array.base), (unsigned long long)type->array.len, id);
|
||||
scratch_buffer_clear();
|
||||
scratch_buffer_printf(" __c3_array%d", id);
|
||||
htable_set(&c->gen_decl, type, scratch_buffer_copy());
|
||||
|
||||
@@ -16,11 +16,11 @@ typedef double Real;
|
||||
typedef uint64_t ByteSize;
|
||||
typedef uint32_t TypeSize;
|
||||
typedef int32_t IndexDiff;
|
||||
typedef int32_t ArrayIndex;
|
||||
typedef int64_t ArrayIndex;
|
||||
typedef uint16_t StructIndex;
|
||||
typedef uint32_t AlignSize;
|
||||
typedef int32_t ScopeId;
|
||||
typedef uint32_t ArraySize;
|
||||
typedef uint64_t ArraySize;
|
||||
typedef uint64_t BitSize;
|
||||
typedef uint16_t FileId;
|
||||
|
||||
@@ -34,7 +34,7 @@ typedef uint16_t FileId;
|
||||
#define UINT12_MAX 4095
|
||||
#define UINT20_MAX 1048575U
|
||||
|
||||
#define MAX_ARRAYINDEX INT32_MAX
|
||||
#define MAX_ARRAYINDEX INT64_MAX
|
||||
#define MAX_FIXUPS 0xFFFFF
|
||||
#define MAX_HASH_SIZE (512 * 1024 * 1024)
|
||||
#define INVALID_SPAN ((SourceSpan){ .row = 0 })
|
||||
@@ -72,6 +72,15 @@ typedef uint16_t FileId;
|
||||
#define TABLE_MAX_LOAD 0.5
|
||||
#define OUTF(...) do { if (!compiler.build.silent) printf(__VA_ARGS__); } while(0)
|
||||
#define OUTN(str__) do { if (!compiler.build.silent) puts(str__); } while(0)
|
||||
#ifdef NDEBUG
|
||||
#define ASSERT_SPANF(node__, check__, format__, ...) do { (void)(check__); } while(0)
|
||||
#define ASSERT_SPAN(node__, check__) do { (void)(check__); } while(0)
|
||||
#define ASSERT_AT(span__, check__) do { (void)(check__);} while(0)
|
||||
#else
|
||||
#define ASSERT_SPANF(node__, check__, format__, ...) do { if (!(check__)) { assert_print_line((node__)->span); eprintf(format__, __VA_ARGS__); ASSERT(check__); } } while(0)
|
||||
#define ASSERT_SPAN(node__, check__) do { if (!(check__)) { assert_print_line((node__)->span); ASSERT(check__); } } while(0)
|
||||
#define ASSERT_AT(span__, check__) do { if (!(check__)) { assert_print_line(span__); ASSERT(check__); } } while(0)
|
||||
#endif
|
||||
|
||||
#define INVALID_PTR ((void*)(uintptr_t)0xAAAAAAAAAAAAAAAA)
|
||||
|
||||
@@ -704,7 +713,7 @@ typedef enum RangeType
|
||||
typedef struct
|
||||
{
|
||||
ResolveStatus status : 3;
|
||||
RangeType range_type;
|
||||
RangeType range_type : 4;
|
||||
bool start_from_end : 1;
|
||||
bool end_from_end : 1;
|
||||
bool is_len : 1;
|
||||
@@ -2021,6 +2030,8 @@ INLINE bool compile_asserts(void)
|
||||
return safe_mode_enabled() || compiler.build.testing;
|
||||
}
|
||||
|
||||
void assert_print_line(SourceSpan span);
|
||||
|
||||
bool ast_is_not_empty(Ast *ast);
|
||||
|
||||
bool ast_is_compile_time(Ast *ast);
|
||||
@@ -2945,6 +2956,7 @@ INLINE TypeInfoId type_info_id_new_base(Type *type, SourceSpan span)
|
||||
return type_infoid(type_info_new_base(type, span));
|
||||
}
|
||||
|
||||
|
||||
INLINE Type *type_new(TypeKind kind, const char *name)
|
||||
{
|
||||
Type *type = CALLOCS(Type);
|
||||
@@ -4236,16 +4248,12 @@ INLINE bool check_module_name(Path *path)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define ASSERT_SPANF(node__, check__, format__, ...) do { (void)(check__); } while(0)
|
||||
#define ASSERT_SPAN(node__, check__) do { (void)(check__); } while(0)
|
||||
#define ASSERT_AT(span__, check__) do { (void)(check__);} while(0)
|
||||
#else
|
||||
#define ASSERT_SPANF(node__, check__, format__, ...) do { if (!(check__)) { assert_print_line((node__)->span); eprintf(format__, __VA_ARGS__); ASSERT(check__); } } while(0)
|
||||
#define ASSERT_SPAN(node__, check__) do { if (!(check__)) { assert_print_line((node__)->span); ASSERT(check__); } } while(0)
|
||||
#define ASSERT_AT(span__, check__) do { if (!(check__)) { assert_print_line(span__); ASSERT(check__); } } while(0)
|
||||
#endif
|
||||
void assert_print_line(SourceSpan span);
|
||||
INLINE bool expr_is_valid_index(Expr *expr)
|
||||
{
|
||||
ASSERT_SPAN(expr, expr_is_const_int(expr));
|
||||
return int_fits(expr->const_expr.ixx, TYPE_I64);
|
||||
}
|
||||
|
||||
|
||||
const char *default_c_compiler(void);
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ static void header_print_type(HeaderContext *c, Type *type)
|
||||
case TYPE_ARRAY:
|
||||
PRINTF("struct { ");
|
||||
header_print_type(c, type->array.base);
|
||||
PRINTF(" arr[%d]; }", type->array.len);
|
||||
PRINTF(" arr[%llu]; }", (unsigned long long)type->array.len);
|
||||
return;
|
||||
case TYPE_ANY:
|
||||
case TYPE_INTERFACE:
|
||||
@@ -227,7 +227,7 @@ static void header_print_type(HeaderContext *c, Type *type)
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
PRINTF("%dx%d", (int)type_bit_size(type->array.base), type->array.len);
|
||||
PRINTF("%dx%llu", (int)type_bit_size(type->array.base), (unsigned long long)type->array.len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -345,7 +345,7 @@ static void header_gen_members(HeaderContext *c, int indent, Decl **members)
|
||||
{
|
||||
case TYPE_ARRAY:
|
||||
header_print_type(c, type->array.base);
|
||||
PRINTF(" %s[%d];\n", member->name, type->array.len);
|
||||
PRINTF(" %s[%llu];\n", member->name, (unsigned long long)type->array.len);
|
||||
break;
|
||||
case TYPE_FLEXIBLE_ARRAY:
|
||||
header_print_type(c, type->array.base);
|
||||
@@ -574,7 +574,7 @@ RETRY:
|
||||
header_print_type(c, flat_type);
|
||||
PRINTF(" ");
|
||||
header_print_type(c, type);
|
||||
PRINTF(" __attribute__((vector_size(%d)));\n", (int)type_size(flat_type) * type->array.len);
|
||||
PRINTF(" __attribute__((vector_size(%llu)));\n", (int)type_size(flat_type) * (unsigned long long)type->array.len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -491,7 +491,7 @@ const char *expr_const_to_error_string(const ExprConst *expr)
|
||||
case CONST_FLOAT:
|
||||
return str_printf("%g", expr->fxx.f);
|
||||
case CONST_STRING:
|
||||
return str_printf("\"%*.s\"", expr->bytes.len, expr->bytes.ptr);
|
||||
return str_printf("\"%*.s\"", (int)expr->bytes.len, expr->bytes.ptr);
|
||||
case CONST_BYTES:
|
||||
return "<binary data>";
|
||||
case CONST_REF:
|
||||
|
||||
@@ -3989,8 +3989,7 @@ INLINE bool sema_expr_analyse_range_internal(SemaContext *context, Range *range,
|
||||
{
|
||||
SourceSpan span = start->span;
|
||||
span = extend_span_with_token(span, end->span);
|
||||
sema_error_at(context, span, "No common type can be found between start and end index.");
|
||||
return false;
|
||||
RETURN_SEMA_ERROR_AT(span, "No common type can be found between start and end index.");
|
||||
}
|
||||
if (!cast_implicit(context, start, common, false) || !cast_implicit(context, end, common, false)) return false;
|
||||
}
|
||||
@@ -4013,12 +4012,12 @@ INLINE bool sema_expr_analyse_range_internal(SemaContext *context, Range *range,
|
||||
if (end && sema_cast_const(end))
|
||||
{
|
||||
// Only ArrayIndex sized
|
||||
if (!int_fits(end->const_expr.ixx, TYPE_I64))
|
||||
if (!expr_is_valid_index(end))
|
||||
{
|
||||
RETURN_SEMA_ERROR(end, "The index cannot be stored in a 64-signed integer, which isn't supported.");
|
||||
}
|
||||
|
||||
int64_t end_index = int_to_i64(end->const_expr.ixx);
|
||||
ArrayIndex end_index = int_to_i64(end->const_expr.ixx);
|
||||
|
||||
if (range->end_from_end)
|
||||
{
|
||||
@@ -4026,11 +4025,11 @@ INLINE bool sema_expr_analyse_range_internal(SemaContext *context, Range *range,
|
||||
// Something like 1 .. ^4 with an unknown length.
|
||||
if (len < 0) return true;
|
||||
// Otherwise we fold the "from end"
|
||||
end_index = len - end_index;
|
||||
if (end_index < 0)
|
||||
if (end_index > len)
|
||||
{
|
||||
RETURN_SEMA_ERROR(end, "An index may only be negative for pointers (it was: %lld).", end_index);
|
||||
RETURN_SEMA_ERROR(end, "An index may only be negative for pointers (it was: %lld).", len - end_index);
|
||||
}
|
||||
end_index = len - end_index;
|
||||
range->end_from_end = false;
|
||||
}
|
||||
if (end_index < 0 && env != RANGE_PTR)
|
||||
@@ -4038,8 +4037,7 @@ INLINE bool sema_expr_analyse_range_internal(SemaContext *context, Range *range,
|
||||
RETURN_SEMA_ERROR(end, "An index may only be negative for pointers (it was: %lld).", end_index);
|
||||
}
|
||||
// No more analysis
|
||||
if (end_index > MAX_ARRAYINDEX || end_index < -MAX_ARRAYINDEX) return true;
|
||||
range->const_end = (ArrayIndex)end_index;
|
||||
range->const_end = end_index;
|
||||
range->range_type = range->is_len ? RANGE_CONST_LEN : RANGE_CONST_END;
|
||||
}
|
||||
else if (!end && len > 0)
|
||||
@@ -4052,24 +4050,23 @@ INLINE bool sema_expr_analyse_range_internal(SemaContext *context, Range *range,
|
||||
if (sema_cast_const(start))
|
||||
{
|
||||
// Only ArrayIndex sized
|
||||
if (!int_fits(start->const_expr.ixx, TYPE_I64))
|
||||
if (!expr_is_valid_index(start))
|
||||
{
|
||||
RETURN_SEMA_ERROR(end, "The index cannot be stored in a 64-signed integer, which isn't supported.");
|
||||
}
|
||||
// Only ArrayIndex sized
|
||||
int64_t start_index = int_to_i64(start->const_expr.ixx);
|
||||
ArrayIndex start_index = int_to_i64(start->const_expr.ixx);
|
||||
if (range->start_from_end)
|
||||
{
|
||||
if (start_index < 0) RETURN_SEMA_ERROR(end, "Negative numbers are not allowed when indexing from the end.");
|
||||
// Something like ^1 .. 4 with an unknown length.
|
||||
if (len < 0) return true;
|
||||
// Otherwise we fold the "from end"
|
||||
start_index = len - start_index;
|
||||
if (start_index < 0)
|
||||
if (len < start_index)
|
||||
{
|
||||
RETURN_SEMA_ERROR(start, "An index may only be negative for pointers (it was: %lld).", start_index);
|
||||
RETURN_SEMA_ERROR(start, "An index may only be negative for pointers (it was: %lld).", len - start_index);
|
||||
}
|
||||
if (start_index > MAX_ARRAYINDEX || start_index < -MAX_ARRAYINDEX) return true;
|
||||
start_index = len - start_index;
|
||||
range->start_from_end = false;
|
||||
}
|
||||
if (start_index < 0 && env != RANGE_PTR)
|
||||
@@ -4083,20 +4080,19 @@ INLINE bool sema_expr_analyse_range_internal(SemaContext *context, Range *range,
|
||||
}
|
||||
if (range->range_type == RANGE_CONST_END)
|
||||
{
|
||||
int64_t end_index = range->const_end;
|
||||
ArrayIndex end_index = range->const_end;
|
||||
if (end_index < start_index) RETURN_SEMA_ERROR(start, "The start index (%lld) should not be greater than the end index (%lld).",
|
||||
start_index, end_index);
|
||||
if (start_index > MAX_ARRAYINDEX) return true;
|
||||
range->const_end = (ArrayIndex)(end_index + 1 - start_index);
|
||||
range->const_end = end_index + 1 - start_index;
|
||||
range->range_type = RANGE_CONST_LEN;
|
||||
range->is_len = true;
|
||||
}
|
||||
if (range->range_type == RANGE_CONST_LEN)
|
||||
{
|
||||
int64_t end_index = range->const_end;
|
||||
ArrayIndex end_index = range->const_end;
|
||||
range->range_type = RANGE_CONST_RANGE;
|
||||
range->start_index = (ArrayIndex)start_index;
|
||||
range->len_index = (ArrayIndex)end_index;
|
||||
range->start_index = start_index;
|
||||
range->len_index = end_index;
|
||||
}
|
||||
}
|
||||
if (len > -1)
|
||||
@@ -9002,8 +8998,10 @@ static inline bool sema_expr_analyse_rethrow(SemaContext *context, Expr *expr)
|
||||
expr->rethrow_expr.in_block = NULL;
|
||||
if (context->rtype && context->rtype->type_kind != TYPE_OPTIONAL)
|
||||
{
|
||||
RETURN_SEMA_ERROR(expr, "This expression implicitly returns with an optional result, "
|
||||
"but the function does not allow optional results. Did you mean to use '!!' instead?");
|
||||
RETURN_SEMA_ERROR(expr, "This expression is doing a rethrow, "
|
||||
"but '%s' returns %s, which isn't an optional type. Did you intend to use '!!' instead?",
|
||||
context->call_env.current_function->name,
|
||||
type_quoted_error_string(context->rtype));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -1130,13 +1130,13 @@ static Type *type_create_array(Type *element_type, ArraySize len, bool vector, b
|
||||
Type *vec_arr;
|
||||
if (vector)
|
||||
{
|
||||
vec_arr = type_new(TYPE_VECTOR, str_printf("%s[<%u>]", element_type->name, len));
|
||||
vec_arr = type_new(TYPE_VECTOR, str_printf("%s[<%llu>]", element_type->name, (unsigned long long)len));
|
||||
vec_arr->array.base = element_type;
|
||||
vec_arr->array.len = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
vec_arr = type_new(TYPE_ARRAY, str_printf("%s[%u]", element_type->name, len));
|
||||
vec_arr = type_new(TYPE_ARRAY, str_printf("%s[%llu]", element_type->name, (unsigned long long)len));
|
||||
vec_arr->array.base = element_type;
|
||||
vec_arr->array.len = len;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ fn void test()
|
||||
int i = 0;
|
||||
if (i!) return; // #error: No optional to rethrow before '!' in the expression, please remove '!'
|
||||
int? j = 0;
|
||||
if (j!) return; // #error: This expression implicitly returns with an optional result, but the function
|
||||
if ((j!)!) return; // #error: This expression implicitly returns with an optional result, but the function
|
||||
if (j!) return; // #error: This expression is doing a rethrow
|
||||
if ((j!)!) return; // #error: This expression is doing a rethrow
|
||||
}
|
||||
|
||||
fn void? test2()
|
||||
|
||||
9
test/test_suite/errors/rethrow_optional_in_non_opt.c3
Normal file
9
test/test_suite/errors/rethrow_optional_in_non_opt.c3
Normal file
@@ -0,0 +1,9 @@
|
||||
module test;
|
||||
import std;
|
||||
fn int? test() => 1;
|
||||
|
||||
fn int main()
|
||||
{
|
||||
test()!; // #error: This expression is doing a rethrow
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user