From bd8eae67f1616ca8fcb434a8ba932731c21891f8 Mon Sep 17 00:00:00 2001 From: acqn Date: Mon, 5 Apr 2021 16:40:32 +0800 Subject: [PATCH] Fixed local struct field access via the address of the struct. --- src/cc65/expr.c | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/cc65/expr.c b/src/cc65/expr.c index 9e08faeeb..74524c47a 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -1340,7 +1340,6 @@ static void Primary (ExprDesc* E) static void StructRef (ExprDesc* Expr) /* Process struct/union field after . or ->. */ { - ident Ident; Type* FinalType; TypeCode Q; @@ -1354,42 +1353,42 @@ static void StructRef (ExprDesc* Expr) } /* Get the symbol table entry and check for a struct/union field */ - strcpy (Ident, CurTok.Ident); NextToken (); - const SymEntry Field = FindStructField (Expr->Type, Ident); + const SymEntry Field = FindStructField (Expr->Type, CurTok.Ident); if (Field.Type == 0) { - Error ("No field named '%s' found in '%s'", Ident, GetFullTypeName (Expr->Type)); + Error ("No field named '%s' found in '%s'", CurTok.Ident, GetFullTypeName (Expr->Type)); /* Make the expression an integer at address zero */ ED_MakeConstAbs (Expr, 0, type_int); return; } - /* A struct/union is usually an lvalue. If not, it is a struct/union passed - ** in the primary register, which is usually the result returned from a - ** function. However, it is possible that this rvalue is the result of - ** certain kind of operations on an lvalue such as assignment, and there - ** are no reasons to disallow such use cases. So we just rely on the check - ** upon function returns to catch the unsupported cases and dereference the - ** rvalue address of the struct/union here all the time. - */ - if (IsTypePtr (Expr->Type) || - (ED_IsRVal (Expr) && - ED_IsLocPrimary (Expr) && - Expr->Type == GetStructReplacementType (Expr->Type))) { + if (IsTypePtr (Expr->Type)) { - if (!ED_IsConst (Expr) && !ED_IsLocPrimary (Expr)) { + /* pointer->field */ + if (!ED_IsQuasiConst (Expr) && !ED_IsLocPrimary (Expr)) { /* If we have a non-const struct/union pointer that is not in the - ** primary yet, load its content now. + ** primary yet, load its content now to get the base address. */ LoadExpr (CF_NONE, Expr); - - /* Clear the offset */ - Expr->IVal = 0; + ED_FinalizeRValLoad (Expr); } - /* Dereference the address expression */ ED_IndExpr (Expr); + } else if (ED_IsRVal (Expr) && + ED_IsLocPrimary (Expr) && + Expr->Type == GetStructReplacementType (Expr->Type)) { + + /* A struct/union is usually an lvalue. If not, it is a struct/union + ** passed in the primary register, which is usually the result returned + ** from a function. However, it is possible that this rvalue is the + ** result of certain kind of operations on an lvalue such as assignment, + ** and there are no reasons to disallow such use cases. So we just rely + ** on the check upon function returns to catch the unsupported cases and + ** dereference the rvalue address of the struct/union here all the time. + */ + ED_IndExpr (Expr); + } else if (!ED_IsLocQuasiConst (Expr) && !ED_IsLocPrimaryOrExpr (Expr)) { /* Load the base address into the primary (and use it as a reference ** later) if it's not quasi-const or in the primary already.