[clang] [clang][Sema] Fix rejection of non-dependent void{} during template instantiation (PR #228340)

Ivy Xu via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 4 04:20:17 PDT 2026


https://github.com/IvyXu420 updated https://github.com/llvm/llvm-project/pull/228340

>From e18bacfeed81a1cf3cd085a88e34ee359079c54d Mon Sep 17 00:00:00 2001
From: Ivy Xu <fakeshadow1337 at gmail.com>
Date: Fri, 2 Oct 2026 03:38:40 +0800
Subject: [PATCH 1/4] Fix clang rejecting valid `void{}` when template is used

---
 clang/lib/Sema/SemaExprCXX.cpp | 2 +-
 clang/test/CXX/drs/cwg23xx.cpp | 4 ++++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 1bf6430665ddfa1..1ed58fcf20af098 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1647,7 +1647,7 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
       return CXXFunctionalCastExpr::Create(
           Context, Ty.getUnqualifiedType(), VK_PRValue, TInfo, CK_ToVoid,
           Exprs[0], /*Path=*/nullptr, CurFPFeatureOverrides(),
-          Exprs[0]->getBeginLoc(), Exprs[0]->getEndLoc());
+          SourceLocation(), Exprs[0]->getEndLoc());
     }
   } else if (RequireCompleteType(TyBeginLoc, ElemTy,
                                  diag::err_invalid_incomplete_type_use,
diff --git a/clang/test/CXX/drs/cwg23xx.cpp b/clang/test/CXX/drs/cwg23xx.cpp
index cfd78465c0dbefe..c81fe223a596c81 100644
--- a/clang/test/CXX/drs/cwg23xx.cpp
+++ b/clang/test/CXX/drs/cwg23xx.cpp
@@ -240,6 +240,10 @@ namespace cwg2351 { // cwg2351: 20
   template void i<void>();
   template const void i<const void>();
 
+  template <class T>
+  void f(T) { void{}; }
+  void g() { f(1); }
+
   static_assert((void({}), true), "");
   // since-cxx11-error at -1 {{cannot initialize non-class type 'void' with a parenthesized initializer list}}
 #else

>From 71dd64f2aa5951756198f7ad7a99bd1ab851be3a Mon Sep 17 00:00:00 2001
From: Ivy Xu <fakeshadow1337 at gmail.com>
Date: Fri, 2 Oct 2026 14:25:05 +0800
Subject: [PATCH 2/4] Add release note

---
 clang/docs/ReleaseNotes.md | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index d22874d4130eeca..04ded7c5b6a2eb3 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -801,6 +801,9 @@ features cannot lower the translation-unit ABI level;
   take effect, causing them to be dropped from llvm.used and omitted from
   the object file. (#GH226572)
 
+- Fixed rejection of non-dependent `void{}` during template instantiation,
+  which previously rebuilt the expression as `void({})`. (#GH226485, #GH181448)
+
 #### Bug Fixes to AST Handling
 
 - Fixed a non-deterministic ordering of unused local typedefs that made

>From ed5657d9a4fcb2dadbbc190d6ca7e4277fcfc5ff Mon Sep 17 00:00:00 2001
From: Ivy Xu <fakeshadow1337 at gmail.com>
Date: Fri, 2 Oct 2026 15:20:06 +0800
Subject: [PATCH 3/4] fix the format

---
 clang/lib/Sema/SemaExprCXX.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 1ed58fcf20af098..bb08c3bf1a0e43b 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1646,8 +1646,8 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
         cast<InitListExpr>(Exprs[0])->getNumInits() == 0) {
       return CXXFunctionalCastExpr::Create(
           Context, Ty.getUnqualifiedType(), VK_PRValue, TInfo, CK_ToVoid,
-          Exprs[0], /*Path=*/nullptr, CurFPFeatureOverrides(),
-          SourceLocation(), Exprs[0]->getEndLoc());
+          Exprs[0], /*Path=*/nullptr, CurFPFeatureOverrides(), SourceLocation(),
+          Exprs[0]->getEndLoc());
     }
   } else if (RequireCompleteType(TyBeginLoc, ElemTy,
                                  diag::err_invalid_incomplete_type_use,

>From 102f689f149cdb8ed4dcec2a3404879ba5fa50bf Mon Sep 17 00:00:00 2001
From: Ivy Xu <fakeshadow1337 at gmail.com>
Date: Fri, 2 Oct 2026 21:08:37 +0800
Subject: [PATCH 4/4] Add a CXXFunctionalCastExpr::CreateListInitializer(...)
 function

---
 clang/include/clang/AST/ExprCXX.h |  5 +++++
 clang/lib/AST/ExprCXX.cpp         |  8 ++++++++
 clang/lib/Sema/SemaExprCXX.cpp    | 21 +++++++++++----------
 3 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 1393da4da2721e4..e42b4cd2d78db0d 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -1869,6 +1869,11 @@ class CXXFunctionalCastExpr final
   static CXXFunctionalCastExpr *
   CreateEmpty(const ASTContext &Context, unsigned PathSize, bool HasFPFeatures);
 
+  static CXXFunctionalCastExpr *
+  CreateListInitializer(const ASTContext &Context, QualType T, ExprValueKind VK,
+                        TypeSourceInfo *Written, CastKind Kind, Expr *Op,
+                        const CXXCastPath *Path, FPOptionsOverride FPO);
+
   SourceLocation getLParenLoc() const { return LParenLoc; }
   void setLParenLoc(SourceLocation L) { LParenLoc = L; }
   SourceLocation getRParenLoc() const { return RParenLoc; }
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 9d42d47f248401e..135269696e0444b 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -974,6 +974,14 @@ CXXFunctionalCastExpr *CXXFunctionalCastExpr::CreateEmpty(const ASTContext &C,
       CXXFunctionalCastExpr(EmptyShell(), PathSize, HasFPFeatures);
 }
 
+CXXFunctionalCastExpr *CXXFunctionalCastExpr::CreateListInitializer(
+    const ASTContext &C, QualType T, ExprValueKind VK, TypeSourceInfo *Written,
+    CastKind K, Expr *Op, const CXXCastPath *BasePath, FPOptionsOverride FPO) {
+  // List-initialization is represented by null paren locations
+  return Create(C, T, VK, Written, K, Op, BasePath, FPO, SourceLocation(),
+                SourceLocation());
+}
+
 SourceLocation CXXFunctionalCastExpr::getBeginLoc() const {
   return getTypeInfoAsWritten()->getTypeLoc().getBeginLoc();
 }
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index bb08c3bf1a0e43b..c32f24808a4df2b 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1644,10 +1644,9 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
           Ty.getUnqualifiedType(), TInfo, Kind.getRange().getEnd());
     if (ListInitialization &&
         cast<InitListExpr>(Exprs[0])->getNumInits() == 0) {
-      return CXXFunctionalCastExpr::Create(
+      return CXXFunctionalCastExpr::CreateListInitializer(
           Context, Ty.getUnqualifiedType(), VK_PRValue, TInfo, CK_ToVoid,
-          Exprs[0], /*Path=*/nullptr, CurFPFeatureOverrides(), SourceLocation(),
-          Exprs[0]->getEndLoc());
+          Exprs[0], /*Path=*/nullptr, CurFPFeatureOverrides());
     }
   } else if (RequireCompleteType(TyBeginLoc, ElemTy,
                                  diag::err_invalid_incomplete_type_use,
@@ -1687,13 +1686,15 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
     // to false.
     bool IsListInit = ListInitialization ||
                       (getLangOpts().HLSL && isa<InitListExpr>(Result.get()));
-    SourceRange Locs = IsListInit
-                           ? SourceRange()
-                           : SourceRange(LParenOrBraceLoc, RParenOrBraceLoc);
-    Result = CXXFunctionalCastExpr::Create(
-        Context, ResultType, Expr::getValueKindForType(Ty), TInfo, CK_NoOp,
-        Result.get(), /*Path=*/nullptr, CurFPFeatureOverrides(),
-        Locs.getBegin(), Locs.getEnd());
+    if (IsListInit)
+      Result = CXXFunctionalCastExpr::CreateListInitializer(
+          Context, ResultType, Expr::getValueKindForType(Ty), TInfo, CK_NoOp,
+          Result.get(), /*Path=*/nullptr, CurFPFeatureOverrides());
+    else
+      Result = CXXFunctionalCastExpr::Create(
+          Context, ResultType, Expr::getValueKindForType(Ty), TInfo, CK_NoOp,
+          Result.get(), /*Path=*/nullptr, CurFPFeatureOverrides(),
+          LParenOrBraceLoc, RParenOrBraceLoc);
   }
 
   return Result;



More information about the cfe-commits mailing list