llvm / llvm/llvm-project

Clang AST: CaseStmt does not encapsulate its full logical body — only first statement is stored as a child

Open
#205,755 4 comments 0 reactions 0 assignees View on GitHub
clang:frontend
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.