Clang AST: CaseStmt does not encapsulate its full logical body — only first statement is stored as a child
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
In Clang's AST, a CaseStmt node only holds the first statement of the case body as its direct child (the "sub-statement"). All subsequent statements in the same case body are stored as siblings of the CaseStmt at the CompoundStmt level. This makes it difficult for AST-based tools to determine which statements logically belong to a given case.
Clang Version:
```
Clang Version: 21.1.5
Target: x86_64-pc-windows-msvc
```
Reproduction:
```
int example(int x) {
switch (x) {
case 1:
int val = 10; // child of CaseStmt
int extra = 20; // sibling of CaseStmt in CompoundStmt
val = val + extra; // sibling of CaseStmt in CompoundStmt
break; // sibling of CaseStmt in CompoundStmt
default:
val = -1;
break;
}
return val;
}
```
Command:
`clang -Xclang -ast-dump -fsyntax-only example.c`
Observed AST structure (simplified):
```
SwitchStmt
└── CompoundStmt
├── CaseStmt (case 1)
│ └── DeclStmt (int val = 10) ← only first statement is a child
├── DeclStmt (int extra = 20) ← sibling, not child of CaseStmt
├── BinaryOperator (val = val + extra) ← sibling
├── BreakStmt ← sibling
├── DefaultStmt
│ └── BinaryOperator (val = -1) ← only first statement is a child
└── BreakStmt ← sibling
```
Expected AST structure (simplified):
```
SwitchStmt
└── CompoundStmt
├── CaseStmt (case 1)
│ ├── DeclStmt (int val = 10)
│ ├── DeclStmt (int extra = 20)
│ ├── BinaryOperator (val = val + extra)
│ └── BreakStmt
└── DefaultStmt
├── BinaryOperator (val = -1)
└── BreakStmt
```
Impact:
Any tool performing AST-based analysis (scoping, code verification, linting) that uses CaseStmt as a scope boundary cannot determine which statements belong to a given case without inspecting the parent CompoundStmt and manually computing boundaries between consecutive CaseStmt/DefaultStmt nodes. This is error-prone and counterintuitive — the syntactic structure suggests all statements between case 1: and the next case/default label belong to that case.
Contributor guide
Research direction
Reproduce the issue with example.c using clang -Xclang -ast-dump -fsyntax-only and inspect how CaseStmt, DefaultStmt, and CompoundStmt are represented. Done means the AST dump exposes all statements between a case label and the next label as part of that case, while preserving the expected switch structure.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 32/100