diff --git a/releasenotes.md b/releasenotes.md index 306486dfd..4bded3aa6 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -38,6 +38,8 @@ - Bad error message when using a generic method without generic parameters #1228 - Private function called from nested macro not visible to linker #1232 - Bitstructs in structs would not be correctly be handled in some cases. +- Fix problem where a $$FUNC would return "" when evaluated for a static in a function #1236. +- `ordinal` is no longer a valid associated value name for enums. ### Stdlib changes - Added `remove_first_item` `remove_last_item` and `remove_item` as aliases for the `match` functions. diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index d20efc912..59666bde8 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1688,6 +1688,7 @@ typedef enum { CALL_ENV_GLOBAL_INIT, CALL_ENV_FUNCTION, + CALL_ENV_FUNCTION_STATIC, CALL_ENV_ATTR, } CallEnvKind; diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index b123a572f..22a0c54cf 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -16,7 +16,6 @@ typedef struct extern ParseRule rules[TOKEN_EOF + 1]; - bool parse_current_is_expr(ParseContext *c) { return rules[c->tok].prefix != NULL; @@ -88,16 +87,18 @@ static bool parse_expr_list(ParseContext *c, Expr ***exprs_ref, TokenType end_to } return true; } - -bool parse_expr_list_no_trail(ParseContext *c, Expr ***exprs_ref, TokenType end_token) +/** + * generic_parameters ::= '(<' expr (',' expr) '>)' + */ +bool parse_generic_parameters(ParseContext *c, Expr ***exprs_ref) { - if (try_consume(c, end_token)) return true; + advance_and_verify(c, TOKEN_LGENPAR); while (true) { ASSIGN_EXPR_OR_RET(Expr *expr, parse_expr(c), false); vec_add(*exprs_ref, expr); if (try_consume(c, TOKEN_COMMA)) continue; - CONSUME_OR_RET(end_token, false); + CONSUME_OR_RET(TOKEN_RGENPAR, false); return true; } } @@ -971,16 +972,14 @@ static Expr *parse_subscript_expr(ParseContext *c, Expr *left) } /** - * generic_expr ::= '(<' generic_parameters '>)' + * generic_expr ::= IDENT generic_parameters */ static Expr *parse_generic_expr(ParseContext *c, Expr *left) { assert(left && expr_ok(left)); - advance_and_verify(c, TOKEN_LGENPAR); - Expr *subs_expr = expr_new_expr(EXPR_GENERIC_IDENT, left); subs_expr->generic_ident_expr.parent = exprid(left); - if (!parse_expr_list_no_trail(c, &subs_expr->generic_ident_expr.parmeters, TOKEN_RGENPAR)) return poisoned_expr; + if (!parse_generic_parameters(c, &subs_expr->generic_ident_expr.parmeters)) return poisoned_expr; RANGE_EXTEND_PREV(subs_expr); return subs_expr; } diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index aa9d36b5a..664d5dfda 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -451,7 +451,6 @@ static inline TypeInfo *parse_base_type(ParseContext *c) } TypeInfo *type_info = NULL; - Type *type_found = NULL; switch (c->tok) { case TOKEN_TYPE_IDENT: @@ -463,7 +462,9 @@ static inline TypeInfo *parse_base_type(ParseContext *c) type_info->unresolved.name = symstr(c); break; case TYPE_TOKENS: - type_found = type_from_token(c->tok); + type_info = type_info_new_curr(c, TYPE_INFO_IDENTIFIER); + type_info->resolve_status = RESOLVE_DONE; + type_info->type = type_from_token(c->tok); break; default: if (c->tok == TOKEN_IDENT) @@ -476,36 +477,25 @@ static inline TypeInfo *parse_base_type(ParseContext *c) } return poisoned_type_info; } - if (type_found) - { - assert(!type_info); - type_info = type_info_new_curr(c, TYPE_INFO_IDENTIFIER); - type_info->resolve_status = RESOLVE_DONE; - type_info->type = type_found; - } - assert(type_info); advance(c); RANGE_EXTEND_PREV(type_info); return type_info; } +/** + * generic_type ::= type generic_parameters + */ static inline TypeInfo *parse_generic_type(ParseContext *c, TypeInfo *type) { assert(type_info_ok(type)); - - advance_and_verify(c, TOKEN_LGENPAR); TypeInfo *generic_type = type_info_new(TYPE_INFO_GENERIC, type->span); - if (!parse_expr_list_no_trail(c, &generic_type->generic.params, TOKEN_RGENPAR)) return poisoned_type_info; + if (!parse_generic_parameters(c, &generic_type->generic.params)) return poisoned_type_info; generic_type->generic.base = type; return generic_type; } /** - * array_type_index - * : '[' constant_expression ']' - * | '[' ']' - * | '[' '*' ']' - * ; + * array_type_index ::= '[' (constant_expression | '*')? ']' * * @param type the type to wrap, may not be poisoned. * @return type (poisoned if fails) @@ -563,9 +553,7 @@ DIRECT_SLICE:; } /** - * vector_type_index - * : '[<' constant_expression '>]' - * ; + * vector_type_index ::= '[<' (constant_expression | '*') '>]' * * @param type the type to wrap, may not be poisoned. * @return type (poisoned if fails) @@ -592,10 +580,7 @@ static inline TypeInfo *parse_vector_type_index(ParseContext *c, TypeInfo *type) } /** - * type - * : base_type - * | type '*' - * | type array_type_index + * type ::= base_type ('*' | array_type_index | vector_type_index | generic_parameters)* * * Assume already stepped into. * @return Type, poisoned if parsing is invalid. @@ -656,10 +641,7 @@ TypeInfo *parse_type_with_base(ParseContext *c, TypeInfo *type_info) } /** - * type - * : base_type - * | type '*' - * | type array_type_index + * type ::= base_type modifiers * * Assume already stepped into. * @return Type, poisoned if parsing is invalid. @@ -670,6 +652,11 @@ TypeInfo *parse_type(ParseContext *c) return parse_type_with_base(c, base); } +/** + * optional_type ::= type '!'? + * @param c + * @return + */ TypeInfo *parse_optional_type(ParseContext *c) { ASSIGN_TYPE_OR_RET(TypeInfo *info, parse_base_type(c), poisoned_type_info); @@ -690,6 +677,13 @@ TypeInfo *parse_optional_type(ParseContext *c) // --- Decl parsing +/** + * interface_impls ::= '(' (type (',' type)* ','? )? ')' + * + * @param c the context + * @param interfaces_ref the list to add interfaces to + * @return false if the parsing failed + */ bool parse_interface_impls(ParseContext *c, TypeInfo ***interfaces_ref) { if (!try_consume(c, TOKEN_LPAREN)) return true; @@ -1913,10 +1907,10 @@ static inline Decl *parse_def_ident(ParseContext *c) decl->define_decl.span = c->span; advance(c); - if (try_consume(c, TOKEN_LGENPAR)) + if (tok_is(c, TOKEN_LGENPAR)) { decl->define_decl.define_kind = DEFINE_IDENT_GENERIC; - if (!parse_expr_list_no_trail(c, &decl->define_decl.generic_params, TOKEN_RGENPAR)) return poisoned_decl; + if (!parse_generic_parameters(c, &decl->define_decl.generic_params)) return poisoned_decl; } if (!parse_attributes_for_global(c, decl)) return poisoned_decl; @@ -2146,7 +2140,7 @@ static inline bool parse_enum_param_list(ParseContext *c, Decl*** parameters_ref if (!parse_enum_param_decl(c, parameters_ref)) return false; Decl *last_parameter = VECLAST(*parameters_ref); assert(last_parameter); - last_parameter->var.index = vec_size(*parameters_ref) - 1; + last_parameter->var.index = vec_size(*parameters_ref) - 1; // NOLINT if (!try_consume(c, TOKEN_COMMA)) { EXPECT_OR_RET(TOKEN_RPAREN, false); @@ -2241,23 +2235,9 @@ static inline Decl *parse_enum_declaration(ParseContext *c) /** * Starts after 'fn' * - * func_name - * : path TYPE_IDENT '.' IDENT - * | TYPE_IDENT '.' IDENT - * | IDENT - * ; + * func_definition ::= func_macro_header fn_parameter_list opt_attributes (func_body | ';') + * func_body ::= ('=>' short_body) | compound_stmt * - * func_definition - * : func_declaration compound_statement - * | func_declaration ';' - * ; - * - * func_declaration - * : FN optional_type func_name '(' opt_parameter_type_list ')' opt_attributes - * ; - * - * @param visibility - * @return Decl* */ static inline Decl *parse_func_definition(ParseContext *c, AstId contracts, bool is_interface) { @@ -2307,6 +2287,7 @@ static inline Decl *parse_func_definition(ParseContext *c, AstId contracts, bool else { PRINT_ERROR_HERE("Expected the beginning of a block or a short statement."); + return poisoned_decl; } DEBUG_LOG("Finished parsing function %s", func->name); diff --git a/src/compiler/parser_internal.h b/src/compiler/parser_internal.h index c5d889ca3..d03116df0 100644 --- a/src/compiler/parser_internal.h +++ b/src/compiler/parser_internal.h @@ -54,7 +54,8 @@ Expr *parse_expression_list(ParseContext *c, bool allow_decls); Decl *parse_local_decl_after_type(ParseContext *c, TypeInfo *type); Decl *parse_var_decl(ParseContext *c); bool parse_current_is_expr(ParseContext *c); -bool parse_expr_list_no_trail(ParseContext *c, Expr ***exprs_ref, TokenType end_token); + +bool parse_generic_parameters(ParseContext *c, Expr ***exprs_ref); bool parse_parameters(ParseContext *c, Decl ***params_ref, Decl **body_params, Variadic *variadic, int *vararg_index_ref, ParameterParseKind parse_kind); diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 3bcfa12e7..bcde3cbd6 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -65,7 +65,6 @@ static inline bool sema_analyse_enum_param(SemaContext *context, Decl *param); static inline bool sema_analyse_enum(SemaContext *context, Decl *decl, bool *erase_decl); static inline bool sema_analyse_error(SemaContext *context, Decl *decl, bool *erase_decl); - static bool sema_check_section(SemaContext *context, Attr *attr) { Expr *expr = attr->exprs[0]; @@ -976,10 +975,9 @@ static bool sema_analyse_interface(SemaContext *context, Decl *decl, bool *erase static bool sema_deep_resolve_function_ptr(SemaContext *context, TypeInfo *type_to_resolve) { - assert(type_to_resolve->type); Type *type = type_to_resolve->type; RETRY: - switch (type->type_kind) + switch (type->type_kind) // NOLINT { case TYPE_POISONED: case TYPE_VOID: @@ -1024,6 +1022,7 @@ RETRY: } UNREACHABLE } + static bool sema_analyse_bitstruct(SemaContext *context, Decl *decl, bool *erase_decl) { if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_BITSTRUCT, erase_decl)) return decl_poison(decl); @@ -1087,15 +1086,17 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, { if (type_is_void(rtype)) { - RETURN_SEMA_ERROR(rtype_info, "@nodiscard cannot be used on %s returning 'void'.", is_macro ? "macros" : "functions"); + RETURN_SEMA_ERROR(rtype_info, "@nodiscard cannot be used on %s returning 'void'.", + is_macro ? "macros" : "functions"); } } if (sig->attrs.maydiscard) { if (!type_is_optional(rtype)) { - SEMA_ERROR(rtype_info, "@maydiscard can only be used on %s returning optional values.", is_macro ? "macros" : "functions"); - return false; + RETURN_SEMA_ERROR(rtype_info, + "@maydiscard can only be used on %s returning optional values.", + is_macro ? "macros" : "functions"); } } if (!sema_deep_resolve_function_ptr(context, rtype_info)) return false; @@ -1106,11 +1107,10 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, { if (variadic_type != VARIADIC_NONE) { - SEMA_ERROR(params[MAX_PARAMS], "The number of params exceeded the max of %d.", MAX_PARAMS); - return false; + RETURN_SEMA_ERROR(params[MAX_PARAMS], "The number of params exceeded the max of %d.", MAX_PARAMS); } - SEMA_ERROR(params[MAX_PARAMS], "The number of params exceeded the max of %d. To accept more arguments, consider using varargs.", MAX_PARAMS); - return false; + RETURN_SEMA_ERROR(params[MAX_PARAMS], "The number of params exceeded the max of %d. To accept more arguments, " + "consider using varargs.", MAX_PARAMS); } TypeInfo *method_parent = type_infoptrzero(type_parent); @@ -1307,6 +1307,7 @@ bool sema_analyse_function_signature(SemaContext *context, Decl *func_decl, Call if (!sema_analyse_signature(context, signature, func_decl->func_decl.type_parent, func_decl->is_export)) return false; Variadic variadic_type = signature->variadic; + // Remove the last empty value. if (variadic_type == VARIADIC_RAW) { @@ -1316,7 +1317,6 @@ bool sema_analyse_function_signature(SemaContext *context, Decl *func_decl, Call } Type **types = NULL; - bool all_ok = true; unsigned param_count = vec_size(params); for (unsigned i = 0; i < param_count; i++) @@ -1326,7 +1326,6 @@ bool sema_analyse_function_signature(SemaContext *context, Decl *func_decl, Call vec_add(types, params[i]->type); } - if (!all_ok) return false; Type *raw_type = sema_resolve_type_get_func(signature, abi); assert(func_decl->type->type_kind == TYPE_FUNC_RAW); assert(raw_type->function.prototype); @@ -1364,6 +1363,9 @@ static inline bool sema_analyse_typedef(SemaContext *context, Decl *decl, bool * return true; } +/** + * Analyse a distinct type. + */ static inline bool sema_analyse_distinct(SemaContext *context, Decl *decl, bool *erase) { // Check the attributes on the distinct type. @@ -1392,24 +1394,21 @@ static inline bool sema_analyse_enum_param(SemaContext *context, Decl *param) assert(param->decl_kind == DECL_VAR && param->var.kind == VARDECL_PARAM && param->var.type_info); if (vec_size(param->attributes)) { - SEMA_ERROR(param->attributes[0], "There are no valid attributes for associated values."); - return false; + RETURN_SEMA_ERROR(param->attributes[0], "There are no valid attributes for associated values."); } TypeInfo *type_info = type_infoptrzero(param->var.type_info); if (!sema_resolve_type_info(context, type_info, RESOLVE_TYPE_DEFAULT)) return false; assert(!param->var.vararg); param->type = type_info->type; assert(param->name); - if (param->name == kw_nameof) + if (param->name == kw_nameof || param->name == kw_ordinal) { - SEMA_ERROR(param, "'nameof' is not a valid parameter name for enums."); - return false; + RETURN_SEMA_ERROR(param, "'%s' is not a valid parameter name for enums.", param->name); } Decl *other = sema_decl_stack_resolve_symbol(param->name); if (other) { - SEMA_ERROR(param, "Duplicate parameter name '%s'.", param->name); - return false; + RETURN_SEMA_ERROR(param, "Duplicate parameter name '%s'.", param->name); } sema_decl_stack_push(param); assert(!param->var.init_expr); @@ -3703,7 +3702,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) } CallEnvKind env_kind = context->call_env.kind; - if (is_static) context->call_env.kind = CALL_ENV_GLOBAL_INIT; + if (is_static) context->call_env.kind = CALL_ENV_FUNCTION_STATIC; if (!sema_expr_analyse_assign_right_side(context, NULL, decl->type, init, false)) { context->call_env.kind = env_kind; diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 11d386f62..77e488c12 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -6829,6 +6829,10 @@ static inline bool sema_expr_analyse_rethrow(SemaContext *context, Expr *expr) { if (context->call_env.kind != CALL_ENV_FUNCTION) { + if (CALL_ENV_FUNCTION_STATIC) + { + RETURN_SEMA_ERROR(expr, "Rethrow cannot be used for a static initializer."); + } RETURN_SEMA_ERROR(expr, "Rethrow cannot be used outside of a function."); } @@ -7066,6 +7070,7 @@ static inline bool sema_expr_analyse_compiler_const(SemaContext *context, Expr * } return false; case CALL_ENV_FUNCTION: + case CALL_ENV_FUNCTION_STATIC: expr->expr_kind = EXPR_IDENTIFIER; expr_resolve_ident(expr, context->call_env.current_function); return true; @@ -7077,6 +7082,7 @@ static inline bool sema_expr_analyse_compiler_const(SemaContext *context, Expr * case CALL_ENV_GLOBAL_INIT: expr_rewrite_to_string(expr, ""); return true; + case CALL_ENV_FUNCTION_STATIC: case CALL_ENV_FUNCTION: { Decl *current_func = context->call_env.current_function; @@ -7867,6 +7873,7 @@ static inline bool sema_expr_analyse_lambda(SemaContext *context, Type *target_t scratch_buffer_append(".$global"); break; case CALL_ENV_FUNCTION: + case CALL_ENV_FUNCTION_STATIC: if (context->current_macro) { scratch_buffer_append(unit->module->name->module); diff --git a/src/compiler/sema_initializers.c b/src/compiler/sema_initializers.c index e283dd38b..0663694f0 100644 --- a/src/compiler/sema_initializers.c +++ b/src/compiler/sema_initializers.c @@ -47,7 +47,8 @@ static inline ConstantEvalKind env_eval_type(SemaContext *context); static inline ConstantEvalKind env_eval_type(SemaContext *context) { - return context->call_env.kind == CALL_ENV_GLOBAL_INIT ? CONSTANT_EVAL_GLOBAL_INIT : CONSTANT_EVAL_LOCAL_INIT; + if (context->call_env.kind == CALL_ENV_FUNCTION) return CONSTANT_EVAL_LOCAL_INIT; + return CONSTANT_EVAL_GLOBAL_INIT; } static inline void sema_not_enough_elements_error(SemaContext *context, Expr *initializer, int element) diff --git a/test/test_suite/enumerations/enum_invalid_param.c3 b/test/test_suite/enumerations/enum_invalid_param.c3 index fb40f9159..3c49e174b 100644 --- a/test/test_suite/enumerations/enum_invalid_param.c3 +++ b/test/test_suite/enumerations/enum_invalid_param.c3 @@ -1,4 +1,4 @@ -enum Test : int (int a, int b) +enum Test : int (int kindof, int qnameof) { FOO = {1, 2} } @@ -7,3 +7,8 @@ enum Test2 : (int a, int nameof) // #error: 'nameof' is not a valid parameter n { FOO = {1, 2} } + +enum Test3 : (int a, int ordinal) // #error: 'ordinal' is not a valid parameter name for enums +{ + FOO = {1, 2} +} diff --git a/test/test_suite/lambda/ct_lambda.c3t b/test/test_suite/lambda/ct_lambda.c3t index 1446fdb1d..d8132b6ba 100644 --- a/test/test_suite/lambda/ct_lambda.c3t +++ b/test/test_suite/lambda/ct_lambda.c3t @@ -84,10 +84,9 @@ fn int main() /* #expect: test.ll -@init.foo = internal unnamed_addr global ptr @"test.$global$lambda1", align 8 -@init.foo.2 = internal unnamed_addr global ptr @"test.$global$lambda2", align 8 +@init.foo = internal unnamed_addr global ptr @"test.foo_fn$lambda1", align 8 +@init.foo.2 = internal unnamed_addr global ptr @"test.foo_fn$lambda2", align 8 -; Function Attrs: define void @test.Foo.test(ptr %0, i32 %1) #0 { entry: %2 = load ptr, ptr %0, align 8 @@ -95,7 +94,6 @@ entry: ret void } -; Function Attrs: define void @test.FooTest.init(ptr %0) #0 { entry: %1 = load ptr, ptr @init.foo, align 8 @@ -103,7 +101,7 @@ entry: ret void } -define internal void @"test.$global$lambda1"(ptr %0, i32 %1) #0 { +define internal void @"test.foo_fn$lambda1"(ptr %0, i32 %1) #0 { entry: %z = alloca ptr, align 8 store ptr %0, ptr %z, align 8 @@ -121,8 +119,7 @@ if.exit: ; preds = %entry ret void } -; Function Attrs: -define internal void @"test.$global$lambda2"(ptr %0, i32 %1) #0 { +define internal void @"test.foo_fn$lambda2"(ptr %0, i32 %1) #0 { entry: %z = alloca ptr, align 8 store ptr %0, ptr %z, align 8