Skip to content

Commit

Permalink
(uptr)&((Foo*)null).a incorrectly inserts a null check. #1544.
Browse files Browse the repository at this point in the history
Fix regression handling typedefs from generic modules.
  • Loading branch information
lerno committed Oct 22, 2024
1 parent 9100638 commit d344cc6
Show file tree
Hide file tree
Showing 10 changed files with 222 additions and 75 deletions.
1 change: 1 addition & 0 deletions releasenotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
- Show error when declarations do not start with `fn` in interfaces. #1565
- `if (try foo)` was handled incorrectly inside a defer.
- `&self` argument not implicitly null checked. #1556.
- `(uptr)&((Foo*)null).a` incorrectly inserts a null check. #1544

### Stdlib changes
- Remove unintended print of `char[]` as String
Expand Down
31 changes: 0 additions & 31 deletions src/compiler/compiler_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -2811,37 +2811,6 @@ INLINE const char *type_invalid_storage_type_name(Type *type)
}
}

static inline StorageType type_storage_type(Type *type)
{
if (!type) return STORAGE_NORMAL;
bool is_distinct = false;
RETRY:
if (type == type_wildcard_optional) return STORAGE_WILDCARD;
switch (type->type_kind)
{
case TYPE_VOID:
return is_distinct ? STORAGE_UNKNOWN : STORAGE_VOID;
case TYPE_WILDCARD:
return STORAGE_WILDCARD;
case TYPE_MEMBER:
case TYPE_UNTYPED_LIST:
case TYPE_TYPEINFO:
case TYPE_FUNC_RAW:
return STORAGE_COMPILE_TIME;
case TYPE_OPTIONAL:
type = type->optional;
goto RETRY;
case TYPE_TYPEDEF:
type = type->canonical;
goto RETRY;
case TYPE_DISTINCT:
is_distinct = true;
type = type->decl->distinct->type;
goto RETRY;
default:
return STORAGE_NORMAL;
}
}

INLINE TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span)
{
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/enums.h
Original file line number Diff line number Diff line change
Expand Up @@ -1014,7 +1014,8 @@ typedef enum FLAG_ATTR

typedef enum
{
STORAGE_NORMAL,
STORAGE_ERROR = -1,
STORAGE_NORMAL = 0,
STORAGE_VOID,
STORAGE_COMPILE_TIME,
STORAGE_WILDCARD,
Expand Down
19 changes: 16 additions & 3 deletions src/compiler/llvm_codegen_expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,7 @@ static void llvm_emit_member_addr(GenContext *c, BEValue *value, Decl *parent, D
{
assert(member->resolve_status == RESOLVE_DONE);
Decl *found = NULL;

do
{
ArrayIndex index = find_member_index(parent, member);
Expand Down Expand Up @@ -1191,12 +1192,12 @@ static inline void llvm_emit_bitaccess(GenContext *c, BEValue *be_value, Expr *e
static inline void llvm_emit_access_addr(GenContext *c, BEValue *be_value, Expr *expr)
{
Expr *parent = expr->access_expr.parent;
llvm_emit_expr(c, be_value, parent);
Decl *member = expr->access_expr.ref;

Type *flat_type = type_flatten(parent->type);
if (flat_type->type_kind == TYPE_ENUM)
{
llvm_emit_expr(c, be_value, parent);
Decl *member = expr->access_expr.ref;

llvm_value_rvalue(c, be_value);
if (!flat_type->decl->backend_ref) llvm_get_typeid(c, parent->type);
assert(member->backend_ref);
Expand All @@ -1207,6 +1208,18 @@ static inline void llvm_emit_access_addr(GenContext *c, BEValue *be_value, Expr
llvm_value_set_address(be_value, ptr, member->type, alignment);
return;
}
if (expr_is_deref(parent))
{
llvm_emit_expr(c, be_value, parent->unary_expr.expr);
llvm_value_rvalue(c, be_value);
llvm_value_set_address_abi_aligned(be_value, be_value->value, parent->type);
}
else
{
llvm_emit_expr(c, be_value, parent);
}
Decl *member = expr->access_expr.ref;

llvm_emit_member_addr(c, be_value, type_lowering(parent->type)->decl, member);
}

Expand Down
28 changes: 19 additions & 9 deletions src/compiler/sema_decls.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ 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 bool sema_analyse_decl_type(SemaContext *context, Type *type, SourceSpan span);
static bool sema_analyse_variable_type(SemaContext *context, Type *type, SourceSpan span);
static inline bool sema_analyse_define(SemaContext *context, Decl *decl, bool *erase_decl);
static inline bool sema_analyse_distinct(SemaContext *context, Decl *decl, bool *erase_decl);

Expand Down Expand Up @@ -243,8 +243,10 @@ static inline bool sema_analyse_struct_member(SemaContext *context, Decl *parent
TypeInfo *type_info = type_infoptr(decl->var.type_info);
if (!sema_resolve_type_info(context, type_info, RESOLVE_TYPE_ALLOW_FLEXIBLE)) return decl_poison(decl);
Type *type = type_info->type;
switch (type_storage_type(type))
switch (sema_resolve_storage_type(context, type))
{
case STORAGE_ERROR:
return false;
case STORAGE_NORMAL:
break;
case STORAGE_VOID:
Expand Down Expand Up @@ -1693,8 +1695,10 @@ static inline bool sema_analyse_operator_element_at(SemaContext *context, Decl *
TypeInfo *rtype;
Decl **params;
if (!sema_analyse_operator_common(context, method, &rtype, &params, 2)) return false;
switch (type_storage_type(rtype->type))
switch (sema_resolve_storage_type(context, rtype->type))
{
case STORAGE_ERROR:
return false;
case STORAGE_NORMAL:
break;
case STORAGE_VOID:
Expand Down Expand Up @@ -3650,10 +3654,12 @@ static bool sema_analyse_attributes_for_var(SemaContext *context, Decl *decl, bo
return true;
}

static bool sema_analyse_decl_type(SemaContext *context, Type *type, SourceSpan span)
static bool sema_analyse_variable_type(SemaContext *context, Type *type, SourceSpan span)
{
switch (type_storage_type(type))
switch (sema_resolve_storage_type(context, type))
{
case STORAGE_ERROR:
return false;
case STORAGE_NORMAL:
return true;
case STORAGE_VOID:
Expand Down Expand Up @@ -3868,8 +3874,10 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
return decl_poison(decl);
}
decl->type = init_expr->type;
switch (type_storage_type(init_expr->type))
switch (sema_resolve_storage_type(context, init_expr->type))
{
case STORAGE_ERROR:
return decl_poison(decl);
case STORAGE_NORMAL:
break;
case STORAGE_WILDCARD:
Expand Down Expand Up @@ -3900,7 +3908,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
{
if (!sema_set_alloca_alignment(context, decl->type, &decl->alignment)) return false;
}
if (!sema_analyse_decl_type(context, decl->type, init_expr->span)) return decl_poison(decl);
if (!sema_analyse_variable_type(context, decl->type, init_expr->span)) return decl_poison(decl);
// Skip further evaluation.
goto EXIT_OK;
}
Expand All @@ -3911,7 +3919,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
: RESOLVE_TYPE_DEFAULT)) return decl_poison(decl);

Type *type = decl->type = type_info->type;
if (!sema_analyse_decl_type(context, type, type_info->span)) return decl_poison(decl);
if (!sema_analyse_variable_type(context, type, type_info->span)) return decl_poison(decl);

type = type_no_optional(type);
if (type_is_user_defined(type) && type->decl)
Expand Down Expand Up @@ -4083,8 +4091,10 @@ static bool sema_generate_parameterized_name_to_scratch(SemaContext *context, Mo
if (!sema_resolve_type_info(context, type_info, RESOLVE_TYPE_DEFAULT)) return false;
Type *type = type_info->type->canonical;
if (type->type_kind == TYPE_OPTIONAL) RETURN_SEMA_ERROR(type_info, "Expected a non-optional type.");
switch (type_storage_type(type))
switch (sema_resolve_storage_type(context, type))
{
case STORAGE_ERROR:
return false;
case STORAGE_NORMAL:
case STORAGE_VOID:
break;
Expand Down
106 changes: 77 additions & 29 deletions src/compiler/sema_expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -888,13 +888,19 @@ static inline bool sema_expr_analyse_ternary(SemaContext *context, Type *infer_t
false)) return false;
}

if (type_storage_type(left->type) == STORAGE_COMPILE_TIME)
switch (sema_resolve_storage_type(context, left->type))
{
if (left->type == type_untypedlist)
{
RETURN_SEMA_ERROR(expr, "The ternary would be an 'untyped list', you need to explicitly type one or both branches to a runtime type.");
}
RETURN_SEMA_ERROR(expr, "A ternary must always return a runtime type, but it was %s.", type_quoted_error_string(left_canonical));
case STORAGE_ERROR:
return false;
case STORAGE_COMPILE_TIME:
if (left->type == type_untypedlist)
{
RETURN_SEMA_ERROR(expr, "The ternary would be an 'untyped list', you need to explicitly type one or both branches to a runtime type.");
}
RETURN_SEMA_ERROR(expr, "A ternary must always return a runtime type, but it was %s.", type_quoted_error_string(left_canonical));
break;
default:
break;
}
if (path != COND_MISSING)
{
Expand Down Expand Up @@ -1278,9 +1284,14 @@ static bool sema_analyse_parameter(SemaContext *context, Expr *arg, Decl *param,
SEMA_NOTE(definition, "The definition is here.");
return false;
}
if (type_storage_type(type) != STORAGE_NORMAL)
switch (sema_resolve_storage_type(context, type))
{
RETURN_SEMA_ERROR(arg, "A value of type %s cannot be passed by reference.", type_quoted_error_string(type));
case STORAGE_ERROR:
return false;
case STORAGE_NORMAL:
break;
default:
RETURN_SEMA_ERROR(arg, "A value of type %s cannot be passed by reference.", type_quoted_error_string(type));
}
if (type && type->canonical != arg->type->canonical)
{
Expand All @@ -1305,8 +1316,10 @@ static bool sema_analyse_parameter(SemaContext *context, Expr *arg, Decl *param,
// foo
if (!sema_analyse_expr_rhs(context, type, arg, true, no_match_ref, false)) return false;
if (IS_OPTIONAL(arg)) *optional_ref = true;
switch (type_storage_type(arg->type))
switch (sema_resolve_storage_type(context, arg->type))
{
case STORAGE_ERROR:
return false;
case STORAGE_NORMAL:
break;
case STORAGE_VOID:
Expand Down Expand Up @@ -1698,10 +1711,15 @@ SPLAT_NORMAL:;
if (!callee->macro)
{
if (!sema_analyse_expr(context, arg)) return false;
if (type_storage_type(arg->type) != STORAGE_NORMAL)
switch (sema_resolve_storage_type(context, arg->type))
{
RETURN_SEMA_ERROR(arg, "A value of type %s cannot be passed as a raw variadic argument.",
type_quoted_error_string(arg->type));
case STORAGE_ERROR:
return false;
case STORAGE_NORMAL:
break;
default:
RETURN_SEMA_ERROR(arg, "A value of type %s cannot be passed as a raw variadic argument.",
type_quoted_error_string(arg->type));
}
cast_promote_vararg(context, arg);
}
Expand All @@ -1711,10 +1729,15 @@ SPLAT_NORMAL:;
case VARIADIC_ANY:
if (!sema_analyse_expr(context, arg)) return false;
Type *type = arg->type;
if (type_storage_type(type) != STORAGE_NORMAL)
switch (sema_resolve_storage_type(context, arg->type))
{
RETURN_SEMA_ERROR(arg, "A value of type %s cannot be passed as a variadic argument.",
type_quoted_error_string(type));
case STORAGE_ERROR:
return false;
case STORAGE_NORMAL:
break;
default:
RETURN_SEMA_ERROR(arg, "A value of type %s cannot be passed as a variadic argument.",
type_quoted_error_string(type));
}
expr_insert_addr(arg);
FALLTHROUGH;
Expand Down Expand Up @@ -2137,9 +2160,19 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
type_quoted_error_string(type_get_ptr(type_info->type)));
}
body_arg->type = type;
if (type_info && type_storage_type(type_info->type) == STORAGE_NORMAL)

if (type_info)
{
if (!sema_set_alloca_alignment(context, body_arg->type, &body_arg->alignment)) return false;
switch (sema_resolve_storage_type(context, type_info->type))
{
case STORAGE_ERROR:
return false;
case STORAGE_NORMAL:
if (!sema_set_alloca_alignment(context, body_arg->type, &body_arg->alignment)) return false;
break;
default:
break;
}
}
}

Expand Down Expand Up @@ -7039,15 +7072,21 @@ static inline bool sema_expr_analyse_taddr(SemaContext *context, Expr *expr, boo
if (!sema_analyse_expr(context, inner)) return false;

Type *type = inner->type;
if (type_storage_type(type) != STORAGE_NORMAL)

switch (sema_resolve_storage_type(context, type))
{
if (failed_ref)
{
*failed_ref = true;
case STORAGE_ERROR:
return false;
}
RETURN_SEMA_ERROR(expr, "It is not possible to take the address from a value of type %s.",
type_quoted_error_string(type));
case STORAGE_NORMAL:
break;
default:
if (failed_ref)
{
*failed_ref = true;
return false;
}
RETURN_SEMA_ERROR(expr, "It is not possible to take the address from a value of type %s.",
type_quoted_error_string(type));
}
// 2. The type is the resulting type of the expression.
expr->type = type_get_ptr_recurse(inner->type);
Expand Down Expand Up @@ -7797,10 +7836,14 @@ static inline bool sema_expr_analyse_ct_alignof(SemaContext *context, Expr *expr
Decl *decl = sema_expr_analyse_var_path(context, main_var);
if (!decl) return false;
Type *type = decl->type;
if (type_storage_type(type) != STORAGE_NORMAL)
switch (sema_resolve_storage_type(context, type))
{
SEMA_ERROR(main_var, "Cannot use '$alignof' on type %s.", type_quoted_error_string(type));
return false;
case STORAGE_ERROR:
return false;
case STORAGE_NORMAL:
break;
default:
RETURN_SEMA_ERROR(main_var, "Cannot use '$alignof' on type %s.", type_quoted_error_string(type));
}
AlignSize align;
if (decl && !decl_is_user_defined_type(decl))
Expand Down Expand Up @@ -8663,9 +8706,14 @@ static inline bool sema_expr_analyse_ct_arg(SemaContext *context, Type *infer_ty
if (!decl)
{
if (!sema_analyse_inferred_expr(context, infer_type, arg_expr)) return false;
if (type_storage_type(arg_expr->type) != STORAGE_NORMAL)
switch (sema_resolve_storage_type(context, arg_expr->type))
{
RETURN_SEMA_ERROR(expr, "The vararg doesn't have a valid runtime type.");
case STORAGE_ERROR:
return false;
case STORAGE_NORMAL:
break;
default:
RETURN_SEMA_ERROR(expr, "The vararg doesn't have a valid runtime type.");
}
decl = decl_new_generated_var(arg_expr->type, VARDECL_PARAM, arg_expr->span);
decl->var.init_expr = arg_expr;
Expand Down
Loading

0 comments on commit d344cc6

Please sign in to comment.