[clang] [Clang] Implement CWG2351 `void{}` (PR #78060)
Mital Ashok via cfe-commits
cfe-commits at lists.llvm.org
Sat Jun 29 03:42:48 PDT 2024
https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/78060
>From 6ed7cad5d4993603221c3d9a777463675d69643b Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Sat, 13 Jan 2024 18:03:15 +0000
Subject: [PATCH 1/3] [SemaCXX] Implement CWG2351 `void{}`
---
clang/docs/ReleaseNotes.rst | 3 ++
clang/include/clang/AST/ExprCXX.h | 5 +--
clang/lib/Sema/SemaExprCXX.cpp | 23 ++++++++----
clang/lib/Sema/SemaInit.cpp | 1 +
clang/test/CXX/drs/dr23xx.cpp | 41 +++++++++++++++++++++-
clang/test/SemaCXX/attr-annotate.cpp | 4 +--
clang/test/SemaCXX/cxx2a-explicit-bool.cpp | 4 +--
clang/test/SemaCXX/sugared-auto.cpp | 6 ++++
clang/www/cxx_dr_status.html | 2 +-
9 files changed, 75 insertions(+), 14 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 92563262cc673..28cd1a8abd4c6 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -157,6 +157,9 @@ Resolutions to C++ Defect Reports
- Clang now diagnoses declarative nested-name-specifiers with pack-index-specifiers.
(`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers <https://cplusplus.github.io/CWG/issues/2858.html>`_).
+- Implemented `CWG2351 <https://wg21.link/CWG2351>`_ which allows ``void{}``
+ as a prvalue of type ``void``.
+
C Language Changes
------------------
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index a915745d2d732..8fa5c0c79f6a0 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -2170,8 +2170,9 @@ class LambdaExpr final : public Expr,
const_child_range children() const;
};
-/// An expression "T()" which creates a value-initialized rvalue of type
-/// T, which is a non-class type. See (C++98 [5.2.3p2]).
+/// An expression "T()" which creates an rvalue of a non-class type T.
+/// For non-void T, the rvalue is value-initialized.
+/// See (C++98 [5.2.3p2]).
class CXXScalarValueInitExpr : public Expr {
friend class ASTStmtReader;
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 779a41620033d..269aedb59ca8f 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1660,12 +1660,23 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
return ExprError(Diag(TyBeginLoc, diag::err_init_for_function_type)
<< Ty << FullRange);
- // C++17 [expr.type.conv]p2:
- // If the type is cv void and the initializer is (), the expression is a
- // prvalue of the specified type that performs no initialization.
- if (!Ty->isVoidType() &&
- RequireCompleteType(TyBeginLoc, ElemTy,
- diag::err_invalid_incomplete_type_use, FullRange))
+ // C++17 [expr.type.conv]p2, per DR2351:
+ // If the type is cv void and the initializer is () or {}, the expression is
+ // a prvalue of the specified type that performs no initialization.
+ if (Ty->isVoidType()) {
+ if (Exprs.empty())
+ return new (Context) CXXScalarValueInitExpr(
+ Ty.getUnqualifiedType(), TInfo, Kind.getRange().getEnd());
+ if (ListInitialization &&
+ cast<InitListExpr>(Exprs[0])->getNumInits() == 0) {
+ return CXXFunctionalCastExpr::Create(
+ Context, Ty.getUnqualifiedType(), VK_PRValue, TInfo, CK_NoOp,
+ Exprs[0], /*Path=*/nullptr, CurFPFeatureOverrides(),
+ Exprs[0]->getBeginLoc(), Exprs[0]->getEndLoc());
+ }
+ } else if (RequireCompleteType(TyBeginLoc, ElemTy,
+ diag::err_invalid_incomplete_type_use,
+ FullRange))
return ExprError();
// Otherwise, the expression is a prvalue of the specified type whose
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 003a157990d30..3bb8407c893d9 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -5344,6 +5344,7 @@ static void TryValueInitialization(Sema &S,
//
// To value-initialize an object of type T means:
QualType T = Entity.getType();
+ assert(!T->isVoidType() && "Cannot value-init void");
// -- if T is an array type, then each element is value-initialized;
T = S.Context.getBaseElementType(T);
diff --git a/clang/test/CXX/drs/dr23xx.cpp b/clang/test/CXX/drs/dr23xx.cpp
index db5b7c3cd3c9a..cd21af0daf3d0 100644
--- a/clang/test/CXX/drs/dr23xx.cpp
+++ b/clang/test/CXX/drs/dr23xx.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -std=c++98 %s -verify=expected -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -std=c++98 %s -verify=expected,cxx98-03 -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -std=c++03 %s -verify=expected,cxx98-03 -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
// RUN: %clang_cc1 -std=c++11 %s -verify=expected,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
// RUN: %clang_cc1 -std=c++14 %s -verify=expected,since-cxx11,since-cxx14 -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
// RUN: %clang_cc1 -std=c++17 %s -verify=expected,since-cxx11,since-cxx14,since-cxx17 -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
@@ -70,6 +71,44 @@ namespace cwg2346 { // cwg2346: 11
}
}
+namespace cwg2351 { // cwg2351: 19
+#if __cplusplus >= 201103L
+ static_assert((void{}, true), "");
+ // since-cxx11-warning at -1 {{left operand of comma operator has no effect}}
+
+ void f() {
+ return void{};
+ }
+
+ template<typename T>
+ void g() {
+ return T{};
+ }
+ template void g<void>();
+ template void g<const void>();
+
+ void h() {
+ return {};
+ // since-cxx11-error at -1 {{void function 'h' must not return a value}}
+ }
+
+ template<typename T, int... I>
+ T i() {
+ return T{I...};
+ }
+ template void i<void>();
+ template const void i<const void>();
+
+ static_assert((void({}), true), "");
+ // since-cxx11-error at -1 {{cannot initialize non-class type 'void' with a parenthesized initializer list}}
+#else
+ int I = (void{}, 0);
+ // cxx98-03-error at -1 {{expected ')'}}
+ // cxx98-03-note at -2 {{to match this '('}}
+ // cxx98-03-error at -3 {{expected expression}}
+#endif
+}
+
namespace cwg2352 { // cwg2352: 10
int **p;
const int *const *const &f1() { return p; }
diff --git a/clang/test/SemaCXX/attr-annotate.cpp b/clang/test/SemaCXX/attr-annotate.cpp
index 3854f72bbcac1..846ef4119f1d7 100644
--- a/clang/test/SemaCXX/attr-annotate.cpp
+++ b/clang/test/SemaCXX/attr-annotate.cpp
@@ -43,10 +43,10 @@ namespace test0 {
template<typename T>
struct B {
[[clang::annotate("test", ((void)T{}, 9))]] void t() {}
- // expected-error at -1 {{illegal initializer type 'void'}}
+ // expected-error at -1 {{cannot create object of function type 'void ()'}}
};
B<int> b;
- B<void> b1;
+ B<void ()> b1;
// expected-note at -1 {{in instantiation of template class}}
}
diff --git a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
index 9fdc059493aac..55f99b2fd355f 100644
--- a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
+++ b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
@@ -75,11 +75,11 @@ struct D {
template <typename T> struct E {
// expected-note at -1+ {{candidate constructor}}
explicit((T{}, false))
- // expected-error at -1 {{illegal initializer type 'void'}}
+ // expected-error at -1 {{cannot create object of function type 'void ()'}}
E(int);
};
-E<void> e = 1;
+E<void ()> e = 1;
// expected-error at -1 {{no viable conversion}}
// expected-note at -2 {{in instantiation of}}
diff --git a/clang/test/SemaCXX/sugared-auto.cpp b/clang/test/SemaCXX/sugared-auto.cpp
index 5fdfb09689b66..b5bb4f0f85a77 100644
--- a/clang/test/SemaCXX/sugared-auto.cpp
+++ b/clang/test/SemaCXX/sugared-auto.cpp
@@ -112,6 +112,12 @@ N t6 = [] { // expected-error {{rvalue of type 'void'}}
return;
}();
+N t7 = [] { // expected-error {{rvalue of type 'Virus' (aka 'void')}}
+ if (true)
+ return Ebola();
+ return SARS{};
+}();
+
} // namespace function_multiple_basic
#define TEST_AUTO(X, A, B) \
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index ea8872c91be60..d696cc523e41d 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -13914,7 +13914,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2351.html">2351</a></td>
<td>CD5</td>
<td><TT>void{}</TT></td>
- <td class="unknown" align="center">Unknown</td>
+ <td class="unreleased" align="center">Clang 19</td>
</tr>
<tr id="2352">
<td><a href="https://cplusplus.github.io/CWG/issues/2352.html">2352</a></td>
>From 70b62c2246be90ea71dd9b836be55674cc385c0a Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Tue, 21 May 2024 16:58:33 +0100
Subject: [PATCH 2/3] Change cast kind to CK_ToVoid instead of CK_NoOp
---
clang/docs/ReleaseNotes.rst | 4 ++--
clang/lib/Sema/SemaExprCXX.cpp | 2 +-
clang/test/CXX/drs/cwg23xx.cpp | 1 -
3 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 0fca837204ba5..67a5cc48043fb 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -232,8 +232,8 @@ Resolutions to C++ Defect Reports
- P0522 implementation is enabled by default in all language versions, and
provisional wording for CWG2398 is implemented.
-- Implemented `CWG2351 <https://wg21.link/CWG2351>`_ which allows ``void{}``
- as a prvalue of type ``void``.
+- Allow ``void{}`` as a prvalue of type ``void``.
+ (`CWG2351: void{} <https://cplusplus.github.io/CWG/issues/2351.html>`_).
C Language Changes
------------------
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index cfb0091bde51e..00579eeb1204e 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1671,7 +1671,7 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
if (ListInitialization &&
cast<InitListExpr>(Exprs[0])->getNumInits() == 0) {
return CXXFunctionalCastExpr::Create(
- Context, Ty.getUnqualifiedType(), VK_PRValue, TInfo, CK_NoOp,
+ Context, Ty.getUnqualifiedType(), VK_PRValue, TInfo, CK_ToVoid,
Exprs[0], /*Path=*/nullptr, CurFPFeatureOverrides(),
Exprs[0]->getBeginLoc(), Exprs[0]->getEndLoc());
}
diff --git a/clang/test/CXX/drs/cwg23xx.cpp b/clang/test/CXX/drs/cwg23xx.cpp
index f89865a360b72..3293e92a36f7d 100644
--- a/clang/test/CXX/drs/cwg23xx.cpp
+++ b/clang/test/CXX/drs/cwg23xx.cpp
@@ -118,7 +118,6 @@ namespace cwg2346 { // cwg2346: 11
namespace cwg2351 { // cwg2351: 19
#if __cplusplus >= 201103L
static_assert((void{}, true), "");
- // since-cxx11-warning at -1 {{left operand of comma operator has no effect}}
void f() {
return void{};
>From 3540155d2c93ea94de58e9b127f832cf0c28f14e Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Sat, 29 Jun 2024 11:41:23 +0100
Subject: [PATCH 3/3] Remove c++03 test that was added
It wasn't needed, there is no difference with the C++98 and C++03 behaviour
---
clang/test/CXX/drs/cwg23xx.cpp | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/clang/test/CXX/drs/cwg23xx.cpp b/clang/test/CXX/drs/cwg23xx.cpp
index bbfa14ccd3a4e..9953b1b690362 100644
--- a/clang/test/CXX/drs/cwg23xx.cpp
+++ b/clang/test/CXX/drs/cwg23xx.cpp
@@ -1,5 +1,4 @@
-// RUN: %clang_cc1 -std=c++98 %s -verify=expected,cxx98-03 -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
-// RUN: %clang_cc1 -std=c++03 %s -verify=expected,cxx98-03 -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -std=c++98 %s -verify=expected,cxx98 -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
// RUN: %clang_cc1 -std=c++11 %s -verify=expected,cxx11-14,since-cxx11 -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
// RUN: %clang_cc1 -std=c++14 %s -verify=expected,cxx11-14,since-cxx11,since-cxx14 -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
// RUN: %clang_cc1 -std=c++17 %s -verify=expected,since-cxx11,since-cxx14,since-cxx17 -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
@@ -146,9 +145,9 @@ namespace cwg2351 { // cwg2351: 19
// since-cxx11-error at -1 {{cannot initialize non-class type 'void' with a parenthesized initializer list}}
#else
int I = (void{}, 0);
- // cxx98-03-error at -1 {{expected ')'}}
- // cxx98-03-note at -2 {{to match this '('}}
- // cxx98-03-error at -3 {{expected expression}}
+ // cxx98-error at -1 {{expected ')'}}
+ // cxx98-note at -2 {{to match this '('}}
+ // cxx98-error at -3 {{expected expression}}
#endif
}
More information about the cfe-commits
mailing list