bug: incomplete nested C member generation and declaration reuse
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 初心者へのやさしさ
- 25/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 活発
- 領域
- build-system, tooling
調査の方向性
Start with the retained C reproducers and generated Go outputs linked in the evidence comment; read the conversion sources at the referenced #1031 snapshot and compare them with the current generator. Reproduce the cases individually, since the inputs reuse owner names and enum constants. Done means supported inputs retain owners, members, accessors, and shared declarations with correct union storage; several failures remain unresolved and the local follow-up is unmerged.
索引モデルが issue の本文から書いたものです。
説明
Summary
Valid non-array C member declarations can make llcppg panic, silently omit the enclosing record, duplicate declarations, or generate incorrect union access/storage. This issue tracks those concrete bugs, rather than a new conversion framework or a catalogue of already-supported syntax.
The reproduced failures fall into six groups:
| Failing C case | Actual behavior | Expected behavior |
|---|---|---|
| Pointer to an inline anonymous struct/union/enum | Struct owner omitted or union pointee lookup panics | Retain the owner, resolve the declared type and preserve pointer levels |
| Tagged struct/union declared inside a union | The inner declaration is unavailable to its pointer member | Resolve the tag in its actual C scope |
| Nested enum values/pointers | Enum lookup fails or owner is omitted | Emit and reuse the enum and its constants |
| Multiple members from one anonymous declaration | Distinct Go types or duplicate enum constants; a value-plus-pointer case omits its owner | Reuse one declaration across all of its declarators |
| Fieldless anonymous struct inside a union | Promoted member accessors are missing | Expose the promoted fields at their actual offsets |
| Scalar classification through that fieldless struct | Integer leaves are missed and storage is incorrectly all-floating | Include all stored scalar leaves when selecting the union representation |
A successful process exit is not sufficient: several cases return success with missing or incorrect declarations.
Environment and evidence
- Scalar/enum and later declaration probes: llcppg
6950e22b8e0c2008384bc06d02575c03e20323a2, the published #1031 snapshot. - Earlier record probes:
6997fe3717414c50632600d684dd3c855cffd9c0with the same conversion change; relevant conversion sources were checked byte-identical. - Linux/amd64, Clang/LLVM 22.1.8, LLGo
b86d349178d6. - These are recorded generation/output inspections and the previously documented package-build checks, not a new full rerun on every later main revision or a general ABI certification.
Each numbered C block below is a separate include/in.h input using the normal C generator configuration. Do not concatenate the blocks: owner names and enum constants are deliberately reused. For non-panic cases, the following Go block is the complete recorded generated/in.go, including files containing only a package declaration. Companion llcppg.i.go files contain only package/marker declarations and do not restore omitted owners.
The same 19 inputs and nine non-panic Go outputs are retained in the evidence comment.
Fix status
- Nested anonymous union support in #1015 is merged and is not a remaining defect listed here.
- Anonymous structs used as named union value members are implemented in the still-open #1031; that is not a merged-main support claim.
- Fieldless-struct promotion and scalar-leaf classification now have a local, uncommitted follow-up on the #1031 worktree. C/C++ fixtures, generator tests, and actual member-address/layout/write checks passed on Linux/amd64 with LLVM 22. Those changes are not yet pushed or merged, so the original failing case remains recorded below.
- Pointer/declaration-registration/enum/declaration-reuse failures below remain unresolved in the recorded implementation.
Reproducers: C input, actual output, expected behavior
1. Pointers to inline anonymous types
Expected: resolve the anonymous declaration once and preserve the pointer member. Struct owners must retain their pointer field; union owners must retain the existing pointer-slot reference representation (**T for a stored T *). Neither owner omission nor a pointee-lookup panic is acceptable.
1. Anonymous struct pointer in a struct
struct StructOwner { struct { int x; } *p; };
Actual generated in.go:
// Code generated by llcppg; DO NOT EDIT.
package pointerprobe
Observed: The enclosing StructOwner is omitted after unsupported anonymous-pointee lookup.
2. Anonymous struct pointer in a union
union UnionOwner { struct { int x; } *p; };
Observed: Panics on the anonymous struct pointee.
3. Anonymous union pointer in a struct
struct StructOwner { union { int x; double d; } *p; };
Actual generated in.go:
// Code generated by llcppg; DO NOT EDIT.
package pointerprobe
Observed: The enclosing StructOwner is omitted after unsupported anonymous-pointee lookup.
4. Anonymous union pointer in a union
union UnionOwner { union { int x; double d; } *p; };
Observed: Panics on the anonymous union pointee.
5. Anonymous enum pointer in a struct
struct Owner {
enum { EZero, EOne } *pointer;
};
Actual generated in.go:
// Code generated by llcppg; DO NOT EDIT.
package scalarprobe
Observed: The enclosing Owner is omitted after unsupported anonymous-enum lookup.
6. Anonymous enum pointer in a union
union Owner {
enum { EZero, EOne } *pointer;
};
Observed: Panics on the anonymous enum pointee.
2. Tagged record declarations inside a union are not registered
Expected: the inner tagged struct/union must be available to its member references. Preserve the named type and the stored pointer; moving the declaration outside the owner must not be required.
7. Inner tagged struct pointer (original combined input)
union UnionOwner { struct InnerS { int x; } *sp; union InnerU { int x; double d; } *up; };
Observed: Panics on struct InnerS * before reaching up. This is the original recorded input, not a claim that both members were independently reached in this run.
8. Inner tagged union pointer, isolated
union UnionOwner { union InnerU { int x; double d; } *up; };
Observed: Panics on union InnerU *; this separately establishes the failure of the second shape above.
3. Nested enum values and named enum pointers
Expected: emit the enum type/constants once and retain the owner's value or pointer member using the enum's actual underlying C integer type.
9. Anonymous enum value in a union
union Owner {
enum { EZero, EOne } value;
};
Observed: Panics on the unresolved anonymous enum. The struct-owner version of this value-only case works and is not listed as a failure.
10. Inner named enum value in a struct
struct Owner {
enum Local { EZero, EOne } value;
};
Actual generated in.go:
// Code generated by llcppg; DO NOT EDIT.
package scalarprobe
Observed: Logs unsupported enum Local and omits Owner.
11. Inner named enum value in a union
union Owner {
enum Local { EZero, EOne } value;
};
Observed: Panics on unsupported enum Local.
12. Inner named enum pointer in a struct
struct Owner {
enum Local { EZero, EOne } *pointer;
};
Actual generated in.go:
// Code generated by llcppg; DO NOT EDIT.
package scalarprobe
Observed: Logs unsupported enum Local and omits Owner.
13. Inner named enum pointer in a union
union Owner {
enum Local { EZero, EOne } *pointer;
};
Observed: Panics on unsupported enum Local *.
4. Shared anonymous declaration identity and multiple declarators
Expected: one C declaration produces one shared Go type and, for enums, one constant set. Apply each declarator's value/pointer layers to that shared type. Separate C declarations must not be merged merely because their fields look alike.
14. Two values of the same anonymous struct declaration
struct Owner { struct { int x, y; } first, second; };
Actual generated in.go:
// Code generated by llcppg; DO NOT EDIT.
package multidecl
import "github.com/goplus/lib/c"
type Owner struct {
First _llcppg_anon_0
Second _llcppg_anon_1
}
type _llcppg_anon_0 struct {
X c.Int
Y c.Int
}
type _llcppg_anon_1 struct {
X c.Int
Y c.Int
}
Observed: Generates First _llcppg_anon_0 and Second _llcppg_anon_1: one C declaration becomes two distinct Go named types instead of one reused type. This is an incorrect-generation result, not a reported CLI panic.
15. Two values of the same anonymous union declaration
struct Owner { union { int x; double y; } first, second; };
Actual generated in.go:
// Code generated by llcppg; DO NOT EDIT.
package multidecl
import (
"github.com/goplus/lib/c"
"unsafe"
)
type Owner struct {
First _llcppg_anon_0
Second _llcppg_anon_1
}
type _llcppg_anon_0 struct {
_xgo_union [1]uint64
}
type _llcppg_anon_1 struct {
_xgo_union [1]uint64
}
func (p *_llcppg_anon_0) XGof_ref_x() *c.Int {
return (*c.Int)(unsafe.Pointer(p))
}
func (p *_llcppg_anon_0) XGof_ref_y() *c.Double {
return (*c.Double)(unsafe.Pointer(p))
}
func (p *_llcppg_anon_1) XGof_ref_x() *c.Int {
return (*c.Int)(unsafe.Pointer(p))
}
func (p *_llcppg_anon_1) XGof_ref_y() *c.Double {
return (*c.Double)(unsafe.Pointer(p))
}
Observed: Generates two separate anonymous Go union types and two accessor sets instead of reusing the one C declaration.
16. Two values of the same anonymous enum declaration in a struct
struct Owner {
enum { EZero, EOne } first, second;
};
Observed: Panics with EZero redeclared in this block because the enum constants are emitted again.
17. Two values of the same anonymous enum declaration in a union
union Owner {
enum { EZero, EOne } first, second;
};
Observed: Fails earlier on unresolved anonymous-enum lookup; constant deduplication is not reached in this input.
18. Value and pointer sharing one anonymous struct declaration
struct Owner { struct { int x, y; } value, *pointer; };
Actual generated in.go:
// Code generated by llcppg; DO NOT EDIT.
package multidecl
import "github.com/goplus/lib/c"
type _llcppg_anon_0 struct {
X c.Int
Y c.Int
}
Observed: Emits the anonymous struct type but then fails to resolve the pointer member and omits Owner. This exact mixed-declarator case has a recorded failure; it should not be generalized to all other untested combinations.
5–6. Fieldless anonymous struct: missing promoted accessors and wrong union storage classification
Expected: promote the actual fieldless struct members through the existing union accessor convention, using their real Clang offsets in the outer union. Include those members in scalar-leaf classification. Named members must keep their access level. A local follow-up now passes this case, but it has not been pushed or merged; the code below records the original failure.
19. One input exposing two independent omissions
union DirectAnonymousStruct {
struct {
int x;
int y;
};
double raw;
};
_Static_assert(__builtin_offsetof(union DirectAnonymousStruct, x) == 0, "x offset");
_Static_assert(__builtin_offsetof(union DirectAnonymousStruct, y) == sizeof(int), "y offset");
Actual generated in.go:
// Code generated by llcppg; DO NOT EDIT.
package directanon
import (
"github.com/goplus/lib/c"
"unsafe"
)
type DirectAnonymousStruct struct {
_xgo_union [1]float64
}
func (p *DirectAnonymousStruct) XGof_ref_raw() *c.Double {
return (*c.Double)(unsafe.Pointer(p))
}
Observed: Only XGof_ref_raw is generated; XGof_ref_x and XGof_ref_y are missing. The same output uses _xgo_union [1]float64, because the leaf walk ignores the inner integer fields. Under the existing union representation rule, this mixed integer/double case needs integer storage ([1]uint64 on the tested target). The C assertions also establish distinct member offsets: x at 0 and y at sizeof(int) (4 here).
Acceptance and boundaries
- Every successfully supported input must retain the owner, all requested members/accessors, and the required types/constants. Do not treat an empty or partial generated package as a passing result.
- Declaration reuse must preserve C type identity, member order and pointer levels. Union members must continue to overlap the same storage; promoted struct fields retain nonzero offsets.
- Preserve already-working external named/typedef references, ordinary scalar fields, callback metadata and named nested access levels.
- Unverified mixed-declarator combinations are not promoted to confirmed failures or verified successes. Invalid/declaration-only spellings that do not create storage members are not missing member bindings.
- Arrays/flexible arrays are tracked in #1035; special types/qualifier and calling semantics in #1033; union bit-fields in #1034. Global variable bindings and unrelated CLI-wide partial-output policy changes are not selected here.
- New public generator APIs, binding constructors or fallback representations are not specified by this bug report. Use existing fixture-driven verification under
_testc/_testcppwhen implementing fixes.
The published reproductions remain unchanged by the local fieldless fix; its outputs must be evaluated separately from the historical failing outputs above.
- 主要言語
- Go
- スター
- 39
- フォーク
- 13
- 平均マージ
- 1時間 38分
- マージ済み PR(30日)
- 250
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
goplus/llcppg のほかの issue
-
feature proposal
難易度 3/5 1〜2日 初心者へのやさしさ 35/100
メンテナーはふだん 1 日以内に返信
-
Proposal: `MethodPrefix` in llcppg.cfg対応中かも @luoliwoshang が今日担当しました。 オープンconfiguration
難易度 4/5 3〜5日 初心者へのやさしさ 30/100
goplus/llcppg#1061 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
bug
難易度 5/5 1週間以上 初心者へのやさしさ 28/100
メンテナーはふだん 1 日以内に返信
-
bug
難易度 4/5 3〜5日 初心者へのやさしさ 55/100
メンテナーはふだん 1 日以内に返信
-
feature proposal
難易度 5/5 1週間以上 初心者へのやさしさ 18/100
メンテナーはふだん 1 日以内に返信
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 81/100
apache/rocketmq-dashboard#6895 ·
メンテナーはふだん 3 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 87/100
777genius/agent-notifications#490 ·
メンテナーはふだん 1 日以内に返信
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
devantler-tech/ksail#7836 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
keyxmakerx/Chronicle#1469 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 73/100
メンテナーはふだん 1 日以内に返信