Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions trunk/examples/programs/regression/c/struct-anonymous-01.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/* #Safe
*-----------------------------------------------------------------------------
* Example with an anonymous struct in a named (outer) struct
*-----------------------------------------------------------------------------
* Author: Manuel Bentele
* Date: 13.11.2025
*---------------------------------------------------------------------------*/

struct foo {
struct {
int a;
};
};

int main()
{
struct foo f;
f.a = 10;
int a = f.a;
//@ assert (a == 10);
return f.a;
}
28 changes: 28 additions & 0 deletions trunk/examples/programs/regression/c/struct-anonymous-02.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* #Safe
*-----------------------------------------------------------------------------
* Example with an anonymous struct and variables in a named (outer) struct
*-----------------------------------------------------------------------------
* Author: Manuel Bentele
* Date: 13.11.2025
*---------------------------------------------------------------------------*/

struct foo {
int a;
struct {
int b;
};
int c;
};

int main()
{
struct foo f;
f.a = 10;
f.b = 20;
f.c = 30;
int a = f.a;
int b = f.b;
int c = f.c;
//@ assert (a == 10 && b == 20 && c == 30);
return f.a + f.b + f.c;
}
27 changes: 27 additions & 0 deletions trunk/examples/programs/regression/c/struct-anonymous-03.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* #Safe
*-----------------------------------------------------------------------------
* Example with nested anonymous structs in a named (outer) struct
*-----------------------------------------------------------------------------
* Author: Manuel Bentele
* Date: 13.11.2025
*---------------------------------------------------------------------------*/

struct foo {
struct {
int a;
struct {
int b;
};
};
};

int main()
{
struct foo f;
f.a = 10;
f.b = 20;
int a = f.a;
int b = f.b;
//@ assert (a == 10 && b == 20);
return f.a + f.b;
}
28 changes: 28 additions & 0 deletions trunk/examples/programs/regression/c/struct-anonymous-04.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* #Safe
*-----------------------------------------------------------------------------
* Example with an anonymous struct in an outer struct as part of a typedef
*-----------------------------------------------------------------------------
* Author: Manuel Bentele
* Date: 13.11.2025
*---------------------------------------------------------------------------*/

typedef struct {
int a;
struct {
int b;
};
int c;
} foo_t;

int main()
{
foo_t f;
f.a = 10;
f.b = 20;
f.c = 30;
int a = f.a;
int b = f.b;
int c = f.c;
//@ assert (a == 10 && b == 20 && c == 30);
return f.a + f.b + f.c;
}
25 changes: 25 additions & 0 deletions trunk/examples/programs/regression/c/union-anonymous-01.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* #Safe
*-----------------------------------------------------------------------------
* Example with an anonymous union in a named (outer) struct
*-----------------------------------------------------------------------------
* Author: Manuel Bentele
* Date: 13.11.2025
*---------------------------------------------------------------------------*/

struct foo {
union {
int a;
int b;
};
};

int main()
{
struct foo f;
f.a = 10;
f.b = 20;
int a = f.a;
int b = f.b;
//@ assert (a == 20 && b == 20);
return f.a + f.b;
}
31 changes: 31 additions & 0 deletions trunk/examples/programs/regression/c/union-anonymous-02.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* #Safe
*-----------------------------------------------------------------------------
* Example with an anonymous union and variables in a named (outer) struct
*-----------------------------------------------------------------------------
* Author: Manuel Bentele
* Date: 13.11.2025
*---------------------------------------------------------------------------*/

struct foo {
int a;
union {
int b;
int c;
};
int d;
};

int main()
{
struct foo f;
f.a = 10;
f.b = 20;
f.c = 30;
f.d = 40;
int a = f.a;
int b = f.b;
int c = f.c;
int d = f.d;
//@ assert (a == 10 && b == 30 && c == 30 && d == 40);
return f.a + f.b + f.c + f.d;
}
30 changes: 30 additions & 0 deletions trunk/examples/programs/regression/c/union-anonymous-03.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* #Safe
*-----------------------------------------------------------------------------
* Example with nested anonymous unions in a named (outer) struct
*-----------------------------------------------------------------------------
* Author: Manuel Bentele
* Date: 13.11.2025
*---------------------------------------------------------------------------*/

struct foo {
union {
int a;
union {
int b;
int c;
};
};
};

int main()
{
struct foo f;
f.a = 10;
f.b = 20;
f.c = 30;
int a = f.a;
int b = f.b;
int c = f.c;
//@ assert (a == 30 && b == 30 && c == 30);
return f.a + f.b + f.c;
}
28 changes: 28 additions & 0 deletions trunk/examples/programs/regression/c/union-anonymous-04.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* #Safe
*-----------------------------------------------------------------------------
* Example with an anonymous union in an outer union as part of a typedef
*-----------------------------------------------------------------------------
* Author: Manuel Bentele
* Date: 13.11.2025
*---------------------------------------------------------------------------*/

typedef union {
int a;
union {
int b;
int c;
};
} foo_t;

int main()
{
foo_t f;
f.a = 10;
f.b = 20;
f.c = 30;
int a = f.a;
int b = f.b;
int c = f.c;
//@ assert (a == 30 && b == 30 && c == 30);
return f.a + f.b + f.c;
}
33 changes: 33 additions & 0 deletions trunk/examples/programs/regression/c/union-anonymous-05.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* #Safe
*-----------------------------------------------------------------------------
* Example with an anonymous struct in an outer union as part of a typedef
*-----------------------------------------------------------------------------
* Author: Manuel Bentele
* Date: 13.11.2025
*---------------------------------------------------------------------------*/

typedef union {
struct {
unsigned int a : 8;
unsigned int b : 8;
unsigned int c : 8;
unsigned int d : 8;
};
unsigned int all;
} foo_t;

int main()
{
foo_t f;
f.a = 10;
f.b = 20;
f.c = 30;
f.d = 40;
int a = f.a;
int b = f.b;
int c = f.c;
int d = f.d;
int all = f.all;
assert (a == 10 && b == 20 && c == 30 && d == 40 && all == 673059850);
return f.all;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2389,7 +2389,7 @@ public Result visit(final IDispatcher main, final IASTSimpleDeclaration node) {
final List<Result> noSkipIntermediateResult =
intermediateResults.stream().filter(a -> !(a instanceof SkipResult)).collect(Collectors.toList());
if (noSkipIntermediateResult.isEmpty()) {
return new SkipResult();
return typeResult;
}
final Result first = noSkipIntermediateResult.get(0);
if (noSkipIntermediateResult.size() == 1) {
Expand Down Expand Up @@ -3630,7 +3630,7 @@ private void processTUchild(final IDispatcher main, final ArrayList<Declaration>
mStaticObjectsHandler.addGlobalVariableDeclaration((VariableDeclaration) boogieDecl, cd, null);
}
} else {
if (childRes instanceof SkipResult || childRes.getNode() == null) {
if (childRes instanceof SkipResult || childRes instanceof TypesResult || childRes.getNode() == null) {
return;
}
assert childRes.getClass() == Result.class;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
Expand Down Expand Up @@ -430,6 +431,16 @@ public Result visit(final IDispatcher main, final IASTCompositeTypeSpecifier nod
bitFieldWidths.add(declaration.getBitfieldSize());
}
} else if (r instanceof SkipResult) { // skip ;)
} else if (r instanceof final TypesResult tr && tr.getCType() instanceof final CStructOrUnion su) {
if (su.isAnonymous()) {
// Flat unnamed (anonymous) struct or union by adding the field(s) to to the parent struct or union.
fNames.addAll(su.getFieldNames());
fTypes.addAll(Arrays.asList(su.getFieldTypes()));
bitFieldWidths.addAll(su.getBitFieldWidths());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the idea to flatten anonymous structs into a parent struct; and I guess, similarly, to flatten anonymous unions into a parent union.

But does it also make sense to flatten an anonymous struct into a parent union, or vice versa? A struct is a kind of product type (basically a tuple, but the fields are named), whereas a union is a sum type (only one of the values is present, not all). It seems to me that this information is lost by flattening one into the other, isn't it?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, after I thought more about this, I think that the should not be flattened for this reason. At least the sizeof computation could be fixed for that reason. I guess the better solution would be to just have a recursive lookup in CStructOrUnion instead.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I was thinking in a similar direction: structs and unions could have special handling for anonymous fields (let's be careful to avoid "name clashes" because they all have the field name ""), and then the field lookup should recurse into these anonymous fields.

Relatedly, is it also possible in C to have an anonymous field but where the struct type is named? (and perhaps declared separately?)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, @maul-esel. So far, anonymous unions are not supported correctly.

I was thinking in a similar direction: structs and unions could have special handling for anonymous fields (let's be careful to avoid "name clashes" because they all have the field name ""), and then the field lookup should recurse into these anonymous fields.

That would be indeed a great conceptual idea. Unfortunately, our representation of anonymous structs and unions is not created exactly like you described it. Declaration nodes with empty names are not stored as valid declarations. This means that anonymous structs and unions cannot be members of a parent type. We could add more hacks but I wanted to keep the changes as simple as possible.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would just suggest to have a separate member in CStructOrUnion for anonymous fields and to adapt the methods (recursive lookup in anonymous fields, somehow return the fields in getters).

} else {
final String msg = "Non-anoymous struct or union declaration cannot be flatten!";
throw new UnsupportedSyntaxException(loc, msg);
}
} else {
final String msg = "Unexpected syntax in struct declaration!";
throw new UnsupportedSyntaxException(loc, msg);
Expand All @@ -438,16 +449,10 @@ public Result visit(final IDispatcher main, final IASTCompositeTypeSpecifier nod

final String cId = node.getName().toString();
final String rslvName = mSymboltable.applyMultiparseRenaming(node.getContainingFilename(), cId);
final StructOrUnion isStructOrUnion;
if (node.getKey() == IASTCompositeTypeSpecifier.k_struct) {
isStructOrUnion = StructOrUnion.STRUCT;
} else if (node.getKey() == IASTCompositeTypeSpecifier.k_union) {
isStructOrUnion = StructOrUnion.UNION;
} else {
throw new UnsupportedOperationException();
}
final StructOrUnion isStructOrUnion = CStructOrUnion.getStructOrUnionFromAstNode(node);
final boolean isAnonymous = CStructOrUnion.isAnonymousFromAstNode(node);

final String identifier = CStructOrUnion.getPrefix(isStructOrUnion) + rslvName;
final String identifier = CStructOrUnion.getPrefix(isStructOrUnion, isAnonymous) + rslvName;

if (mIncompleteCStructOrUnionObjects.containsKey(rslvName)) {
final CStructOrUnion structOrUnion = mIncompleteCStructOrUnionObjects.get(rslvName);
Expand Down
Loading