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

Reply via email to