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
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 是否超出实际结构体
if isinstance(ObjVal.type, ir.PointerType):
actual_pointee: Any = ObjVal.type.pointee
@@ -763,8 +772,18 @@ class ExprAttrHandle(BaseHandle):
return cdefine_result
ObjVal: Any = self.HandleExprLlvm(Node.value)
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
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 + 成员访问
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)
ResolvedKey: str | None = self._find_struct_key_for_class_hint(Gen, AttrClassName)
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
st: Any
ok: bool
st, ok = self._try_Load_struct_from_stub(Gen, ResolvedKey)
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
if st.elements is None:
# stub 仍 opaque(如跨模块泛型仅声明):走泛型特化候选访问
spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st, Node, ResolvedKey, AttrClassName)
if spec_val is not None:
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
CastedObj: Any = Gen.builder.bitcast(ObjVal, ir.PointerType(st), name=f"cast_{ResolvedKey}")
if Node.attr in Gen.class_member_bitoffsets.get(ResolvedKey, {}):
return self._load_bitfield_member(CastedObj, ResolvedKey, Node.attr)
offset: int | None = Gen._get_member_offset(Node.attr, ResolvedKey)
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
if offset < len(st.elements) and isinstance(st.elements[offset], ir.VoidType):
return None
@@ -833,7 +863,15 @@ class ExprAttrHandle(BaseHandle):
bitfield_offsets: Any = Gen.class_member_bitoffsets.get(CN, {})
if Node.attr in bitfield_offsets:
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:
break
# 泛型基础类型字段特化(根本修复):
@@ -1732,15 +1770,20 @@ class ExprAttrHandle(BaseHandle):
"""把 class_member_element_class 记录的类/特化名解析为 Gen.structs 的真实键。
记录值可能是裸名('GSList[BasicBlock]')或带 sha1 前缀
('8e92345fd262a343.GSList[BasicBlock]'),而 Gen.structs 的键可能是
另一种形态。依次尝试:精确键 → 短名键 → class_sha1_map 重建前缀键 →
遍历 Gen.structs 按短名匹配。
('8e92345fd262a343.GSList[BasicBlock]'),且**方括号内元素也可能带模块
前缀**('GSList[29fdb5e25dc949f4.BasicBlock]',跨模块泛型特化登记值)。
Gen.structs 的键可能是另一种形态。比较前统一剥除所有 '<16hex>.' 片段:
依次尝试:精确键 → 归一短名键 → class_sha1_map 重建前缀键 →
遍历 Gen.structs 按归一短名匹配。
"""
if not ClassHint:
return None
if ClassHint in Gen.structs:
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:
return 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:
return prefixed
for key in Gen.structs:
if Gen._extract_short_name(key) == short:
if _strip_sha(Gen._extract_short_name(key)) == short:
return key
return None
@@ -1883,7 +1926,10 @@ class ExprAttrHandle(BaseHandle):
ok_v: bool
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:
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):
k3: str | None = self._pointee_llvm_to_struct_key(Gen, st_v.elements[off])
if k3:
@@ -1898,7 +1944,10 @@ class ExprAttrHandle(BaseHandle):
p_ok: bool
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:
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):
k4: str | None = self._pointee_llvm_to_struct_key(Gen, p_st.elements[p_off])
if k4:
+38
View File
@@ -1792,6 +1792,44 @@ class FunctionHandle(BaseHandle):
found_struct: str | None = FindStructNameInAnnotation(arg.annotation, Gen.structs)
if 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__'):
self.Trans._CurrentCpythonObjectClass = ResolvedClassName
Gen._variadic_info = None
+6
View File
@@ -3,6 +3,7 @@ from typing import Any
import vast as ast
import os
import re
import sys
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import CTypeInfo
from lib.core.VLogger import get_logger as _vlog
@@ -502,6 +503,11 @@ class FuncGenMixin:
if isinstance(_st_diag, ir.IdentifiedStructType):
_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]
try:
import traceback as _tb
_tb.print_stack(file=sys.stderr)
except Exception:
pass
raise KeyError(
f"[fast-fail] 属性 '{field_name}' 在类 '{ClassName}' 中找不到"
f"(class_members={len(_members_diag)} 个: {_member_names_diag}, struct={_struct_diag})"