audit: 프런트엔드 빈틈 열하나와 진법 리터럴

전부 구현 쪽이었다. SPEC 은 §6.2(체이닝·단항 뒤 as), §5 R9(asm), §6.1·§7.3
(extern, 빈 enum/error)을 이미 옳게 적고 있었고 구현만 따라가지 않았다.

  const A: i32 = r();        전역 초기값에 호출. lowering 이 조용히 버리고 0
  static A: i32 = r();       같은 것을 저장소 0 으로
  true == false == true      비교 체이닝
  -x as u32                  괄호 없이 단항 뒤 as
  asm { }                    unsafe 밖에서
  extern fn f();             ABI 문자열 없이
  extern "stdcall" fn f();   c 아닌 ABI
  extern "c" fn f() { }      extern 에 본문
  fn f() -> i32;             extern 아닌데 본문 없음
  enum E { }  error E { }    빈 선언

FRONT-01/02 는 SPEC 에도 규칙이 없었다. §7.1 에 넣었다 -- 전역의 바이트는
이미지에 들어가므로 초기값이 실행될 순간이 없다. 리터럴과 다른 const, 배리언트,
error.Name, 그리고 그것들에 대한 연산까지가 허용된다.

-x as T 와 비교 체이닝을 잡으려면 괄호가 트리에 남아야 해서 FE_NODE_PAREN 을
두었다. 파싱 뒤에는 -x as T 와 -(x as T) 가 같은 트리다.

그리고 0b1010 이 0, 0o17 이 0 이었다. 10진으로 읽다가 b 에서 멈춰 0 을 내는데
0 도 숫자라 아무도 눈치채지 못한다. 값 계산 두 군데를 고쳤다.

262/262, 40/40.
This commit is contained in:
2026-08-17 17:00:29 +09:00
parent c7a1b98654
commit b4f947b643
24 changed files with 252 additions and 32 deletions
+1
View File
@@ -546,6 +546,7 @@ pub fn main() -> !void {
- `&mut x`, mutable slice 생성과 `&mut Self` 메서드 호출은 `var` place에서만 가능하다. `let``^T`를 보유해도 그 대상을 안전 코드에서 변경할 수 없다. by-value `self: Self`는 소비 메서드 안에서 자신의 필드를 무효 상태로 바꿀 수 있는 가변 local owner로 취급한다.
- 모든 변수는 사용 전 초기화 필수(정적 검사). 명시적 미초기화는 `= undefined`(unsafe 아님, 단 읽기 전 쓰기 필수는 여전히 검사).
- 섀도잉 허용(같은 스코프에서 `let` 재선언).
- **전역 `const`/`static`/`var`의 초기값은 컴파일 시점에 알 수 있어야 한다.** 저장소가 이미지에 들어가므로 초기값이 실행될 순간이 없다. 리터럴, 다른 `const`, 열거형 배리언트, `error.Name`, 그리고 그것들에 대한 연산과 캐스트·집합체 리터럴까지가 허용되며 함수 호출은 허용되지 않는다. 실행 시점에 계산해야 하는 값은 `main`에서 만든다.
### 7.2 제어 흐름