Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

bug: incomplete nested C member generation and declaration reuse

オープン
#1,032 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
5/5
見積もり時間
1週間以上
初心者へのやさしさ
25/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
活発
技術スタック
c, go

調査の方向性

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: 6997fe3717414c50632600d684dd3c855cffd9c0 with 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/_testcpp when 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 を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

goplus/llcppg のほかの issue

goplus/llcppg の issue をすべて見る

似ている issue

Go の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。