mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Improved error messages for foo(void), foo(int!) declarations.
This commit is contained in:
@@ -1594,7 +1594,7 @@ Expr *parse_type_expression_with_path(ParseContext *c, Path *path)
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSIGN_TYPE_OR_RET(type, parse_failable_type(c), poisoned_expr);
|
||||
ASSIGN_TYPE_OR_RET(type, parse_optional_type(c), poisoned_expr);
|
||||
}
|
||||
if (tok_is(c, TOKEN_LBRACE))
|
||||
{
|
||||
|
||||
@@ -703,7 +703,7 @@ TypeInfo *parse_type(ParseContext *c)
|
||||
return parse_type_with_base(c, base);
|
||||
}
|
||||
|
||||
TypeInfo *parse_failable_type(ParseContext *c)
|
||||
TypeInfo *parse_optional_type(ParseContext *c)
|
||||
{
|
||||
ASSIGN_TYPE_OR_RET(TypeInfo *info, parse_base_type(c), poisoned_type_info);
|
||||
ASSIGN_TYPE_OR_RET(info, parse_type_with_base(c, info), poisoned_type_info);
|
||||
@@ -771,7 +771,7 @@ Decl *parse_decl(ParseContext *c)
|
||||
bool is_threadlocal = try_consume(c, TOKEN_TLOCAL);
|
||||
bool is_static = !is_threadlocal && try_consume(c, TOKEN_STATIC);
|
||||
|
||||
ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_failable_type(c), poisoned_decl);
|
||||
ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_optional_type(c), poisoned_decl);
|
||||
|
||||
ASSIGN_DECL_OR_RET(Decl * decl, parse_decl_after_type(c, type), poisoned_decl);
|
||||
if (type->failable && decl->var.unwrap)
|
||||
@@ -959,7 +959,7 @@ static inline Decl *parse_global_declaration(ParseContext *c, Visibility visibil
|
||||
{
|
||||
bool threadlocal = try_consume(c, TOKEN_TLOCAL);
|
||||
|
||||
ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_failable_type(c), poisoned_decl);
|
||||
ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_optional_type(c), poisoned_decl);
|
||||
|
||||
Decl *decl = DECL_VAR_NEW(type, VARDECL_GLOBAL, visibility);
|
||||
|
||||
@@ -999,7 +999,12 @@ static inline Decl *parse_global_declaration(ParseContext *c, Visibility visibil
|
||||
*/
|
||||
static inline bool parse_param_decl(ParseContext *c, Visibility parent_visibility, Decl*** parameters, bool require_name)
|
||||
{
|
||||
ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_type(c), false);
|
||||
ASSIGN_TYPE_OR_RET(TypeInfo *type, parse_optional_type(c), false);
|
||||
if (type->failable)
|
||||
{
|
||||
SEMA_ERROR(type, "Parameters may not be failable.");
|
||||
return false;
|
||||
}
|
||||
bool vararg = try_consume(c, TOKEN_ELLIPSIS);
|
||||
Decl *param = DECL_VAR_NEW(type, VARDECL_PARAM, parent_visibility);
|
||||
param->var.vararg = vararg;
|
||||
@@ -1069,7 +1074,7 @@ bool parse_parameters(ParseContext *c, Visibility visibility, Decl ***params_ref
|
||||
|
||||
if (!ellipsis && parse_next_is_typed_parameter(c))
|
||||
{
|
||||
ASSIGN_TYPE_OR_RET(type, parse_type(c), false);
|
||||
ASSIGN_TYPE_OR_RET(type, parse_optional_type(c), false);
|
||||
ellipsis = try_consume(c, TOKEN_ELLIPSIS);
|
||||
}
|
||||
|
||||
@@ -1159,7 +1164,7 @@ bool parse_parameters(ParseContext *c, Visibility visibility, Decl ***params_ref
|
||||
default:
|
||||
if (!type && parse_next_may_be_type(c))
|
||||
{
|
||||
ASSIGN_TYPE_OR_RET(type, parse_type(c), false);
|
||||
ASSIGN_TYPE_OR_RET(type, parse_optional_type(c), false);
|
||||
param_kind = VARDECL_PARAM;
|
||||
no_name = true;
|
||||
span = type->span;
|
||||
@@ -1168,6 +1173,11 @@ bool parse_parameters(ParseContext *c, Visibility visibility, Decl ***params_ref
|
||||
SEMA_ERROR_HERE("Expected a parameter.");
|
||||
return false;
|
||||
}
|
||||
if (type && type->failable)
|
||||
{
|
||||
SEMA_ERROR(type, "Parameters may not be failable.");
|
||||
return false;
|
||||
}
|
||||
Decl *param = decl_new_var(name, span, type, param_kind, visibility);
|
||||
param->var.type_info = type;
|
||||
if (!no_name)
|
||||
@@ -1523,7 +1533,7 @@ static inline Decl *parse_define_type(ParseContext *c, Visibility visibility)
|
||||
Decl *decl = decl_new_with_type(alias_name, name_loc, DECL_TYPEDEF, visibility);
|
||||
decl->typedef_decl.is_func = true;
|
||||
decl->typedef_decl.is_distinct = distinct;
|
||||
ASSIGN_TYPE_OR_RET(TypeInfo *type_info, parse_failable_type(c), poisoned_decl);
|
||||
ASSIGN_TYPE_OR_RET(TypeInfo *type_info, parse_optional_type(c), poisoned_decl);
|
||||
decl->typedef_decl.function_signature.returntype = type_infoid(type_info);
|
||||
if (!parse_parameter_list(c, decl->visibility, &(decl->typedef_decl.function_signature), true))
|
||||
{
|
||||
@@ -1726,7 +1736,7 @@ static inline bool parse_func_macro_header(ParseContext *c, bool is_macro,
|
||||
}
|
||||
|
||||
// 2. Now we must have a type - either that is the return type or the method type.
|
||||
ASSIGN_TYPE_OR_RET(rtype, parse_failable_type(c), false);
|
||||
ASSIGN_TYPE_OR_RET(rtype, parse_optional_type(c), false);
|
||||
|
||||
// 4. We might have a type here, if so then we read it.
|
||||
if (!tok_is(c, TOKEN_DOT) && !parse_is_macro_name(c))
|
||||
|
||||
@@ -375,7 +375,7 @@ static inline bool parse_foreach_var(ParseContext *c, Ast *foreach)
|
||||
// If we don't get foreach (foo ... or foreach (*foo ... then a type is expected.
|
||||
if (!tok_is(c, TOKEN_IDENT) && !tok_is(c, TOKEN_AMP))
|
||||
{
|
||||
ASSIGN_TYPE_OR_RET(type, parse_failable_type(c), false);
|
||||
ASSIGN_TYPE_OR_RET(type, parse_optional_type(c), false);
|
||||
|
||||
// Add the failable to the type for nicer error reporting.
|
||||
RANGE_EXTEND_PREV(type);
|
||||
|
||||
@@ -24,7 +24,7 @@ Expr *parse_type_expression_with_path(ParseContext *c, Path *path);
|
||||
Expr *parse_expr(ParseContext *c);
|
||||
bool consume_ident(ParseContext *c, const char* name);
|
||||
TypeInfo *parse_type(ParseContext *c);
|
||||
TypeInfo *parse_failable_type(ParseContext *c);
|
||||
TypeInfo *parse_optional_type(ParseContext *c);
|
||||
TypeInfo *parse_type_with_base(ParseContext *c, TypeInfo *type_info);
|
||||
Expr* parse_constant_expr(ParseContext *c);
|
||||
void parse_imports(ParseContext *c);
|
||||
|
||||
@@ -49,8 +49,20 @@ static bool sema_check_section(SemaContext *context, Attr *attr)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_check_no_duplicate_parameter(Decl **decls, Decl *current, unsigned current_index, unsigned count)
|
||||
static inline bool sema_check_param_uniqueness_and_type(Decl **decls, Decl *current, unsigned current_index, unsigned count)
|
||||
{
|
||||
if (current->type && current->type == type_void)
|
||||
{
|
||||
if (count == 1 && !current->name && current->var.kind == VARDECL_PARAM)
|
||||
{
|
||||
SEMA_ERROR(current, "C-style 'foo(void)' style argument declarations are not valid, please remove 'void'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
SEMA_ERROR(current, "Parameters may not be of type 'void'.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const char *name = current->name;
|
||||
if (!name) return true;
|
||||
for (int i = 0; i < current_index; i++)
|
||||
@@ -637,7 +649,7 @@ static inline Type *sema_analyse_function_signature(SemaContext *context, CallAB
|
||||
all_ok = false;
|
||||
continue;
|
||||
}
|
||||
if (!sema_check_no_duplicate_parameter(params, param, i, param_count))
|
||||
if (!sema_check_param_uniqueness_and_type(params, param, i, param_count))
|
||||
{
|
||||
all_ok = false;
|
||||
continue;
|
||||
@@ -1980,7 +1992,7 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl)
|
||||
case VARDECL_ERASE:
|
||||
UNREACHABLE
|
||||
}
|
||||
if (!sema_check_no_duplicate_parameter(parameters, param, i, param_count)) return decl_poison(decl);
|
||||
if (!sema_check_param_uniqueness_and_type(parameters, param, i, param_count)) return decl_poison(decl);
|
||||
param->resolve_status = RESOLVE_DONE;
|
||||
}
|
||||
DeclId body_param = decl->macro_decl.body_param;
|
||||
@@ -2021,7 +2033,7 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl)
|
||||
case VARDECL_ERASE:
|
||||
UNREACHABLE
|
||||
}
|
||||
if (!sema_check_no_duplicate_parameter(body_parameters, param, i, body_param_count)) return decl_poison(decl);
|
||||
if (!sema_check_param_uniqueness_and_type(body_parameters, param, i, body_param_count)) return decl_poison(decl);
|
||||
param->resolve_status = RESOLVE_DONE;
|
||||
}
|
||||
bool pure = false;
|
||||
|
||||
@@ -1416,12 +1416,27 @@ FAIL_MISSING:
|
||||
if (params && params[i]->var.vararg) continue;
|
||||
|
||||
// 17d. Argument missing, that's bad.
|
||||
if (is_func_ptr)
|
||||
if (!uses_named_parameters || is_func_ptr || !params[i]->name)
|
||||
{
|
||||
SEMA_ERROR(call, "The call is missing parameter(s), please check the definition.");
|
||||
if (entries_needed == 1)
|
||||
{
|
||||
SEMA_ERROR(call, "A parameter was expected for the call.");
|
||||
return false;
|
||||
}
|
||||
if (num_args)
|
||||
{
|
||||
unsigned needed = entries_needed - num_args;
|
||||
SEMA_ERROR(args[num_args - 1],
|
||||
"Expected %d more %s after this one, did you forget %s?",
|
||||
needed, needed > 1 ? "arguments" : "argument", needed > 1 ? "them" : "it");
|
||||
}
|
||||
else
|
||||
{
|
||||
SEMA_ERROR(call, "The call needs %d parameters, please provide them.", entries_needed);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
SEMA_ERROR(call, "The mandatory parameter '%s' was not set, please add it.", params[i]->name);
|
||||
SEMA_ERROR(call, "The parameter '%s' must be set, did you forget it?", params[i]->name);
|
||||
return false;
|
||||
}
|
||||
call->call_expr.arguments = actual_args;
|
||||
|
||||
@@ -6,7 +6,7 @@ struct St12
|
||||
{
|
||||
int a @align(16);
|
||||
}
|
||||
fn St12 f12_0(void) { while (1) {}; unreachable(); }
|
||||
fn St12 f12_0() { while (1) {}; unreachable(); }
|
||||
fn void f12_1(St12 a0) {}
|
||||
|
||||
struct St13_0 { long[3] f0; }
|
||||
|
||||
@@ -39,7 +39,7 @@ struct St {
|
||||
|
||||
extern fn St func_returning_struct();
|
||||
|
||||
fn void loop(void) {
|
||||
fn void loop() {
|
||||
func_returning_struct();
|
||||
}
|
||||
|
||||
|
||||
3
test/test_suite/functions/failable_param.c3
Normal file
3
test/test_suite/functions/failable_param.c3
Normal file
@@ -0,0 +1,3 @@
|
||||
module test;
|
||||
|
||||
fn void test4(void!); // #error: Parameters may not be failable.
|
||||
2
test/test_suite/functions/void_params.c3
Normal file
2
test/test_suite/functions/void_params.c3
Normal file
@@ -0,0 +1,2 @@
|
||||
fn void test(int, void) {} // #error: Parameters may not be of type 'void'.
|
||||
fn void test3(void); // #error: C-style 'foo(void)' style argument declarations are not valid
|
||||
@@ -6,7 +6,7 @@ struct St12
|
||||
{
|
||||
int a @align(16);
|
||||
}
|
||||
fn St12 f12_0(void) { while (1) {}; unreachable(); }
|
||||
fn St12 f12_0() { while (1) {}; unreachable(); }
|
||||
fn void f12_1(St12 a0) {}
|
||||
|
||||
struct St13_0 { long[3] f0; }
|
||||
|
||||
@@ -39,7 +39,7 @@ struct St {
|
||||
|
||||
extern fn St func_returning_struct();
|
||||
|
||||
fn void loop(void) {
|
||||
fn void loop() {
|
||||
func_returning_struct();
|
||||
}
|
||||
|
||||
|
||||
3
test/test_suite2/functions/failable_param.c3
Normal file
3
test/test_suite2/functions/failable_param.c3
Normal file
@@ -0,0 +1,3 @@
|
||||
module test;
|
||||
|
||||
fn void test4(void!); // #error: Parameters may not be failable.
|
||||
2
test/test_suite2/functions/void_params.c3
Normal file
2
test/test_suite2/functions/void_params.c3
Normal file
@@ -0,0 +1,2 @@
|
||||
fn void test(int, void) {} // #error: Parameters may not be of type 'void'.
|
||||
fn void test3(void); // #error: C-style 'foo(void)' style argument declarations are not valid
|
||||
Reference in New Issue
Block a user