mibintc updated this revision to Diff 253983.
mibintc added a comment.

Here's another revision, I believe this handles all of @rjmccall 's requests.  
Thank you, John, for your review!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D76384/new/

https://reviews.llvm.org/D76384

Files:
  clang/include/clang/AST/Expr.h
  clang/include/clang/AST/ExprCXX.h
  clang/include/clang/AST/JSONNodeDumper.h
  clang/include/clang/AST/RecursiveASTVisitor.h
  clang/include/clang/AST/Stmt.h
  clang/include/clang/AST/StmtVisitor.h
  clang/include/clang/AST/TextNodeDumper.h
  clang/include/clang/Basic/LangOptions.h
  clang/include/clang/Basic/StmtNodes.td
  clang/include/clang/Serialization/ASTBitCodes.h
  clang/lib/AST/ASTImporter.cpp
  clang/lib/AST/Expr.cpp
  clang/lib/AST/ExprCXX.cpp
  clang/lib/AST/ExprClassification.cpp
  clang/lib/AST/ExprConstant.cpp
  clang/lib/AST/ItaniumMangle.cpp
  clang/lib/AST/JSONNodeDumper.cpp
  clang/lib/AST/StmtPrinter.cpp
  clang/lib/AST/StmtProfile.cpp
  clang/lib/AST/TextNodeDumper.cpp
  clang/lib/Analysis/BodyFarm.cpp
  clang/lib/Analysis/CFG.cpp
  clang/lib/Analysis/ReachableCode.cpp
  clang/lib/Analysis/ThreadSafetyCommon.cpp
  clang/lib/Basic/LangOptions.cpp
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/CodeGen/CGExprComplex.cpp
  clang/lib/CodeGen/CGExprScalar.cpp
  clang/lib/CodeGen/CGObjC.cpp
  clang/lib/CodeGen/CGStmtOpenMP.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
  clang/lib/Frontend/Rewrite/RewriteObjC.cpp
  clang/lib/Index/IndexBody.cpp
  clang/lib/Sema/AnalysisBasedWarnings.cpp
  clang/lib/Sema/SemaChecking.cpp
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaExceptionSpec.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaOpenMP.cpp
  clang/lib/Sema/SemaOverload.cpp
  clang/lib/Sema/SemaPseudoObject.cpp
  clang/lib/Sema/TreeTransform.h
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/lib/Serialization/ASTWriter.cpp
  clang/lib/Serialization/ASTWriterStmt.cpp
  clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
  clang/test/AST/ast-dump-expr-json.c
  clang/test/AST/ast-dump-expr.c
  clang/test/AST/dump.cpp
  clang/test/Import/compound-assign-op/test.cpp
  clang/tools/libclang/CXCursor.cpp

Index: clang/tools/libclang/CXCursor.cpp
===================================================================
--- clang/tools/libclang/CXCursor.cpp
+++ clang/tools/libclang/CXCursor.cpp
@@ -431,10 +431,6 @@
     K = CXCursor_BinaryOperator;
     break;
 
-  case Stmt::CompoundAssignOperatorClass:
-    K = CXCursor_CompoundAssignOperator;
-    break;
-
   case Stmt::ConditionalOperatorClass:
     K = CXCursor_ConditionalOperator;
     break;
Index: clang/test/Import/compound-assign-op/test.cpp
===================================================================
--- clang/test/Import/compound-assign-op/test.cpp
+++ clang/test/Import/compound-assign-op/test.cpp
@@ -2,42 +2,42 @@
 
 // CHECK: VarDecl
 // CHECK-NEXT: Integer
-// CHECK-NEXT: CompoundAssignOperator
+// CHECK-NEXT: BinaryOperator
 // CHECK-SAME: '+='
 
 // CHECK: VarDecl
 // CHECK-NEXT: Integer
-// CHECK-NEXT: CompoundAssignOperator
+// CHECK-NEXT: BinaryOperator
 // CHECK-SAME: '-='
 
 // CHECK: VarDecl
 // CHECK-NEXT: Integer
-// CHECK-NEXT: CompoundAssignOperator
+// CHECK-NEXT: BinaryOperator
 // CHECK-SAME: '*='
 
 // CHECK: VarDecl
 // CHECK-NEXT: Integer
-// CHECK-NEXT: CompoundAssignOperator
+// CHECK-NEXT: BinaryOperator
 // CHECK-SAME: '/='
 
 // CHECK: VarDecl
 // CHECK-NEXT: Integer
-// CHECK-NEXT: CompoundAssignOperator
+// CHECK-NEXT: BinaryOperator
 // CHECK-SAME: '&='
 
 // CHECK: VarDecl
 // CHECK-NEXT: Integer
-// CHECK-NEXT: CompoundAssignOperator
+// CHECK-NEXT: BinaryOperator
 // CHECK-SAME: '^='
 
 // CHECK: VarDecl
 // CHECK-NEXT: Integer
-// CHECK-NEXT: CompoundAssignOperator
+// CHECK-NEXT: BinaryOperator
 // CHECK-SAME: '<<='
 
 // CHECK: VarDecl
 // CHECK-NEXT: Integer
-// CHECK-NEXT: CompoundAssignOperator
+// CHECK-NEXT: BinaryOperator
 // CHECK-SAME: '>>='
 
 void expr() {
Index: clang/test/AST/dump.cpp
===================================================================
--- clang/test/AST/dump.cpp
+++ clang/test/AST/dump.cpp
@@ -14,14 +14,14 @@
 #pragma omp declare reduction(fun : float : omp_out += omp_in) initializer(omp_priv = omp_orig + 15)
 
 // CHECK:      |-OMPDeclareReductionDecl {{.+}} <line:[[@LINE-4]]:35> col:35 operator+ 'int' combiner 0x{{.+}}
-// CHECK-NEXT: | |-CompoundAssignOperator {{.+}} <col:47, col:58> 'int' lvalue '*=' ComputeLHSTy='int' ComputeResultTy='int'
+// CHECK-NEXT: | |-BinaryOperator {{.+}} <col:47, col:58> 'int' lvalue '*=' ComputeLHSTy='int' ComputeResultTy='int'
 // CHECK-NEXT: | | |-DeclRefExpr {{.+}} <col:47> 'int' lvalue Var {{.+}} 'omp_out' 'int'
 // CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} <col:58> 'int' <LValueToRValue>
 // CHECK-NEXT: | |   `-DeclRefExpr {{.+}} <col:58> 'int' lvalue Var {{.+}} 'omp_in' 'int'
 // CHECK-NEXT: | |-VarDecl {{.+}} <col:35> col:35 implicit used omp_in 'int'
 // CHECK-NEXT: | `-VarDecl {{.+}} <col:35> col:35 implicit used omp_out 'int'
 // CHECK-NEXT: |-OMPDeclareReductionDecl {{.+}} <col:40> col:40 operator+ 'char' combiner 0x{{.+}}
-// CHECK-NEXT: | |-CompoundAssignOperator {{.+}} <col:47, col:58> 'char' lvalue '*=' ComputeLHSTy='int' ComputeResultTy='int'
+// CHECK-NEXT: | |-BinaryOperator {{.+}} <col:47, col:58> 'char' lvalue '*=' ComputeLHSTy='int' ComputeResultTy='int'
 // CHECK-NEXT: | | |-DeclRefExpr {{.+}} <col:47> 'char' lvalue Var {{.+}} 'omp_out' 'char'
 // CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} <col:58> 'int' <IntegralCast>
 // CHECK-NEXT: | |   `-ImplicitCastExpr {{.+}} <col:58> 'char' <LValueToRValue>
@@ -29,7 +29,7 @@
 // CHECK-NEXT: | |-VarDecl {{.+}} <col:40> col:40 implicit used omp_in 'char'
 // CHECK-NEXT: | `-VarDecl {{.+}} <col:40> col:40 implicit used omp_out 'char'
 // CHECK-NEXT: |-OMPDeclareReductionDecl {{.+}} <line:[[@LINE-17]]:37> col:37 fun 'float' combiner 0x{{.+}} initializer 0x{{.+}}
-// CHECK-NEXT: | |-CompoundAssignOperator {{.+}} <col:45, col:56> 'float' lvalue '+=' ComputeLHSTy='float' ComputeResultTy='float'
+// CHECK-NEXT: | |-BinaryOperator {{.+}} <col:45, col:56> 'float' lvalue '+=' ComputeLHSTy='float' ComputeResultTy='float'
 // CHECK-NEXT: | | |-DeclRefExpr {{.+}} <col:45> 'float' lvalue Var {{.+}} 'omp_out' 'float'
 // CHECK-NEXT: | | `-ImplicitCastExpr {{.+}} <col:56> 'float' <LValueToRValue>
 // CHECK-NEXT: | |   `-DeclRefExpr {{.+}} <col:56> 'float' lvalue Var {{.+}} 'omp_in' 'float'
Index: clang/test/AST/ast-dump-expr.c
===================================================================
--- clang/test/AST/ast-dump-expr.c
+++ clang/test/AST/ast-dump-expr.c
@@ -16,7 +16,7 @@
   // CHECK-NEXT: IntegerLiteral 0x{{[^ ]*}} <col:7> 'int' 12
 
   a += a;
-  // CHECK: CompoundAssignOperator 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:8> 'int' '+=' ComputeLHSTy='int' ComputeResultTy='int'
+  // CHECK: BinaryOperator 0x{{[^ ]*}} <line:[[@LINE-1]]:3, col:8> 'int' '+=' ComputeLHSTy='int' ComputeResultTy='int'
   // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:3> 'int' lvalue ParmVar 0x{{[^ ]*}} 'a' 'int'
   // CHECK-NEXT: ImplicitCastExpr
   // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} <col:8> 'int' lvalue ParmVar 0x{{[^ ]*}} 'a' 'int'
Index: clang/test/AST/ast-dump-expr-json.c
===================================================================
--- clang/test/AST/ast-dump-expr-json.c
+++ clang/test/AST/ast-dump-expr-json.c
@@ -270,7 +270,6 @@
 // CHECK-NEXT:  ]
 // CHECK-NEXT: }
 
-
 // CHECK:  "kind": "FunctionDecl",
 // CHECK-NEXT:  "loc": {
 // CHECK-NEXT:   "offset": 157,
@@ -417,7 +416,7 @@
 // CHECK-NEXT:     },
 // CHECK-NEXT:     {
 // CHECK-NEXT:      "id": "0x{{.*}}",
-// CHECK-NEXT:      "kind": "CompoundAssignOperator",
+// CHECK-NEXT:      "kind": "BinaryOperator",
 // CHECK-NEXT:      "range": {
 // CHECK-NEXT:       "begin": {
 // CHECK-NEXT:        "offset": 191,
@@ -529,7 +528,6 @@
 // CHECK-NEXT:  ]
 // CHECK-NEXT: }
 
-
 // CHECK:  "kind": "FunctionDecl",
 // CHECK-NEXT:  "loc": {
 // CHECK-NEXT:   "offset": 210,
Index: clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -141,12 +141,10 @@
       SVal V = state->getSVal(LHS, LCtx);
 
       // Get the computation type.
-      QualType CTy =
-        cast<CompoundAssignOperator>(B)->getComputationResultType();
+      QualType CTy = B->getComputationResultType();
       CTy = getContext().getCanonicalType(CTy);
 
-      QualType CLHSTy =
-        cast<CompoundAssignOperator>(B)->getComputationLHSType();
+      QualType CLHSTy = B->getComputationLHSType();
       CLHSTy = getContext().getCanonicalType(CLHSTy);
 
       QualType LTy = getContext().getCanonicalType(LHS->getType());
Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1666,12 +1666,6 @@
       break;
     }
 
-    case Stmt::CompoundAssignOperatorClass:
-      Bldr.takeNodes(Pred);
-      VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
-      Bldr.addNodes(Dst);
-      break;
-
     case Stmt::CompoundLiteralExprClass:
       Bldr.takeNodes(Pred);
       VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(S), Pred, Dst);
Index: clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
@@ -446,7 +446,6 @@
 
     return true;
   }
-  case Stmt::CompoundAssignOperatorClass:
   case Stmt::BinaryOperatorClass: {
     const BinaryOperator *BinOp1 = cast<BinaryOperator>(Stmt1);
     const BinaryOperator *BinOp2 = cast<BinaryOperator>(Stmt2);
Index: clang/lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterStmt.cpp
+++ clang/lib/Serialization/ASTWriterStmt.cpp
@@ -891,21 +891,23 @@
 
 void ASTStmtWriter::VisitBinaryOperator(BinaryOperator *E) {
   VisitExpr(E);
+  bool HasFPFeatures = E->hasFPFeatures();
+  // Write this first for easy access when deserializing, as they affect the
+  // size of the UnaryOperator.
+  Record.push_back(HasFPFeatures);
+  Record.push_back(E->getOpcode()); // FIXME: stable encoding
   Record.AddStmt(E->getLHS());
   Record.AddStmt(E->getRHS());
-  Record.push_back(E->getOpcode()); // FIXME: stable encoding
   Record.AddSourceLocation(E->getOperatorLoc());
-  Record.push_back(E->getFPFeatures().getInt());
+  if (HasFPFeatures)
+    Record.push_back(E->getFPFeatures().getAsOpaqueInt());
+  if (E->isCompoundAssignmentOp()) {
+    Record.AddTypeRef(E->getComputationLHSType());
+    Record.AddTypeRef(E->getComputationResultType());
+  }
   Code = serialization::EXPR_BINARY_OPERATOR;
 }
 
-void ASTStmtWriter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
-  VisitBinaryOperator(E);
-  Record.AddTypeRef(E->getComputationLHSType());
-  Record.AddTypeRef(E->getComputationResultType());
-  Code = serialization::EXPR_COMPOUND_ASSIGN_OPERATOR;
-}
-
 void ASTStmtWriter::VisitConditionalOperator(ConditionalOperator *E) {
   VisitExpr(E);
   Record.AddStmt(E->getCond());
@@ -1486,7 +1488,7 @@
 void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
   VisitCallExpr(E);
   Record.push_back(E->getOperator());
-  Record.push_back(E->getFPFeatures().getInt());
+  Record.push_back(E->getFPFeatures().getAsOpaqueInt());
   Record.AddSourceRange(E->Range);
   Code = serialization::EXPR_CXX_OPERATOR_CALL;
 }
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -583,7 +583,6 @@
   RECORD(EXPR_CALL);
   RECORD(EXPR_MEMBER);
   RECORD(EXPR_BINARY_OPERATOR);
-  RECORD(EXPR_COMPOUND_ASSIGN_OPERATOR);
   RECORD(EXPR_CONDITIONAL_OPERATOR);
   RECORD(EXPR_IMPLICIT_CAST);
   RECORD(EXPR_CSTYLE_CAST);
@@ -3905,7 +3904,7 @@
 
 /// Write an FP_PRAGMA_OPTIONS block for the given FPOptions.
 void ASTWriter::WriteFPPragmaOptions(const FPOptions &Opts) {
-  RecordData::value_type Record[] = {Opts.getInt()};
+  RecordData::value_type Record[] = {Opts.getAsOpaqueInt()};
   Stream.EmitRecord(FP_PRAGMA_OPTIONS, Record);
 }
 
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1023,18 +1023,22 @@
 }
 
 void ASTStmtReader::VisitBinaryOperator(BinaryOperator *E) {
+  bool hasFP_Features;
+  BinaryOperator::Opcode opc;
   VisitExpr(E);
+  E->setHasFPFeatures(hasFP_Features = Record.readInt());
+  E->setOpcode(opc = (BinaryOperator::Opcode)Record.readInt());
   E->setLHS(Record.readSubExpr());
   E->setRHS(Record.readSubExpr());
-  E->setOpcode((BinaryOperator::Opcode)Record.readInt());
   E->setOperatorLoc(readSourceLocation());
-  E->setFPFeatures(FPOptions(Record.readInt()));
-}
-
-void ASTStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
-  VisitBinaryOperator(E);
-  E->setComputationLHSType(Record.readType());
-  E->setComputationResultType(Record.readType());
+  if (hasFP_Features) {
+    int x = Record.readInt();
+    E->setFPFeatures(FPOptions(x));
+  }
+  if (BinaryOperator::isCompoundAssignmentOp(opc)) {
+    E->setComputationLHSType(Record.readType());
+    E->setComputationResultType(Record.readType());
+  }
 }
 
 void ASTStmtReader::VisitConditionalOperator(ConditionalOperator *E) {
@@ -2691,6 +2695,8 @@
       return nullptr;
     }
     switch ((StmtCode)MaybeStmtCode.get()) {
+    default:
+      llvm_unreachable("Unexpected StmtCode");
     case STMT_STOP:
       Finished = true;
       break;
@@ -2905,11 +2911,9 @@
       break;
 
     case EXPR_BINARY_OPERATOR:
-      S = new (Context) BinaryOperator(Empty);
-      break;
-
-    case EXPR_COMPOUND_ASSIGN_OPERATOR:
-      S = new (Context) CompoundAssignOperator(Empty);
+      S = BinaryOperator::CreateEmpty(Context,
+                                      Record[ASTStmtReader::NumExprFields],
+                                      Record[ASTStmtReader::NumExprFields + 1]);
       break;
 
     case EXPR_CONDITIONAL_OPERATOR:
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -10184,7 +10184,7 @@
     return E;
 
   Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
-  getSema().FPFeatures = E->getFPFeatures();
+  getSema().FPFeatures = E->getFPFeatures(getSema().getASTContext());
 
   return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(),
                                             LHS.get(), RHS.get());
@@ -10234,13 +10234,6 @@
       E->getOperatorLoc(), Decomp.Opcode, UnqualLookups, LHS.get(), RHS.get());
 }
 
-template<typename Derived>
-ExprResult
-TreeTransform<Derived>::TransformCompoundAssignOperator(
-                                                      CompoundAssignOperator *E) {
-  return getDerived().TransformBinaryOperator(E);
-}
-
 template<typename Derived>
 ExprResult TreeTransform<Derived>::
 TransformBinaryConditionalOperator(BinaryConditionalOperator *e) {
Index: clang/lib/Sema/SemaPseudoObject.cpp
===================================================================
--- clang/lib/Sema/SemaPseudoObject.cpp
+++ clang/lib/Sema/SemaPseudoObject.cpp
@@ -448,11 +448,10 @@
   ExprResult result;
   if (opcode == BO_Assign) {
     result = semanticRHS;
-    syntactic = new (S.Context) BinaryOperator(syntacticLHS, capturedRHS,
-                                               opcode, capturedRHS->getType(),
-                                               capturedRHS->getValueKind(),
-                                               OK_Ordinary, opcLoc,
-                                               FPOptions());
+    syntactic = BinaryOperator::Create(
+        S.Context, syntacticLHS, capturedRHS, opcode, capturedRHS->getType(),
+        capturedRHS->getValueKind(), OK_Ordinary, opcLoc,
+	FPOptions::defaultWithoutTrailingStorage());
   } else {
     ExprResult opLHS = buildGet();
     if (opLHS.isInvalid()) return ExprError();
@@ -463,14 +462,12 @@
     result = S.BuildBinOp(Sc, opcLoc, nonCompound, opLHS.get(), semanticRHS);
     if (result.isInvalid()) return ExprError();
 
-    syntactic =
-      new (S.Context) CompoundAssignOperator(syntacticLHS, capturedRHS, opcode,
-                                             result.get()->getType(),
-                                             result.get()->getValueKind(),
-                                             OK_Ordinary,
-                                             opLHS.get()->getType(),
-                                             result.get()->getType(),
-                                             opcLoc, FPOptions());
+    syntactic = BinaryOperator::Create(
+        S.Context, syntacticLHS, capturedRHS, opcode, result.get()->getType(),
+        result.get()->getValueKind(), OK_Ordinary, opcLoc,
+	FPOptions::defaultWithoutTrailingStorage(),
+        opLHS.get()->getType(),
+        result.get()->getType());
   }
 
   // The result of the assignment, if not void, is the value set into
@@ -1586,9 +1583,10 @@
                                              Expr *LHS, Expr *RHS) {
   // Do nothing if either argument is dependent.
   if (LHS->isTypeDependent() || RHS->isTypeDependent())
-    return new (Context) BinaryOperator(LHS, RHS, opcode, Context.DependentTy,
-                                        VK_RValue, OK_Ordinary, opcLoc,
-                                        FPOptions());
+    return BinaryOperator::Create(Context, LHS, RHS, opcode,
+                                  Context.DependentTy, VK_RValue, OK_Ordinary,
+                                  opcLoc,
+	                          FPOptions::defaultWithoutTrailingStorage());
 
   // Filter out non-overload placeholder types in the RHS.
   if (RHS->getType()->isNonOverloadPlaceholderType()) {
@@ -1639,30 +1637,31 @@
 /// operations.
 Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) {
   Expr *syntax = E->getSyntacticForm();
+  BinaryOperator *bop = dyn_cast<BinaryOperator>(syntax);
   if (UnaryOperator *uop = dyn_cast<UnaryOperator>(syntax)) {
     Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr());
     return new (Context) UnaryOperator(
         op, uop->getOpcode(), uop->getType(), uop->getValueKind(),
         uop->getObjectKind(), uop->getOperatorLoc(), uop->canOverflow());
-  } else if (CompoundAssignOperator *cop
-               = dyn_cast<CompoundAssignOperator>(syntax)) {
-    Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS());
-    Expr *rhs = cast<OpaqueValueExpr>(cop->getRHS())->getSourceExpr();
-    return new (Context) CompoundAssignOperator(lhs, rhs, cop->getOpcode(),
-                                                cop->getType(),
-                                                cop->getValueKind(),
-                                                cop->getObjectKind(),
-                                                cop->getComputationLHSType(),
-                                                cop->getComputationResultType(),
-                                                cop->getOperatorLoc(),
-                                                FPOptions());
-  } else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(syntax)) {
+  } else if (bop && bop->isCompoundAssignmentOp()) {
     Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS());
     Expr *rhs = cast<OpaqueValueExpr>(bop->getRHS())->getSourceExpr();
     return new (Context) BinaryOperator(lhs, rhs, bop->getOpcode(),
-                                        bop->getType(), bop->getValueKind(),
-                                        bop->getObjectKind(),
-                                        bop->getOperatorLoc(), FPOptions());
+                                  bop->getType(),
+                                  bop->getValueKind(),
+                                  bop->getObjectKind(),
+                                  bop->getOperatorLoc(),
+	                          FPOptions::defaultWithoutTrailingStorage(),
+                                  bop->getComputationLHSType(),
+                                  bop->getComputationResultType());
+  } else if (bop) {
+    Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS());
+    Expr *rhs = cast<OpaqueValueExpr>(bop->getRHS())->getSourceExpr();
+    return new (Context) BinaryOperator(lhs, rhs, bop->getOpcode(),
+                                  bop->getType(), bop->getValueKind(),
+                                  bop->getObjectKind(),
+                                  bop->getOperatorLoc(),
+	                          FPOptions::defaultWithoutTrailingStorage());
   } else if (isa<CallExpr>(syntax)) {
     return syntax;
   } else {
Index: clang/lib/Sema/SemaOverload.cpp
===================================================================
--- clang/lib/Sema/SemaOverload.cpp
+++ clang/lib/Sema/SemaOverload.cpp
@@ -12974,8 +12974,8 @@
         Context, NamingClass, NestedNameSpecifierLoc(), OpNameInfo,
         /*ADL*/ true, IsOverloaded(Fns), Fns.begin(), Fns.end());
     return CXXOperatorCallExpr::Create(Context, Op, Fn, ArgsArray,
-                                       Context.DependentTy, VK_RValue, OpLoc,
-                                       FPOptions());
+                                 Context.DependentTy, VK_RValue, OpLoc,
+                                 FPOptions::defaultWithoutTrailingStorage());
   }
 
   // Build an empty overload set.
@@ -13048,8 +13048,8 @@
 
       Args[0] = Input;
       CallExpr *TheCall = CXXOperatorCallExpr::Create(
-          Context, Op, FnExpr.get(), ArgsArray, ResultTy, VK, OpLoc,
-          FPOptions(), Best->IsADLCandidate);
+          Context, Op, FnExpr.get(), ArgsArray, ResultTy, VK, OpLoc, FPFeatures,
+          Best->IsADLCandidate);
 
       if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl))
         return ExprError();
@@ -13218,14 +13218,14 @@
       // If there are no functions to store, just build a dependent
       // BinaryOperator or CompoundAssignment.
       if (Opc <= BO_Assign || Opc > BO_OrAssign)
-        return new (Context) BinaryOperator(
-            Args[0], Args[1], Opc, Context.DependentTy, VK_RValue, OK_Ordinary,
-            OpLoc, FPFeatures);
+        return BinaryOperator::Create(Context, Args[0], Args[1], Opc,
+                                      Context.DependentTy, VK_RValue,
+                                      OK_Ordinary, OpLoc, FPFeatures);
 
-      return new (Context) CompoundAssignOperator(
-          Args[0], Args[1], Opc, Context.DependentTy, VK_LValue, OK_Ordinary,
-          Context.DependentTy, Context.DependentTy, OpLoc,
-          FPFeatures);
+      return BinaryOperator::Create(Context, Args[0], Args[1], Opc,
+                                    Context.DependentTy, VK_LValue, OK_Ordinary,
+                                    OpLoc, FPFeatures,
+                                    Context.DependentTy, Context.DependentTy);
     }
 
     // FIXME: save results of ADL from here?
@@ -13705,8 +13705,8 @@
     // Can't add any actual overloads yet
 
     return CXXOperatorCallExpr::Create(Context, OO_Subscript, Fn, Args,
-                                       Context.DependentTy, VK_RValue, RLoc,
-                                       FPOptions());
+                                   Context.DependentTy, VK_RValue, RLoc,
+                                   FPOptions::defaultWithoutTrailingStorage());
   }
 
   // Handle placeholders on both operands.
@@ -13781,7 +13781,8 @@
 
         CXXOperatorCallExpr *TheCall =
             CXXOperatorCallExpr::Create(Context, OO_Subscript, FnExpr.get(),
-                                        Args, ResultTy, VK, RLoc, FPOptions());
+                                   Args, ResultTy, VK, RLoc,
+                                   FPOptions::defaultWithoutTrailingStorage());
 
         if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl))
           return ExprError();
@@ -14405,7 +14406,8 @@
 
   CXXOperatorCallExpr *TheCall =
       CXXOperatorCallExpr::Create(Context, OO_Call, NewFn.get(), MethodArgs,
-                                  ResultTy, VK, RParenLoc, FPOptions());
+                                  ResultTy, VK, RParenLoc,
+                                  FPOptions::defaultWithoutTrailingStorage());
 
   if (CheckCallReturnType(Method->getReturnType(), LParenLoc, TheCall, Method))
     return true;
@@ -14522,7 +14524,7 @@
   ExprValueKind VK = Expr::getValueKindForType(ResultTy);
   ResultTy = ResultTy.getNonLValueExprType(Context);
   CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
-      Context, OO_Arrow, FnExpr.get(), Base, ResultTy, VK, OpLoc, FPOptions());
+      Context, OO_Arrow, FnExpr.get(), Base, ResultTy, VK, OpLoc, FPFeatures);
 
   if (CheckCallReturnType(Method->getReturnType(), OpLoc, TheCall, Method))
     return ExprError();
Index: clang/lib/Sema/SemaOpenMP.cpp
===================================================================
--- clang/lib/Sema/SemaOpenMP.cpp
+++ clang/lib/Sema/SemaOpenMP.cpp
@@ -9187,20 +9187,18 @@
     AtomicBody = AtomicBody->IgnoreParenImpCasts();
     if (AtomicBody->getType()->isScalarType() ||
         AtomicBody->isInstantiationDependent()) {
-      if (const auto *AtomicCompAssignOp = dyn_cast<CompoundAssignOperator>(
-              AtomicBody->IgnoreParenImpCasts())) {
-        // Check for Compound Assignment Operation
-        Op = BinaryOperator::getOpForCompoundAssignment(
-            AtomicCompAssignOp->getOpcode());
-        OpLoc = AtomicCompAssignOp->getOperatorLoc();
-        E = AtomicCompAssignOp->getRHS();
-        X = AtomicCompAssignOp->getLHS()->IgnoreParens();
-        IsXLHSInRHSPart = true;
-      } else if (auto *AtomicBinOp = dyn_cast<BinaryOperator>(
-                     AtomicBody->IgnoreParenImpCasts())) {
-        // Check for Binary Operation
-        if (checkBinaryOperation(AtomicBinOp, DiagId, NoteId))
+      if (auto *AtomicBinOp =
+              dyn_cast<BinaryOperator>(AtomicBody->IgnoreParenImpCasts())) {
+        if (AtomicBinOp->isCompoundAssignmentOp()) {
+          Op = BinaryOperator::getOpForCompoundAssignment(
+              AtomicBinOp->getOpcode());
+          OpLoc = AtomicBinOp->getOperatorLoc();
+          E = AtomicBinOp->getRHS();
+          X = AtomicBinOp->getLHS()->IgnoreParens();
+          IsXLHSInRHSPart = true;
+        } else if (checkBinaryOperation(AtomicBinOp, DiagId, NoteId))
           return true;
+        // Check for Binary Operation
       } else if (const auto *AtomicUnaryOp = dyn_cast<UnaryOperator>(
                      AtomicBody->IgnoreParenImpCasts())) {
         // Check for Unary Operation
@@ -14801,8 +14799,8 @@
           ELoc, Context.getPointerType(FnTy), VK_RValue, OK_Ordinary,
           S.DefaultLvalueConversion(DeclareReductionRef.get()).get());
       Expr *Args[] = {LHS.get(), RHS.get()};
-      ReductionOp =
-          CallExpr::Create(Context, OVE, Args, Context.VoidTy, VK_RValue, ELoc);
+      ReductionOp = CallExpr::Create(Context, OVE, Args, Context.VoidTy,
+                                     VK_RValue, ELoc);
     } else {
       ReductionOp = S.BuildBinOp(
           Stack->getCurScope(), ReductionId.getBeginLoc(), BOK, LHSDRE, RHSDRE);
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -7001,9 +7001,10 @@
         return ExprError();
       if (RHS.get() == BO->getRHS())
         return E;
-      return new (Context) BinaryOperator(
-          BO->getLHS(), RHS.get(), BO_Comma, BO->getType(), BO->getValueKind(),
-          BO->getObjectKind(), BO->getOperatorLoc(), BO->getFPFeatures());
+      return BinaryOperator::Create(
+          Context, BO->getLHS(), RHS.get(), BO_Comma, BO->getType(),
+          BO->getValueKind(), BO->getObjectKind(), BO->getOperatorLoc(),
+          BO->getFPFeatures(getASTContext()));
     }
   }
 
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -13065,13 +13065,13 @@
     BinOpResTy = S.GetSignedVectorType(BinOpResTy);
 
   if (IsCompAssign)
-    return new (Context) CompoundAssignOperator(
-        LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, BinOpResTy, BinOpResTy,
-        OpLoc, FPFeatures);
+    return BinaryOperator::Create(Context, LHS.get(), RHS.get(), Opc, ResultTy,
+                                  VK, OK, OpLoc, FPFeatures,
+                                  BinOpResTy, BinOpResTy);
 
   LHS = convertVector(LHS.get(), Context.FloatTy, S);
-  auto *BO = new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, BinOpResTy,
-                                          VK, OK, OpLoc, FPFeatures);
+  auto *BO = BinaryOperator::Create(Context, LHS.get(), RHS.get(), Opc,
+                                    BinOpResTy, VK, OK, OpLoc, FPFeatures);
   return convertVector(BO, ResultTy->castAs<VectorType>()->getElementType(), S);
 }
 
@@ -13385,8 +13385,8 @@
     if (ConvertHalfVec)
       return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, false,
                                  OpLoc, FPFeatures);
-    return new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, ResultTy, VK,
-                                        OK, OpLoc, FPFeatures);
+    return BinaryOperator::Create(Context, LHS.get(), RHS.get(), Opc, ResultTy,
+                                  VK, OK, OpLoc, FPFeatures);
   }
 
   // Handle compound assignments.
@@ -13400,9 +13400,12 @@
     return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, true,
                                OpLoc, FPFeatures);
 
-  return new (Context) CompoundAssignOperator(
-      LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, CompLHSTy, CompResultTy,
-      OpLoc, FPFeatures);
+  if (!BinaryOperator::isCompoundAssignmentOp(Opc))
+    return BinaryOperator::Create(Context, LHS.get(), RHS.get(), Opc, ResultTy,
+                                  VK, OK, OpLoc, FPFeatures);
+  return BinaryOperator::Create(Context, LHS.get(), RHS.get(), Opc, ResultTy,
+                                VK, OK, OpLoc, FPFeatures,
+                                CompLHSTy, CompResultTy);
 }
 
 /// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison
Index: clang/lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- clang/lib/Sema/SemaExceptionSpec.cpp
+++ clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1302,7 +1302,6 @@
   case Expr::OMPArrayShapingExprClass:
   case Expr::BinaryOperatorClass:
   case Expr::DependentCoawaitExprClass:
-  case Expr::CompoundAssignOperatorClass:
   case Expr::CStyleCastExprClass:
   case Expr::CXXStaticCastExprClass:
   case Expr::CXXFunctionalCastExprClass:
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -13665,8 +13665,9 @@
   Expr *Comparison
     = new (S.Context) BinaryOperator(IterationVarRefRVal.build(S, Loc),
                      IntegerLiteral::Create(S.Context, Upper, SizeType, Loc),
-                                     BO_NE, S.Context.BoolTy,
-                                     VK_RValue, OK_Ordinary, Loc, FPOptions());
+                                  BO_NE, S.Context.BoolTy,
+                                  VK_RValue, OK_Ordinary, Loc,
+                                  FPOptions::defaultWithoutTrailingStorage());
 
   // Create the pre-increment of the iteration variable. We can determine
   // whether the increment will overflow based on the value of the array
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -10858,7 +10858,8 @@
 /// Analyze the given compound assignment for the possible losing of
 /// floating-point precision.
 static void AnalyzeCompoundAssignment(Sema &S, BinaryOperator *E) {
-  assert(isa<CompoundAssignOperator>(E) &&
+
+  assert(E->isCompoundAssignmentOp() &&
          "Must be compound assignment operation");
   // Recurse on the LHS and RHS in here
   AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc());
@@ -10869,9 +10870,7 @@
 
   // Now check the outermost expression
   const auto *ResultBT = E->getLHS()->getType()->getAs<BuiltinType>();
-  const auto *RBT = cast<CompoundAssignOperator>(E)
-                        ->getComputationResultType()
-                        ->getAs<BuiltinType>();
+  const auto *RBT = E->getComputationResultType()->getAs<BuiltinType>();
 
   // The below checks assume source is floating point.
   if (!ResultBT || !RBT || !RBT->isFloatingPoint()) return;
@@ -11727,7 +11726,7 @@
     if (BO->getOpcode() == BO_Assign)
       return AnalyzeAssignment(S, BO);
     // And with compound assignments.
-    if (BO->isAssignmentOp())
+    if (BO->isAssignmentOp() || BO->isCompoundAssignmentOp())
       return AnalyzeCompoundAssignment(S, BO);
   }
 
@@ -12534,7 +12533,7 @@
       Region = LHSRegion;
       Visit(BO->getLHS());
 
-      if (O && isa<CompoundAssignOperator>(BO))
+      if (O && BO->isCompoundAssignmentOp())
         notePostUse(O, BO);
 
     } else {
@@ -12542,7 +12541,7 @@
       Region = LHSRegion;
       Visit(BO->getLHS());
 
-      if (O && isa<CompoundAssignOperator>(BO))
+      if (O && BO->isCompoundAssignmentOp())
         notePostUse(O, BO);
 
       Region = RHSRegion;
@@ -12564,10 +12563,6 @@
     }
   }
 
-  void VisitCompoundAssignOperator(const CompoundAssignOperator *CAO) {
-    VisitBinAssign(CAO);
-  }
-
   void VisitUnaryPreInc(const UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
   void VisitUnaryPreDec(const UnaryOperator *UO) { VisitUnaryPreIncDec(UO); }
   void VisitUnaryPreIncDec(const UnaryOperator *UO) {
Index: clang/lib/Sema/AnalysisBasedWarnings.cpp
===================================================================
--- clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2075,7 +2075,6 @@
   else {
     AC.getCFGBuildOptions()
       .setAlwaysAdd(Stmt::BinaryOperatorClass)
-      .setAlwaysAdd(Stmt::CompoundAssignOperatorClass)
       .setAlwaysAdd(Stmt::BlockExprClass)
       .setAlwaysAdd(Stmt::CStyleCastExprClass)
       .setAlwaysAdd(Stmt::DeclRefExprClass)
Index: clang/lib/Index/IndexBody.cpp
===================================================================
--- clang/lib/Index/IndexBody.cpp
+++ clang/lib/Index/IndexBody.cpp
@@ -75,6 +75,11 @@
     if (auto BO = dyn_cast<BinaryOperator>(Parent)) {
       if (BO->getOpcode() == BO_Assign && BO->getLHS()->IgnoreParenCasts() == E)
         Roles |= (unsigned)SymbolRole::Write;
+      if (BO->isCompoundAssignmentOp() &&
+          BO->getLHS()->IgnoreParenCasts() == E) {
+        Roles |= (unsigned)SymbolRole::Read;
+        Roles |= (unsigned)SymbolRole::Write;
+      }
 
     } else if (auto UO = dyn_cast<UnaryOperator>(Parent)) {
       if (UO->isIncrementDecrementOp()) {
@@ -84,12 +89,6 @@
         Roles |= (unsigned)SymbolRole::AddressOf;
       }
 
-    } else if (auto CA = dyn_cast<CompoundAssignOperator>(Parent)) {
-      if (CA->getLHS()->IgnoreParenCasts() == E) {
-        Roles |= (unsigned)SymbolRole::Read;
-        Roles |= (unsigned)SymbolRole::Write;
-      }
-
     } else if (auto CE = dyn_cast<CallExpr>(Parent)) {
       if (CE->getCallee()->IgnoreParenCasts() == E) {
         addCallRole(Roles, Relations);
Index: clang/lib/Frontend/Rewrite/RewriteObjC.cpp
===================================================================
--- clang/lib/Frontend/Rewrite/RewriteObjC.cpp
+++ clang/lib/Frontend/Rewrite/RewriteObjC.cpp
@@ -2026,8 +2026,9 @@
 
   const auto *FT = msgSendType->castAs<FunctionType>();
 
-  CallExpr *Exp = CallExpr::Create(
-      *Context, ICE, Args, FT->getCallResultType(*Context), VK_RValue, EndLoc);
+  CallExpr *Exp =
+      CallExpr::Create(*Context, ICE, Args, FT->getCallResultType(*Context),
+                       VK_RValue, EndLoc);
   return Exp;
 }
 
@@ -2998,7 +2999,7 @@
     BinaryOperator *lessThanExpr =
       new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy,
                                    VK_RValue, OK_Ordinary, SourceLocation(),
-                                   FPOptions());
+                                   FPOptions::defaultWithoutTrailingStorage());
     // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...))
     ConditionalOperator *CondExpr =
       new (Context) ConditionalOperator(lessThanExpr,
Index: clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
===================================================================
--- clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
+++ clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -2108,8 +2108,9 @@
                              DRE, nullptr, VK_RValue);
 
   const auto *FT = msgSendType->castAs<FunctionType>();
-  CallExpr *Exp = CallExpr::Create(
-      *Context, ICE, Args, FT->getCallResultType(*Context), VK_RValue, EndLoc);
+  CallExpr *Exp =
+      CallExpr::Create(*Context, ICE, Args, FT->getCallResultType(*Context),
+                       VK_RValue, EndLoc);
   return Exp;
 }
 
@@ -2877,8 +2878,9 @@
                              CK_BitCast,
                              DictLiteralValueME);
   // (const id <NSCopying> [])keys
-  Expr *NSKeyCallExpr = CallExpr::Create(
-      *Context, NSDictDRE, KeyExprs, NSDictFType, VK_LValue, SourceLocation());
+  Expr *NSKeyCallExpr =
+      CallExpr::Create(*Context, NSDictDRE, KeyExprs, NSDictFType, VK_LValue,
+                       SourceLocation());
 
   MemberExpr *DictLiteralKeyME =
       MemberExpr::CreateImplicit(*Context, NSKeyCallExpr, false, ARRFD,
@@ -7486,8 +7488,9 @@
                       VK_LValue, SourceLocation());
       BinaryOperator *addExpr =
         new (Context) BinaryOperator(castExpr, DRE, BO_Add,
-                                     Context->getPointerType(Context->CharTy),
-                                     VK_RValue, OK_Ordinary, SourceLocation(), FPOptions());
+                                  Context->getPointerType(Context->CharTy),
+                                  VK_RValue, OK_Ordinary, SourceLocation(),
+                                  FPOptions::defaultWithoutTrailingStorage());
       // Don't forget the parens to enforce the proper binding.
       ParenExpr *PE = new (Context) ParenExpr(SourceLocation(),
                                               SourceLocation(),
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -3613,13 +3613,13 @@
 
   /// Emit an l-value for an assignment (simple or compound) of complex type.
   LValue EmitComplexAssignmentLValue(const BinaryOperator *E);
-  LValue EmitComplexCompoundAssignmentLValue(const CompoundAssignOperator *E);
-  LValue EmitScalarCompoundAssignWithComplex(const CompoundAssignOperator *E,
+  LValue EmitComplexCompoundAssignmentLValue(const BinaryOperator *E);
+  LValue EmitScalarCompoundAssignWithComplex(const BinaryOperator *E,
                                              llvm::Value *&Result);
 
   // Note: only available for agg return types
   LValue EmitBinaryOperatorLValue(const BinaryOperator *E);
-  LValue EmitCompoundAssignmentLValue(const CompoundAssignOperator *E);
+  LValue EmitCompoundAssignmentLValue(const BinaryOperator *E);
   // Note: only available for agg return types
   LValue EmitCallExprLValue(const CallExpr *E);
   // Note: only available for agg return types
Index: clang/lib/CodeGen/CGStmtOpenMP.cpp
===================================================================
--- clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -2931,7 +2931,8 @@
     CodeGenFunction::OpaqueValueMapping OpaqueUB(CGF, &UBRefExpr, UB);
     // Generate condition for loop.
     BinaryOperator Cond(&IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue,
-                        OK_Ordinary, S.getBeginLoc(), FPOptions());
+                        OK_Ordinary, S.getBeginLoc(),
+                        FPOptions::defaultWithoutTrailingStorage());
     // Increment for loop counter.
     UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary,
                       S.getBeginLoc(), true);
Index: clang/lib/CodeGen/CGObjC.cpp
===================================================================
--- clang/lib/CodeGen/CGObjC.cpp
+++ clang/lib/CodeGen/CGObjC.cpp
@@ -1492,10 +1492,12 @@
     finalArg = &argCast;
 
 
-  BinaryOperator assign(&ivarRef, finalArg, BO_Assign,
+  BinaryOperator *assign = BinaryOperator::Create(getContext(),
+                        &ivarRef, finalArg, BO_Assign,
                         ivarRef.getType(), VK_RValue, OK_Ordinary,
-                        SourceLocation(), FPOptions());
-  EmitStmt(&assign);
+                        SourceLocation(),
+                        FPOptions::defaultWithoutTrailingStorage());
+  EmitStmt(assign);
 }
 
 /// Generate an Objective-C property setter function.
@@ -3569,7 +3571,7 @@
   CallExpr *CalleeExp = cast<CallExpr>(PID->getSetterCXXAssignment());
   CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
       C, OO_Equal, CalleeExp->getCallee(), Args, DestTy->getPointeeType(),
-      VK_LValue, SourceLocation(), FPOptions());
+      VK_LValue, SourceLocation(), FPOptions::defaultWithoutTrailingStorage());
 
   EmitStmt(TheCall);
 
Index: clang/lib/CodeGen/CGExprScalar.cpp
===================================================================
--- clang/lib/CodeGen/CGExprScalar.cpp
+++ clang/lib/CodeGen/CGExprScalar.cpp
@@ -777,20 +777,21 @@
   Value *EmitFixedPointBinOp(const BinOpInfo &Ops);
 
   BinOpInfo EmitBinOps(const BinaryOperator *E);
-  LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E,
-                            Value *(ScalarExprEmitter::*F)(const BinOpInfo &),
-                                  Value *&Result);
+  LValue
+  EmitCompoundAssignLValue(const BinaryOperator *E,
+                           Value *(ScalarExprEmitter::*F)(const BinOpInfo &),
+                           Value *&Result);
 
-  Value *EmitCompoundAssign(const CompoundAssignOperator *E,
+  Value *EmitCompoundAssign(const BinaryOperator *E,
                             Value *(ScalarExprEmitter::*F)(const BinOpInfo &));
 
   // Binary operators and binary compound assignment operators.
-#define HANDLEBINOP(OP) \
-  Value *VisitBin ## OP(const BinaryOperator *E) {                         \
-    return Emit ## OP(EmitBinOps(E));                                      \
-  }                                                                        \
-  Value *VisitBin ## OP ## Assign(const CompoundAssignOperator *E) {       \
-    return EmitCompoundAssign(E, &ScalarExprEmitter::Emit ## OP);          \
+#define HANDLEBINOP(OP)                                                        \
+  Value *VisitBin##OP(const BinaryOperator *E) {                               \
+    return Emit##OP(EmitBinOps(E));                                            \
+  }                                                                            \
+  Value *VisitBin##OP##Assign(const BinaryOperator *E) {                       \
+    return EmitCompoundAssign(E, &ScalarExprEmitter::Emit##OP);                \
   }
   HANDLEBINOP(Mul)
   HANDLEBINOP(Div)
@@ -2897,15 +2898,14 @@
   Result.RHS = Visit(E->getRHS());
   Result.Ty  = E->getType();
   Result.Opcode = E->getOpcode();
-  Result.FPFeatures = E->getFPFeatures();
+  Result.FPFeatures = E->getFPFeatures(CGF.getContext());
   Result.E = E;
   return Result;
 }
 
 LValue ScalarExprEmitter::EmitCompoundAssignLValue(
-                                              const CompoundAssignOperator *E,
-                        Value *(ScalarExprEmitter::*Func)(const BinOpInfo &),
-                                                   Value *&Result) {
+    const BinaryOperator *E,
+    Value *(ScalarExprEmitter::*Func)(const BinOpInfo &), Value *&Result) {
   QualType LHSTy = E->getLHS()->getType();
   BinOpInfo OpInfo;
 
@@ -2917,7 +2917,7 @@
   OpInfo.RHS = Visit(E->getRHS());
   OpInfo.Ty = E->getComputationResultType();
   OpInfo.Opcode = E->getOpcode();
-  OpInfo.FPFeatures = E->getFPFeatures();
+  OpInfo.FPFeatures = E->getFPFeatures(CGF.getContext());
   OpInfo.E = E;
   // Load/convert the LHS.
   LValue LHSLV = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
@@ -3032,8 +3032,9 @@
   return LHSLV;
 }
 
-Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
-                      Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) {
+Value *ScalarExprEmitter::EmitCompoundAssign(
+    const BinaryOperator *E,
+    Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) {
   bool Ignore = TestAndClearIgnoreResultAssign();
   Value *RHS = nullptr;
   LValue LHS = EmitCompoundAssignLValue(E, Func, RHS);
@@ -4623,9 +4624,7 @@
   return MakeAddrLValue(Addr, E->getType());
 }
 
-
-LValue CodeGenFunction::EmitCompoundAssignmentLValue(
-                                            const CompoundAssignOperator *E) {
+LValue CodeGenFunction::EmitCompoundAssignmentLValue(const BinaryOperator *E) {
   ScalarExprEmitter Scalar(*this);
   Value *Result = nullptr;
   switch (E->getOpcode()) {
Index: clang/lib/CodeGen/CGExprComplex.cpp
===================================================================
--- clang/lib/CodeGen/CGExprComplex.cpp
+++ clang/lib/CodeGen/CGExprComplex.cpp
@@ -251,13 +251,13 @@
   };
 
   BinOpInfo EmitBinOps(const BinaryOperator *E);
-  LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E,
-                                  ComplexPairTy (ComplexExprEmitter::*Func)
-                                  (const BinOpInfo &),
-                                  RValue &Val);
-  ComplexPairTy EmitCompoundAssign(const CompoundAssignOperator *E,
-                                   ComplexPairTy (ComplexExprEmitter::*Func)
-                                   (const BinOpInfo &));
+  LValue EmitCompoundAssignLValue(
+      const BinaryOperator *E,
+      ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo &),
+      RValue &Val);
+  ComplexPairTy EmitCompoundAssign(
+      const BinaryOperator *E,
+      ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo &));
 
   ComplexPairTy EmitBinAdd(const BinOpInfo &Op);
   ComplexPairTy EmitBinSub(const BinOpInfo &Op);
@@ -285,16 +285,16 @@
   }
 
   // Compound assignments.
-  ComplexPairTy VisitBinAddAssign(const CompoundAssignOperator *E) {
+  ComplexPairTy VisitBinAddAssign(const BinaryOperator *E) {
     return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinAdd);
   }
-  ComplexPairTy VisitBinSubAssign(const CompoundAssignOperator *E) {
+  ComplexPairTy VisitBinSubAssign(const BinaryOperator *E) {
     return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinSub);
   }
-  ComplexPairTy VisitBinMulAssign(const CompoundAssignOperator *E) {
+  ComplexPairTy VisitBinMulAssign(const BinaryOperator *E) {
     return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinMul);
   }
-  ComplexPairTy VisitBinDivAssign(const CompoundAssignOperator *E) {
+  ComplexPairTy VisitBinDivAssign(const BinaryOperator *E) {
     return EmitCompoundAssign(E, &ComplexExprEmitter::EmitBinDiv);
   }
 
@@ -884,11 +884,9 @@
   return Ops;
 }
 
-
-LValue ComplexExprEmitter::
-EmitCompoundAssignLValue(const CompoundAssignOperator *E,
-          ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&),
-                         RValue &Val) {
+LValue ComplexExprEmitter::EmitCompoundAssignLValue(
+    const BinaryOperator *E,
+    ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo &), RValue &Val) {
   TestAndClearIgnoreReal();
   TestAndClearIgnoreImag();
   QualType LHSTy = E->getLHS()->getType();
@@ -955,9 +953,9 @@
 }
 
 // Compound assignments.
-ComplexPairTy ComplexExprEmitter::
-EmitCompoundAssign(const CompoundAssignOperator *E,
-                   ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&)){
+ComplexPairTy ComplexExprEmitter::EmitCompoundAssign(
+    const BinaryOperator *E,
+    ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo &)) {
   RValue Val;
   LValue LV = EmitCompoundAssignLValue(E, Func, Val);
 
@@ -1160,16 +1158,16 @@
   }
 }
 
-LValue CodeGenFunction::
-EmitComplexCompoundAssignmentLValue(const CompoundAssignOperator *E) {
+LValue
+CodeGenFunction::EmitComplexCompoundAssignmentLValue(const BinaryOperator *E) {
   CompoundFunc Op = getComplexOp(E->getOpcode());
   RValue Val;
   return ComplexExprEmitter(*this).EmitCompoundAssignLValue(E, Op, Val);
 }
 
-LValue CodeGenFunction::
-EmitScalarCompoundAssignWithComplex(const CompoundAssignOperator *E,
-                                    llvm::Value *&Result) {
+LValue
+CodeGenFunction::EmitScalarCompoundAssignWithComplex(const BinaryOperator *E,
+                                                     llvm::Value *&Result) {
   CompoundFunc Op = getComplexOp(E->getOpcode());
   RValue Val;
   LValue Ret = ComplexExprEmitter(*this).EmitCompoundAssignLValue(E, Op, Val);
Index: clang/lib/CodeGen/CGExpr.cpp
===================================================================
--- clang/lib/CodeGen/CGExpr.cpp
+++ clang/lib/CodeGen/CGExpr.cpp
@@ -1271,15 +1271,17 @@
     return EmitObjCSelectorLValue(cast<ObjCSelectorExpr>(E));
   case Expr::ObjCIsaExprClass:
     return EmitObjCIsaExpr(cast<ObjCIsaExpr>(E));
-  case Expr::BinaryOperatorClass:
-    return EmitBinaryOperatorLValue(cast<BinaryOperator>(E));
-  case Expr::CompoundAssignOperatorClass: {
-    QualType Ty = E->getType();
-    if (const AtomicType *AT = Ty->getAs<AtomicType>())
-      Ty = AT->getValueType();
-    if (!Ty->isAnyComplexType())
-      return EmitCompoundAssignmentLValue(cast<CompoundAssignOperator>(E));
-    return EmitComplexCompoundAssignmentLValue(cast<CompoundAssignOperator>(E));
+  case Expr::BinaryOperatorClass: {
+    const auto *const BO = cast<BinaryOperator>(E);
+    if (BO->isCompoundAssignmentOp()) {
+      QualType Ty = BO->getType();
+      if (const AtomicType *AT = Ty->getAs<AtomicType>())
+        Ty = AT->getValueType();
+      if (!Ty->isAnyComplexType())
+        return EmitCompoundAssignmentLValue(BO);
+      return EmitComplexCompoundAssignmentLValue(BO);
+    }
+    return EmitBinaryOperatorLValue(BO);
   }
   case Expr::CallExprClass:
   case Expr::CXXMemberCallExprClass:
Index: clang/lib/Basic/LangOptions.cpp
===================================================================
--- clang/lib/Basic/LangOptions.cpp
+++ clang/lib/Basic/LangOptions.cpp
@@ -10,6 +10,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/AST/ASTContext.h"
 #include "clang/Basic/LangOptions.h"
 
 using namespace clang;
@@ -47,3 +48,13 @@
   const int Ver = OpenCLCPlusPlus ? OpenCLCPlusPlusVersion : OpenCLVersion;
   return VersionTuple(Ver / 100, (Ver % 100) / 10);
 }
+
+FPOptions FPOptions::defaultWithoutTrailingStorage(const ASTContext &C) {
+  FPOptions result(C.getLangOpts());
+  return result;
+}
+
+bool FPOptions::requiresTrailingStorage(const ASTContext &C) {
+  // For the time being, always return true.
+  return true;
+}
Index: clang/lib/Analysis/ThreadSafetyCommon.cpp
===================================================================
--- clang/lib/Analysis/ThreadSafetyCommon.cpp
+++ clang/lib/Analysis/ThreadSafetyCommon.cpp
@@ -222,7 +222,6 @@
   case Stmt::UnaryOperatorClass:
     return translateUnaryOperator(cast<UnaryOperator>(S), Ctx);
   case Stmt::BinaryOperatorClass:
-  case Stmt::CompoundAssignOperatorClass:
     return translateBinaryOperator(cast<BinaryOperator>(S), Ctx);
 
   case Stmt::ArraySubscriptExprClass:
Index: clang/lib/Analysis/ReachableCode.cpp
===================================================================
--- clang/lib/Analysis/ReachableCode.cpp
+++ clang/lib/Analysis/ReachableCode.cpp
@@ -561,12 +561,6 @@
       R1 = UO->getSubExpr()->getSourceRange();
       return UO->getOperatorLoc();
     }
-    case Expr::CompoundAssignOperatorClass: {
-      const CompoundAssignOperator *CAO = cast<CompoundAssignOperator>(S);
-      R1 = CAO->getLHS()->getSourceRange();
-      R2 = CAO->getRHS()->getSourceRange();
-      return CAO->getOperatorLoc();
-    }
     case Expr::BinaryConditionalOperatorClass:
     case Expr::ConditionalOperatorClass: {
       const AbstractConditionalOperator *CO =
Index: clang/lib/Analysis/CFG.cpp
===================================================================
--- clang/lib/Analysis/CFG.cpp
+++ clang/lib/Analysis/CFG.cpp
@@ -2150,8 +2150,12 @@
     case Stmt::BinaryConditionalOperatorClass:
       return VisitConditionalOperator(cast<BinaryConditionalOperator>(S), asc);
 
-    case Stmt::BinaryOperatorClass:
+    case Stmt::BinaryOperatorClass: {
+      auto  BO = dyn_cast<BinaryOperator>(S);
+      if (BO->isCompoundAssignmentOp())
+        return VisitStmt(S, asc);
       return VisitBinaryOperator(cast<BinaryOperator>(S), asc);
+    }
 
     case Stmt::BlockExprClass:
       return VisitBlockExpr(cast<BlockExpr>(S), asc);
Index: clang/lib/Analysis/BodyFarm.cpp
===================================================================
--- clang/lib/Analysis/BodyFarm.cpp
+++ clang/lib/Analysis/BodyFarm.cpp
@@ -114,21 +114,21 @@
 
 BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS,
                                          QualType Ty) {
- return new (C) BinaryOperator(const_cast<Expr*>(LHS), const_cast<Expr*>(RHS),
-                               BO_Assign, Ty, VK_RValue,
-                               OK_Ordinary, SourceLocation(), FPOptions());
+  return BinaryOperator::Create(
+      C, const_cast<Expr *>(LHS), const_cast<Expr *>(RHS), BO_Assign, Ty,
+      VK_RValue, OK_Ordinary, SourceLocation(),
+      FPOptions::defaultWithoutTrailingStorage());
 }
 
 BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS,
                                          BinaryOperator::Opcode Op) {
   assert(BinaryOperator::isLogicalOp(Op) ||
          BinaryOperator::isComparisonOp(Op));
-  return new (C) BinaryOperator(const_cast<Expr*>(LHS),
-                                const_cast<Expr*>(RHS),
-                                Op,
-                                C.getLogicalOperationType(),
-                                VK_RValue,
-                                OK_Ordinary, SourceLocation(), FPOptions());
+  return BinaryOperator::Create(C, const_cast<Expr *>(LHS),
+                                const_cast<Expr *>(RHS), Op,
+                                C.getLogicalOperationType(), VK_RValue,
+                                OK_Ordinary, SourceLocation(),
+                                FPOptions::defaultWithoutTrailingStorage());
 }
 
 CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) {
@@ -296,7 +296,8 @@
       /*Args=*/CallArgs,
       /*QualType=*/C.VoidTy,
       /*ExprValueType=*/VK_RValue,
-      /*SourceLocation=*/SourceLocation(), FPOptions());
+      /*SourceLocation=*/SourceLocation(),
+      /*FPFeatures=*/FPOptions::defaultWithoutTrailingStorage());
 }
 
 /// Create a fake body for std::call_once.
@@ -578,8 +579,8 @@
   ASTMaker M(C);
   DeclRefExpr *DR = M.makeDeclRefExpr(PV);
   ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
-  CallExpr *CE =
-      CallExpr::Create(C, ICE, None, C.VoidTy, VK_RValue, SourceLocation());
+  CallExpr *CE = CallExpr::Create(C, ICE, None, C.VoidTy, VK_RValue,
+                                  SourceLocation());
   return CE;
 }
 
Index: clang/lib/AST/TextNodeDumper.cpp
===================================================================
--- clang/lib/AST/TextNodeDumper.cpp
+++ clang/lib/AST/TextNodeDumper.cpp
@@ -869,15 +869,12 @@
 
 void TextNodeDumper::VisitBinaryOperator(const BinaryOperator *Node) {
   OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
-}
-
-void TextNodeDumper::VisitCompoundAssignOperator(
-    const CompoundAssignOperator *Node) {
-  OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode())
-     << "' ComputeLHSTy=";
-  dumpBareType(Node->getComputationLHSType());
-  OS << " ComputeResultTy=";
-  dumpBareType(Node->getComputationResultType());
+  if (Node->isCompoundAssignmentOp()) {
+    OS << " ComputeLHSTy=";
+    dumpBareType(Node->getComputationLHSType());
+    OS << " ComputeResultTy=";
+    dumpBareType(Node->getComputationResultType());
+  }
 }
 
 void TextNodeDumper::VisitAddrLabelExpr(const AddrLabelExpr *Node) {
Index: clang/lib/AST/StmtProfile.cpp
===================================================================
--- clang/lib/AST/StmtProfile.cpp
+++ clang/lib/AST/StmtProfile.cpp
@@ -1238,11 +1238,6 @@
   ID.AddInteger(S->getOpcode());
 }
 
-void
-StmtProfiler::VisitCompoundAssignOperator(const CompoundAssignOperator *S) {
-  VisitBinaryOperator(S);
-}
-
 void StmtProfiler::VisitConditionalOperator(const ConditionalOperator *S) {
   VisitExpr(S);
 }
@@ -1511,35 +1506,35 @@
 
   case OO_PlusEqual:
     BinaryOp = BO_AddAssign;
-    return Stmt::CompoundAssignOperatorClass;
+    return Stmt::BinaryOperatorClass;
 
   case OO_MinusEqual:
     BinaryOp = BO_SubAssign;
-    return Stmt::CompoundAssignOperatorClass;
+    return Stmt::BinaryOperatorClass;
 
   case OO_StarEqual:
     BinaryOp = BO_MulAssign;
-    return Stmt::CompoundAssignOperatorClass;
+    return Stmt::BinaryOperatorClass;
 
   case OO_SlashEqual:
     BinaryOp = BO_DivAssign;
-    return Stmt::CompoundAssignOperatorClass;
+    return Stmt::BinaryOperatorClass;
 
   case OO_PercentEqual:
     BinaryOp = BO_RemAssign;
-    return Stmt::CompoundAssignOperatorClass;
+    return Stmt::BinaryOperatorClass;
 
   case OO_CaretEqual:
     BinaryOp = BO_XorAssign;
-    return Stmt::CompoundAssignOperatorClass;
+    return Stmt::BinaryOperatorClass;
 
   case OO_AmpEqual:
     BinaryOp = BO_AndAssign;
-    return Stmt::CompoundAssignOperatorClass;
+    return Stmt::BinaryOperatorClass;
 
   case OO_PipeEqual:
     BinaryOp = BO_OrAssign;
-    return Stmt::CompoundAssignOperatorClass;
+    return Stmt::BinaryOperatorClass;
 
   case OO_LessLess:
     BinaryOp = BO_Shl;
@@ -1551,11 +1546,11 @@
 
   case OO_LessLessEqual:
     BinaryOp = BO_ShlAssign;
-    return Stmt::CompoundAssignOperatorClass;
+    return Stmt::BinaryOperatorClass;
 
   case OO_GreaterGreaterEqual:
     BinaryOp = BO_ShrAssign;
-    return Stmt::CompoundAssignOperatorClass;
+    return Stmt::BinaryOperatorClass;
 
   case OO_EqualEqual:
     BinaryOp = BO_EQ;
@@ -1642,8 +1637,7 @@
       Visit(S->getArg(I));
     if (SC == Stmt::UnaryOperatorClass)
       ID.AddInteger(UnaryOp);
-    else if (SC == Stmt::BinaryOperatorClass ||
-             SC == Stmt::CompoundAssignOperatorClass)
+    else if (SC == Stmt::BinaryOperatorClass)
       ID.AddInteger(BinaryOp);
     else
       assert(SC == Stmt::ArraySubscriptExprClass);
Index: clang/lib/AST/StmtPrinter.cpp
===================================================================
--- clang/lib/AST/StmtPrinter.cpp
+++ clang/lib/AST/StmtPrinter.cpp
@@ -1448,12 +1448,6 @@
   PrintExpr(Node->getRHS());
 }
 
-void StmtPrinter::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
-  PrintExpr(Node->getLHS());
-  OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " ";
-  PrintExpr(Node->getRHS());
-}
-
 void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) {
   PrintExpr(Node->getCond());
   OS << " ? ";
Index: clang/lib/AST/JSONNodeDumper.cpp
===================================================================
--- clang/lib/AST/JSONNodeDumper.cpp
+++ clang/lib/AST/JSONNodeDumper.cpp
@@ -1162,14 +1162,12 @@
 
 void JSONNodeDumper::VisitBinaryOperator(const BinaryOperator *BO) {
   JOS.attribute("opcode", BinaryOperator::getOpcodeStr(BO->getOpcode()));
-}
-
-void JSONNodeDumper::VisitCompoundAssignOperator(
-    const CompoundAssignOperator *CAO) {
-  VisitBinaryOperator(CAO);
-  JOS.attribute("computeLHSType", createQualType(CAO->getComputationLHSType()));
-  JOS.attribute("computeResultType",
-                createQualType(CAO->getComputationResultType()));
+  if (BO->isCompoundAssignmentOp()) {
+    JOS.attribute("computeLHSType",
+                  createQualType(BO->getComputationLHSType()));
+    JOS.attribute("computeResultType",
+                  createQualType(BO->getComputationResultType()));
+  }
 }
 
 void JSONNodeDumper::VisitMemberExpr(const MemberExpr *ME) {
Index: clang/lib/AST/ItaniumMangle.cpp
===================================================================
--- clang/lib/AST/ItaniumMangle.cpp
+++ clang/lib/AST/ItaniumMangle.cpp
@@ -4168,7 +4168,6 @@
     break;
   }
 
-  case Expr::CompoundAssignOperatorClass: // fallthrough
   case Expr::BinaryOperatorClass: {
     const BinaryOperator *BO = cast<BinaryOperator>(E);
     if (BO->getOpcode() == BO_PtrMemD)
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -7485,7 +7485,6 @@
     return VisitUnaryPreIncDec(UO);
   }
   bool VisitBinAssign(const BinaryOperator *BO);
-  bool VisitCompoundAssignOperator(const CompoundAssignOperator *CAO);
 
   bool VisitCastExpr(const CastExpr *E) {
     switch (E->getCastKind()) {
@@ -7786,32 +7785,28 @@
       UO->isIncrementOp(), nullptr);
 }
 
-bool LValueExprEvaluator::VisitCompoundAssignOperator(
-    const CompoundAssignOperator *CAO) {
+bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) {
   if (!Info.getLangOpts().CPlusPlus14 && !Info.keepEvaluatingAfterFailure())
-    return Error(CAO);
-
-  APValue RHS;
+    return Error(E);
 
-  // The overall lvalue result is the result of evaluating the LHS.
-  if (!this->Visit(CAO->getLHS())) {
-    if (Info.noteFailure())
-      Evaluate(RHS, this->Info, CAO->getRHS());
-    return false;
-  }
+  if (E->isCompoundAssignmentOp()) {
+    APValue RHS;
 
-  if (!Evaluate(RHS, this->Info, CAO->getRHS()))
-    return false;
+    // The overall lvalue result is the result of evaluating the LHS.
+    if (!this->Visit(E->getLHS())) {
+      if (Info.noteFailure())
+        Evaluate(RHS, this->Info, E->getRHS());
+      return false;
+    }
 
-  return handleCompoundAssignment(
-      this->Info, CAO,
-      Result, CAO->getLHS()->getType(), CAO->getComputationLHSType(),
-      CAO->getOpForCompoundAssignment(CAO->getOpcode()), RHS);
-}
+    if (!Evaluate(RHS, this->Info, E->getRHS()))
+      return false;
 
-bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) {
-  if (!Info.getLangOpts().CPlusPlus14 && !Info.keepEvaluatingAfterFailure())
-    return Error(E);
+    return handleCompoundAssignment(
+        this->Info, E, Result, E->getLHS()->getType(),
+        E->getComputationLHSType(),
+        E->getOpForCompoundAssignment(E->getOpcode()), RHS);
+  }
 
   APValue NewVal;
 
@@ -14182,7 +14177,6 @@
   case Expr::OMPArraySectionExprClass:
   case Expr::OMPArrayShapingExprClass:
   case Expr::MemberExprClass:
-  case Expr::CompoundAssignOperatorClass:
   case Expr::CompoundLiteralExprClass:
   case Expr::ExtVectorElementExprClass:
   case Expr::DesignatedInitExprClass:
Index: clang/lib/AST/ExprClassification.cpp
===================================================================
--- clang/lib/AST/ExprClassification.cpp
+++ clang/lib/AST/ExprClassification.cpp
@@ -297,7 +297,6 @@
     return ClassifyInternal(Ctx,cast<GenericSelectionExpr>(E)->getResultExpr());
 
   case Expr::BinaryOperatorClass:
-  case Expr::CompoundAssignOperatorClass:
     // C doesn't have any binary expressions that are lvalues.
     if (Lang.CPlusPlus)
       return ClassifyBinaryOp(Ctx, cast<BinaryOperator>(E));
Index: clang/lib/AST/ExprCXX.cpp
===================================================================
--- clang/lib/AST/ExprCXX.cpp
+++ clang/lib/AST/ExprCXX.cpp
@@ -530,12 +530,12 @@
     : CallExpr(CXXOperatorCallExprClass, Fn, /*PreArgs=*/{}, Args, Ty, VK,
                OperatorLoc, /*MinNumArgs=*/0, UsesADL) {
   CXXOperatorCallExprBits.OperatorKind = OpKind;
-  CXXOperatorCallExprBits.FPFeatures = FPFeatures.getInt();
+  CXXOperatorCallExprBits.FPFeatures = FPFeatures.getAsOpaqueInt();
+  assert((CXXOperatorCallExprBits.FPFeatures == FPFeatures.getAsOpaqueInt()) &&
+         "FPFeatures overflow!");
   assert(
       (CXXOperatorCallExprBits.OperatorKind == static_cast<unsigned>(OpKind)) &&
       "OperatorKind overflow!");
-  assert((CXXOperatorCallExprBits.FPFeatures == FPFeatures.getInt()) &&
-         "FPFeatures overflow!");
   Range = getSourceRangeImpl();
 }
 
@@ -1639,4 +1639,4 @@
   void *Mem = Ctx.Allocate(sizeof(CUDAKernelCallExpr) + SizeOfTrailingObjects,
                            alignof(CUDAKernelCallExpr));
   return new (Mem) CUDAKernelCallExpr(NumArgs, Empty);
-}
\ No newline at end of file
+}
Index: clang/lib/AST/Expr.cpp
===================================================================
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -1352,8 +1352,9 @@
                                     ADLCallKind UsesADL) {
   assert(!(reinterpret_cast<uintptr_t>(Mem) % alignof(CallExpr)) &&
          "Misaligned memory in CallExpr::CreateTemporary!");
-  return new (Mem) CallExpr(CallExprClass, Fn, /*PreArgs=*/{}, /*Args=*/{}, Ty,
-                            VK, RParenLoc, /*MinNumArgs=*/0, UsesADL);
+  return new (Mem)
+      CallExpr(CallExprClass, Fn, /*PreArgs=*/{}, /*Args=*/{}, Ty, VK,
+               RParenLoc, /*MinNumArgs=*/0, UsesADL);
 }
 
 CallExpr *CallExpr::CreateEmpty(const ASTContext &Ctx, unsigned NumArgs,
@@ -2358,7 +2359,6 @@
     R2 = BO->getRHS()->getSourceRange();
     return true;
   }
-  case CompoundAssignOperatorClass:
   case VAArgExprClass:
   case AtomicExprClass:
     return false;
@@ -3370,7 +3370,6 @@
 
   case MSPropertyRefExprClass:
   case MSPropertySubscriptExprClass:
-  case CompoundAssignOperatorClass:
   case VAArgExprClass:
   case AtomicExprClass:
   case CXXThrowExprClass:
@@ -4341,6 +4340,31 @@
   return new (Mem) ParenListExpr(EmptyShell(), NumExprs);
 }
 
+BinaryOperator *BinaryOperator::CreateEmpty(const ASTContext &C,
+                                            unsigned hasFPFeatures,
+                                            unsigned isCompound) {
+  unsigned SizeOfTrailingObjects =
+      BinaryOperator::sizeOfTrailingObjects(hasFPFeatures, isCompound);
+  void *Mem = C.Allocate(sizeof(BinaryOperator) + SizeOfTrailingObjects,
+                         alignof(BinaryOperator));
+  return new (Mem) BinaryOperator(EmptyShell(), hasFPFeatures, isCompound);
+}
+
+BinaryOperator *
+BinaryOperator::Create(const ASTContext &C, Expr *lhs, Expr *rhs, Opcode opc,
+                       QualType ResTy, ExprValueKind VK, ExprObjectKind OK,
+                       SourceLocation opLoc, FPOptions FPFeatures,
+                       QualType CompLHSType, QualType CompResultType) {
+  bool hasFPFeatures = FPFeatures.requiresTrailingStorage();
+  unsigned SizeOfTrailingObjects =
+      BinaryOperator::sizeOfTrailingObjects(hasFPFeatures,
+                                            isCompoundAssignmentOp(opc));
+  void *Mem = C.Allocate(sizeof(BinaryOperator) + SizeOfTrailingObjects,
+                         alignof(BinaryOperator));
+  return new (Mem) BinaryOperator(lhs, rhs, opc, ResTy, VK, OK, opLoc,
+                                  FPFeatures, CompLHSType, CompResultType);
+}
+
 const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) {
   if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(e))
     e = ewc->getSubExpr();
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -606,7 +606,6 @@
     ExpectedStmt VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E);
     ExpectedStmt VisitExpressionTraitExpr(ExpressionTraitExpr *E);
     ExpectedStmt VisitArraySubscriptExpr(ArraySubscriptExpr *E);
-    ExpectedStmt VisitCompoundAssignOperator(CompoundAssignOperator *E);
     ExpectedStmt VisitImplicitCastExpr(ImplicitCastExpr *E);
     ExpectedStmt VisitExplicitCastExpr(ExplicitCastExpr *E);
     ExpectedStmt VisitOffsetOfExpr(OffsetOfExpr *OE);
@@ -6688,9 +6687,20 @@
   if (Err)
     return std::move(Err);
 
-  return new (Importer.getToContext()) BinaryOperator(
-      ToLHS, ToRHS, E->getOpcode(), ToType, E->getValueKind(),
-      E->getObjectKind(), ToOperatorLoc, E->getFPFeatures());
+  if (E->isCompoundAssign()) {
+    if (Err)
+      return std::move(Err);
+    return BinaryOperator::Create(
+        Importer.getToContext(), ToLHS, ToRHS, E->getOpcode(), ToType,
+        E->getValueKind(), E->getObjectKind(),
+        ToOperatorLoc, E->getFPFeatures(Importer.getToContext()),
+        importChecked(Err, E->getComputationLHSType()),
+        importChecked(Err, E->getComputationResultType()));
+  }
+  return BinaryOperator::Create(
+      Importer.getToContext(), ToLHS, ToRHS, E->getOpcode(), ToType,
+      E->getValueKind(), E->getObjectKind(), ToOperatorLoc,
+      E->getFPFeatures(Importer.getToContext()));
 }
 
 ExpectedStmt ASTNodeImporter::VisitConditionalOperator(ConditionalOperator *E) {
@@ -6785,25 +6795,6 @@
       ToRBracketLoc);
 }
 
-ExpectedStmt
-ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
-  Error Err = Error::success();
-  auto ToLHS = importChecked(Err, E->getLHS());
-  auto ToRHS = importChecked(Err, E->getRHS());
-  auto ToType = importChecked(Err, E->getType());
-  auto ToComputationLHSType = importChecked(Err, E->getComputationLHSType());
-  auto ToComputationResultType =
-      importChecked(Err, E->getComputationResultType());
-  auto ToOperatorLoc = importChecked(Err, E->getOperatorLoc());
-  if (Err)
-    return std::move(Err);
-
-  return new (Importer.getToContext()) CompoundAssignOperator(
-      ToLHS, ToRHS, E->getOpcode(), ToType, E->getValueKind(),
-      E->getObjectKind(), ToComputationLHSType, ToComputationResultType,
-      ToOperatorLoc, E->getFPFeatures());
-}
-
 Expected<CXXCastPath>
 ASTNodeImporter::ImportCastPath(CastExpr *CE) {
   CXXCastPath Path;
Index: clang/include/clang/Serialization/ASTBitCodes.h
===================================================================
--- clang/include/clang/Serialization/ASTBitCodes.h
+++ clang/include/clang/Serialization/ASTBitCodes.h
@@ -1562,7 +1562,7 @@
       /// A BinaryOperator record.
       EXPR_BINARY_OPERATOR,
 
-      /// A CompoundAssignOperator record.
+      /// Defunct: CompoundAssignOperator is part of BinaryOperator
       EXPR_COMPOUND_ASSIGN_OPERATOR,
 
       /// A ConditionOperator record.
Index: clang/include/clang/Basic/StmtNodes.td
===================================================================
--- clang/include/clang/Basic/StmtNodes.td
+++ clang/include/clang/Basic/StmtNodes.td
@@ -74,7 +74,6 @@
 def MemberExpr : StmtNode<Expr>;
 def CastExpr : StmtNode<Expr, 1>;
 def BinaryOperator : StmtNode<Expr>;
-def CompoundAssignOperator : StmtNode<BinaryOperator>;
 def AbstractConditionalOperator : StmtNode<Expr, 1>;
 def ConditionalOperator : StmtNode<AbstractConditionalOperator>;
 def BinaryConditionalOperator : StmtNode<AbstractConditionalOperator>;
Index: clang/include/clang/Basic/LangOptions.h
===================================================================
--- clang/include/clang/Basic/LangOptions.h
+++ clang/include/clang/Basic/LangOptions.h
@@ -26,6 +26,8 @@
 
 namespace clang {
 
+class ASTContext;
+
 /// Bitfields of LangOptions, split out from LangOptions in order to ensure that
 /// this large collection of bitfields is a trivial class type.
 class LangOptionsBase {
@@ -356,11 +358,10 @@
 /// Floating point control options
 class FPOptions {
 public:
-  FPOptions() : fp_contract(LangOptions::FPC_Off),
-                fenv_access(LangOptions::FEA_Off),
-                rounding(LangOptions::FPR_ToNearest),
-                exceptions(LangOptions::FPE_Ignore)
-        {}
+  FPOptions()
+      : fp_contract(LangOptions::FPC_Off), fenv_access(LangOptions::FEA_Off),
+        rounding(LangOptions::FPR_ToNearest),
+        exceptions(LangOptions::FPE_Ignore) {}
 
   // Used for serializing.
   explicit FPOptions(unsigned I)
@@ -372,12 +373,26 @@
 
   explicit FPOptions(const LangOptions &LangOpts)
       : fp_contract(LangOpts.getDefaultFPContractMode()),
-        fenv_access(LangOptions::FEA_Off),
-        rounding(LangOptions::FPR_ToNearest),
-        exceptions(LangOptions::FPE_Ignore)
-        {}
+        fenv_access(LangOptions::FEA_Off), rounding(LangOptions::FPR_ToNearest),
+        exceptions(LangOptions::FPE_Ignore) {}
   // FIXME: Use getDefaultFEnvAccessMode() when available.
 
+
+  /// Return the default value of FPOptions that's used when trailing
+  /// storage isn't required.
+  static FPOptions defaultWithoutTrailingStorage(const ASTContext &C);
+  static FPOptions defaultWithoutTrailingStorage() {
+    FPOptions result;
+    return result;
+  }
+  // Does this FPOptions require trailing storage when stored in various
+  // AST nodes, or can it be recreated using `defaultWithoutTrailingStorage`?
+  bool requiresTrailingStorage(const ASTContext &C);
+  bool requiresTrailingStorage() {
+     // For the time being, always return true.
+     return true;
+  }
+
   bool allowFPContractWithinStatement() const {
     return fp_contract == LangOptions::FPC_On;
   }
@@ -429,9 +444,9 @@
   }
 
   /// Used to serialize this.
-  unsigned getInt() const {
-    return fp_contract | (fenv_access << 2) | (rounding << 3)
-        | (exceptions << 6);
+  unsigned getAsOpaqueInt() const {
+    return fp_contract | (fenv_access << 2) | (rounding << 3) |
+           (exceptions << 6);
   }
 
 private:
Index: clang/include/clang/AST/TextNodeDumper.h
===================================================================
--- clang/include/clang/AST/TextNodeDumper.h
+++ clang/include/clang/AST/TextNodeDumper.h
@@ -247,7 +247,6 @@
   void VisitMemberExpr(const MemberExpr *Node);
   void VisitExtVectorElementExpr(const ExtVectorElementExpr *Node);
   void VisitBinaryOperator(const BinaryOperator *Node);
-  void VisitCompoundAssignOperator(const CompoundAssignOperator *Node);
   void VisitAddrLabelExpr(const AddrLabelExpr *Node);
   void VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node);
   void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node);
Index: clang/include/clang/AST/StmtVisitor.h
===================================================================
--- clang/include/clang/AST/StmtVisitor.h
+++ clang/include/clang/AST/StmtVisitor.h
@@ -70,16 +70,16 @@
       case BO_LAnd:      DISPATCH(BinLAnd,      BinaryOperator);
       case BO_LOr :      DISPATCH(BinLOr,       BinaryOperator);
       case BO_Assign:    DISPATCH(BinAssign,    BinaryOperator);
-      case BO_MulAssign: DISPATCH(BinMulAssign, CompoundAssignOperator);
-      case BO_DivAssign: DISPATCH(BinDivAssign, CompoundAssignOperator);
-      case BO_RemAssign: DISPATCH(BinRemAssign, CompoundAssignOperator);
-      case BO_AddAssign: DISPATCH(BinAddAssign, CompoundAssignOperator);
-      case BO_SubAssign: DISPATCH(BinSubAssign, CompoundAssignOperator);
-      case BO_ShlAssign: DISPATCH(BinShlAssign, CompoundAssignOperator);
-      case BO_ShrAssign: DISPATCH(BinShrAssign, CompoundAssignOperator);
-      case BO_AndAssign: DISPATCH(BinAndAssign, CompoundAssignOperator);
-      case BO_OrAssign:  DISPATCH(BinOrAssign,  CompoundAssignOperator);
-      case BO_XorAssign: DISPATCH(BinXorAssign, CompoundAssignOperator);
+      case BO_MulAssign: DISPATCH(BinMulAssign, BinaryOperator);
+      case BO_DivAssign: DISPATCH(BinDivAssign, BinaryOperator);
+      case BO_RemAssign: DISPATCH(BinRemAssign, BinaryOperator);
+      case BO_AddAssign: DISPATCH(BinAddAssign, BinaryOperator);
+      case BO_SubAssign: DISPATCH(BinSubAssign, BinaryOperator);
+      case BO_ShlAssign: DISPATCH(BinShlAssign, BinaryOperator);
+      case BO_ShrAssign: DISPATCH(BinShrAssign, BinaryOperator);
+      case BO_AndAssign: DISPATCH(BinAndAssign, BinaryOperator);
+      case BO_OrAssign:  DISPATCH(BinOrAssign,  BinaryOperator);
+      case BO_XorAssign: DISPATCH(BinXorAssign, BinaryOperator);
       case BO_Comma:     DISPATCH(BinComma,     BinaryOperator);
       }
     } else if (PTR(UnaryOperator) UnOp = dyn_cast<UnaryOperator>(S)) {
@@ -141,9 +141,9 @@
 
   // If the implementation doesn't implement compound assignment operator
   // methods, fall back on VisitCompoundAssignOperator.
-#define CAO_FALLBACK(NAME) \
-  RetTy VisitBin ## NAME(PTR(CompoundAssignOperator) S, ParamTys... P) { \
-    DISPATCH(CompoundAssignOperator, CompoundAssignOperator); \
+#define CAO_FALLBACK(NAME)                                                     \
+  RetTy VisitBin##NAME(PTR(BinaryOperator) S, ParamTys... P) {                 \
+    DISPATCH(BinAssign, BinaryOperator);                                       \
   }
   CAO_FALLBACK(MulAssign) CAO_FALLBACK(DivAssign) CAO_FALLBACK(RemAssign)
   CAO_FALLBACK(AddAssign) CAO_FALLBACK(SubAssign) CAO_FALLBACK(ShlAssign)
Index: clang/include/clang/AST/Stmt.h
===================================================================
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -524,9 +524,7 @@
 
     unsigned Opc : 6;
 
-    /// This is only meaningful for operations on floating point
-    /// types and 0 otherwise.
-    unsigned FPFeatures : 8;
+    unsigned HasFPFeatures : 1;
 
     SourceLocation OpLoc;
   };
Index: clang/include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- clang/include/clang/AST/RecursiveASTVisitor.h
+++ clang/include/clang/AST/RecursiveASTVisitor.h
@@ -424,10 +424,10 @@
 // assignment methods.  Compound assignment operators are not
 // classes in themselves (they're all opcodes in
 // CompoundAssignOperator) but do have visitors.
-#define OPERATOR(NAME)                                                         \
-  GENERAL_BINOP_FALLBACK(NAME##Assign, CompoundAssignOperator)
+#define OPERATOR(NAME) GENERAL_BINOP_FALLBACK(NAME##Assign, BinaryOperator)
 
   CAO_LIST()
+
 #undef OPERATOR
 #undef GENERAL_BINOP_FALLBACK
 
@@ -567,7 +567,7 @@
 
 #define OPERATOR(NAME)                                                         \
   case BO_##NAME##Assign:                                                      \
-    DISPATCH_STMT(Bin##NAME##Assign, CompoundAssignOperator, S);
+    DISPATCH_STMT(Bin##NAME##Assign, BinaryOperator, S);
 
       CAO_LIST()
 #undef OPERATOR
@@ -2678,7 +2678,6 @@
 DEF_TRAVERSE_STMT(ConditionalOperator, {})
 DEF_TRAVERSE_STMT(UnaryOperator, {})
 DEF_TRAVERSE_STMT(BinaryOperator, {})
-DEF_TRAVERSE_STMT(CompoundAssignOperator, {})
 DEF_TRAVERSE_STMT(CXXNoexceptExpr, {})
 DEF_TRAVERSE_STMT(PackExpansionExpr, {})
 DEF_TRAVERSE_STMT(SizeOfPackExpr, {})
Index: clang/include/clang/AST/JSONNodeDumper.h
===================================================================
--- clang/include/clang/AST/JSONNodeDumper.h
+++ clang/include/clang/AST/JSONNodeDumper.h
@@ -262,7 +262,7 @@
   void VisitPredefinedExpr(const PredefinedExpr *PE);
   void VisitUnaryOperator(const UnaryOperator *UO);
   void VisitBinaryOperator(const BinaryOperator *BO);
-  void VisitCompoundAssignOperator(const CompoundAssignOperator *CAO);
+  void VisitCompoundAssignOperator(const BinaryOperator *CAO);
   void VisitMemberExpr(const MemberExpr *ME);
   void VisitCXXNewExpr(const CXXNewExpr *NE);
   void VisitCXXDeleteExpr(const CXXDeleteExpr *DE);
Index: clang/include/clang/AST/ExprCXX.h
===================================================================
--- clang/include/clang/AST/ExprCXX.h
+++ clang/include/clang/AST/ExprCXX.h
@@ -166,7 +166,7 @@
   // Set the FP contractability status of this operator. Only meaningful for
   // operations on floating point types.
   void setFPFeatures(FPOptions F) {
-    CXXOperatorCallExprBits.FPFeatures = F.getInt();
+    CXXOperatorCallExprBits.FPFeatures = F.getAsOpaqueInt();
   }
   FPOptions getFPFeatures() const {
     return FPOptions(CXXOperatorCallExprBits.FPFeatures);
Index: clang/include/clang/AST/Expr.h
===================================================================
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -3462,32 +3462,54 @@
 /// value-dependent). If either x or y is type-dependent, or if the
 /// "+" resolves to an overloaded operator, CXXOperatorCallExpr will
 /// be used to express the computation.
-class BinaryOperator : public Expr {
+class BinaryOperator final
+    : public Expr,
+      private llvm::TrailingObjects<BinaryOperator, FPOptions, QualType> {
   enum { LHS, RHS, END_EXPR };
   Stmt *SubExprs[END_EXPR];
 
+  /// Return the size in bytes needed for the trailing objects.
+  /// Used by the derived classes to allocate the right amount of storage.
+  static unsigned sizeOfTrailingObjects(bool hasFP, bool isCompound) {
+    return (hasFP ? 1 : 0) * sizeof(unsigned) +
+           (isCompound ? 2 : 0) * sizeof(QualType);
+  }
+  unsigned numTrailingObjects(OverloadToken<FPOptions>) const {
+    return hasFPFeatures() ?  1 : 0;
+  }
+  unsigned numTrailingObjects(OverloadToken<QualType>) const {
+    auto opc = static_cast<Opcode>(BinaryOperatorBits.Opc);
+    return isCompoundAssignmentOp(opc) ?  2 : 0;
+  }
+
 public:
   typedef BinaryOperatorKind Opcode;
 
   BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
-                 ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc,
-                 FPOptions FPFeatures)
+                 ExprValueKind VK, ExprObjectKind OK,
+                 SourceLocation opLoc, FPOptions FPFeatures,
+                 QualType CompLHSType = QualType(),
+                 QualType CompResultType = QualType())
       : Expr(BinaryOperatorClass, ResTy, VK, OK) {
     BinaryOperatorBits.Opc = opc;
-    BinaryOperatorBits.FPFeatures = FPFeatures.getInt();
     BinaryOperatorBits.OpLoc = opLoc;
     SubExprs[LHS] = lhs;
     SubExprs[RHS] = rhs;
-    assert(!isCompoundAssignmentOp() &&
-           "Use CompoundAssignOperator for compound assignments");
+    assert(((isCompoundAssignmentOp() && CompLHSType != QualType() &&
+             CompResultType != QualType()) ||
+           (!isCompoundAssignmentOp() && CompLHSType == QualType() &&
+             CompResultType == QualType())) &&
+           "Expected binaryoperator opcode");
+    BinaryOperatorBits.HasFPFeatures = FPFeatures.requiresTrailingStorage();
+    if (BinaryOperatorBits.HasFPFeatures)
+      *getTrailingObjects<FPOptions>() = FPFeatures;
+    if (isCompoundAssignmentOp()) {
+      setComputationLHSType(CompLHSType);
+      setComputationResultType(CompResultType);
+    }
     setDependence(computeDependence(this));
   }
 
-  /// Construct an empty binary operator.
-  explicit BinaryOperator(EmptyShell Empty) : Expr(BinaryOperatorClass, Empty) {
-    BinaryOperatorBits.Opc = BO_Comma;
-  }
-
   SourceLocation getExprLoc() const { return getOperatorLoc(); }
   SourceLocation getOperatorLoc() const { return BinaryOperatorBits.OpLoc; }
   void setOperatorLoc(SourceLocation L) { BinaryOperatorBits.OpLoc = L; }
@@ -3616,8 +3638,7 @@
                                                Expr *LHS, Expr *RHS);
 
   static bool classof(const Stmt *S) {
-    return S->getStmtClass() >= firstBinaryOperatorConstant &&
-           S->getStmtClass() <= lastBinaryOperatorConstant;
+    return S->getStmtClass() == BinaryOperatorClass;
   }
 
   // Iterators
@@ -3631,11 +3652,36 @@
   // Set the FP contractability status of this operator. Only meaningful for
   // operations on floating point types.
   void setFPFeatures(FPOptions F) {
-    BinaryOperatorBits.FPFeatures = F.getInt();
+    assert(hasFPFeatures());
+    *getTrailingObjects<FPOptions>() = FPOptions(F.getAsOpaqueInt());
   }
 
+  static BinaryOperator *
+  CreateEmpty(const ASTContext &C, unsigned hasFPFeatures, unsigned isCompound);
+
+  static BinaryOperator *Create(const ASTContext &C, Expr *lhs, Expr *rhs,
+                                Opcode opc, QualType ResTy, ExprValueKind VK,
+                                ExprObjectKind OK,
+                                SourceLocation opLoc, FPOptions FPFeatures,
+                                QualType CompLHSType = QualType(),
+                                QualType CompResultType = QualType());
+
+  bool isCompoundAssign() const {
+    auto opc = static_cast<Opcode>(BinaryOperatorBits.Opc);
+    return isCompoundAssignmentOp(opc);
+ }
+
+  void setHasFPFeatures(bool B) { BinaryOperatorBits.HasFPFeatures = B; }
+  bool hasFPFeatures() const { return BinaryOperatorBits.HasFPFeatures; }
   FPOptions getFPFeatures() const {
-    return FPOptions(BinaryOperatorBits.FPFeatures);
+    assert(hasFPFeatures());
+    return *getTrailingObjects<FPOptions>();
+  }
+  FPOptions getFPFeatures(const ASTContext &C) const {
+    if (hasFPFeatures())
+      return *getTrailingObjects<FPOptions>();
+    else
+      return FPOptions::defaultWithoutTrailingStorage(C);
   }
 
   // Get the FP contractability status of this operator. Only meaningful for
@@ -3648,62 +3694,56 @@
   // operations on floating point types.
   bool isFEnvAccessOn() const { return getFPFeatures().allowFEnvAccess(); }
 
+  /// For compound assignments (e.g. +=), we keep
+  /// track of the type the operation is performed in.  Due to the semantics of
+  /// these operators, the operands are promoted, the arithmetic performed, an
+  /// implicit conversion back to the result type done, then the assignment
+  /// takes place.  This captures the intermediate type which the computation
+  /// is done in.
+  /// The two computation types are the type the LHS is converted
+  /// to for the computation and the type of the result; the two are
+  /// distinct in a few cases (specifically, int+=ptr and ptr-=ptr).
+  QualType getComputationLHSType() const {
+    assert(isCompoundAssignmentOp() &&
+           "Expected compound assignment operator");
+    return getTrailingObjects<QualType>()[0];
+  }
+  void setComputationLHSType(QualType T) {
+    assert(isCompoundAssignmentOp() &&
+           "Expected compound assignment operator");
+    getTrailingObjects<QualType>()[0] = T;
+  }
+  QualType getComputationResultType() const {
+    assert(isCompoundAssignmentOp() &&
+           "Expected compound assignment operator");
+    return getTrailingObjects<QualType>()[1];
+  }
+  void setComputationResultType(QualType T) {
+    assert(isCompoundAssignmentOp() &&
+           "Expected compound assignment operator");
+    getTrailingObjects<QualType>()[1] = T;
+  }
+
 protected:
   BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
                  ExprValueKind VK, ExprObjectKind OK, SourceLocation opLoc,
                  FPOptions FPFeatures, bool dead2)
-      : Expr(CompoundAssignOperatorClass, ResTy, VK, OK) {
+      : Expr(BinaryOperatorClass, ResTy, VK, OK) {
     BinaryOperatorBits.Opc = opc;
-    BinaryOperatorBits.FPFeatures = FPFeatures.getInt();
     BinaryOperatorBits.OpLoc = opLoc;
     SubExprs[LHS] = lhs;
     SubExprs[RHS] = rhs;
     setDependence(computeDependence(this));
   }
 
-  BinaryOperator(StmtClass SC, EmptyShell Empty) : Expr(SC, Empty) {
-    BinaryOperatorBits.Opc = BO_MulAssign;
-  }
-};
-
-/// CompoundAssignOperator - For compound assignments (e.g. +=), we keep
-/// track of the type the operation is performed in.  Due to the semantics of
-/// these operators, the operands are promoted, the arithmetic performed, an
-/// implicit conversion back to the result type done, then the assignment takes
-/// place.  This captures the intermediate type which the computation is done
-/// in.
-class CompoundAssignOperator : public BinaryOperator {
-  QualType ComputationLHSType;
-  QualType ComputationResultType;
-public:
-  CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResType,
-                         ExprValueKind VK, ExprObjectKind OK,
-                         QualType CompLHSType, QualType CompResultType,
-                         SourceLocation OpLoc, FPOptions FPFeatures)
-    : BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, FPFeatures,
-                     true),
-      ComputationLHSType(CompLHSType),
-      ComputationResultType(CompResultType) {
-    assert(isCompoundAssignmentOp() &&
-           "Only should be used for compound assignments");
-  }
-
-  /// Build an empty compound assignment operator expression.
-  explicit CompoundAssignOperator(EmptyShell Empty)
-    : BinaryOperator(CompoundAssignOperatorClass, Empty) { }
-
-  // The two computation types are the type the LHS is converted
-  // to for the computation and the type of the result; the two are
-  // distinct in a few cases (specifically, int+=ptr and ptr-=ptr).
-  QualType getComputationLHSType() const { return ComputationLHSType; }
-  void setComputationLHSType(QualType T) { ComputationLHSType = T; }
-
-  QualType getComputationResultType() const { return ComputationResultType; }
-  void setComputationResultType(QualType T) { ComputationResultType = T; }
-
-  static bool classof(const Stmt *S) {
-    return S->getStmtClass() == CompoundAssignOperatorClass;
+  BinaryOperator(EmptyShell Empty, unsigned hasFPFeatures, unsigned isCompound)
+      : Expr(BinaryOperatorClass, Empty) {
+    if (isCompound)
+      BinaryOperatorBits.Opc = BO_MulAssign;
+    else
+      BinaryOperatorBits.Opc = BO_Mul;
   }
+  friend TrailingObjects;
 };
 
 /// AbstractConditionalOperator - An abstract base class for
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to