This the fixes the incorrect flow analysis caused by the def being seen
to have the wrong size (structure field of structure def seen through a
constant pointer). Fixes the ICE, but the pointer constant is broken
somewhere in dags, presumably.
This fixes the problem of using nil for two different compound types
within the one expression. The problem is all compound types have the
same low-level type (ev_invalid) and this caused the two different nils
to have the same type when taken back up to expression level.
While expression symbols worked for what they are, they weren't so good
for ivar access because every ivar of a class (and its super classes)
would be accessed at method scope creation, generating spurious access
errors if any were private. That is, when the access checks worked at
all.
The end goal was to fix erroneous non-constant initializer errors for
the following (ie, nested initializer blocks):
typedef struct { int x; int y; } Point;
typedef struct { int width; int height; } Extent;
typedef struct Rect_s { Point offset; Extent extent; } Rect;
Rect makeRect (int xpos, int ypos, int xlen, int ylen)
{
Rect rect = {{xpos, ypos}, {xlen, ylen}};
return rect;
}
However, it turned out that nested initializer blocks for local
variables did not work at all in that the relocations were lost because
fake defs were being created for the generated instructions.
Thus, instead of creating fake defs, simply record the offset relative
to the base def, the type, and the basic type initializer expression,
then generate instructions that all refer to the correct def but with a
relative offset.
Other than using the new element system, static initializers are largely
unaffected.
This is for adding methods to classes and protocols via their interface,
not for adding methods by adding protocols (they still get copied).
Slightly more memory efficient.
Copying methods is done when adding protocols to classes (the current
use for adding regular methods is an incorrect solution to a different
problem). However, when a method is added to a class, the type of its
self parameter is set to be a pointer to the class. Thus, not only does
the method need to be copied, the self parameter does too, otherwise
the self parameter of methods added via protocols will have their type
set to be a pointer to the last class seen adding the protocol.
That is, if, while compiling the implementation for class A, but the
interface for class B is comes after the interface for class A, and both
A and B add protocol P, then all methods in protocol P will have self
pointing to B rather than A.
@protocol P
-method;
@end
@interface A <P>
@end
@interface B <P>
@end
@implementation A
-method {} // self is B, not A!
@end
Duplicate methods in an interface (especially across protocols and
between protocols and the interface) are both harmless and even to be
expected. They certainly should not cause the compiler to demand
duplicate method implementations :)
This is actually a double issue: when a class implementing a protocol
used the protocol in @protocol(), not only would the protocol get
emitted as part of the class data specifying that the class conforms to
the protocol, a second instance would be emitted again when @protocol()
was used. On top of that, only the instance referenced by @protocol()
would be initialized. Now, both class emission and @protocol() get their
protocol def from the same place and thus only one, properly
initialized, protocol instance is emitted.
The problem was an erroneous assumption that the methods had to be
defined. Any class implementing a protocol must implement (and thus
define) the methods, but a protocol declaration cannot: it merely
declares the methods, and it's entirely possible for a module to see
only the protocol definition and not any classes implementing the
protocol.
Unlike gcc, qfcc requires foo to be defined, not just declared (I
suspect this is a bug in gcc, or even the ObjC spec), because allowing
forward declarations causes an empty (no methods) protocol to be
emitted, and then when the protocol is actually defined, one with
methods, resulting in two different versions of the same protocol, which
comments in the gnu objc runtime specifically state is a problem but is
not checked because it "never happens in practice" (found while
investigating gcc's behavior with @protocol and just what some of the
comments about static instance lists meant).
It proved to be too fragile in its current implementation. It broke
pointers to incomplete structs and switch enum checking, and getting it
to work for other things was overly invasive. I still want the encoding,
but need to come up with something more robust.a
Such declarations were being lost, thus in the following, the id field
never got added:
typedef struct qwaq_mevent_s {
int id;
int x, y, z;
int buttons;
} qwaq_mevent_t;
typedef is meant to create a simple renaming of a potentially complex
type, not create a new type. Keeping the parameter type alias info makes
the types effectively different when it comes to overloaded function
resolution, which is quite contrary to the goal. Does expose some
breakage elsewhere, though.
For technical reasons (programmer laziness), qfcc does not fix up local
def type encodings when writing the debug symbols file (type encoding
location not readily accessible).
The debug subsystem now uses the resources system to ensure it cleans
up, and its data is now semi-private. Unfortunately, PR_LoadDebug had to
remain public for qfprogs because using PR_RunLoadFuncs would cause
builtin resolution to complain.
Attempting to define a variable with an incomplete type is an error, and
results in a default size 1 of allocated, but I forgot to set default
alignment when implementing alignment.
The addition of xdef data has made qfo_to_progs unusable in qfprogs,
resulting in various invalid memory accesses. It always was an ugly hack
anyway, so this is the first step to proper qfo support in qfprogs.
I was originally going to put it in the debug syms file, but I realized
that the data persistence code would need access to both def type and
certainly correct def offsets for defs in far data.
This far better reflects the actual meaning. It is very likely that
ty_none is a holdover from long before there was full type encoding and
it meant that the union in qfcc's type_t had no data. This is still
true for basic types, but only if not a function, field or pointer type.
If the type was function, field or pointer, it was not true, so it was
misnamed pretty much from the start.
It was long wrong anyway as it checked past the end of the function's
parameters, which caused a segfault when calling varargs functions with
no formal parameters.
The encoding is 3:5 giving 3 bits for alignment (log2) and 5 bits for
size, with alignment in the 3 most significant bits. This keeps the
format backwards compatible as until doubles were added, all types were
aligned to 1 word which gets encoded as 0, and the size is unaffected.
This fixed the uninitialized temp warning in HUD.r. The problem was
caused by the flow analyzer not being able to detect that the struct
temp was being initialized by the move statement due to the address of
the temp being in a pointer temp. While it would be good to use a
constant pointer for the address of the struct temp or improving the
flow analyzer to track actual data, avoiding the temp in the first place
results in nicer code as it removes a move statement.
With this, cast address initializers work. I have to wonder if the alias
value short-circuit was legacy from long before the rewrite, as it was
quite trivial to handle in the back-end.
All functions are stored in the overload functions table, even those
that are never explicitly overloaded, but only explicitly overloaded
functions (those with @overload) use the type-qualified naming.
Only as scalars, I still need to think about what to do for vectors and
quaternions due to param size issues. Also, doubles are not yet
guaranteed to be correctly aligned.
I plan on adding doubles, and so it's necessary to ensure that attempts
to align doubles in local or far data spaces remain aligned after final
linking.