mirror of
https://github.com/byteworksinc/ORCA-C.git
synced 2025-01-16 05:33:25 +00:00
Implement support for anonymous structures and unions (C11).
Note that this implementation allows anonymous structures and unions to participate in initialization. That is, you can have a braced initializer list corresponding to an anonymous structure or union. Also, anonymous structures within unions follow the initialization rules for structures (and vice versa). I think the better interpretation of the standard text is that anonymous structures and unions cannot participate in initialization as such, and instead their members are treated as members of the containing structure or union for purposes of initialization. However, all other compilers I am aware of allow anonymous structures and unions to participate in initialization, so I have implemented it that way too.
This commit is contained in:
parent
44a1ba5205
commit
99e268e3b9
@ -373,7 +373,7 @@ type
|
||||
pnext: identPtr); {next parameter}
|
||||
external: ();
|
||||
global,private: ();
|
||||
none: ();
|
||||
none: (anonMemberField: boolean); {field from an anonymous struct/union member?}
|
||||
end;
|
||||
|
||||
{mini-assembler}
|
||||
|
@ -18,7 +18,7 @@ uses CCommon, MM, Scanner, Symbol, CGI;
|
||||
{$segment 'SCANNER'}
|
||||
|
||||
const
|
||||
symFileVersion = 29; {version number of .sym file format}
|
||||
symFileVersion = 30; {version number of .sym file format}
|
||||
|
||||
var
|
||||
inhibitHeader: boolean; {should .sym includes be blocked?}
|
||||
@ -1104,6 +1104,8 @@ procedure EndInclude {chPtr: ptr};
|
||||
WriteByte(ord(ip^.isForwardDeclared));
|
||||
WriteByte(ord(ip^.class));
|
||||
WriteByte(ord(ip^.storage));
|
||||
if ip^.storage = none then
|
||||
WriteByte(ord(ip^.anonMemberField));
|
||||
end; {WriteIdent}
|
||||
|
||||
|
||||
@ -1803,6 +1805,8 @@ var
|
||||
sp^.isForwardDeclared := boolean(ReadByte);
|
||||
sp^.class := tokenEnum(ReadByte);
|
||||
sp^.storage := storageType(ReadByte);
|
||||
if sp^.storage = none then
|
||||
sp^.anonMemberField := boolean(ReadByte);
|
||||
ReadIdent := sp;
|
||||
end; {ReadIdent}
|
||||
|
||||
|
280
Parser.pas
280
Parser.pas
@ -2422,7 +2422,8 @@ var
|
||||
while i <> 0 do begin
|
||||
ip := tp^.fieldList;
|
||||
while ip <> nil do begin
|
||||
Fill(1, ip^.iType);
|
||||
if not ip^.anonMemberField then
|
||||
Fill(1, ip^.iType);
|
||||
ip := ip^.next;
|
||||
end; {while}
|
||||
i := i-1;
|
||||
@ -2648,8 +2649,11 @@ var
|
||||
{ writeln('Initializer: ', ip^.bitsize:10, ip^.bitdisp:10, bitCount:10); {debug}
|
||||
if kind = unionType then
|
||||
ip := nil
|
||||
else
|
||||
else begin
|
||||
ip := ip^.next;
|
||||
while (ip <> nil) and ip^.anonMemberField do
|
||||
ip := ip^.next;
|
||||
end; {else}
|
||||
if token.kind = commach then begin
|
||||
if ip <> nil then
|
||||
NextToken;
|
||||
@ -2813,6 +2817,39 @@ var
|
||||
variable: identPtr; {variable being defined}
|
||||
didFlexibleArray: boolean; {have we seen a flexible array member?}
|
||||
fieldDeclSpecifiers: declSpecifiersRecord; {decl specifiers for field}
|
||||
tPtr: typePtr; {for building types}
|
||||
anonMember: boolean; {processing an anonymous struct/union?}
|
||||
|
||||
procedure AddField(variable: identPtr; anonMemberField: boolean);
|
||||
|
||||
{ add a field to the field list }
|
||||
{ }
|
||||
{ parameters }
|
||||
{ variable - field to add }
|
||||
{ checkDups - check for duplicate-named fields }
|
||||
{ anonMemberField - is this a field from an anonymous }
|
||||
{ struct/union member? }
|
||||
|
||||
label 1;
|
||||
|
||||
var
|
||||
tfl: identPtr; {for traversing field list}
|
||||
|
||||
begin {AddField}
|
||||
if variable^.name^ <> '~anonymous' then begin
|
||||
tfl := fl; {(check for dups)}
|
||||
while tfl <> nil do begin
|
||||
if tfl^.name^ = variable^.name^ then begin
|
||||
Error(42);
|
||||
goto 1;
|
||||
end; {if}
|
||||
tfl := tfl^.next;
|
||||
end; {while}
|
||||
end; {if}
|
||||
1: variable^.next := fl;
|
||||
variable^.anonMemberField := anonMemberField;
|
||||
fl := variable;
|
||||
end; {AddField}
|
||||
|
||||
begin {FieldList}
|
||||
ldoingParameters := doingParameters; {allow fields in K&R dec. area}
|
||||
@ -2830,124 +2867,138 @@ var
|
||||
goto 1;
|
||||
end; {if}
|
||||
DeclarationSpecifiers(fieldDeclSpecifiers, specifierQualifierListElement, ident);
|
||||
if not skipDeclarator then
|
||||
repeat {declare the variables...}
|
||||
if didFlexibleArray then
|
||||
Error(118);
|
||||
variable := nil;
|
||||
if token.kind <> colonch then begin
|
||||
Declarator(fieldDeclSpecifiers, variable, fieldListSpace, false);
|
||||
if variable <> nil then {enter the var in the field list}
|
||||
begin
|
||||
tfl := fl; {(check for dups)}
|
||||
while tfl <> nil do begin
|
||||
if tfl^.name^ = variable^.name^ then
|
||||
Error(42);
|
||||
tfl := tfl^.next;
|
||||
end; {while}
|
||||
variable^.next := fl;
|
||||
fl := variable;
|
||||
repeat {declare the variables...}
|
||||
if didFlexibleArray then
|
||||
Error(118);
|
||||
variable := nil;
|
||||
anonMember := false;
|
||||
if token.kind <> colonch then begin
|
||||
if (token.kind = semicolonch) then begin
|
||||
tPtr := fieldDeclSpecifiers.typeSpec;
|
||||
while tPtr^.kind = definedType do
|
||||
tPtr := tPtr^.dType;
|
||||
if (tPtr^.kind in [structType,unionType])
|
||||
and (tPtr^.sName = nil)
|
||||
and ((structsy in fieldDeclSpecifiers.declarationModifiers)
|
||||
or (unionsy in fieldDeclSpecifiers.declarationModifiers))
|
||||
then begin
|
||||
variable := NewSymbol(@'~anonymous', tPtr, ident,
|
||||
fieldListSpace, defined);
|
||||
anonMember := true;
|
||||
end; {if}
|
||||
end; {if}
|
||||
if kind = unionType then begin
|
||||
disp := 0;
|
||||
bitdisp := 0;
|
||||
end; {if}
|
||||
if token.kind = colonch then {handle a bit field}
|
||||
begin
|
||||
NextToken;
|
||||
Expression(arrayExpression,[commach,semicolonch]);
|
||||
if (expressionValue >= maxBitField) or (expressionValue < 0) then
|
||||
begin
|
||||
Error(54);
|
||||
expressionValue := maxBitField-1;
|
||||
end; {if}
|
||||
if (bitdisp+long(expressionValue).lsw > maxBitField)
|
||||
or (long(expressionValue).lsw = 0) then begin
|
||||
disp := disp+((bitDisp+7) div 8);
|
||||
bitdisp := 0;
|
||||
if long(expressionValue).lsw = 0 then
|
||||
if variable <> nil then
|
||||
Error(55);
|
||||
end; {if}
|
||||
if variable <> nil then begin
|
||||
variable^.disp := disp;
|
||||
variable^.bitdisp := bitdisp;
|
||||
variable^.bitsize := long(expressionValue).lsw;
|
||||
tPtr := variable^.itype;
|
||||
end {if}
|
||||
else
|
||||
tPtr := fieldDeclSpecifiers.typeSpec;
|
||||
bitdisp := bitdisp+long(expressionValue).lsw;
|
||||
if kind = unionType then
|
||||
if ((bitDisp+7) div 8) > maxDisp then
|
||||
maxDisp := ((bitDisp+7) div 8);
|
||||
if (tPtr^.kind <> scalarType)
|
||||
or not (tPtr^.baseType in
|
||||
[cgByte,cgUByte,cgWord,cgUWord,cgLong,cgULong])
|
||||
or (expressionValue > tPtr^.size*8)
|
||||
or ((expressionValue > 1) and (tPtr^.cType = ctBool)) then
|
||||
Error(115);
|
||||
if _Alignassy in fieldDeclSpecifiers.declarationModifiers then
|
||||
Error(142);
|
||||
end {if}
|
||||
else if variable <> nil then begin
|
||||
if bitdisp <> 0 then begin
|
||||
disp := disp+((bitDisp+7) div 8);
|
||||
bitdisp := 0;
|
||||
end; {if}
|
||||
else
|
||||
Declarator(fieldDeclSpecifiers, variable, fieldListSpace, false);
|
||||
if variable <> nil then {enter the var in the field list}
|
||||
AddField(variable, false);
|
||||
end; {if}
|
||||
if kind = unionType then begin
|
||||
disp := 0;
|
||||
bitdisp := 0;
|
||||
end; {if}
|
||||
if token.kind = colonch then {handle a bit field}
|
||||
begin
|
||||
NextToken;
|
||||
Expression(arrayExpression,[commach,semicolonch]);
|
||||
if (expressionValue >= maxBitField) or (expressionValue < 0) then
|
||||
begin
|
||||
Error(54);
|
||||
expressionValue := maxBitField-1;
|
||||
end; {if}
|
||||
if (bitdisp+long(expressionValue).lsw > maxBitField)
|
||||
or (long(expressionValue).lsw = 0) then begin
|
||||
disp := disp+((bitDisp+7) div 8);
|
||||
bitdisp := 0;
|
||||
if long(expressionValue).lsw = 0 then
|
||||
if variable <> nil then
|
||||
Error(55);
|
||||
end; {if}
|
||||
if variable <> nil then begin
|
||||
variable^.disp := disp;
|
||||
variable^.bitdisp := bitdisp;
|
||||
variable^.bitsize := 0;
|
||||
disp := disp + variable^.itype^.size;
|
||||
if disp > maxDisp then
|
||||
maxDisp := disp;
|
||||
if variable^.itype^.size = 0 then
|
||||
if (variable^.itype^.kind = arrayType)
|
||||
and (disp > 0) then begin {handle flexible array member}
|
||||
didFlexibleArray := true;
|
||||
tp^.flexibleArrayMember := true;
|
||||
end {if}
|
||||
else
|
||||
Error(117);
|
||||
variable^.bitsize := long(expressionValue).lsw;
|
||||
tPtr := variable^.itype;
|
||||
end {if}
|
||||
else
|
||||
Error(116);
|
||||
|
||||
if variable <> nil then {check for a const member}
|
||||
tPtr := variable^.itype
|
||||
else
|
||||
tPtr := fieldDeclSpecifiers.typeSpec;
|
||||
while tPtr^.kind in [definedType,arrayType] do begin
|
||||
if tqConst in tPtr^.qualifiers then
|
||||
tp^.constMember := true;
|
||||
if tPtr^.kind = definedType then
|
||||
tPtr := tPtr^.dType
|
||||
else {if tPtr^.kind = arrayType then}
|
||||
tPtr := tPtr^.aType;
|
||||
end; {while}
|
||||
bitdisp := bitdisp+long(expressionValue).lsw;
|
||||
if kind = unionType then
|
||||
if ((bitDisp+7) div 8) > maxDisp then
|
||||
maxDisp := ((bitDisp+7) div 8);
|
||||
if (tPtr^.kind <> scalarType)
|
||||
or not (tPtr^.baseType in
|
||||
[cgByte,cgUByte,cgWord,cgUWord,cgLong,cgULong])
|
||||
or (expressionValue > tPtr^.size*8)
|
||||
or ((expressionValue > 1) and (tPtr^.cType = ctBool)) then
|
||||
Error(115);
|
||||
if _Alignassy in fieldDeclSpecifiers.declarationModifiers then
|
||||
Error(142);
|
||||
end {if}
|
||||
else if variable <> nil then begin
|
||||
if bitdisp <> 0 then begin
|
||||
disp := disp+((bitDisp+7) div 8);
|
||||
bitdisp := 0;
|
||||
end; {if}
|
||||
variable^.disp := disp;
|
||||
variable^.bitdisp := bitdisp;
|
||||
variable^.bitsize := 0;
|
||||
if anonMember then begin
|
||||
tfl := variable^.itype^.fieldList;
|
||||
while tfl <> nil do begin
|
||||
ufl := pointer(Malloc(sizeof(identRecord)));
|
||||
ufl^ := tfl^;
|
||||
AddField(ufl, true);
|
||||
ufl^.disp := ufl^.disp + disp;
|
||||
tfl := tfl^.next;
|
||||
end; {while}
|
||||
end; {if}
|
||||
disp := disp + variable^.itype^.size;
|
||||
if disp > maxDisp then
|
||||
maxDisp := disp;
|
||||
if variable^.itype^.size = 0 then
|
||||
if (variable^.itype^.kind = arrayType)
|
||||
and (disp > 0) then begin {handle flexible array member}
|
||||
didFlexibleArray := true;
|
||||
tp^.flexibleArrayMember := true;
|
||||
end {if}
|
||||
else
|
||||
Error(117);
|
||||
end {if}
|
||||
else
|
||||
Error(116);
|
||||
|
||||
if variable <> nil then {check for a const member}
|
||||
tPtr := variable^.itype
|
||||
else
|
||||
tPtr := fieldDeclSpecifiers.typeSpec;
|
||||
while tPtr^.kind in [definedType,arrayType] do begin
|
||||
if tqConst in tPtr^.qualifiers then
|
||||
tp^.constMember := true;
|
||||
if tPtr^.kind in [structType,unionType] then begin
|
||||
if tPtr^.constMember then
|
||||
tp^.constMember := true;
|
||||
if tPtr^.flexibleArrayMember then
|
||||
if kind = structType then
|
||||
Error(169)
|
||||
else {if kind = unionType then}
|
||||
tp^.flexibleArrayMember := true;
|
||||
end; {if}
|
||||
if tPtr^.kind = definedType then
|
||||
tPtr := tPtr^.dType
|
||||
else {if tPtr^.kind = arrayType then}
|
||||
tPtr := tPtr^.aType;
|
||||
end; {while}
|
||||
if tqConst in tPtr^.qualifiers then
|
||||
tp^.constMember := true;
|
||||
if tPtr^.kind in [structType,unionType] then begin
|
||||
if tPtr^.constMember then
|
||||
tp^.constMember := true;
|
||||
if tPtr^.flexibleArrayMember then
|
||||
if kind = structType then
|
||||
Error(169)
|
||||
else {if kind = unionType then}
|
||||
tp^.flexibleArrayMember := true;
|
||||
end; {if}
|
||||
|
||||
if token.kind = commach then {allow repeated declarations}
|
||||
begin
|
||||
NextToken;
|
||||
done := false;
|
||||
end {if}
|
||||
else
|
||||
done := true;
|
||||
until done or (token.kind = eofsy)
|
||||
else
|
||||
Error(116);
|
||||
if token.kind = commach then {allow repeated declarations}
|
||||
begin
|
||||
NextToken;
|
||||
done := false;
|
||||
end {if}
|
||||
else
|
||||
done := true;
|
||||
until done or (token.kind = eofsy);
|
||||
Match(semicolonch,22); {insist on a closing ';'}
|
||||
end; {while}
|
||||
if fl <> nil then begin
|
||||
@ -3359,6 +3410,10 @@ while token.kind in allowedTokens do begin
|
||||
useGlobalPool := lUseGlobalPool;
|
||||
myTypeSpec := structTypePtr;
|
||||
mySkipDeclarator := token.kind = semicolonch;
|
||||
if tKind = structType then
|
||||
myDeclarationModifiers := myDeclarationModifiers + [structsy]
|
||||
else
|
||||
myDeclarationModifiers := myDeclarationModifiers + [unionsy];
|
||||
typeDone := true;
|
||||
end;
|
||||
|
||||
@ -4626,8 +4681,11 @@ var
|
||||
end; {if}
|
||||
if union then
|
||||
fp := nil
|
||||
else
|
||||
else begin
|
||||
fp := fp^.next;
|
||||
while (fp <> nil) and fp^.anonMemberField do
|
||||
fp := fp^.next;
|
||||
end; {else}
|
||||
end; {while}
|
||||
end; {else}
|
||||
disp := endDisp;
|
||||
|
@ -1288,7 +1288,8 @@ var
|
||||
if ip = nil then ip := defaultStruct^.fieldList;
|
||||
|
||||
while ip <> nil do begin
|
||||
GenSymbol(ip, none);
|
||||
if ip^.name^ <> '~anonymous' then
|
||||
GenSymbol(ip, none);
|
||||
ip := ip^.next;
|
||||
end; {while}
|
||||
end; {ExpandStructType}
|
||||
@ -2116,7 +2117,9 @@ if needSymbol then begin
|
||||
else
|
||||
p^.next := nil;
|
||||
end; {if}
|
||||
if class in [autosy,registersy] then {check and set the storage class}
|
||||
if space = fieldListSpace then {check and set the storage class}
|
||||
p^.storage := none
|
||||
else if class in [autosy,registersy] then
|
||||
begin
|
||||
if doingFunction or doingParameters then begin
|
||||
p^.storage := stackFrame;
|
||||
|
@ -29,3 +29,4 @@
|
||||
{1} c11unicode.c
|
||||
{1} c11uchar.c
|
||||
{1} c11ternary.c
|
||||
{1} c11anonsu.c
|
||||
|
75
Tests/Conformance/c11anonsu.c
Normal file
75
Tests/Conformance/c11anonsu.c
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Test anonymous structures and unions (C11).
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
|
||||
struct S {
|
||||
int a;
|
||||
union {
|
||||
volatile struct {
|
||||
long b;
|
||||
char c;
|
||||
};
|
||||
double d;
|
||||
};
|
||||
} s1 = {1,2,3};
|
||||
|
||||
struct T {
|
||||
int a;
|
||||
union {
|
||||
volatile struct {
|
||||
long b;
|
||||
char c;
|
||||
} s;
|
||||
double d;
|
||||
} u;
|
||||
};
|
||||
|
||||
int main(void) {
|
||||
struct S *s1p = &s1;
|
||||
|
||||
if (s1.a != 1)
|
||||
goto Fail;
|
||||
if (s1.b != 2)
|
||||
goto Fail;
|
||||
if (s1.c != 3)
|
||||
goto Fail;
|
||||
|
||||
s1.d = 123.5;
|
||||
if (s1p->d != 123.5)
|
||||
goto Fail;
|
||||
|
||||
struct S s2 = {4,5,6};
|
||||
struct S *s2p = &s2;
|
||||
|
||||
if (s2.a != 4)
|
||||
goto Fail;
|
||||
if (s2.b != 5)
|
||||
goto Fail;
|
||||
if (s2.c != 6)
|
||||
goto Fail;
|
||||
|
||||
s2.d = 123.5;
|
||||
if (s2p->d != 123.5)
|
||||
goto Fail;
|
||||
|
||||
if (sizeof(struct S) != sizeof(struct T))
|
||||
goto Fail;
|
||||
|
||||
if (offsetof(struct S, a) != offsetof(struct T, a))
|
||||
goto Fail;
|
||||
if (offsetof(struct S, b) != offsetof(struct T, u.s.b))
|
||||
goto Fail;
|
||||
if (offsetof(struct S, c) != offsetof(struct T, u.s.c))
|
||||
goto Fail;
|
||||
if (offsetof(struct S, d) != offsetof(struct T, u.d))
|
||||
goto Fail;
|
||||
|
||||
printf ("Passed Conformance Test c11anonsu\n");
|
||||
return 0;
|
||||
|
||||
Fail:
|
||||
printf ("Failed Conformance Test c11anonsu\n");
|
||||
}
|
17
cc.notes
17
cc.notes
@ -562,6 +562,23 @@ Compound literals can also be used in initializers, as in the following declarat
|
||||
|
||||
(This declaration could be used inside or outside of a function, with the compound literal having automatic or static storage duration, respectively.)
|
||||
|
||||
27. (C11) ORCA/C now supports anonymous structures and unions. These are unnamed members of a structure or union that themselves have structure or union type. Their structure or union type must be declared directly within the declaration of the containing structure or union type (not using a typedef) and must not have a tag. Anonymous structures or unions may be nested.
|
||||
|
||||
Here is an example of a structure containing an anonymous union that in turn contains an anonymous structure:
|
||||
|
||||
struct S {
|
||||
int a;
|
||||
union {
|
||||
struct {
|
||||
long b;
|
||||
char c;
|
||||
};
|
||||
double d;
|
||||
};
|
||||
} s;
|
||||
|
||||
Members of anonymous structures or unions (including nested ones) may be accessed as if they are members of the containing structure or union. For example, given the declaration above, the expressions s.a, s.b, s.c, and s.d may be used to access the various fields. All the fields must have distinct names.
|
||||
|
||||
|
||||
Multi-Character Character Constants
|
||||
-----------------------------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user