https://github.com/Z3rox-dev created
https://github.com/llvm/llvm-project/pull/181579
Fix a crash in CodeGen (`Unexpected placeholder builtin type!` in
`CodeGenTypes::ConvertType`) when a GNU statement expression ends with `extern
void;` preceded by other statements.
## Root Cause
`extern void;` produces a null `DeclGroupPtrTy`, causing `ActOnDeclStmt` to
return `StmtError()`. In `ParseCompoundStatementBody`, this unconditionally set
`LastIsError = true`. For multi-statement statement expressions, the check:
```cpp
if (isStmtExpr && LastIsError && !Stmts.empty())
return StmtError();
```
caused the entire compound statement to fail. This cascaded up to
`ParsePostfixExpressionSuffix` where `ExpressionListIsInvalid` created a
`RecoveryExpr` with `<dependent type>` **without emitting a proper error
diagnostic**. Since no error was recorded by Sema, CodeGen proceeded and hit
`llvm_unreachable` when encountering the dependent type.
## Fix
Refine `LastIsError` in `ParseCompoundStatementBody` to only be set when
`R.isInvalid()` **and** a new error diagnostic was actually emitted during
parsing of that statement. `extern void;` only emits a warning (not an error),
so it no longer triggers the cascade. The proper type-checking error (`passing
'void' to parameter of incompatible type 'int'`) is now emitted as expected.
## Reproducer
```c
extern int bar(int);
int foo(int x) {
return 1 + bar(({
switch (x) { default: break; }
extern void;
}));
}
```
Before: crash with `UNREACHABLE executed at CodeGenTypes.cpp: Unexpected
placeholder builtin type!`
After: clean error `passing 'void' to parameter of incompatible type 'int'`
## Testing
- All `check-clang-sema` (1255), `check-clang-parser` (403),
`check-clang-semacxx` (1378), `check-clang-codegen` (2937) tests pass with zero
failures.
- Added regression test `clang/test/CodeGen/stmt-expr-void-cast.c`.
>From 56bc8b1f916a51d7f4973d78319296dc29007c5f Mon Sep 17 00:00:00 2001
From: Giovanni Baldon <[email protected]>
Date: Sun, 15 Feb 2026 22:57:44 +0100
Subject: [PATCH] [Clang][Parse] Fix crash on stmt-expr ending with 'extern
void;'
Fix a crash in CodeGen ('Unexpected placeholder builtin type!' in
CodeGenTypes::ConvertType) when a GNU statement expression ends
with 'extern void;' preceded by other statements.
'extern void;' produces a null DeclGroupPtrTy, causing
ActOnDeclStmt to return StmtError(). In ParseCompoundStatementBody,
this unconditionally set LastIsError=true. For multi-statement
statement expressions, the check:
if (isStmtExpr && LastIsError && !Stmts.empty())
return StmtError();
caused the entire compound statement to fail. This cascaded up
through ParsePostfixExpressionSuffix where ExpressionListIsInvalid
created a RecoveryExpr with <dependent type> without emitting a
proper error diagnostic. Since no error was recorded, CodeGen
proceeded and hit llvm_unreachable when encountering the dependent
type.
The fix refines LastIsError to only be set when R.isInvalid() AND
a new error diagnostic was actually emitted during parsing of that
statement. 'extern void;' only emits a warning, not an error, so
it no longer triggers the cascade. The proper type-checking error
('passing void to parameter of incompatible type int') is now
emitted as expected.
Fixes #173921
---
clang/lib/Parse/ParseStmt.cpp | 11 +++++++-
clang/test/CodeGen/stmt-expr-void-cast.c | 33 ++++++++++++++++++++++++
2 files changed, 43 insertions(+), 1 deletion(-)
create mode 100644 clang/test/CodeGen/stmt-expr-void-cast.c
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 1a45ed66950be..8c43e49e8f4e4 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -1160,6 +1160,8 @@ StmtResult Parser::ParseCompoundStatementBody(bool
isStmtExpr) {
bool LastIsError = false;
while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) &&
Tok.isNot(tok::eof)) {
+ unsigned PrevErrors = Actions.getDiagnostics().getNumErrors();
+
if (Tok.is(tok::annot_pragma_unused)) {
HandlePragmaUnused();
continue;
@@ -1214,7 +1216,14 @@ StmtResult Parser::ParseCompoundStatementBody(bool
isStmtExpr) {
if (R.isUsable())
Stmts.push_back(R.get());
- LastIsError = R.isInvalid();
+ // Only treat the last statement as an error if an actual error diagnostic
+ // was emitted during parsing. Constructs like "extern void;" may produce
+ // an invalid StmtResult (via null DeclGroup) with only a warning, which
+ // should not cause the entire compound statement to fail in a stmt-expr.
+ // See https://github.com/llvm/llvm-project/issues/173921
+ LastIsError =
+ R.isInvalid() &&
+ Actions.getDiagnostics().getNumErrors() > PrevErrors;
}
// StmtExpr needs to do copy initialization for last statement.
// If last statement is invalid, the last statement in `Stmts` will be
diff --git a/clang/test/CodeGen/stmt-expr-void-cast.c
b/clang/test/CodeGen/stmt-expr-void-cast.c
new file mode 100644
index 0000000000000..48891aa89b4a8
--- /dev/null
+++ b/clang/test/CodeGen/stmt-expr-void-cast.c
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -emit-llvm -verify %s -o /dev/null
+
+// Regression test for https://github.com/llvm/llvm-project/issues/173921
+// Ensure that "extern void;" inside a multi-statement GNU statement expression
+// does not cause a crash in CodeGen due to a leaked RecoveryExpr with
+// dependent type.
+
+extern int bar(int); // expected-note 3{{passing argument to parameter here}}
+
+int test_switch(int x) {
+ return 1 + bar(({ // expected-error {{passing 'void' to parameter of
incompatible type 'int'}}
+ int y;
+ switch (x) {
+ default:
+ y = 7;
+ break;
+ }
+ extern void; // expected-warning {{declaration does not declare
anything}}
+ }));
+}
+
+int test_single_stmt(int x) {
+ return bar(({ // expected-error {{passing 'void' to parameter of
incompatible type 'int'}}
+ extern void; // expected-warning {{declaration does not declare
anything}}
+ }));
+}
+
+int test_if(int x) {
+ return bar(({ // expected-error {{passing 'void' to parameter of
incompatible type 'int'}}
+ if (x) {}
+ extern void; // expected-warning {{declaration does not declare
anything}}
+ }));
+}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits