mirror of
https://github.com/cc65/cc65.git
synced 2024-12-23 04:30:10 +00:00
Fixed local struct field access via the address of the struct.
This commit is contained in:
parent
f5365c7ffd
commit
bd8eae67f1
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user