fix(translator,peephole): TPC 属性链解析修复与窥孔 T1-T3 收尾

- TPC(lib/core): 泛型父特化形参按声明类登记 var_struct_class; _find_struct_key 键归一支持方括号内嵌 sha 前缀; 字段探测失败不再冒泡 FuncGen fail-fast; cast 局部通用指针槽按静态类 bitcast; 属性解析失败附诊断
- 窥孔(includes/llvmlite/__function.vp): 窥孔移至 Renumber 前使输出 SSA 编号连续; T3 no-op bitcast 消除; T4(数组 bitcast->GEP)验证干扰返回类型收敛已移除
- 附调试打点与 1.log
This commit is contained in:
TermiNexus committed 2026-09-08 12:52:48 +08:00
1 parent 76d1ee6076
commit 0bda395ecc
20 files changed
+103 -463

No files matched your search

Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
成功 90.80 成功 120.25
@@ -1 +0,0 @@
{"stdio": "285b6aa29a34754d", "testcheck": "748d0424e8976fa0", "w32.win32console": "bbdf3bbd4c3bc28c", "win32console": "bbdf3bbd4c3bc28c", "stdint": "f5522571bcce7bcb", "w32.win32base": "fc980acec33d69a7", "win32base": "fc980acec33d69a7"}
Whitespace-only changes.
@@ -1,23 +0,0 @@
"""
Auto-generated Python stub file from stdio.vp
Module: stdio
"""
import t, c
def printf(fmt: t.CConst | str, *args) -> int | t.State: pass
def fprintf(stream: bytes, fmt: t.CConst | str, *args) -> int | t.State: pass
def sprintf(buf: bytes, fmt: t.CConst | str, *args) -> int | t.State: pass
def snprintf(buf: bytes, size: t.CSizeT, fmt: t.CConst | str, *args) -> int | t.State: pass
def puts(s: t.CConst | str) -> int | t.State: pass
def fputs(s: t.CConst | str, stream: bytes) -> int | t.State: pass
def fgets(buf: bytes, size: int, stream: bytes) -> bytes | t.State: pass
def fflush(stream: bytes) -> int | t.State: pass
@@ -1 +0,0 @@
{}
@@ -1,49 +0,0 @@
"""
Auto-generated Python stub file from main.vp
Module: main
"""
import c
import t
import stdio
import testcheck
class Box[T]:
value: T
def __init__(self: Box, v: T) -> t.CInt: pass
def get(self: Box) -> T: pass
def set(self: Box, v: T) -> t.CInt: pass
def test_explicit_box() -> t.CInt: pass
class Pair[T1, T2]:
first: T1
second: T2
def __init__(self: Pair, a: T1, b: T2) -> t.CInt: pass
def sum_as_int(self: Pair) -> t.CInt: pass
def test_explicit_pair() -> t.CInt: pass
class Wrapper[T]:
data: T
def __init__(self: Wrapper, v: T) -> t.CInt: pass
def get(self: Wrapper) -> T: pass
def test_mixed_generic_class() -> t.CInt: pass
class Counter[T]:
count: T
def __init__(self: Counter, start: T) -> t.CInt: pass
def increment(self: Counter) -> t.CInt: pass
def get_count(self: Counter) -> T: pass
def test_explicit_counter() -> t.CInt: pass
def test_explicit_box_set() -> t.CInt: pass
def main() -> t.CInt: pass
@@ -1 +0,0 @@
285b6aa29a34754d|bbdf3bbd4c3bc28c|f5522571bcce7bcb|fc980acec33d69a7
@@ -1,31 +0,0 @@
"""
Auto-generated Python stub file from testcheck.vp
Module: testcheck
"""
import t, c
import stdio
from w32.win32console import SetConsoleOutputCP, SetConsoleCP
CP_UTF8: t.CDefine = 65001
_pass_count: t.CExtern | t.CInt
_fail_count: t.CExtern | t.CInt
_total_pass: t.CExtern | t.CInt
_total_fail: t.CExtern | t.CInt
def begin(name: str) -> t.CInt: pass
def section(name: str) -> t.CInt: pass
def ok(msg: str) -> t.CInt: pass
def fail(msg: str) -> t.CInt: pass
def check(cond: t.CInt, ok_msg: str, fail_msg: str) -> t.CInt: pass
def info(msg: str) -> t.CInt: pass
def end() -> t.CInt: pass
def summary() -> t.CInt: pass
@@ -1 +0,0 @@
{"d:\\Users\\TermiNexus\\Desktop\\TransPyC\\Test\\GenericTest4\\App\\main.vp": {"sha1": "42e09c6149524d9d", "mtime": 1784741370.3625746, "size": 3247}, "d:\\Users\\TermiNexus\\Desktop\\TransPyC\\includes\\stdint.vp": {"sha1": "f5522571bcce7bcb", "mtime": 1785563642.3805652, "size": 4356}, "d:\\Users\\TermiNexus\\Desktop\\TransPyC\\includes\\stdio.vp": {"sha1": "285b6aa29a34754d", "mtime": 1785332415.1829746, "size": 561}, "d:\\Users\\TermiNexus\\Desktop\\TransPyC\\includes\\testcheck.vp": {"sha1": "748d0424e8976fa0", "mtime": 1785332415.20287, "size": 1919}, "d:\\Users\\TermiNexus\\Desktop\\TransPyC\\includes\\w32\\win32base.vp": {"sha1": "fc980acec33d69a7", "mtime": 1785332415.2228394, "size": 2653}, "d:\\Users\\TermiNexus\\Desktop\\TransPyC\\includes\\w32\\win32console.vp": {"sha1": "bbdf3bbd4c3bc28c", "mtime": 1781200703.5338137, "size": 5604}}
-6
View File
@@ -1,6 +0,0 @@
285b6aa29a34754d:includes/stdio.vp
42e09c6149524d9d:main.vp
748d0424e8976fa0:includes/testcheck.vp
bbdf3bbd4c3bc28c:includes/w32\win32console.vp
f5522571bcce7bcb:includes/stdint.vp
fc980acec33d69a7:includes/w32\win32base.vp
@@ -1 +0,0 @@
f5522571bcce7bcb|fc980acec33d69a7
-138
View File
@@ -1,138 +0,0 @@
"""
Auto-generated Python stub file from w32.win32console.vp
Module: w32.win32console
"""
import c
import t
from stdint import *
from w32.win32base import *
ENABLE_PROCESSED_INPUT: t.CDefine = 0x0001
ENABLE_LINE_INPUT: t.CDefine = 0x0002
ENABLE_ECHO_INPUT: t.CDefine = 0x0004
ENABLE_WINDOW_INPUT: t.CDefine = 0x0008
ENABLE_MOUSE_INPUT: t.CDefine = 0x0010
ENABLE_INSERT_MODE: t.CDefine = 0x0020
ENABLE_QUICK_EDIT_MODE: t.CDefine = 0x0040
ENABLE_EXTENDED_FLAGS: t.CDefine = 0x0080
ENABLE_PROCESSED_OUTPUT: t.CDefine = 0x0001
ENABLE_WRAP_AT_EOL_OUTPUT: t.CDefine = 0x0002
ENABLE_VIRTUAL_TERMINAL_PROCESSING: t.CDefine = 0x0004
DISABLE_NEWLINE_AUTO_RETURN: t.CDefine = 0x0008
ENABLE_LVB_GRID_WORLDWIDE: t.CDefine = 0x0010
FOREGROUND_BLUE: t.CDefine = 0x0001
FOREGROUND_GREEN: t.CDefine = 0x0002
FOREGROUND_RED: t.CDefine = 0x0004
FOREGROUND_INTENSITY: t.CDefine = 0x0008
BACKGROUND_BLUE: t.CDefine = 0x0010
BACKGROUND_GREEN: t.CDefine = 0x0020
BACKGROUND_RED: t.CDefine = 0x0040
BACKGROUND_INTENSITY: t.CDefine = 0x0080
KEY_EVENT: t.CDefine = 0x0001
MOUSE_EVENT: t.CDefine = 0x0002
WINDOW_BUFFER_SIZE_EVENT: t.CDefine = 0x0004
MENU_EVENT: t.CDefine = 0x0008
FOCUS_EVENT: t.CDefine = 0x0010
class COORD:
X: SHORT
Y: SHORT
class SMALL_RECT:
Left: SHORT
Top: SHORT
Right: SHORT
Bottom: SHORT
class CONSOLE_SCREEN_BUFFER_INFO:
dwSize: COORD
dwCursorPosition: COORD
wAttributes: WORD
srWindow: SMALL_RECT
dwMaximumWindowSize: COORD
class CONSOLE_CURSOR_INFO:
dwSize: ULONG
bVisible: BOOL
class CHAR_INFO:
UnicodeChar: WCHAR
Attributes: WORD
class KEY_EVENT_RECORD:
bKeyDown: BOOL
wRepeatCount: WORD
wVirtualKeyCode: WORD
wVirtualScanCode: WORD
uChar: WCHAR
dwControlKeyState: ULONG
class MOUSE_EVENT_RECORD:
dwMousePosition: COORD
dwButtonState: ULONG
dwControlKeyState: ULONG
dwEventFlags: ULONG
class WINDOW_BUFFER_SIZE_RECORD:
dwSize: COORD
class INPUT_RECORD:
EventType: WORD
Event: KEY_EVENT_RECORD
def SetConsoleOutputCP(codepage: UINT) -> BOOL | t.State: pass
def SetConsoleCP(codepage: UINT) -> BOOL | t.State: pass
def GetConsoleCP() -> UINT | t.State: pass
def GetConsoleOutputCP() -> UINT | t.State: pass
def GetConsoleScreenBufferInfo(hConsoleOutput: HANDLE, lpConsoleScreenBufferInfo: CONSOLE_SCREEN_BUFFER_INFO | t.CPtr) -> BOOL | t.State: pass
def SetConsoleScreenBufferSize(hConsoleOutput: HANDLE, dwSize: COORD) -> BOOL | t.State: pass
def SetConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD) -> BOOL | t.State: pass
def GetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass
def SetConsoleCursorInfo(hConsoleOutput: HANDLE, lpConsoleCursorInfo: CONSOLE_CURSOR_INFO | t.CPtr) -> BOOL | t.State: pass
def SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) -> BOOL | t.State: pass
def FillConsoleOutputCharacterA(hConsoleOutput: HANDLE, cCharacter: t.CChar, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass
def FillConsoleOutputCharacterW(hConsoleOutput: HANDLE, cCharacter: WCHAR, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfCharsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass
def FillConsoleOutputAttribute(hConsoleOutput: HANDLE, wAttribute: WORD, nLength: ULONG, dwWriteCoord: COORD, lpNumberOfAttrsWritten: ULONG | t.CPtr) -> BOOL | t.State: pass
def WriteConsoleA(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass
def WriteConsoleW(hConsoleOutput: HANDLE, lpBuffer: t.CConst | VOIDPTR, nNumberOfCharsToWrite: ULONG, lpNumberOfCharsWritten: ULONG | t.CPtr, lpReserved: VOIDPTR) -> BOOL | t.State: pass
def ReadConsoleA(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass
def ReadConsoleW(hConsoleInput: HANDLE, lpBuffer: VOIDPTR, nNumberOfCharsToRead: ULONG, lpNumberOfCharsRead: ULONG | t.CPtr, pInputControl: VOIDPTR) -> BOOL | t.State: pass
def GetConsoleMode(hConsoleHandle: HANDLE, lpMode: ULONG | t.CPtr) -> BOOL | t.State: pass
def SetConsoleMode(hConsoleHandle: HANDLE, dwMode: ULONG) -> BOOL | t.State: pass
def ReadConsoleInputA(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass
def ReadConsoleInputW(hConsoleInput: HANDLE, lpBuffer: INPUT_RECORD | t.CPtr, nLength: ULONG, lpNumberOfEventsRead: ULONG | t.CPtr) -> BOOL | t.State: pass
def GetNumberOfConsoleInputEvents(hConsoleInput: HANDLE, lpNumberOfEvents: ULONG | t.CPtr) -> BOOL | t.State: pass
def FlushConsoleInputBuffer(hConsoleInput: HANDLE) -> BOOL | t.State: pass
def SetConsoleTitleA(lpConsoleTitle: LPCSTR) -> BOOL | t.State: pass
def SetConsoleTitleW(lpConsoleTitle: LPCWSTR) -> BOOL | t.State: pass
def GetConsoleTitleA(lpConsoleTitle: CHARPTR, nSize: ULONG) -> ULONG | t.State: pass
def GetConsoleTitleW(lpConsoleTitle: WCHARPTR, nSize: ULONG) -> ULONG | t.State: pass
def AllocConsole() -> BOOL | t.State: pass
def FreeConsole() -> BOOL | t.State: pass
def SetConsoleWindowInfo(hConsoleOutput: HANDLE, bAbsolute: BOOL, lpConsoleWindow: SMALL_RECT | t.CPtr) -> BOOL | t.State: pass
def ScrollConsoleScreenBufferA(hConsoleOutput: HANDLE, lpScrollRectangle: SMALL_RECT | t.CPtr, lpClipRectangle: SMALL_RECT | t.CPtr, dwDestinationOrigin: COORD, lpFill: CHAR_INFO | t.CPtr) -> BOOL | t.State: pass
Whitespace-only changes.
-100
View File
@@ -1,100 +0,0 @@
"""
Auto-generated Python stub file from stdint.vp
Module: stdint
"""
import c
import t
INT: t.CTypedef = t.CInt
INTPTR: t.CTypedef = t.CInt | t.CPtr
BOOL: t.CTypedef = t.CInt
UINT: t.CTypedef = t.CUnsignedInt
UINTPTR: t.CTypedef = UINT | t.CPtr
BYTE: t.CTypedef = t.CUnsignedChar
BYTEPTR: t.CTypedef = BYTE | t.CPtr
WORD: t.CTypedef = t.CUInt16T
DWORD: t.CTypedef = t.CUInt32T
QWORD: t.CTypedef = t.CUInt64T
TCHAR: t.CTypedef = t.CChar
CHARLIST: t.CTypedef = str | t.CPtr
VOID: t.CTypedef = t.CVoid
SHORT: t.CTypedef = t.CShort
SHORTPTR: t.CTypedef = t.CShort | t.CPtr
USHORT: t.CTypedef = t.CUnsignedShort
USHORTPTR: t.CTypedef = t.CUnsignedShort | t.CPtr
LONGLONG: t.CTypedef = t.CLongLong
ULONGLONG: t.CTypedef = t.CUnsignedLongLong
LONG: t.CTypedef = t.CLong
ULONG: t.CTypedef = t.CUnsignedLong
WCHAR: t.CTypedef = WORD
WCHARPTR: t.CTypedef = WORD | t.CPtr
CHARPTR: t.CTypedef = t.CChar | t.CPtr
FSIZE_t: t.CTypedef = DWORD
LBA_t: t.CTypedef = DWORD
VOIDPTR: t.CTypedef = t.CVoid | t.CPtr
FLOAT: t.CTypedef = t.CFloat
DOUBLE: t.CTypedef = t.CDouble
FLOAT8: t.CTypedef = t.CFloat8T
FLOAT16: t.CTypedef = t.CFloat16T
FLOAT32: t.CTypedef = t.CFloat32T
FLOAT64: t.CTypedef = t.CFloat64T
FLOAT128: t.CTypedef = t.CFloat128T
INT8: t.CTypedef = t.CInt8T
INT16: t.CTypedef = t.CInt16T
INT32: t.CTypedef = t.CInt32T
INT64: t.CTypedef = t.CInt64T
UINT8: t.CTypedef = t.CUInt8T
UINT16: t.CTypedef = t.CUInt16T
UINT32: t.CTypedef = t.CUInt32T
UINT64: t.CTypedef = t.CUInt64T
INT8PTR: t.CTypedef = t.CInt8T | t.CPtr
INT16PTR: t.CTypedef = t.CInt16T | t.CPtr
INT32PTR: t.CTypedef = t.CInt32T | t.CPtr
INT64PTR: t.CTypedef = t.CInt64T | t.CPtr
UINT8PTR: t.CTypedef = t.CUInt8T | t.CPtr
UINT16PTR: t.CTypedef = t.CUInt16T | t.CPtr
UINT32PTR: t.CTypedef = t.CUInt32T | t.CPtr
UINT64PTR: t.CTypedef = t.CUInt64T | t.CPtr
CHAR8: t.CTypedef = t.CChar8T
CHAR16: t.CTypedef = t.CChar16T
CHAR32: t.CTypedef = t.CChar32T
CHAR8PTR: t.CTypedef = t.CChar8T | t.CPtr
CHAR16PTR: t.CTypedef = t.CChar16T | t.CPtr
CHAR32PTR: t.CTypedef = t.CChar32T | t.CPtr
i8: t.CTypedef = t.CInt8T
i16: t.CTypedef = t.CInt16T
i32: t.CTypedef = t.CInt32T
i64: t.CTypedef = t.CInt64T
u8: t.CTypedef = t.CUInt8T
u16: t.CTypedef = t.CUInt16T
u32: t.CTypedef = t.CUInt32T
u64: t.CTypedef = t.CUInt64T
SIZE_T: t.CTypedef = t.CSizeT
SSIZE_T: t.CTypedef = t.CPtrDiffT
PTRDIFF_T: t.CTypedef = t.CPtrDiffT
int8_t: t.CTypedef = t.CInt8T
int16_t: t.CTypedef = t.CInt16T
int32_t: t.CTypedef = t.CInt32T
int64_t: t.CTypedef = t.CInt64T
uint8_t: t.CTypedef = t.CUInt8T
uint16_t: t.CTypedef = t.CUInt16T
uint32_t: t.CTypedef = t.CUInt32T
uint64_t: t.CTypedef = t.CUInt64T
size_t: t.CTypedef = t.CSizeT
ssize_t: t.CTypedef = t.CPtrDiffT
ptrdiff_t: t.CTypedef = t.CPtrDiffT
intptr_t: t.CTypedef = t.CIntPtrT
uintptr_t: t.CTypedef = t.CUIntPtrT
wchar_t: t.CTypedef = t.CWCharT
char8_t: t.CTypedef = t.CChar8T
char16_t: t.CTypedef = t.CChar16T
char32_t: t.CTypedef = t.CChar32T
float8_t: t.CTypedef = t.CFloat8T
float16_t: t.CTypedef = t.CFloat16T
float32_t: t.CTypedef = t.CFloat32T
float64_t: t.CTypedef = t.CFloat64T
float128_t: t.CTypedef = t.CFloat128T
_Bool: t.CTypedef = t.CBool
@@ -1 +0,0 @@
f5522571bcce7bcb
-100
View File
@@ -1,100 +0,0 @@
"""
Auto-generated Python stub file from w32.win32base.vp
Module: w32.win32base
"""
import c
import t
from stdint import *
HANDLE: t.CTypedef = VOIDPTR
LPCSTR: t.CTypedef = t.CConst | t.CChar | t.CPtr
LPCWSTR: t.CTypedef = t.CConst | t.CUnsignedShort | t.CPtr
INVALID_HANDLE_VALUE: t.CDefine = -1
NULL: t.CDefine = 0
TRUE: t.CDefine = 1
FALSE: t.CDefine = 0
INFINITE: t.CDefine = 0xFFFFFFFF
WAIT_FAILED: t.CDefine = 0xFFFFFFFF
WAIT_OBJECT_0: t.CDefine = 0
WAIT_TIMEOUT: t.CDefine = 258
WAIT_ABANDONED: t.CDefine = 0x80
MAX_PATH: t.CDefine = 260
ERROR_SUCCESS: t.CDefine = 0
ERROR_FILE_NOT_FOUND: t.CDefine = 2
ERROR_ACCESS_DENIED: t.CDefine = 5
ERROR_INSUFFICIENT_BUFFER: t.CDefine = 122
class SECURITY_ATTRIBUTES:
nLength: ULONG
lpSecurityDescriptor: VOIDPTR
bInheritHandle: BOOL
class OVERLAPPED:
Internal: ULONGLONG
InternalHigh: ULONGLONG
Offset: ULONG
OffsetHigh: ULONG
hEvent: HANDLE
class FILETIME:
dwLowDateTime: DWORD
dwHighDateTime: DWORD
class SYSTEMTIME:
wYear: WORD
wMonth: WORD
wDayOfWeek: WORD
wDay: WORD
wHour: WORD
wMinute: WORD
wSecond: WORD
wMilliseconds: WORD
class GUID:
Data1: DWORD
Data2: WORD
Data3: WORD
Data4: BYTEPTR
class LARGE_INTEGER:
QuadPart: LONGLONG
class ULARGE_INTEGER:
QuadPart: ULONGLONG
def GetLastError() -> ULONG | t.State: pass
def SetLastError(dwErrCode: ULONG) -> t.State: pass
def CloseHandle(hObject: HANDLE) -> BOOL | t.State: pass
def GetProcAddress(hModule: HANDLE, lpProcName: LPCSTR) -> VOIDPTR | t.State: pass
def GetModuleHandleA(lpModuleName: LPCSTR) -> HANDLE | t.State: pass
def GetModuleHandleW(lpModuleName: LPCWSTR) -> HANDLE | t.State: pass
def LoadLibraryA(lpLibFileName: LPCSTR) -> HANDLE | t.State: pass
def LoadLibraryW(lpLibFileName: LPCWSTR) -> HANDLE | t.State: pass
def FreeLibrary(hLibModule: HANDLE) -> BOOL | t.State: pass
def GetSystemTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass
def GetLocalTime(lpSystemTime: SYSTEMTIME | t.CPtr) -> t.State: pass
def FileTimeToSystemTime(lpFileTime: FILETIME | t.CPtr, lpSystemTime: SYSTEMTIME | t.CPtr) -> BOOL | t.State: pass
def SystemTimeToFileTime(lpSystemTime: SYSTEMTIME | t.CPtr, lpFileTime: FILETIME | t.CPtr) -> BOOL | t.State: pass
def QueryPerformanceCounter(lpPerformanceCount: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass
def QueryPerformanceFrequency(lpFrequency: LARGE_INTEGER | t.CPtr) -> BOOL | t.State: pass
def Sleep(dwMilliseconds: ULONG) -> t.State: pass
def SleepEx(dwMilliseconds: ULONG, bAlertable: BOOL) -> ULONG | t.State: pass
def GetTickCount() -> ULONG | t.State: pass
def GetTickCount64() -> ULONGLONG | t.State: pass
def GetCommandLineA() -> CHARPTR | t.State: pass
+58 -9
View File
@@ -652,7 +652,16 @@ class ExprAttrHandle(BaseHandle):
Gen.class_member_bitoffsets[ClassName][AttrName] = bo Gen.class_member_bitoffsets[ClassName][AttrName] = bo
return self._load_bitfield_member(ObjVal, ClassName, AttrName) return self._load_bitfield_member(ObjVal, ClassName, AttrName)
offset = Gen._get_member_offset(AttrName, ClassName) try:
offset = Gen._get_member_offset(AttrName, ClassName)
except KeyError as _ke:
_vsc2: Any = getattr(Gen, 'var_struct_class', {}) or {}
raise KeyError(
f"{_ke} | [attr-diag] var={VarName} "
f"var_struct_class={_vsc2.get(VarName)!r} "
f"objval_pointee={getattr(getattr(ObjVal, 'type', None), 'pointee', None)!r} "
f"node={self._ExprText(Node)!r} "
f"base={self._ExprText(Node.value)!r}") from None
# 检查 offset 是否超出实际结构体 # 检查 offset 是否超出实际结构体
if isinstance(ObjVal.type, ir.PointerType): if isinstance(ObjVal.type, ir.PointerType):
actual_pointee: Any = ObjVal.type.pointee actual_pointee: Any = ObjVal.type.pointee
@@ -763,8 +772,18 @@ class ExprAttrHandle(BaseHandle):
return cdefine_result return cdefine_result
ObjVal: Any = self.HandleExprLlvm(Node.value) ObjVal: Any = self.HandleExprLlvm(Node.value)
if not ObjVal or not isinstance(ObjVal.type, ir.PointerType): if not ObjVal or not isinstance(ObjVal.type, ir.PointerType):
import sys as _sys1
_sys1.stderr.write(
f"[CHAIN-DBG] nested no-obj: node={self._ExprText(Node)!r} "
f"inner={self._ExprText(Node.value)!r} objval_type={getattr(ObjVal, 'type', None)!r}\n")
return None return None
pointee: Any = ObjVal.type.pointee pointee: Any = ObjVal.type.pointee
if not (isinstance(pointee, ir.IntType)
or isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType))):
import sys as _sys1b
_sys1b.stderr.write(
f"[CHAIN-DBG] nested unhandled-pointee: node={self._ExprText(Node)!r} "
f"objval_type={ObjVal.type!r} pointee={pointee!r}\n")
# char* → struct* cast + 成员访问 # char* → struct* cast + 成员访问
if isinstance(pointee, ir.IntType) and pointee.width == 8: if isinstance(pointee, ir.IntType) and pointee.width == 8:
@@ -788,23 +807,34 @@ class ExprAttrHandle(BaseHandle):
AttrClassName = self._resolve_attr_parent_hint(Node.value, Gen) AttrClassName = self._resolve_attr_parent_hint(Node.value, Gen)
ResolvedKey: str | None = self._find_struct_key_for_class_hint(Gen, AttrClassName) ResolvedKey: str | None = self._find_struct_key_for_class_hint(Gen, AttrClassName)
if ResolvedKey is None or ResolvedKey not in Gen.structs: if ResolvedKey is None or ResolvedKey not in Gen.structs:
import sys as _sys2
_sys2.stderr.write(
f"[CHAIN-DBG] char* key-miss: node={self._ExprText(Node)!r} "
f"attr_class={AttrClassName!r} resolved_key={ResolvedKey!r} "
f"objval_type={ObjVal.type!r}\n")
return None return None
st: Any st: Any
ok: bool ok: bool
st, ok = self._try_Load_struct_from_stub(Gen, ResolvedKey) st, ok = self._try_Load_struct_from_stub(Gen, ResolvedKey)
if not isinstance(st, ir.IdentifiedStructType): if not isinstance(st, ir.IdentifiedStructType):
import sys as _sys3
_sys3.stderr.write(f"[CHAIN-DBG] char* not-struct: key={ResolvedKey!r} st={st!r}\n")
return None return None
if st.elements is None: if st.elements is None:
# stub 仍 opaque(如跨模块泛型仅声明):走泛型特化候选访问 # stub 仍 opaque(如跨模块泛型仅声明):走泛型特化候选访问
spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st, Node, ResolvedKey, AttrClassName) spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st, Node, ResolvedKey, AttrClassName)
if spec_val is not None: if spec_val is not None:
return spec_val return spec_val
import sys as _sys4
_sys4.stderr.write(f"[CHAIN-DBG] char* opaque-miss: key={ResolvedKey!r} node={self._ExprText(Node)!r}\n")
return None return None
CastedObj: Any = Gen.builder.bitcast(ObjVal, ir.PointerType(st), name=f"cast_{ResolvedKey}") CastedObj: Any = Gen.builder.bitcast(ObjVal, ir.PointerType(st), name=f"cast_{ResolvedKey}")
if Node.attr in Gen.class_member_bitoffsets.get(ResolvedKey, {}): if Node.attr in Gen.class_member_bitoffsets.get(ResolvedKey, {}):
return self._load_bitfield_member(CastedObj, ResolvedKey, Node.attr) return self._load_bitfield_member(CastedObj, ResolvedKey, Node.attr)
offset: int | None = Gen._get_member_offset(Node.attr, ResolvedKey) offset: int | None = Gen._get_member_offset(Node.attr, ResolvedKey)
if offset is None: if offset is None:
import sys as _sys5
_sys5.stderr.write(f"[CHAIN-DBG] char* offset-miss: key={ResolvedKey!r} attr={Node.attr!r} st={st!r}\n")
return None return None
if offset < len(st.elements) and isinstance(st.elements[offset], ir.VoidType): if offset < len(st.elements) and isinstance(st.elements[offset], ir.VoidType):
return None return None
@@ -833,7 +863,15 @@ class ExprAttrHandle(BaseHandle):
bitfield_offsets: Any = Gen.class_member_bitoffsets.get(CN, {}) bitfield_offsets: Any = Gen.class_member_bitoffsets.get(CN, {})
if Node.attr in bitfield_offsets: if Node.attr in bitfield_offsets:
return self._load_bitfield_member(ObjVal, CN, Node.attr) return self._load_bitfield_member(ObjVal, CN, Node.attr)
offset = Gen._get_member_offset(Node.attr, CN) try:
offset = Gen._get_member_offset(Node.attr, CN)
except KeyError as _ke2:
raise KeyError(
f"{_ke2} | [attr-diag-nested] "
f"objval_pointee={getattr(getattr(ObjVal, 'type', None), 'pointee', None)!r} "
f"node={self._ExprText(Node)!r} "
f"inner={self._ExprText(Node.value)!r} "
f"parent_hint={parent_hint!r}") from None
if offset is None: if offset is None:
break break
# 泛型基础类型字段特化(根本修复): # 泛型基础类型字段特化(根本修复):
@@ -1732,15 +1770,20 @@ class ExprAttrHandle(BaseHandle):
"""把 class_member_element_class 记录的类/特化名解析为 Gen.structs 的真实键。 """把 class_member_element_class 记录的类/特化名解析为 Gen.structs 的真实键。
记录值可能是裸名('GSList[BasicBlock]')或带 sha1 前缀 记录值可能是裸名('GSList[BasicBlock]')或带 sha1 前缀
('8e92345fd262a343.GSList[BasicBlock]'),而 Gen.structs 的键可能是 ('8e92345fd262a343.GSList[BasicBlock]'),且**方括号内元素也可能带模块
另一种形态。依次尝试:精确键 → 短名键 → class_sha1_map 重建前缀键 → 前缀**('GSList[29fdb5e25dc949f4.BasicBlock]',跨模块泛型特化登记值)。
遍历 Gen.structs 按短名匹配。 Gen.structs 的键可能是另一种形态。比较前统一剥除所有 '<16hex>.' 片段:
依次尝试:精确键 → 归一短名键 → class_sha1_map 重建前缀键 →
遍历 Gen.structs 按归一短名匹配。
""" """
if not ClassHint: if not ClassHint:
return None return None
if ClassHint in Gen.structs: if ClassHint in Gen.structs:
return ClassHint return ClassHint
short: str = Gen._extract_short_name(ClassHint) import re as _re_sha
def _strip_sha(s: str) -> str:
return _re_sha.sub(r'(?i)[0-9a-f]{16}\.', '', s)
short: str = _strip_sha(Gen._extract_short_name(ClassHint))
if short in Gen.structs: if short in Gen.structs:
return short return short
expected_sha1: str | None = (getattr(Gen, 'class_sha1_map', {}) or {}).get(short) expected_sha1: str | None = (getattr(Gen, 'class_sha1_map', {}) or {}).get(short)
@@ -1749,7 +1792,7 @@ class ExprAttrHandle(BaseHandle):
if prefixed in Gen.structs: if prefixed in Gen.structs:
return prefixed return prefixed
for key in Gen.structs: for key in Gen.structs:
if Gen._extract_short_name(key) == short: if _strip_sha(Gen._extract_short_name(key)) == short:
return key return key
return None return None
@@ -1883,7 +1926,10 @@ class ExprAttrHandle(BaseHandle):
ok_v: bool ok_v: bool
st_v, ok_v = self._try_Load_struct_from_stub(Gen, owner_key) st_v, ok_v = self._try_Load_struct_from_stub(Gen, owner_key)
if isinstance(st_v, ir.IdentifiedStructType) and st_v.elements is not None: if isinstance(st_v, ir.IdentifiedStructType) and st_v.elements is not None:
off: int | None = Gen._get_member_offset(AttrName, owner_key) try:
off: int | None = Gen._get_member_offset(AttrName, owner_key)
except KeyError:
off = None
if off is not None and off < len(st_v.elements): if off is not None and off < len(st_v.elements):
k3: str | None = self._pointee_llvm_to_struct_key(Gen, st_v.elements[off]) k3: str | None = self._pointee_llvm_to_struct_key(Gen, st_v.elements[off])
if k3: if k3:
@@ -1898,7 +1944,10 @@ class ExprAttrHandle(BaseHandle):
p_ok: bool p_ok: bool
p_st, p_ok = self._try_Load_struct_from_stub(Gen, p_key) p_st, p_ok = self._try_Load_struct_from_stub(Gen, p_key)
if isinstance(p_st, ir.IdentifiedStructType) and p_st.elements is not None: if isinstance(p_st, ir.IdentifiedStructType) and p_st.elements is not None:
p_off: int | None = Gen._get_member_offset(AttrName, p_key) try:
p_off: int | None = Gen._get_member_offset(AttrName, p_key)
except KeyError:
p_off = None
if p_off is not None and p_off < len(p_st.elements): if p_off is not None and p_off < len(p_st.elements):
k4: str | None = self._pointee_llvm_to_struct_key(Gen, p_st.elements[p_off]) k4: str | None = self._pointee_llvm_to_struct_key(Gen, p_st.elements[p_off])
if k4: if k4:
+38
View File
@@ -1792,6 +1792,44 @@ class FunctionHandle(BaseHandle):
found_struct: str | None = FindStructNameInAnnotation(arg.annotation, Gen.structs) found_struct: str | None = FindStructNameInAnnotation(arg.annotation, Gen.structs)
if found_struct: if found_struct:
Gen.var_struct_class[param_name] = found_struct Gen.var_struct_class[param_name] = found_struct
# 普通类注解形参(非 BinOp 联合):rowptr[X] / t.CPtr[X] / X / t.X
# 一律按"声明类"登记 var_struct_class。避免按 param.type.pointee 匹配
# 到泛型父特化(如 class Function(GSListNode[Function]) 的形参 func 被
# 登记成 GSListNode[Function],其 struct 仅含 Next → func.Blocks 访问
# fast-fail "属性 'Blocks' 在类 'GSListNode[Function]' 中找不到")。
# 泛型占位(rowptr[T])的 T 不在 Gen.structs,自动跳过、保留 pointee 匹配。
for i, arg in enumerate(Node.args.args):
if arg.annotation is None:
continue
if isinstance(arg.annotation, ast.BinOp) and isinstance(arg.annotation.op, ast.BitOr):
continue # 联合注解由上方循环处理
param_name = ParamNames[i] if i < len(ParamNames) else arg.arg
if param_name not in Gen.variables:
continue
ann = arg.annotation
target: str | None = None
if isinstance(ann, ast.Name):
target = ann.id
elif isinstance(ann, ast.Attribute):
target = ann.attr
elif isinstance(ann, ast.Subscript):
subv = ann.value
subname = getattr(subv, 'id', None) or getattr(subv, 'attr', '')
if subname in ('rowptr', 'CPtr', 'Ptr'):
slc = ann.slice
if isinstance(slc, ast.Name):
target = slc.id
elif isinstance(slc, ast.Attribute):
target = slc.attr
if not target:
continue
key: str | None = target if target in Gen.structs else None
if key is None:
_sha_t: str | None = (getattr(Gen, 'class_sha1_map', {}) or {}).get(target)
if _sha_t and f'{_sha_t}.{target}' in Gen.structs:
key = f'{_sha_t}.{target}'
if key:
Gen.var_struct_class[param_name] = key
if ResolvedClassName and (IsMethod or RawFuncName == '__init__'): if ResolvedClassName and (IsMethod or RawFuncName == '__init__'):
self.Trans._CurrentCpythonObjectClass = ResolvedClassName self.Trans._CurrentCpythonObjectClass = ResolvedClassName
Gen._variadic_info = None Gen._variadic_info = None
+6
View File
@@ -3,6 +3,7 @@ from typing import Any
import vast as ast import vast as ast
import os import os
import re import re
import sys
import llvmlite.ir as ir import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import CTypeInfo from lib.core.Handles.HandlesBase import CTypeInfo
from lib.core.VLogger import get_logger as _vlog from lib.core.VLogger import get_logger as _vlog
@@ -502,6 +503,11 @@ class FuncGenMixin:
if isinstance(_st_diag, ir.IdentifiedStructType): if isinstance(_st_diag, ir.IdentifiedStructType):
_struct_diag = f"{len(_st_diag.elements)} elems" if _st_diag.elements is not None else 'opaque' _struct_diag = f"{len(_st_diag.elements)} elems" if _st_diag.elements is not None else 'opaque'
_member_names_diag: list = [n for n, _ in _members_diag][:16] _member_names_diag: list = [n for n, _ in _members_diag][:16]
try:
import traceback as _tb
_tb.print_stack(file=sys.stderr)
except Exception:
pass
raise KeyError( raise KeyError(
f"[fast-fail] 属性 '{field_name}' 在类 '{ClassName}' 中找不到" f"[fast-fail] 属性 '{field_name}' 在类 '{ClassName}' 中找不到"
f"(class_members={len(_members_diag)} 个: {_member_names_diag}, struct={_struct_diag})" f"(class_members={len(_members_diag)} 个: {_member_names_diag}, struct={_struct_diag})"