From b03ae8bb17e9fd5efec0a6e431e6eb0e8d3a0371 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Fri, 19 Sep 2025 18:05:29 +0200 Subject: [PATCH] Alias and distinct types didn't check the underlying type wasn't compile time or optional. --- releasenotes.md | 1 + src/compiler/parse_global.c | 2 +- src/compiler/sema_decls.c | 38 ++++++++++++++++++++++++--- test/test_suite/types/bad_typedefs.c3 | 13 +++++++++ 4 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 test/test_suite/types/bad_typedefs.c3 diff --git a/releasenotes.md b/releasenotes.md index 41a25d9dd..53da49918 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -34,6 +34,7 @@ - Fix compile time format check when the formatting string is a constant slice. - Compiler segfault for invalid e-mails in project.json. #2488 - Taking `.ordinal` from an enum passed by pointer and then taking the address of this result would return the enum, not int. +- Alias and distinct types didn't check the underlying type wasn't compile time or optional. ### Stdlib changes - Added generic `InterfaceList` to store a list of values that implement a specific interface diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index bef7e04b5..86ff53558 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -1910,7 +1910,7 @@ static inline Decl *parse_typedef_declaration(ParseContext *c) return poisoned_decl; } // 2. Now parse the type which we know is here. - ASSIGN_TYPE_OR_RET(decl->distinct, parse_type(c), poisoned_decl); + ASSIGN_TYPE_OR_RET(decl->distinct, parse_optional_type(c), poisoned_decl); ASSERT(!tok_is(c, TOKEN_LBRACE)); diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 0a8d88f9a..d0ef096de 100755 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -41,7 +41,7 @@ static bool sema_analyse_attributes_for_var(SemaContext *context, Decl *decl, bo static bool sema_check_section(SemaContext *context, Attr *attr); static inline bool sema_analyse_attribute_decl(SemaContext *context, SemaContext *c, Decl *decl, bool *erase_decl); -static inline bool sema_analyse_typedef(SemaContext *context, Decl *decl, bool *erase_decl); +static inline bool sema_analyse_type_alias(SemaContext *context, Decl *decl, bool *erase_decl); static bool sema_analyse_variable_type(SemaContext *context, Type *type, SourceSpan span); static inline bool sema_analyse_alias(SemaContext *context, Decl *decl, bool *erase_decl); static inline bool sema_analyse_distinct(SemaContext *context, Decl *decl, bool *erase_decl); @@ -1460,7 +1460,7 @@ static inline bool sema_analyse_fntype(SemaContext *context, Decl *decl, bool *e return sema_analyse_function_signature(context, decl, NULL, sig->abi, sig); } -static inline bool sema_analyse_typedef(SemaContext *context, Decl *decl, bool *erase_decl) +static inline bool sema_analyse_type_alias(SemaContext *context, Decl *decl, bool *erase_decl) { if (!sema_analyse_attributes(context, decl, decl->attributes, ATTR_ALIAS, erase_decl)) return decl_poison(decl); if (*erase_decl) return true; @@ -1478,6 +1478,24 @@ static inline bool sema_analyse_typedef(SemaContext *context, Decl *decl, bool * TypeInfo *info = decl->type_alias_decl.type_info; info->in_def = true; if (!sema_resolve_type_info(context, info, RESOLVE_TYPE_DEFAULT)) return false; + if (type_is_optional(info->type)) + { + RETURN_SEMA_ERROR(info, "You cannot create an alias for an optional type like %s.", type_quoted_error_string(info->type)); + } + switch (sema_resolve_storage_type(context, info->type)) + { + case STORAGE_ERROR: + return false; + case STORAGE_NORMAL: + case STORAGE_UNKNOWN: + case STORAGE_VOID: + break; + case STORAGE_WILDCARD: + RETURN_SEMA_ERROR(info, "You cannot create an alias for the wildcard type."); + case STORAGE_COMPILE_TIME: + RETURN_SEMA_ERROR(info, "You cannot create an alias for %s as it is a compile time type.", + type_invalid_storage_type_name(info->type)); + } decl->type->canonical = info->type->canonical; // Do we need anything else? return true; @@ -1504,6 +1522,20 @@ static inline bool sema_analyse_distinct(SemaContext *context, Decl *decl, bool // Optional isn't allowed of course. if (type_is_optional(info->type)) RETURN_SEMA_ERROR(decl, "You cannot create a distinct type from an optional."); + switch (sema_resolve_storage_type(context, info->type)) + { + case STORAGE_ERROR: + return false; + case STORAGE_NORMAL: + case STORAGE_UNKNOWN: + case STORAGE_VOID: + break; + case STORAGE_WILDCARD: + RETURN_SEMA_ERROR(info, "You cannot create a distinct type from the wildcard type."); + case STORAGE_COMPILE_TIME: + RETURN_SEMA_ERROR(info, "You cannot create a distinct type for %s as it is a compile time type.", + type_invalid_storage_type_name(info->type)); + } // Distinct types drop the canonical part. info->type = info->type->canonical; @@ -5386,7 +5418,7 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl) if (!sema_analyse_distinct(context, decl, &erase_decl)) goto FAILED; break; case DECL_TYPEDEF: - if (!sema_analyse_typedef(context, decl, &erase_decl)) goto FAILED; + if (!sema_analyse_type_alias(context, decl, &erase_decl)) goto FAILED; break; case DECL_ENUM: if (!sema_analyse_enum(context, decl, &erase_decl)) goto FAILED; diff --git a/test/test_suite/types/bad_typedefs.c3 b/test/test_suite/types/bad_typedefs.c3 new file mode 100644 index 000000000..c06739c5c --- /dev/null +++ b/test/test_suite/types/bad_typedefs.c3 @@ -0,0 +1,13 @@ +module test; +import std; + +struct Foo { struct x { int a; } } +alias Floo = $typeof(Foo.x); // #error: You cannot create an alias for a member reference as it is a compile time type +alias Void = void?; // #error: You cannot create an alias for an optional type +typedef Floo2 = $typeof(Foo.x); // #error: You cannot create a distinct type for a member reference +typedef Void2 = void?; // #error: You cannot create a distinct type from + +fn void main() +{ + +} \ No newline at end of file