mibintc updated this revision to Diff 251699.
mibintc retitled this revision from "Move FPFeatures from BinaryOperator 
bitfields to Trailing storage - preliminary" to "Move FPFeatures from 
BinaryOperator bitfields to Trailing storage".
mibintc added a comment.

This revision has been rebased, the LIT test failures seen in the previous 
revision have been corrected: check-all passes.  Still owe you some polishing. 
I'm going to add a couple inline comments.


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/ReachableCode.cpp
  clang/lib/Analysis/ThreadSafetyCommon.cpp
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/CodeGen/CGExprComplex.cpp
  clang/lib/CodeGen/CGExprScalar.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/SemaAttr.cpp
  clang/lib/Sema/SemaChecking.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/Analysis/loopexit-cfg-output.cpp
  clang/test/Import/compound-assign-op/test.cpp
  clang/test/Sema/warn-unreachable.c
  clang/tools/libclang/CXCursor.cpp

Index: clang/tools/libclang/CXCursor.cpp
===================================================================
--- clang/tools/libclang/CXCursor.cpp
+++ clang/tools/libclang/CXCursor.cpp
@@ -383,10 +383,6 @@
     K = CXCursor_BinaryOperator;
     break;
 
-  case Stmt::CompoundAssignOperatorClass:
-    K = CXCursor_CompoundAssignOperator;
-    break;
-
   case Stmt::ConditionalOperatorClass:
     K = CXCursor_ConditionalOperator;
     break;
Index: clang/test/Sema/warn-unreachable.c
===================================================================
--- clang/test/Sema/warn-unreachable.c
+++ clang/test/Sema/warn-unreachable.c
@@ -83,8 +83,8 @@
     -           // expected-warning {{will never be executed}}
       halt();
   case 8:
-    i
-      +=        // expected-warning {{will never be executed}}
+    i           // expected-warning {{will never be executed}}
+      +=
       halt();
   case 9:
     halt()
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/Analysis/loopexit-cfg-output.cpp
===================================================================
--- clang/test/Analysis/loopexit-cfg-output.cpp
+++ clang/test/Analysis/loopexit-cfg-output.cpp
@@ -208,9 +208,9 @@
 // CHECK-NEXT:   Succs (2): B4 B1
 
 // CHECK:       [B3]
-// CHECK-NEXT:   1: j
-// CHECK-NEXT:   2: 2
-// CHECK-NEXT:   3: [B3.1] += [B3.2]
+// CHECK-NEXT:   1: 2
+// CHECK-NEXT:   2: j
+// CHECK-NEXT:   3: [B3.2] += [B3.1]
 // CHECK-NEXT:   Preds (2): B4 B5
 // CHECK-NEXT:   Succs (1): B2
 
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
@@ -417,7 +417,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,
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
@@ -1664,12 +1664,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
@@ -445,7 +445,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
@@ -778,6 +778,7 @@
   VisitExpr(E);
   Record.push_back(E->getNumArgs());
   Record.AddSourceLocation(E->getRParenLoc());
+  Record.push_back(E->getFPFeatures().getInt());
   Record.AddStmt(E->getCallee());
   for (CallExpr::arg_iterator Arg = E->arg_begin(), ArgEnd = E->arg_end();
        Arg != ArgEnd; ++Arg)
@@ -868,21 +869,24 @@
 
 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->isCompoundAssignmentOp());
   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().getInt());
+  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());
@@ -1463,7 +1467,6 @@
 void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
   VisitCallExpr(E);
   Record.push_back(E->getOperator());
-  Record.push_back(E->getFPFeatures().getInt());
   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
@@ -582,7 +582,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);
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -915,6 +915,7 @@
   unsigned NumArgs = Record.readInt();
   assert((NumArgs == E->getNumArgs()) && "Wrong NumArgs!");
   E->setRParenLoc(readSourceLocation());
+  E->setFPFeatures(FPOptions(Record.readInt()));
   E->setCallee(Record.readSubExpr());
   for (unsigned I = 0; I != NumArgs; ++I)
     E->setArg(I, Record.readSubExpr());
@@ -1006,18 +1007,23 @@
 }
 
 void ASTStmtReader::VisitBinaryOperator(BinaryOperator *E) {
+  bool hasFP_Features;
+  bool isCompoundAssign;
   VisitExpr(E);
+  E->setHasFPFeatures(hasFP_Features = Record.readInt());
+  E->setIsCompoundAssign(isCompoundAssign = 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 (isCompoundAssign) {
+    E->setComputationLHSType(Record.readType());
+    E->setComputationResultType(Record.readType());
+  }
 }
 
 void ASTStmtReader::VisitConditionalOperator(ConditionalOperator *E) {
@@ -1579,7 +1585,6 @@
 void ASTStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
   VisitCallExpr(E);
   E->CXXOperatorCallExprBits.OperatorKind = Record.readInt();
-  E->CXXOperatorCallExprBits.FPFeatures = Record.readInt();
   E->Range = Record.readSourceRange();
 }
 
@@ -2865,11 +2870,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
@@ -3372,7 +3372,8 @@
     // Build the CallExpr
     ExprResult TheCall = CallExpr::Create(
         SemaRef.Context, Callee, SubExprs, Builtin->getCallResultType(),
-        Expr::getValueKindForType(Builtin->getReturnType()), RParenLoc);
+        Expr::getValueKindForType(Builtin->getReturnType()), RParenLoc,
+        FPOptions());
 
     // Type-check the __builtin_shufflevector expression.
     return SemaRef.SemaBuiltinShuffleVector(cast<CallExpr>(TheCall.get()));
@@ -10069,7 +10070,10 @@
     return E;
 
   Sema::FPFeaturesStateRAII FPFeaturesState(getSema());
-  getSema().FPFeatures = E->getFPFeatures();
+  if (E->HasFPFeatures())
+    getSema().FPFeatures = E->getFPFeatures();
+  else
+    getSema().FPFeatures = FPOptions();
 
   return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(),
                                             LHS.get(), RHS.get());
@@ -10120,13 +10124,6 @@
 }
 
 template<typename Derived>
-ExprResult
-TreeTransform<Derived>::TransformCompoundAssignOperator(
-                                                      CompoundAssignOperator *E) {
-  return getDerived().TransformBinaryOperator(E);
-}
-
-template<typename Derived>
 ExprResult TreeTransform<Derived>::
 TransformBinaryConditionalOperator(BinaryConditionalOperator *e) {
   // Just rebuild the common and RHS expressions and see whether we
Index: clang/lib/Sema/SemaPseudoObject.cpp
===================================================================
--- clang/lib/Sema/SemaPseudoObject.cpp
+++ clang/lib/Sema/SemaPseudoObject.cpp
@@ -448,11 +448,12 @@
   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());
   } else {
     ExprResult opLHS = buildGet();
     if (opLHS.isInvalid()) return ExprError();
@@ -463,14 +464,14 @@
     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,
+                                     opLHS.get()->getType(),
+                                     result.get()->getType(),
+                                     opcLoc, FPOptions());
   }
 
   // The result of the assignment, if not void, is the value set into
@@ -1586,9 +1587,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());
 
   // Filter out non-overload placeholder types in the RHS.
   if (RHS->getType()->isNonOverloadPlaceholderType()) {
@@ -1639,30 +1641,30 @@
 /// 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());
+    return BinaryOperator::Create(Context, lhs, rhs, bop->getOpcode(),
+                                  bop->getType(),
+                                  bop->getValueKind(),
+                                  bop->getObjectKind(),
+                                  bop->getComputationLHSType(),
+                                  bop->getComputationResultType(),
+                                  bop->getOperatorLoc(),
+                                  FPOptions());
+  } else if (bop) {
+    Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS());
+    Expr *rhs = cast<OpaqueValueExpr>(bop->getRHS())->getSourceExpr();
+    return BinaryOperator::Create(Context, lhs, rhs, bop->getOpcode(),
+                                  bop->getType(), bop->getValueKind(),
+                                  bop->getObjectKind(),
+                                  bop->getOperatorLoc(), FPOptions());
   } else {
     assert(syntax->hasPlaceholderType(BuiltinType::PseudoObject));
     return stripOpaqueValuesFromPseudoObjectRef(*this, syntax);
Index: clang/lib/Sema/SemaOverload.cpp
===================================================================
--- clang/lib/Sema/SemaOverload.cpp
+++ clang/lib/Sema/SemaOverload.cpp
@@ -12719,7 +12719,7 @@
       // lookup to instantiation time to be able to search into type dependent
       // base classes.
       CallExpr *CE = CallExpr::Create(Context, Fn, Args, Context.DependentTy,
-                                      VK_RValue, RParenLoc);
+                                      VK_RValue, RParenLoc, FPFeatures);
       CE->markDependentForPostponedNameLookup();
       *Result = CE;
       return true;
@@ -13006,7 +13006,7 @@
       Args[0] = Input;
       CallExpr *TheCall = CXXOperatorCallExpr::Create(
           Context, Op, FnExpr.get(), ArgsArray, ResultTy, VK, OpLoc,
-          FPOptions(), Best->IsADLCandidate);
+          FPFeatures, Best->IsADLCandidate);
 
       if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl))
         return ExprError();
@@ -13175,11 +13175,11 @@
       // 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(
+        return BinaryOperator::Create(Context,
             Args[0], Args[1], Opc, Context.DependentTy, VK_RValue, OK_Ordinary,
             OpLoc, FPFeatures);
 
-      return new (Context) CompoundAssignOperator(
+      return BinaryOperator::Create(Context,
           Args[0], Args[1], Opc, Context.DependentTy, VK_LValue, OK_Ordinary,
           Context.DependentTy, Context.DependentTy, OpLoc,
           FPFeatures);
@@ -13856,7 +13856,7 @@
 
   if (isa<CXXPseudoDestructorExpr>(NakedMemExpr))
     return CallExpr::Create(Context, MemExprE, Args, Context.VoidTy, VK_RValue,
-                            RParenLoc);
+                            RParenLoc, FPFeatures);
 
   UnbridgedCastsSet UnbridgedCasts;
   if (checkArgPlaceholdersForOverload(*this, Args, UnbridgedCasts))
@@ -14459,7 +14459,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
@@ -9042,20 +9042,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>(
+      if (auto *AtomicBinOp = dyn_cast<BinaryOperator>(
                      AtomicBody->IgnoreParenImpCasts())) {
-        // Check for Binary Operation
-        if (checkBinaryOperation(AtomicBinOp, DiagId, NoteId))
+        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
@@ -14620,7 +14618,8 @@
           S.DefaultLvalueConversion(DeclareReductionRef.get()).get());
       Expr *Args[] = {LHS.get(), RHS.get()};
       ReductionOp =
-          CallExpr::Create(Context, OVE, Args, Context.VoidTy, VK_RValue, ELoc);
+          CallExpr::Create(Context, OVE, Args, Context.VoidTy, VK_RValue, ELoc,
+                           S.FPFeatures);
     } 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
@@ -6998,9 +6998,10 @@
         return ExprError();
       if (RHS.get() == BO->getRHS())
         return E;
-      return new (Context) BinaryOperator(
+      return BinaryOperator::Create(Context,
           BO->getLHS(), RHS.get(), BO_Comma, BO->getType(), BO->getValueKind(),
-          BO->getObjectKind(), BO->getOperatorLoc(), BO->getFPFeatures());
+          BO->getObjectKind(), BO->getOperatorLoc(),
+          BO->HasFPFeatures() ? BO->getFPFeatures() : FPOptions());
     }
   }
 
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -5756,7 +5756,7 @@
       }
 
       return CallExpr::Create(Context, Fn, /*Args=*/{}, Context.VoidTy,
-                              VK_RValue, RParenLoc);
+                              VK_RValue, RParenLoc, FPFeatures);
     }
     if (Fn->getType() == Context.PseudoObjectTy) {
       ExprResult result = CheckPlaceholderExpr(Fn);
@@ -5778,7 +5778,7 @@
             Fn->getBeginLoc());
 
         return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy,
-                                VK_RValue, RParenLoc);
+                                VK_RValue, RParenLoc, FPFeatures);
       }
     }
 
@@ -5807,7 +5807,7 @@
     if (!find.HasFormOfMemberPointer) {
       if (Expr::hasAnyTypeDependentArguments(ArgExprs))
         return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy,
-                                VK_RValue, RParenLoc);
+                                VK_RValue, RParenLoc, FPFeatures);
       OverloadExpr *ovl = find.Expression;
       if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(ovl))
         return BuildOverloadedCallExpr(
@@ -6003,7 +6003,7 @@
                                    ResultTy, VK_RValue, RParenLoc, NumParams);
   } else {
     TheCall = CallExpr::Create(Context, Fn, Args, ResultTy, VK_RValue,
-                               RParenLoc, NumParams, UsesADL);
+                               RParenLoc, FPFeatures, NumParams, UsesADL);
   }
 
   if (!getLangOpts().CPlusPlus) {
@@ -6033,7 +6033,7 @@
             RParenLoc, NumParams);
       else
         TheCall = CallExpr::Create(Context, Fn, Args, ResultTy, VK_RValue,
-                                   RParenLoc, NumParams, UsesADL);
+                                   RParenLoc, FPFeatures, NumParams, UsesADL);
     }
     // We can now handle the nulled arguments for the default arguments.
     TheCall->setNumArgsUnsafe(std::max<unsigned>(Args.size(), NumParams));
@@ -12890,12 +12890,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,
+        BinOpResTy, BinOpResTy, OpLoc, FPFeatures);
 
   LHS = convertVector(LHS.get(), Context.FloatTy, S);
-  auto *BO = new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, BinOpResTy,
+  auto *BO = BinaryOperator::Create(Context,
+                                          LHS.get(), RHS.get(), Opc, BinOpResTy,
                                           VK, OK, OpLoc, FPFeatures);
   return convertVector(BO, ResultTy->castAs<VectorType>()->getElementType(), S);
 }
@@ -13210,8 +13211,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.
@@ -13225,9 +13226,13 @@
     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,
+                                CompLHSTy, CompResultTy, OpLoc, FPFeatures);
 }
 
 /// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison
@@ -18320,7 +18325,7 @@
                               CK_BuiltinFnToFnPtr)
                 .get();
         return CallExpr::Create(Context, E, /*Args=*/{}, Context.IntTy,
-                                VK_RValue, SourceLocation());
+                                VK_RValue, SourceLocation(), FPFeatures);
       }
     }
 
Index: clang/lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- clang/lib/Sema/SemaExceptionSpec.cpp
+++ clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1301,7 +1301,6 @@
   case Expr::OMPArraySectionExprClass:
   case Expr::BinaryOperatorClass:
   case Expr::DependentCoawaitExprClass:
-  case Expr::CompoundAssignOperatorClass:
   case Expr::CStyleCastExprClass:
   case Expr::CXXStaticCastExprClass:
   case Expr::CXXFunctionalCastExprClass:
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -10853,7 +10853,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());
@@ -10864,9 +10865,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;
@@ -11722,7 +11721,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);
   }
 
@@ -12529,7 +12528,7 @@
       Region = LHSRegion;
       Visit(BO->getLHS());
 
-      if (O && isa<CompoundAssignOperator>(BO))
+      if (O && BO->isCompoundAssignmentOp())
         notePostUse(O, BO);
 
     } else {
@@ -12537,7 +12536,7 @@
       Region = LHSRegion;
       Visit(BO->getLHS());
 
-      if (O && isa<CompoundAssignOperator>(BO))
+      if (O && BO->isCompoundAssignmentOp())
         notePostUse(O, BO);
 
       Region = RHSRegion;
@@ -12559,10 +12558,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/SemaAttr.cpp
===================================================================
--- clang/lib/Sema/SemaAttr.cpp
+++ clang/lib/Sema/SemaAttr.cpp
@@ -930,12 +930,15 @@
   switch (FPC) {
   case LangOptions::FPC_On:
     FPFeatures.setAllowFPContractWithinStatement();
+    FPFeatures.setHasPragmaFPFeatures();
     break;
   case LangOptions::FPC_Fast:
     FPFeatures.setAllowFPContractAcrossStatement();
+    FPFeatures.setHasPragmaFPFeatures();
     break;
   case LangOptions::FPC_Off:
     FPFeatures.setDisallowFPContract();
+    FPFeatures.setHasPragmaFPFeatures();
     break;
   }
 }
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,10 @@
     if (auto BO = dyn_cast<BinaryOperator>(Parent)) {
       if (BO->getOpcode() == BO_Assign && BO->getLHS()->IgnoreParenCasts() == E)
         Roles |= (unsigned)SymbolRole::Write;
+      if (BO->isCompoundAssignmentOp()) {
+        Roles |= (unsigned)SymbolRole::Read;
+        Roles |= (unsigned)SymbolRole::Write;
+      }
 
     } else if (auto UO = dyn_cast<UnaryOperator>(Parent)) {
       if (UO->isIncrementDecrementOp()) {
@@ -84,12 +88,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
@@ -2027,7 +2027,8 @@
   const auto *FT = msgSendType->castAs<FunctionType>();
 
   CallExpr *Exp = CallExpr::Create(
-      *Context, ICE, Args, FT->getCallResultType(*Context), VK_RValue, EndLoc);
+      *Context, ICE, Args, FT->getCallResultType(*Context), VK_RValue, EndLoc,
+      FPOptions());
   return Exp;
 }
 
@@ -2613,7 +2614,7 @@
 
   const auto *FT = msgSendType->castAs<FunctionType>();
   CallExpr *STCE = CallExpr::Create(*Context, PE, MsgExprs, FT->getReturnType(),
-                                    VK_RValue, SourceLocation());
+                                    VK_RValue, SourceLocation(), FPOptions());
   return STCE;
 }
 
@@ -2706,7 +2707,7 @@
           DeclRefExpr(*Context, SuperConstructorFunctionDecl, false, superType,
                       VK_LValue, SourceLocation());
       SuperRep = CallExpr::Create(*Context, DRE, InitExprs, superType,
-                                  VK_LValue, SourceLocation());
+                                  VK_LValue, SourceLocation(), FPOptions());
       // The code for super is a little tricky to prevent collision with
       // the structure definition in the header. The rewriter has it's own
       // internal definition (__rw_objc_super) that is uses. This is why
@@ -2801,7 +2802,7 @@
           DeclRefExpr(*Context, SuperConstructorFunctionDecl, false, superType,
                       VK_LValue, SourceLocation());
       SuperRep = CallExpr::Create(*Context, DRE, InitExprs, superType,
-                                  VK_LValue, SourceLocation());
+                                  VK_LValue, SourceLocation(), FPOptions());
       // The code for super is a little tricky to prevent collision with
       // the structure definition in the header. The rewriter has it's own
       // internal definition (__rw_objc_super) that is uses. This is why
@@ -2966,7 +2967,7 @@
 
   const auto *FT = msgSendType->castAs<FunctionType>();
   CallExpr *CE = CallExpr::Create(*Context, PE, MsgExprs, FT->getReturnType(),
-                                  VK_RValue, EndLoc);
+                                  VK_RValue, EndLoc, FPOptions());
   Stmt *ReplacingStmt = CE;
   if (MsgSendStretFlavor) {
     // We have the method which returns a struct/union. Must also generate
@@ -3816,7 +3817,7 @@
     BlkExprs.push_back(*I);
   }
   CallExpr *CE = CallExpr::Create(*Context, PE, BlkExprs, Exp->getType(),
-                                  VK_RValue, SourceLocation());
+                                  VK_RValue, SourceLocation(), FPOptions());
   return CE;
 }
 
@@ -4526,7 +4527,7 @@
     InitExprs.push_back(FlagExp);
   }
   NewRep = CallExpr::Create(*Context, DRE, InitExprs, FType, VK_LValue,
-                            SourceLocation());
+                            SourceLocation(), FPOptions());
   NewRep = new (Context) UnaryOperator(
       NewRep, UO_AddrOf, Context->getPointerType(NewRep->getType()), VK_RValue,
       OK_Ordinary, SourceLocation(), false);
Index: clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
===================================================================
--- clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
+++ clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp
@@ -2109,7 +2109,8 @@
 
   const auto *FT = msgSendType->castAs<FunctionType>();
   CallExpr *Exp = CallExpr::Create(
-      *Context, ICE, Args, FT->getCallResultType(*Context), VK_RValue, EndLoc);
+      *Context, ICE, Args, FT->getCallResultType(*Context), VK_RValue, EndLoc,
+      FPOptions());
   return Exp;
 }
 
@@ -2690,7 +2691,7 @@
 
   auto *FT = msgSendType->castAs<FunctionType>();
   CallExpr *CE = CallExpr::Create(*Context, PE, MsgExprs, FT->getReturnType(),
-                                  VK_RValue, EndLoc);
+                                  VK_RValue, EndLoc, FPOptions());
   ReplaceStmt(Exp, CE);
   return CE;
 }
@@ -2730,7 +2731,7 @@
     InitExprs.push_back(Exp->getElement(i));
   Expr *NSArrayCallExpr =
       CallExpr::Create(*Context, NSArrayDRE, InitExprs, NSArrayFType, VK_LValue,
-                       SourceLocation());
+                       SourceLocation(), FPOptions());
 
   FieldDecl *ARRFD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
                                     SourceLocation(),
@@ -2811,7 +2812,7 @@
 
   const FunctionType *FT = msgSendType->castAs<FunctionType>();
   CallExpr *CE = CallExpr::Create(*Context, PE, MsgExprs, FT->getReturnType(),
-                                  VK_RValue, EndLoc);
+                                  VK_RValue, EndLoc, FPOptions());
   ReplaceStmt(Exp, CE);
   return CE;
 }
@@ -2859,7 +2860,7 @@
   // (const id [])objects
   Expr *NSValueCallExpr =
       CallExpr::Create(*Context, NSDictDRE, ValueExprs, NSDictFType, VK_LValue,
-                       SourceLocation());
+                       SourceLocation(), FPOptions());
 
   FieldDecl *ARRFD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
                                        SourceLocation(),
@@ -2878,7 +2879,8 @@
                              DictLiteralValueME);
   // (const id <NSCopying> [])keys
   Expr *NSKeyCallExpr = CallExpr::Create(
-      *Context, NSDictDRE, KeyExprs, NSDictFType, VK_LValue, SourceLocation());
+      *Context, NSDictDRE, KeyExprs, NSDictFType, VK_LValue, SourceLocation(),
+      FPOptions());
 
   MemberExpr *DictLiteralKeyME =
       MemberExpr::CreateImplicit(*Context, NSKeyCallExpr, false, ARRFD,
@@ -2962,7 +2964,7 @@
 
   const FunctionType *FT = msgSendType->castAs<FunctionType>();
   CallExpr *CE = CallExpr::Create(*Context, PE, MsgExprs, FT->getReturnType(),
-                                  VK_RValue, EndLoc);
+                                  VK_RValue, EndLoc, FPOptions());
   ReplaceStmt(Exp, CE);
   return CE;
 }
@@ -3174,7 +3176,7 @@
   DeclRefExpr *DRE = new (Context)
       DeclRefExpr(*Context, FD, false, castType, VK_RValue, SourceLocation());
   CallExpr *STCE = CallExpr::Create(*Context, DRE, MsgExprs, castType,
-                                    VK_LValue, SourceLocation());
+                                    VK_LValue, SourceLocation(), FPOptions());
 
   FieldDecl *FieldD = FieldDecl::Create(*Context, nullptr, SourceLocation(),
                                     SourceLocation(),
@@ -3275,7 +3277,7 @@
           DeclRefExpr(*Context, SuperConstructorFunctionDecl, false, superType,
                       VK_LValue, SourceLocation());
       SuperRep = CallExpr::Create(*Context, DRE, InitExprs, superType,
-                                  VK_LValue, SourceLocation());
+                                  VK_LValue, SourceLocation(), FPOptions());
       // The code for super is a little tricky to prevent collision with
       // the structure definition in the header. The rewriter has it's own
       // internal definition (__rw_objc_super) that is uses. This is why
@@ -3370,7 +3372,7 @@
           DeclRefExpr(*Context, SuperConstructorFunctionDecl, false, superType,
                       VK_LValue, SourceLocation());
       SuperRep = CallExpr::Create(*Context, DRE, InitExprs, superType,
-                                  VK_LValue, SourceLocation());
+                                  VK_LValue, SourceLocation(), FPOptions());
       // The code for super is a little tricky to prevent collision with
       // the structure definition in the header. The rewriter has it's own
       // internal definition (__rw_objc_super) that is uses. This is why
@@ -3535,7 +3537,7 @@
 
   const FunctionType *FT = msgSendType->castAs<FunctionType>();
   CallExpr *CE = CallExpr::Create(*Context, PE, MsgExprs, FT->getReturnType(),
-                                  VK_RValue, EndLoc);
+                                  VK_RValue, EndLoc, FPOptions());
   Stmt *ReplacingStmt = CE;
   if (MsgSendStretFlavor) {
     // We have the method which returns a struct/union. Must also generate
@@ -4646,7 +4648,7 @@
     BlkExprs.push_back(*I);
   }
   CallExpr *CE = CallExpr::Create(*Context, PE, BlkExprs, Exp->getType(),
-                                  VK_RValue, SourceLocation());
+                                  VK_RValue, SourceLocation(), FPOptions());
   return CE;
 }
 
@@ -5388,7 +5390,7 @@
     InitExprs.push_back(FlagExp);
   }
   NewRep = CallExpr::Create(*Context, DRE, InitExprs, FType, VK_LValue,
-                            SourceLocation());
+                            SourceLocation(), FPOptions());
 
   if (GlobalBlockExpr) {
     assert (!GlobalConstructionExp &&
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/CGExprScalar.cpp
===================================================================
--- clang/lib/CodeGen/CGExprScalar.cpp
+++ clang/lib/CodeGen/CGExprScalar.cpp
@@ -91,6 +91,7 @@
   Value *RHS;
   QualType Ty;  // Computation Type.
   BinaryOperator::Opcode Opcode; // Opcode of BinOp to perform
+  bool HasFPFeatures;
   FPOptions FPFeatures;
   const Expr *E;      // Entire expr, for error unsupported.  May not be binop.
 
@@ -777,11 +778,11 @@
   Value *EmitFixedPointBinOp(const BinOpInfo &Ops);
 
   BinOpInfo EmitBinOps(const BinaryOperator *E);
-  LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E,
+  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.
@@ -789,7 +790,7 @@
   Value *VisitBin ## OP(const BinaryOperator *E) {                         \
     return Emit ## OP(EmitBinOps(E));                                      \
   }                                                                        \
-  Value *VisitBin ## OP ## Assign(const CompoundAssignOperator *E) {       \
+  Value *VisitBin ## OP ## Assign(const BinaryOperator *E) {       \
     return EmitCompoundAssign(E, &ScalarExprEmitter::Emit ## OP);          \
   }
   HANDLEBINOP(Mul)
@@ -2897,13 +2898,17 @@
   Result.RHS = Visit(E->getRHS());
   Result.Ty  = E->getType();
   Result.Opcode = E->getOpcode();
-  Result.FPFeatures = E->getFPFeatures();
+  Result.HasFPFeatures = E->HasFPFeatures();
+  if (Result.HasFPFeatures)
+    Result.FPFeatures = E->getFPFeatures();
+  else
+    Result.FPFeatures = FPOptions(CGF.getLangOpts());
   Result.E = E;
   return Result;
 }
 
 LValue ScalarExprEmitter::EmitCompoundAssignLValue(
-                                              const CompoundAssignOperator *E,
+                                              const BinaryOperator *E,
                         Value *(ScalarExprEmitter::*Func)(const BinOpInfo &),
                                                    Value *&Result) {
   QualType LHSTy = E->getLHS()->getType();
@@ -2917,7 +2922,11 @@
   OpInfo.RHS = Visit(E->getRHS());
   OpInfo.Ty = E->getComputationResultType();
   OpInfo.Opcode = E->getOpcode();
-  OpInfo.FPFeatures = E->getFPFeatures();
+  OpInfo.HasFPFeatures = E->HasFPFeatures();
+  if (OpInfo.HasFPFeatures)
+    OpInfo.FPFeatures = E->getFPFeatures();
+  else
+    OpInfo.FPFeatures = FPOptions(CGF.getLangOpts());
   OpInfo.E = E;
   // Load/convert the LHS.
   LValue LHSLV = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
@@ -3032,7 +3041,7 @@
   return LHSLV;
 }
 
-Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
+Value *ScalarExprEmitter::EmitCompoundAssign(const BinaryOperator *E,
                       Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) {
   bool Ignore = TestAndClearIgnoreResultAssign();
   Value *RHS = nullptr;
@@ -4625,7 +4634,7 @@
 
 
 LValue CodeGenFunction::EmitCompoundAssignmentLValue(
-                                            const CompoundAssignOperator *E) {
+                                            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,11 +251,11 @@
   };
 
   BinOpInfo EmitBinOps(const BinaryOperator *E);
-  LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E,
+  LValue EmitCompoundAssignLValue(const BinaryOperator *E,
                                   ComplexPairTy (ComplexExprEmitter::*Func)
                                   (const BinOpInfo &),
                                   RValue &Val);
-  ComplexPairTy EmitCompoundAssign(const CompoundAssignOperator *E,
+  ComplexPairTy EmitCompoundAssign(const BinaryOperator *E,
                                    ComplexPairTy (ComplexExprEmitter::*Func)
                                    (const BinOpInfo &));
 
@@ -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);
   }
 
@@ -886,7 +886,7 @@
 
 
 LValue ComplexExprEmitter::
-EmitCompoundAssignLValue(const CompoundAssignOperator *E,
+EmitCompoundAssignLValue(const BinaryOperator *E,
           ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&),
                          RValue &Val) {
   TestAndClearIgnoreReal();
@@ -956,7 +956,7 @@
 
 // Compound assignments.
 ComplexPairTy ComplexExprEmitter::
-EmitCompoundAssign(const CompoundAssignOperator *E,
+EmitCompoundAssign(const BinaryOperator *E,
                    ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&)){
   RValue Val;
   LValue LV = EmitCompoundAssignLValue(E, Func, Val);
@@ -1161,14 +1161,14 @@
 }
 
 LValue CodeGenFunction::
-EmitComplexCompoundAssignmentLValue(const CompoundAssignOperator *E) {
+EmitComplexCompoundAssignmentLValue(const BinaryOperator *E) {
   CompoundFunc Op = getComplexOp(E->getOpcode());
   RValue Val;
   return ComplexExprEmitter(*this).EmitCompoundAssignLValue(E, Op, Val);
 }
 
 LValue CodeGenFunction::
-EmitScalarCompoundAssignWithComplex(const CompoundAssignOperator *E,
+EmitScalarCompoundAssignWithComplex(const BinaryOperator *E,
                                     llvm::Value *&Result) {
   CompoundFunc Op = getComplexOp(E->getOpcode());
   RValue Val;
Index: clang/lib/CodeGen/CGExpr.cpp
===================================================================
--- clang/lib/CodeGen/CGExpr.cpp
+++ clang/lib/CodeGen/CGExpr.cpp
@@ -1272,15 +1272,18 @@
   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));
-  }
+    {
+    auto 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:
   case Expr::CXXOperatorCallExprClass:
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/BodyFarm.cpp
===================================================================
--- clang/lib/Analysis/BodyFarm.cpp
+++ clang/lib/Analysis/BodyFarm.cpp
@@ -114,7 +114,8 @@
 
 BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS,
                                          QualType Ty) {
- return new (C) BinaryOperator(const_cast<Expr*>(LHS), const_cast<Expr*>(RHS),
+  return BinaryOperator::Create(C, const_cast<Expr*>(LHS),
+                               const_cast<Expr*>(RHS),
                                BO_Assign, Ty, VK_RValue,
                                OK_Ordinary, SourceLocation(), FPOptions());
 }
@@ -123,7 +124,7 @@
                                          BinaryOperator::Opcode Op) {
   assert(BinaryOperator::isLogicalOp(Op) ||
          BinaryOperator::isComparisonOp(Op));
-  return new (C) BinaryOperator(const_cast<Expr*>(LHS),
+  return BinaryOperator::Create(C, const_cast<Expr*>(LHS),
                                 const_cast<Expr*>(RHS),
                                 Op,
                                 C.getLogicalOperationType(),
@@ -269,7 +270,7 @@
   }
 
   return CallExpr::Create(C, SubExpr, CallArgs, C.VoidTy, VK_RValue,
-                          SourceLocation());
+                          SourceLocation(), FPOptions());
 }
 
 static CallExpr *create_call_once_lambda_call(ASTContext &C, ASTMaker M,
@@ -514,7 +515,7 @@
       /*Args=*/None,
       /*QualType=*/C.VoidTy,
       /*ExprValueType=*/VK_RValue,
-      /*SourceLocation=*/SourceLocation());
+      /*SourceLocation=*/SourceLocation(), FPOptions());
 
   // (2) Create the assignment to the predicate.
   Expr *DoneValue =
@@ -579,7 +580,8 @@
   DeclRefExpr *DR = M.makeDeclRefExpr(PV);
   ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty);
   CallExpr *CE =
-      CallExpr::Create(C, ICE, None, C.VoidTy, VK_RValue, SourceLocation());
+      CallExpr::Create(C, ICE, None, C.VoidTy, VK_RValue, SourceLocation(),
+                       FPOptions());
   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
@@ -1228,11 +1228,6 @@
   ID.AddInteger(S->getOpcode());
 }
 
-void
-StmtProfiler::VisitCompoundAssignOperator(const CompoundAssignOperator *S) {
-  VisitBinaryOperator(S);
-}
-
 void StmtProfiler::VisitConditionalOperator(const ConditionalOperator *S) {
   VisitExpr(S);
 }
@@ -1501,35 +1496,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;
@@ -1541,11 +1536,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;
@@ -1632,8 +1627,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
@@ -1437,12 +1437,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
@@ -4127,7 +4127,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
@@ -7480,7 +7480,6 @@
     return VisitUnaryPreIncDec(UO);
   }
   bool VisitBinAssign(const BinaryOperator *BO);
-  bool VisitCompoundAssignOperator(const CompoundAssignOperator *CAO);
 
   bool VisitCastExpr(const CastExpr *E) {
     switch (E->getCastKind()) {
@@ -7781,32 +7780,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;
 
@@ -14155,7 +14150,6 @@
   case Expr::ArraySubscriptExprClass:
   case Expr::OMPArraySectionExprClass:
   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
@@ -295,7 +295,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
@@ -528,14 +528,11 @@
                                          FPOptions FPFeatures,
                                          ADLCallKind UsesADL)
     : CallExpr(CXXOperatorCallExprClass, Fn, /*PreArgs=*/{}, Args, Ty, VK,
-               OperatorLoc, /*MinNumArgs=*/0, UsesADL) {
+               OperatorLoc, FPFeatures, /*MinNumArgs=*/0, UsesADL) {
   CXXOperatorCallExprBits.OperatorKind = OpKind;
-  CXXOperatorCallExprBits.FPFeatures = FPFeatures.getInt();
   assert(
       (CXXOperatorCallExprBits.OperatorKind == static_cast<unsigned>(OpKind)) &&
       "OperatorKind overflow!");
-  assert((CXXOperatorCallExprBits.FPFeatures == FPFeatures.getInt()) &&
-         "FPFeatures overflow!");
   Range = getSourceRangeImpl();
 }
 
@@ -595,7 +592,7 @@
                                      QualType Ty, ExprValueKind VK,
                                      SourceLocation RP, unsigned MinNumArgs)
     : CallExpr(CXXMemberCallExprClass, Fn, /*PreArgs=*/{}, Args, Ty, VK, RP,
-               MinNumArgs, NotADL) {}
+               FPOptions(), MinNumArgs, NotADL) {}
 
 CXXMemberCallExpr::CXXMemberCallExpr(unsigned NumArgs, EmptyShell Empty)
     : CallExpr(CXXMemberCallExprClass, /*NumPreArgs=*/0, NumArgs, Empty) {}
@@ -834,7 +831,7 @@
                                        SourceLocation LitEndLoc,
                                        SourceLocation SuffixLoc)
     : CallExpr(UserDefinedLiteralClass, Fn, /*PreArgs=*/{}, Args, Ty, VK,
-               LitEndLoc, /*MinNumArgs=*/0, NotADL),
+               LitEndLoc, FPOptions(), /*MinNumArgs=*/0, NotADL),
       UDSuffixLoc(SuffixLoc) {}
 
 UserDefinedLiteral::UserDefinedLiteral(unsigned NumArgs, EmptyShell Empty)
@@ -1611,7 +1608,7 @@
                                        ExprValueKind VK, SourceLocation RP,
                                        unsigned MinNumArgs)
     : CallExpr(CUDAKernelCallExprClass, Fn, /*PreArgs=*/Config, Args, Ty, VK,
-               RP, MinNumArgs, NotADL) {}
+               RP, FPOptions(), MinNumArgs, NotADL) {}
 
 CUDAKernelCallExpr::CUDAKernelCallExpr(unsigned NumArgs, EmptyShell Empty)
     : CallExpr(CUDAKernelCallExprClass, /*NumPreArgs=*/END_PREARG, NumArgs,
Index: clang/lib/AST/Expr.cpp
===================================================================
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -1221,11 +1221,13 @@
 
 CallExpr::CallExpr(StmtClass SC, Expr *Fn, ArrayRef<Expr *> PreArgs,
                    ArrayRef<Expr *> Args, QualType Ty, ExprValueKind VK,
-                   SourceLocation RParenLoc, unsigned MinNumArgs,
+                   SourceLocation RParenLoc, FPOptions FP_Features,
+                   unsigned MinNumArgs,
                    ADLCallKind UsesADL)
     : Expr(SC, Ty, VK, OK_Ordinary), RParenLoc(RParenLoc) {
   NumArgs = std::max<unsigned>(Args.size(), MinNumArgs);
   unsigned NumPreArgs = PreArgs.size();
+  FPFeatures = FP_Features;
   CallExprBits.NumPreArgs = NumPreArgs;
   assert((NumPreArgs == getNumPreArgs()) && "NumPreArgs overflow!");
 
@@ -1261,7 +1263,8 @@
 
 CallExpr *CallExpr::Create(const ASTContext &Ctx, Expr *Fn,
                            ArrayRef<Expr *> Args, QualType Ty, ExprValueKind VK,
-                           SourceLocation RParenLoc, unsigned MinNumArgs,
+                           SourceLocation RParenLoc, FPOptions FP_Features,
+                           unsigned MinNumArgs,
                            ADLCallKind UsesADL) {
   unsigned NumArgs = std::max<unsigned>(Args.size(), MinNumArgs);
   unsigned SizeOfTrailingObjects =
@@ -1269,7 +1272,7 @@
   void *Mem =
       Ctx.Allocate(sizeof(CallExpr) + SizeOfTrailingObjects, alignof(CallExpr));
   return new (Mem) CallExpr(CallExprClass, Fn, /*PreArgs=*/{}, Args, Ty, VK,
-                            RParenLoc, MinNumArgs, UsesADL);
+                            RParenLoc, FP_Features, MinNumArgs, UsesADL);
 }
 
 CallExpr *CallExpr::CreateTemporary(void *Mem, Expr *Fn, QualType Ty,
@@ -1278,7 +1281,7 @@
   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);
+                         VK, RParenLoc, FPOptions(), /*MinNumArgs=*/0, UsesADL);
 }
 
 CallExpr *CallExpr::CreateEmpty(const ASTContext &Ctx, unsigned NumArgs,
@@ -2283,7 +2286,6 @@
     R2 = BO->getRHS()->getSourceRange();
     return true;
   }
-  case CompoundAssignOperatorClass:
   case VAArgExprClass:
   case AtomicExprClass:
     return false;
@@ -3293,7 +3295,6 @@
 
   case MSPropertyRefExprClass:
   case MSPropertySubscriptExprClass:
-  case CompoundAssignOperatorClass:
   case VAArgExprClass:
   case AtomicExprClass:
   case CXXThrowExprClass:
@@ -4263,6 +4264,45 @@
   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) {
+  bool hasFPFeatures = FPFeatures.hasPragmaFPFeatures();
+  unsigned SizeOfTrailingObjects =
+                  BinaryOperator::sizeOfTrailingObjects(hasFPFeatures, 0);
+  void *Mem = C.Allocate(sizeof(BinaryOperator) + SizeOfTrailingObjects,
+                         alignof(BinaryOperator));
+  return new (Mem) BinaryOperator(lhs, rhs, opc, ResTy, VK, OK,
+                                  opLoc, FPFeatures);
+}
+
+BinaryOperator *
+BinaryOperator::Create(const ASTContext &C,
+                 Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
+                 ExprValueKind VK, ExprObjectKind OK,
+                 QualType CompLHSType, QualType CompResultType,
+                 SourceLocation opLoc, FPOptions FPFeatures){
+  bool hasFPFeatures = FPFeatures.hasPragmaFPFeatures();
+  unsigned SizeOfTrailingObjects =
+      BinaryOperator::sizeOfTrailingObjects(hasFPFeatures, 1);
+  void *Mem = C.Allocate(sizeof(BinaryOperator) + SizeOfTrailingObjects,
+                         alignof(BinaryOperator));
+  return new (Mem) BinaryOperator(lhs, rhs, opc, ResTy, VK, OK,
+                 CompLHSType, CompResultType, opLoc, FPFeatures);
+}
+
 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);
@@ -6685,12 +6684,26 @@
   auto ToRHS = importChecked(Err, E->getRHS());
   auto ToType = importChecked(Err, E->getType());
   auto ToOperatorLoc = importChecked(Err, E->getOperatorLoc());
+  auto HasFPFeatures = E->HasFPFeatures();
   if (Err)
     return std::move(Err);
 
-  return new (Importer.getToContext()) BinaryOperator(
+  if (E->IsCompoundAssign()) {
+    auto ToComputationLHSType = importChecked(Err, E->getComputationLHSType());
+    auto ToComputationResultType =
+      importChecked(Err, E->getComputationResultType());
+    if (Err)
+      return std::move(Err);
+    return BinaryOperator::Create(Importer.getToContext(),
+      ToLHS, ToRHS, E->getOpcode(), ToType, E->getValueKind(),
+      E->getObjectKind(), ToComputationLHSType, ToComputationResultType,
+      ToOperatorLoc,
+      HasFPFeatures ? E->getFPFeatures() : FPOptions());
+  }
+  return BinaryOperator::Create(Importer.getToContext(),
       ToLHS, ToRHS, E->getOpcode(), ToType, E->getValueKind(),
-      E->getObjectKind(), ToOperatorLoc, E->getFPFeatures());
+      E->getObjectKind(), ToOperatorLoc,
+      HasFPFeatures ? E->getFPFeatures() : FPOptions());
 }
 
 ExpectedStmt ASTNodeImporter::VisitConditionalOperator(ConditionalOperator *E) {
@@ -6785,25 +6798,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;
@@ -7555,8 +7549,8 @@
   }
 
   return CallExpr::Create(Importer.getToContext(), ToCallee, ToArgs, ToType,
-                          E->getValueKind(), ToRParenLoc, /*MinNumArgs=*/0,
-                          E->getADLCallKind());
+                          E->getValueKind(), ToRParenLoc, FPOptions(),
+                          /*MinNumArgs=*/0, E->getADLCallKind());
 }
 
 ExpectedStmt ASTNodeImporter::VisitLambdaExpr(LambdaExpr *E) {
Index: clang/include/clang/Serialization/ASTBitCodes.h
===================================================================
--- clang/include/clang/Serialization/ASTBitCodes.h
+++ clang/include/clang/Serialization/ASTBitCodes.h
@@ -1556,9 +1556,6 @@
       /// A BinaryOperator record.
       EXPR_BINARY_OPERATOR,
 
-      /// A CompoundAssignOperator record.
-      EXPR_COMPOUND_ASSIGN_OPERATOR,
-
       /// A ConditionOperator record.
       EXPR_CONDITIONAL_OPERATOR,
 
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
@@ -359,7 +359,8 @@
   FPOptions() : fp_contract(LangOptions::FPC_Off),
                 fenv_access(LangOptions::FEA_Off),
                 rounding(LangOptions::FPR_ToNearest),
-                exceptions(LangOptions::FPE_Ignore)
+                exceptions(LangOptions::FPE_Ignore),
+                has_pragma_features(0)
         {}
 
   // Used for serializing.
@@ -367,17 +368,25 @@
       : fp_contract(static_cast<LangOptions::FPContractModeKind>(I & 3)),
         fenv_access(static_cast<LangOptions::FEnvAccessModeKind>((I >> 2) & 1)),
         rounding(static_cast<LangOptions::FPRoundingModeKind>((I >> 3) & 7)),
-        exceptions(static_cast<LangOptions::FPExceptionModeKind>((I >> 6) & 3))
+        exceptions(static_cast<LangOptions::FPExceptionModeKind>((I >> 6) & 3)),
+        has_pragma_features((I >> 7) & 1)
         {}
 
   explicit FPOptions(const LangOptions &LangOpts)
       : fp_contract(LangOpts.getDefaultFPContractMode()),
         fenv_access(LangOptions::FEA_Off),
         rounding(LangOptions::FPR_ToNearest),
-        exceptions(LangOptions::FPE_Ignore)
+        exceptions(LangOptions::FPE_Ignore),
+        has_pragma_features(0)
         {}
   // FIXME: Use getDefaultFEnvAccessMode() when available.
 
+  bool hasPragmaFPFeatures() const { return has_pragma_features;; }
+  void setHasPragmaFPFeatures(bool B = true) {
+    has_pragma_features = B;
+  }
+
+
   bool allowFPContractWithinStatement() const {
     return fp_contract == LangOptions::FPC_On;
   }
@@ -431,7 +440,8 @@
   /// Used to serialize this.
   unsigned getInt() const {
     return fp_contract | (fenv_access << 2) | (rounding << 3)
-        | (exceptions << 6);
+        | (exceptions << 6)
+        | (has_pragma_features << 7);
   }
 
 private:
@@ -442,6 +452,7 @@
   unsigned fenv_access : 1;
   unsigned rounding : 3;
   unsigned exceptions : 2;
+  unsigned has_pragma_features : 1;
 };
 
 /// Describes the kind of translation unit being processed.
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)) {
@@ -142,8 +142,8 @@
   // 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); \
+  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
@@ -523,10 +523,6 @@
 
     unsigned Opc : 6;
 
-    /// This is only meaningful for operations on floating point
-    /// types and 0 otherwise.
-    unsigned FPFeatures : 8;
-
     SourceLocation OpLoc;
   };
 
@@ -606,9 +602,6 @@
     /// The kind of this overloaded operator. One of the enumerator
     /// value of OverloadedOperatorKind.
     unsigned OperatorKind : 6;
-
-    // Only meaningful for floating point types.
-    unsigned FPFeatures : 8;
   };
 
   class CXXRewrittenBinaryOperatorBitfields {
Index: clang/include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- clang/include/clang/AST/RecursiveASTVisitor.h
+++ clang/include/clang/AST/RecursiveASTVisitor.h
@@ -425,9 +425,10 @@
 // classes in themselves (they're all opcodes in
 // CompoundAssignOperator) but do have visitors.
 #define OPERATOR(NAME)                                                         \
-  GENERAL_BINOP_FALLBACK(NAME##Assign, CompoundAssignOperator)
+  GENERAL_BINOP_FALLBACK(NAME##Assign, BinaryOperator)
 
   CAO_LIST()
+
 #undef OPERATOR
 #undef GENERAL_BINOP_FALLBACK
 
@@ -567,7 +568,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
@@ -2676,7 +2677,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,16 +166,16 @@
   // Set the FP contractability status of this operator. Only meaningful for
   // operations on floating point types.
   void setFPFeatures(FPOptions F) {
-    CXXOperatorCallExprBits.FPFeatures = F.getInt();
+    FPFeatures = F;
   }
   FPOptions getFPFeatures() const {
-    return FPOptions(CXXOperatorCallExprBits.FPFeatures);
+    return FPFeatures;
   }
 
   // Get the FP contractability status of this operator. Only meaningful for
   // operations on floating point types.
   bool isFPContractableWithinStatement() const {
-    return getFPFeatures().allowFPContractWithinStatement();
+    return FPFeatures.allowFPContractWithinStatement();
   }
 };
 
Index: clang/include/clang/AST/Expr.h
===================================================================
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -2567,12 +2567,15 @@
   static constexpr ADLCallKind NotADL = ADLCallKind::NotADL;
   static constexpr ADLCallKind UsesADL = ADLCallKind::UsesADL;
 
+  FPOptions FPFeatures;
+
 protected:
   /// Build a call expression, assuming that appropriate storage has been
   /// allocated for the trailing objects.
   CallExpr(StmtClass SC, Expr *Fn, ArrayRef<Expr *> PreArgs,
            ArrayRef<Expr *> Args, QualType Ty, ExprValueKind VK,
-           SourceLocation RParenLoc, unsigned MinNumArgs, ADLCallKind UsesADL);
+           SourceLocation RParenLoc, FPOptions FP_Features,
+           unsigned MinNumArgs, ADLCallKind UsesADL);
 
   /// Build an empty call expression, for deserialization.
   CallExpr(StmtClass SC, unsigned NumPreArgs, unsigned NumArgs,
@@ -2614,7 +2617,8 @@
   /// expression on the stack.
   static CallExpr *Create(const ASTContext &Ctx, Expr *Fn,
                           ArrayRef<Expr *> Args, QualType Ty, ExprValueKind VK,
-                          SourceLocation RParenLoc, unsigned MinNumArgs = 0,
+                          SourceLocation RParenLoc, FPOptions FP_Features,
+                          unsigned MinNumArgs = 0,
                           ADLCallKind UsesADL = NotADL);
 
   /// Create a temporary call expression with no arguments in the memory
@@ -2658,6 +2662,21 @@
     return dyn_cast_or_null<FunctionDecl>(getCalleeDecl());
   }
 
+  // Set the FPFeatures status of this CallExpr. Only meaningful for
+  // operations on floating point types. e.g. intrinsics
+  void setFPFeatures(FPOptions F) {
+    FPFeatures = F;
+  }
+  FPOptions getFPFeatures() const {
+    return FPFeatures;
+  }
+
+  // Get the FP contractability status of this CallExpr. Only meaningful for
+  // operations on floating point types. e.g. intrinsics
+  bool isFPContractableWithinStatement() const {
+    return FPFeatures.allowFPContractWithinStatement();
+  }
+
   /// getNumArgs - Return the number of actual arguments to this call.
   unsigned getNumArgs() const { return NumArgs; }
 
@@ -3394,9 +3413,24 @@
 /// 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, unsigned, QualType> {
   enum { LHS, RHS, END_EXPR };
   Stmt *SubExprs[END_EXPR];
+  bool hasFPFeatures;
+  bool isCompoundAssign;
+
+  /// 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<unsigned>) const {
+    return hasFPFeatures ? 1 : 0; }
+  unsigned numTrailingObjects(OverloadToken<QualType>) const {
+    return isCompoundAssign ? 2 : 0; }
 
 public:
   typedef BinaryOperatorKind Opcode;
@@ -3406,18 +3440,37 @@
                  FPOptions FPFeatures)
       : Expr(BinaryOperatorClass, ResTy, VK, OK) {
     BinaryOperatorBits.Opc = opc;
-    BinaryOperatorBits.FPFeatures = FPFeatures.getInt();
     BinaryOperatorBits.OpLoc = opLoc;
+    hasFPFeatures = FPFeatures.hasPragmaFPFeatures();
+    isCompoundAssign = 0;
+    if (hasFPFeatures) {
+      *getTrailingObjects<unsigned>() = FPFeatures.getInt();
+    }
     SubExprs[LHS] = lhs;
     SubExprs[RHS] = rhs;
     assert(!isCompoundAssignmentOp() &&
-           "Use CompoundAssignOperator for compound assignments");
+           "Use BinaryOperator for compound assignments");
     setDependence(computeDependence(this));
   }
-
-  /// Construct an empty binary operator.
-  explicit BinaryOperator(EmptyShell Empty) : Expr(BinaryOperatorClass, Empty) {
-    BinaryOperatorBits.Opc = BO_Comma;
+  BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
+                 ExprValueKind VK, ExprObjectKind OK,
+                 QualType CompLHSType, QualType CompResultType,
+                 SourceLocation opLoc, FPOptions FPFeatures)
+    : Expr(BinaryOperatorClass, ResTy, VK, OK) {
+    BinaryOperatorBits.Opc = opc;
+    BinaryOperatorBits.OpLoc = opLoc;
+    SubExprs[LHS] = lhs;
+    SubExprs[RHS] = rhs;
+    hasFPFeatures = FPFeatures.hasPragmaFPFeatures();
+    isCompoundAssign = 1;
+    if (hasFPFeatures) {
+      *getTrailingObjects<unsigned>() = FPFeatures.getInt();
+    }
+    assert(isCompoundAssignmentOp() &&
+           "Expected CompoundAssignOperator for compound assignments");
+    setComputationLHSType(CompLHSType);
+    setComputationResultType(CompResultType);
+    setDependence(computeDependence(this));
   }
 
   SourceLocation getExprLoc() const { return getOperatorLoc(); }
@@ -3548,8 +3601,7 @@
                                                Expr *LHS, Expr *RHS);
 
   static bool classof(const Stmt *S) {
-    return S->getStmtClass() >= firstBinaryOperatorConstant &&
-           S->getStmtClass() <= lastBinaryOperatorConstant;
+    return S->getStmtClass() == BinaryOperatorClass;
   }
 
   // Iterators
@@ -3563,11 +3615,49 @@
   // 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<unsigned>() = F.getInt();
+  }
+
+  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);
+  static BinaryOperator *Create(const ASTContext &C,
+                 Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy,
+                 ExprValueKind VK, ExprObjectKind OK,
+                 QualType CompLHSType, QualType CompResultType,
+                 SourceLocation opLoc, FPOptions FPFeatures);
+
+  unsigned getFPFeat() const {
+    assert(HasFPFeatures());
+    return *getTrailingObjects<unsigned>();
+  }
+  unsigned getFPFeat() {
+    assert(HasFPFeatures());
+    return *getTrailingObjects<unsigned>();
   }
 
+  void setIsCompoundAssign(bool B) {
+    isCompoundAssign = B;
+  }
+  bool IsCompoundAssign() const {
+    return isCompoundAssign;
+  }
+
+  void setHasFPFeatures(bool B) {
+    hasFPFeatures = B;
+  }
+  bool HasFPFeatures() const {
+    return hasFPFeatures;
+  }
   FPOptions getFPFeatures() const {
-    return FPOptions(BinaryOperatorBits.FPFeatures);
+    assert(HasFPFeatures());
+    return FPOptions(*getTrailingObjects<unsigned>());
   }
 
   // Get the FP contractability status of this operator. Only meaningful for
@@ -3580,62 +3670,37 @@
   // operations on floating point types.
   bool isFEnvAccessOn() const { return getFPFeatures().allowFEnvAccess(); }
 
+  QualType getComputationLHSType() const {
+    return getTrailingObjects<QualType>()[0];
+  }
+  void setComputationLHSType(QualType T) {
+    getTrailingObjects<QualType>()[0] = T;
+  }
+  QualType getComputationResultType() const {
+    return getTrailingObjects<QualType>()[1];
+  }
+  void setComputationResultType(QualType T) {
+    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;
   }
+  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