Crash when trying to define a method macro that isn't @construct but has no arguments.

This commit is contained in:
Christoffer Lerno
2025-02-20 15:51:21 +01:00
parent 341a70bd5d
commit 79db06ecd1
3 changed files with 31 additions and 13 deletions

View File

@@ -15,6 +15,7 @@
- Test runner with tracking allocator didn't properly handle teardown_fn
- Correctly give an error if a character literal contains a line break.
- Implicitly unwrapped optional value in defer incorrectly copied #1982.
- Crash when trying to define a method macro that isn't `@construct` but has no arguments.
### Stdlib changes

View File

@@ -11,7 +11,7 @@
static inline bool sema_analyse_func_macro(SemaContext *context, Decl *decl, AttributeDomain domain, bool *erase_decl);
static inline bool sema_analyse_func(SemaContext *context, Decl *decl, bool *erase_decl);
static inline bool sema_analyse_macro(SemaContext *context, Decl *decl, bool *erase_decl);
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfo *method_parent, bool is_export, bool is_deprecated, SourceSpan span);
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfo *method_parent, bool is_export, bool is_deprecated, Decl *decl);
static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl);
static inline bool sema_check_param_uniqueness_and_type(SemaContext *context, Decl **decls, Decl *current,
unsigned current_index, unsigned count);
@@ -1093,7 +1093,7 @@ ERROR:
return decl_poison(decl);
}
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfo *method_parent, bool is_export, bool is_deprecated, SourceSpan span)
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfo *method_parent, bool is_export, bool is_deprecated, Decl *decl)
{
Variadic variadic_type = sig->variadic;
Decl **params = sig->params;
@@ -1177,6 +1177,15 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig,
param->var.is_self = true;
}
// Ensure it has at least one parameter if method.
if (method_parent && !vec_size(params) && decl->operator != OVERLOAD_CONSTRUCT)
{
RETURN_SEMA_ERROR(decl, "A method must start with an argument of the type "
"it is a method of, e.g. 'fn void %s.%s(%s* self)', "
"unless it is a 'construct' method,",
type_to_error_string(method_parent->type), decl->name, type_to_error_string(method_parent->type));
}
// Check parameters
for (unsigned i = 0; i < param_count; i++)
{
@@ -1352,7 +1361,7 @@ bool sema_analyse_function_signature(SemaContext *context, Decl *func_decl, Type
bool deprecated = func_decl->resolved_attributes && func_decl->attrs_resolved && func_decl->attrs_resolved->deprecated;
if (!sema_analyse_signature(context, signature, parent, func_decl->is_export, deprecated, func_decl->span)) return false;
if (!sema_analyse_signature(context, signature, parent, func_decl->is_export, deprecated, func_decl)) return false;
Variadic variadic_type = signature->variadic;
@@ -2358,15 +2367,6 @@ static inline bool sema_analyse_method(SemaContext *context, Decl *decl)
bool is_constructor = decl->operator == OVERLOAD_CONSTRUCT;
// Ensure it has at least one parameter.
if (!vec_size(params) && !is_constructor)
{
RETURN_SEMA_ERROR(decl, "A method must start with an argument of the type "
"it is a method of, e.g. 'fn void %s.%s(%s* self)', "
"unless it is a 'construct' method,",
type_to_error_string(par_type), decl->name, type_to_error_string(par_type));
}
// Ensure that the first parameter is valid.
if (!is_constructor && !sema_is_valid_method_param(context, params[0], par_type, is_dynamic)) return false;
@@ -3874,7 +3874,7 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl, bool *er
if (!sema_analyse_signature(context, &decl->func_decl.signature,
type_infoptrzero(decl->func_decl.type_parent),
false, deprecated, decl->span)) return false;
false, deprecated, decl)) return false;
DeclId body_param = decl->func_decl.body_param;
if (!decl->func_decl.signature.is_at_macro && body_param && !decl->func_decl.signature.is_safemacro)

View File

@@ -0,0 +1,17 @@
import std::io;
// Issue #1990
struct Foo
{
uint field;
}
macro Foo.bar() // #error: A method must start with an argument
{
io.printn("UwU");
}
fn void main()
{
Foo foo = {};
foo.bar();
}