[clang] [Clang] Initializer list on RHS of assignment (PR #100548)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 25 03:04:25 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Mital Ashok (MitalAshok)
<details>
<summary>Changes</summary>
This implements [CWG2768](https://cplusplus.github.io/CWG/issues/2768.html).
Also fixes a bug where `x op= {v}` was treated as `x op= v` for compound assignments, which shouldn't have happened.
Fixes #<!-- -->100527
---
Full diff: https://github.com/llvm/llvm-project/pull/100548.diff
5 Files Affected:
- (modified) clang/docs/ReleaseNotes.rst (+4)
- (modified) clang/lib/Sema/SemaExpr.cpp (+50-15)
- (modified) clang/test/CXX/drs/cwg27xx.cpp (+20-6)
- (added) clang/test/SemaCXX/assign-init-list.cpp (+20)
- (modified) clang/www/cxx_dr_status.html (+1-1)
``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 0b79e952b48af..bc048e8bfacba 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -84,6 +84,9 @@ C++2c Feature Support
Resolutions to C++ Defect Reports
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+- Reject assigning to enums with an initailizer list containing an integer.
+ (`CWG2768: Assignment to enumeration variable with a braced-init-list <https://cplusplus.github.io/CWG/issues/2768.html>`_).
+
C Language Changes
------------------
@@ -150,6 +153,7 @@ Bug Fixes to C++ Support
^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed a crash when an expression with a dependent ``__typeof__`` type is used as the operand of a unary operator. (#GH97646)
+- Reject compound assignment operators with a braced-init-list.
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 74c0e01705905..7b9301cf9c560 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -14578,21 +14578,56 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
BinaryOperatorKind Opc,
Expr *LHSExpr, Expr *RHSExpr) {
if (getLangOpts().CPlusPlus11 && isa<InitListExpr>(RHSExpr)) {
- // The syntax only allows initializer lists on the RHS of assignment,
- // so we don't need to worry about accepting invalid code for
- // non-assignment operators.
- // C++11 5.17p9:
- // The meaning of x = {v} [...] is that of x = T(v) [...]. The meaning
- // of x = {} is x = T().
- InitializationKind Kind = InitializationKind::CreateDirectList(
- RHSExpr->getBeginLoc(), RHSExpr->getBeginLoc(), RHSExpr->getEndLoc());
- InitializedEntity Entity =
- InitializedEntity::InitializeTemporary(LHSExpr->getType());
- InitializationSequence InitSeq(*this, Entity, Kind, RHSExpr);
- ExprResult Init = InitSeq.Perform(*this, Entity, Kind, RHSExpr);
- if (Init.isInvalid())
- return Init;
- RHSExpr = Init.get();
+ // C++11 [expr.ass]p9, per CWG2768:
+ // A braced-init-list B may appear on the right-hand side of
+ // - an assignment to a scalar of type T, in which case the initializer
+ // list shall have at most a single element. The meaning of x=B is x = t,
+ // where t is an invented temporary variable declared and initialized as
+ // T t = B
+ switch (Opc) {
+ case BO_Assign: {
+ QualType LHSTy = LHSExpr->getType();
+ assert(!LHSTy->isDependentType() &&
+ "Should not have tried to create a builtin binary operator");
+ if (LHSTy->isScalarType()) {
+ InitializationKind Kind =
+ InitializationKind::CreateCopy(RHSExpr->getBeginLoc(), OpLoc);
+ InitializedEntity Entity =
+ InitializedEntity::InitializeTemporary(LHSExpr->getType());
+ InitializationSequence InitSeq(*this, Entity, Kind, RHSExpr);
+ ExprResult InventedTemporary =
+ InitSeq.Perform(*this, Entity, Kind, RHSExpr);
+ if (InventedTemporary.isInvalid())
+ return InventedTemporary;
+ assert(cast<InitListExpr>(RHSExpr)->getNumInits() <= 1 &&
+ "The initialization should have failed");
+ RHSExpr = InventedTemporary.get();
+ }
+ break;
+ }
+ case BO_MulAssign:
+ case BO_DivAssign:
+ case BO_RemAssign:
+ case BO_AddAssign:
+ case BO_SubAssign:
+ case BO_ShlAssign:
+ case BO_ShrAssign:
+ case BO_AndAssign:
+ case BO_XorAssign:
+ case BO_OrAssign: {
+ // A compound assignment like `i += {0}` is equivalent to `i = i + {0}`,
+ // which is a parsing error
+ StringRef Op = BinaryOperator::getOpcodeStr(Opc);
+ [[maybe_unused]] bool AssignmentStripped = Op.consume_back("=");
+ assert(AssignmentStripped);
+ Diag(OpLoc, diag::err_init_list_bin_op)
+ << 1 << Op << getExprRange(RHSExpr);
+ return ExprError();
+ }
+ default:
+ llvm_unreachable("Non-assignment binary operator with braced-init-list "
+ "should not be parsed");
+ }
}
ExprResult LHS = LHSExpr, RHS = RHSExpr;
diff --git a/clang/test/CXX/drs/cwg27xx.cpp b/clang/test/CXX/drs/cwg27xx.cpp
index 406c8ea41f3b2..abf669c2c9691 100644
--- a/clang/test/CXX/drs/cwg27xx.cpp
+++ b/clang/test/CXX/drs/cwg27xx.cpp
@@ -1,10 +1,10 @@
// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++98 -pedantic-errors -verify=expected %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -pedantic-errors -verify=expected %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++14 -pedantic-errors -verify=expected %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -pedantic-errors -verify=expected %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -pedantic-errors -verify=expected %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -pedantic-errors -verify=expected,since-cxx23 %s
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++2c -pedantic-errors -verify=expected,since-cxx23,since-cxx26 %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 -pedantic-errors -verify=expected,since-cxx11,cxx11-14 %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++14 -pedantic-errors -verify=expected,since-cxx11,cxx11-14 %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++17 -pedantic-errors -verify=expected,since-cxx11 %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++20 -pedantic-errors -verify=expected,since-cxx11 %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++23 -pedantic-errors -verify=expected,since-cxx11,since-cxx23 %s
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++2c -pedantic-errors -verify=expected,since-cxx11,since-cxx23,since-cxx26 %s
namespace cwg2718 { // cwg2718: 2.7
struct B {};
@@ -101,6 +101,20 @@ static_assert(!__is_layout_compatible(StructWithAnonUnion, StructWithAnonUnion3)
#endif
} // namespace cwg2759
+namespace cwg2768 { // cwg2768: 20
+#if __cplusplus >= 201103L
+enum class E {E1};
+
+void f() {
+ E e;
+ e = E{0}; // #1
+ // cxx11-14-error at -1 {{cannot initialize a value of type 'E' with an rvalue of type 'int'}}
+ e = {0}; // #2
+ // since-cxx11-error at -1 {{cannot initialize a value of type 'E' with an rvalue of type 'int'}}
+}
+#endif
+} // namespace cwg2768
+
namespace cwg2789 { // cwg2789: 18
#if __cplusplus >= 202302L
template <typename T = int>
diff --git a/clang/test/SemaCXX/assign-init-list.cpp b/clang/test/SemaCXX/assign-init-list.cpp
new file mode 100644
index 0000000000000..293348092b684
--- /dev/null
+++ b/clang/test/SemaCXX/assign-init-list.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+
+template<typename T>
+void f(T dependent) {
+ int i;
+ i = { dependent, dependent };
+}
+
+template<typename T>
+void f2(T dependent) {
+ int i;
+ i = { dependent, dependent }; // expected-error {{excess elements in scalar initializer}}
+}
+template void f2(int); // expected-note {{in instantiation of function template specialization 'f2<int>' requested here}}
+
+void g() {
+ int i;
+ i = {0};
+ i += {0}; // expected-error {{initializer list cannot be used on the right hand side of operator '+'}}
+}
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index 937f67981e296..359f98c95062b 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -16424,7 +16424,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2768.html">2768</a></td>
<td>DRWP</td>
<td>Assignment to enumeration variable with a <I>braced-init-list</I></td>
- <td class="unknown" align="center">Unknown</td>
+ <td class="unreleased" align="center">Clang 20</td>
</tr>
<tr class="open" id="2769">
<td><a href="https://cplusplus.github.io/CWG/issues/2769.html">2769</a></td>
``````````
</details>
https://github.com/llvm/llvm-project/pull/100548
More information about the cfe-commits
mailing list