[clang] [Clang] Initializer list on RHS of assignment (PR #100548)

via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 25 06:48:35 PDT 2024


================
@@ -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("=");
----------------
cor3ntin wrote:

We have `getOpForCompoundAssignment`, I think using that would be cleaner that doing string manipulations

https://github.com/llvm/llvm-project/pull/100548


More information about the cfe-commits mailing list