[clang] Add check in SemaChecking for multiple unsequenced volatile accesses (PR #180955)

Nikita Terentev via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 21 05:13:10 PDT 2026


https://github.com/Seraphimt updated https://github.com/llvm/llvm-project/pull/180955

>From 8411b532a145c3b5a39a3785a1ab6c3dbaf446e8 Mon Sep 17 00:00:00 2001
From: Seraphimt <svet58585 at mail.ru>
Date: Wed, 11 Feb 2026 12:18:06 +0300
Subject: [PATCH 01/12] Add warning to Sema for multi unseq use volatile.

---
 clang/lib/Sema/SemaChecking.cpp         | 42 ++++++++++++++++++-------
 clang/test/SemaCXX/warn-unsequenced.cpp | 26 +++++++++++++++
 2 files changed, 56 insertions(+), 12 deletions(-)

diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 89171246d0bcb..b9d1ae9240923 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -14015,7 +14015,7 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
   };
 
   /// An object for which we can track unsequenced uses.
-  using Object = const NamedDecl *;
+  using Object = const ValueDecl *;
 
   /// Different flavors of object usage which we track. We only track the
   /// least-sequenced usage of each kind.
@@ -14034,6 +14034,12 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
     UK_Count = UK_ModAsSideEffect + 1
   };
 
+  enum WarningKind {
+    WK_UseAndMod,
+    WK_ModAndMod,
+    WK_Volatile_UseAndUse
+  };
+
   /// Bundle together a sequencing region and the expression corresponding
   /// to a specific usage. One Usage is stored for each usage kind in UsageInfo.
   struct Usage {
@@ -14179,7 +14185,7 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
   /// \p IsModMod is true when we are checking for a mod-mod unsequenced
   /// usage and false we are checking for a mod-use unsequenced usage.
   void checkUsage(Object O, UsageInfo &UI, const Expr *UsageExpr,
-                  UsageKind OtherKind, bool IsModMod) {
+                  UsageKind OtherKind, WarningKind WarnKind) {
     if (UI.Diagnosed)
       return;
 
@@ -14192,11 +14198,22 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
     if (OtherKind == UK_Use)
       std::swap(Mod, ModOrUse);
 
+    unsigned DiagID = 0;
+    switch (WarnKind) {
+    case WK_UseAndMod:
+      DiagID = diag::warn_unsequenced_mod_use;
+      break;
+    case WK_ModAndMod: 
+      DiagID = diag::warn_unsequenced_mod_mod;
+      break;
+    case WK_Volatile_UseAndUse:
+      DiagID = diag::warn_unsequenced_use_use_volatile;
+      break;
+    }
+
     SemaRef.DiagRuntimeBehavior(
         Mod->getExprLoc(), {Mod, ModOrUse},
-        SemaRef.PDiag(IsModMod ? diag::warn_unsequenced_mod_mod
-                               : diag::warn_unsequenced_mod_use)
-            << O << SourceRange(ModOrUse->getExprLoc()));
+        SemaRef.PDiag(DiagID)<< O << SourceRange(ModOrUse->getExprLoc()));
     UI.Diagnosed = true;
   }
 
@@ -14229,27 +14246,28 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
   void notePreUse(Object O, const Expr *UseExpr) {
     UsageInfo &UI = UsageMap[O];
     // Uses conflict with other modifications.
-    checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsValue, /*IsModMod=*/false);
+    checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsValue, WK_UseAndMod);
+    // Volatile uses conflict with other uses.
+    if (O->getType().isVolatileQualified())
+      checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_Use, WK_Volatile_UseAndUse);
   }
 
   void notePostUse(Object O, const Expr *UseExpr) {
     UsageInfo &UI = UsageMap[O];
-    checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsSideEffect,
-               /*IsModMod=*/false);
+    checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsSideEffect, WK_UseAndMod);
     addUsage(O, UI, UseExpr, /*UsageKind=*/UK_Use);
   }
 
   void notePreMod(Object O, const Expr *ModExpr) {
     UsageInfo &UI = UsageMap[O];
     // Modifications conflict with other modifications and with uses.
-    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsValue, /*IsModMod=*/true);
-    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_Use, /*IsModMod=*/false);
+    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsValue, WK_ModAndMod);
+    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_Use, WK_UseAndMod);
   }
 
   void notePostMod(Object O, const Expr *ModExpr, UsageKind UK) {
     UsageInfo &UI = UsageMap[O];
-    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsSideEffect,
-               /*IsModMod=*/true);
+    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsSideEffect, WK_ModAndMod);
     addUsage(O, UI, ModExpr, /*UsageKind=*/UK);
   }
 
diff --git a/clang/test/SemaCXX/warn-unsequenced.cpp b/clang/test/SemaCXX/warn-unsequenced.cpp
index 50dde8f3a5789..6019eb3929304 100644
--- a/clang/test/SemaCXX/warn-unsequenced.cpp
+++ b/clang/test/SemaCXX/warn-unsequenced.cpp
@@ -815,3 +815,29 @@ void test_var() {
 }
 
 } // namespace templates
+
+namespace muliple_read_volatile {
+  volatile int v1;
+  
+  void PositiveTest(){
+    int x = 0;
+    int y = 0;
+    x = v1 + v1;        // cxx11-warning {{unsequenced accesses to volatile qualified 'v1'}}
+                        // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
+    v1 = v1 * v1;       // cxx11-warning {{unsequenced accesses to volatile qualified 'v1'}}
+                        // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
+    x = v1 + (y++, v1); // cxx11-warning {{unsequenced accesses to volatile qualified 'v1'}}
+                        // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
+    x = v1 + y || y;    // cxx11-warning {{unsequenced accesses to volatile qualified 'v1'}}
+                        // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
+  }
+  
+  void NegativeTest(){
+    int x = 0;
+    int y = 0;
+    x = v1 + y;   // no-warning
+    v1 = v1 * y;  // no-warning
+    x = (v1, v1); // no-warning
+    x = v1 || v1; // no-warning
+  }
+} // namespace volatiles
\ No newline at end of file

>From 4889b198e22806080f7b602b29526858135f4f02 Mon Sep 17 00:00:00 2001
From: Seraphimt <svet58585 at mail.ru>
Date: Wed, 11 Feb 2026 15:58:17 +0300
Subject: [PATCH 02/12] Minor fix.

---
 clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 ++
 clang/test/SemaCXX/warn-unsequenced.cpp          | 4 ++--
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f12677ac11600..defd168b2c629 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2581,6 +2581,8 @@ def warn_unsequenced_mod_mod : Warning<
   "multiple unsequenced modifications to %0">, InGroup<Unsequenced>;
 def warn_unsequenced_mod_use : Warning<
   "unsequenced modification and access to %0">, InGroup<Unsequenced>;
+def warn_unsequenced_use_use_volatile : Warning<
+  "unsequenced volatile accesses to %0">, InGroup<Unsequenced>;
 
 def select_initialized_entity_kind : TextSubstitution<
   "%select{copying variable|copying parameter|initializing template parameter|"
diff --git a/clang/test/SemaCXX/warn-unsequenced.cpp b/clang/test/SemaCXX/warn-unsequenced.cpp
index 6019eb3929304..3b4a8ec9380d0 100644
--- a/clang/test/SemaCXX/warn-unsequenced.cpp
+++ b/clang/test/SemaCXX/warn-unsequenced.cpp
@@ -828,7 +828,7 @@ namespace muliple_read_volatile {
                         // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
     x = v1 + (y++, v1); // cxx11-warning {{unsequenced accesses to volatile qualified 'v1'}}
                         // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
-    x = v1 + y || y;    // cxx11-warning {{unsequenced accesses to volatile qualified 'v1'}}
+    x = v1 + v1 || y;   // cxx11-warning {{unsequenced accesses to volatile qualified 'v1'}}
                         // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
   }
   
@@ -840,4 +840,4 @@ namespace muliple_read_volatile {
     x = (v1, v1); // no-warning
     x = v1 || v1; // no-warning
   }
-} // namespace volatiles
\ No newline at end of file
+} // namespace muliple_read_volatile
\ No newline at end of file

>From 204bd16181542dc2724cb9c1ab358d218de73d77 Mon Sep 17 00:00:00 2001
From: Seraphimt <svet58585 at mail.ru>
Date: Wed, 11 Feb 2026 20:47:24 +0300
Subject: [PATCH 03/12] Fix clang-format.

---
 clang/lib/Sema/SemaChecking.cpp | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index b9d1ae9240923..4c2eaad980394 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -14034,11 +14034,7 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
     UK_Count = UK_ModAsSideEffect + 1
   };
 
-  enum WarningKind {
-    WK_UseAndMod,
-    WK_ModAndMod,
-    WK_Volatile_UseAndUse
-  };
+  enum WarningKind { WK_UseAndMod, WK_ModAndMod, WK_Volatile_UseAndUse };
 
   /// Bundle together a sequencing region and the expression corresponding
   /// to a specific usage. One Usage is stored for each usage kind in UsageInfo.
@@ -14203,7 +14199,7 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
     case WK_UseAndMod:
       DiagID = diag::warn_unsequenced_mod_use;
       break;
-    case WK_ModAndMod: 
+    case WK_ModAndMod:
       DiagID = diag::warn_unsequenced_mod_mod;
       break;
     case WK_Volatile_UseAndUse:
@@ -14213,7 +14209,7 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
 
     SemaRef.DiagRuntimeBehavior(
         Mod->getExprLoc(), {Mod, ModOrUse},
-        SemaRef.PDiag(DiagID)<< O << SourceRange(ModOrUse->getExprLoc()));
+        SemaRef.PDiag(DiagID) << O << SourceRange(ModOrUse->getExprLoc()));
     UI.Diagnosed = true;
   }
 

>From 36f0b43070bfb20ed86f190f9ba4d5f3cf297fc2 Mon Sep 17 00:00:00 2001
From: Seraphimt <svet58585 at mail.ru>
Date: Thu, 12 Feb 2026 20:39:06 +0300
Subject: [PATCH 04/12] Add new line in end tests file.

---
 clang/test/SemaCXX/warn-unsequenced.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/SemaCXX/warn-unsequenced.cpp b/clang/test/SemaCXX/warn-unsequenced.cpp
index 3b4a8ec9380d0..73b1e3718b211 100644
--- a/clang/test/SemaCXX/warn-unsequenced.cpp
+++ b/clang/test/SemaCXX/warn-unsequenced.cpp
@@ -840,4 +840,4 @@ namespace muliple_read_volatile {
     x = (v1, v1); // no-warning
     x = v1 || v1; // no-warning
   }
-} // namespace muliple_read_volatile
\ No newline at end of file
+} // namespace muliple_read_volatile

>From 0fd7b2ed0e4715f642f760783368a46ee9a46ce0 Mon Sep 17 00:00:00 2001
From: Seraphimt <svet58585 at mail.ru>
Date: Fri, 13 Feb 2026 22:14:25 +0300
Subject: [PATCH 05/12] Fix message.

---
 clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index defd168b2c629..90f455611536b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2582,7 +2582,7 @@ def warn_unsequenced_mod_mod : Warning<
 def warn_unsequenced_mod_use : Warning<
   "unsequenced modification and access to %0">, InGroup<Unsequenced>;
 def warn_unsequenced_use_use_volatile : Warning<
-  "unsequenced volatile accesses to %0">, InGroup<Unsequenced>;
+  "unsequenced accesses to volatile qualified %0">, InGroup<Unsequenced>;
 
 def select_initialized_entity_kind : TextSubstitution<
   "%select{copying variable|copying parameter|initializing template parameter|"

>From d8edb3d1f48db3da764da0d46791dd79e110befd Mon Sep 17 00:00:00 2001
From: Seraphimt <svet58585 at mail.ru>
Date: Sat, 14 Feb 2026 17:03:24 +0300
Subject: [PATCH 06/12] Add Wno-sequence-point in tests.

---
 clang/test/CodeGen/PowerPC/builtins-ppc-fma.c                 | 2 +-
 clang/test/CodeGen/SystemZ/builtins-systemz-i128.c            | 2 +-
 clang/test/CodeGen/SystemZ/builtins-systemz-vector.c          | 2 +-
 .../CodeGen/SystemZ/builtins-systemz-vector2-constrained.c    | 2 +-
 clang/test/CodeGen/SystemZ/builtins-systemz-vector2.c         | 2 +-
 clang/test/CodeGen/SystemZ/builtins-systemz-vector3.c         | 2 +-
 clang/test/CodeGen/SystemZ/builtins-systemz-vector4.c         | 2 +-
 clang/test/CodeGen/SystemZ/builtins-systemz-vector5.c         | 2 +-
 .../CodeGen/SystemZ/builtins-systemz-zvector-constrained.c    | 4 ++--
 clang/test/CodeGen/SystemZ/builtins-systemz-zvector-error.c   | 2 +-
 clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c         | 4 ++--
 .../CodeGen/SystemZ/builtins-systemz-zvector2-constrained.c   | 4 ++--
 clang/test/CodeGen/SystemZ/builtins-systemz-zvector2.c        | 4 ++--
 clang/test/CodeGen/SystemZ/builtins-systemz-zvector3.c        | 4 ++--
 clang/test/CodeGen/SystemZ/builtins-systemz-zvector4.c        | 4 ++--
 clang/test/CodeGen/SystemZ/builtins-systemz.c                 | 4 ++--
 16 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c b/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c
index 61421fbf2fecd..4dd7295d8efe1 100644
--- a/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c
+++ b/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -triple powerpc64le-gnu-linux \
-// RUN: -target-feature +vsx -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck      \
+// RUN: -target-feature +vsx -Wall -Wno-sequence-point -Werror -emit-llvm %s -o - | FileCheck      \
 // RUN: %s
 
 typedef __attribute__((vector_size(4 * sizeof(float)))) float vec_float;
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-i128.c b/clang/test/CodeGen/SystemZ/builtins-systemz-i128.c
index 2a20607123af9..436d6a0039f9b 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-i128.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-i128.c
@@ -2,7 +2,7 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z14 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-unused -Wno-sequence-point -Werror -emit-llvm %s -o - | FileCheck %s
 
 #include <vecintrin.h>
 
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-vector.c b/clang/test/CodeGen/SystemZ/builtins-systemz-vector.c
index ae3b08a1b67eb..0cf7e3732b8c4 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-vector.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-vector.c
@@ -1,6 +1,6 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z13 -triple s390x-ibm-linux -flax-vector-conversions=none \
-// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 
 typedef __attribute__((vector_size(16))) signed char vec_schar;
 typedef __attribute__((vector_size(16))) signed short vec_sshort;
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-vector2-constrained.c b/clang/test/CodeGen/SystemZ/builtins-systemz-vector2-constrained.c
index 12c675041af76..682e6f613f44c 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-vector2-constrained.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-vector2-constrained.c
@@ -1,6 +1,6 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z14 -triple s390x-ibm-linux -flax-vector-conversions=none \
-// RUN: -ffp-exception-behavior=strict -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -ffp-exception-behavior=strict -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 
 typedef __attribute__((vector_size(16))) double vec_double;
 typedef __attribute__((vector_size(16))) float vec_float;
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-vector2.c b/clang/test/CodeGen/SystemZ/builtins-systemz-vector2.c
index 8f9e164ebef8c..3af63f225afad 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-vector2.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-vector2.c
@@ -1,6 +1,6 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z14 -triple s390x-ibm-linux -flax-vector-conversions=none \
-// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 
 typedef __attribute__((vector_size(16))) signed char vec_schar;
 typedef __attribute__((vector_size(16))) signed short vec_sshort;
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-vector3.c b/clang/test/CodeGen/SystemZ/builtins-systemz-vector3.c
index e4af1c1e54b86..0a04affb9c445 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-vector3.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-vector3.c
@@ -1,6 +1,6 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z15 -triple s390x-ibm-linux -flax-vector-conversions=none \
-// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 
 typedef __attribute__((vector_size(16))) signed char vec_schar;
 typedef __attribute__((vector_size(16))) signed short vec_sshort;
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-vector4.c b/clang/test/CodeGen/SystemZ/builtins-systemz-vector4.c
index c5ce47cea2ea8..09ab10fac5116 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-vector4.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-vector4.c
@@ -1,6 +1,6 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z16 -triple s390x-ibm-linux -flax-vector-conversions=none \
-// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 
 typedef __attribute__((vector_size(16))) signed char vec_schar;
 typedef __attribute__((vector_size(16))) signed short vec_sshort;
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-vector5.c b/clang/test/CodeGen/SystemZ/builtins-systemz-vector5.c
index b765fa64b33d4..95fe321d606b1 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-vector5.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-vector5.c
@@ -1,6 +1,6 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z17 -triple s390x-ibm-linux -flax-vector-conversions=none \
-// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 
 typedef __attribute__((vector_size(16))) signed char vec_schar;
 typedef __attribute__((vector_size(16))) signed short vec_sshort;
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector-constrained.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector-constrained.c
index 4993df20df143..af750a24767c6 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector-constrained.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector-constrained.c
@@ -2,11 +2,11 @@
 // RUN: %clang_cc1 -target-cpu z13 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
 // RUN: -ffp-exception-behavior=strict \
-// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 // RUN: %clang_cc1 -target-cpu z13 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
 // RUN: -ffp-exception-behavior=strict \
-// RUN: -Wall -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
 
 #include <vecintrin.h>
 
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector-error.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector-error.c
index 2ec1d960aa5bb..d82cbf0c51b2b 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector-error.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector-error.c
@@ -1,7 +1,7 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z13 -triple s390x-linux-gnu \
 // RUN: -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-unused -Werror -fsyntax-only -verify %s
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -fsyntax-only -verify %s
 
 #include <vecintrin.h>
 
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c
index 42298339733d4..9f1283724201c 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c
@@ -1,10 +1,10 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z13 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 // RUN: %clang_cc1 -target-cpu z13 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
 
 #include <vecintrin.h>
 
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector2-constrained.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector2-constrained.c
index 25b3e0b68cd02..6dea4f6bf6600 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector2-constrained.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector2-constrained.c
@@ -2,11 +2,11 @@
 // RUN: %clang_cc1 -target-cpu z14 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
 // RUN: -ffp-exception-behavior=strict \
-// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 // RUN: %clang_cc1 -target-cpu z14 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
 // RUN: -ffp-exception-behavior=strict \
-// RUN: -Wall -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
 
 #include <vecintrin.h>
 
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector2.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector2.c
index c1ef178fcfaa9..aedd7f734edb8 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector2.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector2.c
@@ -1,10 +1,10 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z14 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 // RUN: %clang_cc1 -target-cpu z14 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
 
 #include <vecintrin.h>
 
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector3.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector3.c
index ce8b315127237..dd7ec19b2412f 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector3.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector3.c
@@ -1,10 +1,10 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z15 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 // RUN: %clang_cc1 -target-cpu z15 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
 
 #include <vecintrin.h>
 
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector4.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector4.c
index adc55927ce366..23685cdff8994 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector4.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector4.c
@@ -1,10 +1,10 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z16 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 // RUN: %clang_cc1 -target-cpu z16 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
 
 #include <vecintrin.h>
 
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz.c b/clang/test/CodeGen/SystemZ/builtins-systemz.c
index 4848bef4b4aad..61c7cd934f7c4 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz.c
@@ -1,6 +1,6 @@
 // REQUIRES: systemz-registered-target
-// RUN: %clang_cc1 -target-cpu zEC12 -triple s390x-ibm-linux -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -target-cpu zEC12 -triple s390x-ibm-linux -Wall -Wno-unused -Werror -emit-llvm -x c++ %s -o - | FileCheck %s
+// RUN: %clang_cc1 -target-cpu zEC12 -triple s390x-ibm-linux -Wall -Wno-unused -Wno-sequence-point -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -target-cpu zEC12 -triple s390x-ibm-linux -Wall -Wno-unused -Wno-sequence-point -Werror -emit-llvm -x c++ %s -o - | FileCheck %s
 
 #include <stdint.h>
 #include <htmintrin.h>

>From da20fc4992ed4912c071d76041dc7ee7a612d0f2 Mon Sep 17 00:00:00 2001
From: Seraphimt <svet58585 at mail.ru>
Date: Sat, 14 Feb 2026 18:14:56 +0300
Subject: [PATCH 07/12] Add Wno-sequence-point in tests x2.

---
 clang/test/CodeGen/PowerPC/builtins-ppc-fma.c                 | 2 +-
 .../CodeGen/SystemZ/builtins-systemz-vector-constrained.c     | 2 +-
 clang/test/CodeGen/SystemZ/builtins-systemz-zvector5.c        | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c b/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c
index 4dd7295d8efe1..e26d7793ffb2b 100644
--- a/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c
+++ b/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -triple powerpc64le-gnu-linux \
-// RUN: -target-feature +vsx -Wall -Wno-sequence-point -Werror -emit-llvm %s -o - | FileCheck      \
+// RUN: -target-feature +vsx -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck      \
 // RUN: %s
 
 typedef __attribute__((vector_size(4 * sizeof(float)))) float vec_float;
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-vector-constrained.c b/clang/test/CodeGen/SystemZ/builtins-systemz-vector-constrained.c
index ff24ef9a091b7..0877067a1fdcd 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-vector-constrained.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-vector-constrained.c
@@ -1,6 +1,6 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z13 -triple s390x-ibm-linux -flax-vector-conversions=none \
-// RUN: -ffp-exception-behavior=strict -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -ffp-exception-behavior=strict -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 
 typedef __attribute__((vector_size(16))) signed long long vec_slong;
 typedef __attribute__((vector_size(16))) double vec_double;
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector5.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector5.c
index cd0fafdb7435f..b354219e817f0 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector5.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector5.c
@@ -1,10 +1,10 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z17 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 // RUN: %clang_cc1 -target-cpu z17 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
+// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
 
 #include <vecintrin.h>
 

>From 852668f1bc6dbf39d7137f510a8f864169664c3e Mon Sep 17 00:00:00 2001
From: Seraphimt <svet58585 at mail.ru>
Date: Thu, 20 Aug 2026 19:37:24 +0300
Subject: [PATCH 08/12] Corrections based on review

---
 clang/docs/ReleaseNotes.rst             |   854 +-
 clang/lib/Sema/SemaChecking.cpp         | 33921 +++++++++++-----------
 clang/test/SemaCXX/warn-unsequenced.cpp |  1689 +-
 3 files changed, 18239 insertions(+), 18225 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 59fdbc80e8bed..d227c16c1f257 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1,426 +1,428 @@
-.. If you want to modify sections/contents permanently, you should modify both
-   ReleaseNotes.rst and ReleaseNotesTemplate.txt.
-
-===========================================
-Clang |release| |ReleaseNotesTitle|
-===========================================
-
-.. contents::
-   :local:
-   :depth: 2
-
-Written by the `LLVM Team <https://llvm.org/>`_
-
-.. only:: PreRelease
-
-  .. warning::
-     These are in-progress notes for the upcoming Clang |version| release.
-     Release notes for previous releases can be found on
-     `the Releases Page <https://llvm.org/releases/>`_.
-
-Introduction
-============
-
-This document contains the release notes for the Clang C/C++/Objective-C
-frontend, part of the LLVM Compiler Infrastructure, release |release|. Here we
-describe the status of Clang in some detail, including major
-improvements from the previous release and new feature work. For the
-general LLVM release notes, see `the LLVM
-documentation <https://llvm.org/docs/ReleaseNotes.html>`_. For the libc++ release notes,
-see `this page <https://libcxx.llvm.org/ReleaseNotes.html>`_. All LLVM releases
-may be downloaded from the `LLVM releases web site <https://llvm.org/releases/>`_.
-
-For more information about Clang or LLVM, including information about the
-latest release, please see the `Clang Web Site <https://clang.llvm.org>`_ or the
-`LLVM Web Site <https://llvm.org>`_.
-
-Potentially Breaking Changes
-============================
-
-C/C++ Language Potentially Breaking Changes
--------------------------------------------
-
-C++ Specific Potentially Breaking Changes
------------------------------------------
-
-- Clang now more aggressively optimizes away stores to objects after they are
-  dead. This behavior can be disabled with ``-fno-lifetime-dse``.
-
-ABI Changes in This Version
----------------------------
-
-AST Dumping Potentially Breaking Changes
-----------------------------------------
-
-- The JSON AST dump now includes all fields from ``AvailabilityAttr``: ``platform``,
-  ``introduced``, ``deprecated``, ``obsoleted``, ``unavailable``, ``message``,
-  ``strict``, ``replacement``, ``priority``, and ``environment``. Previously, these
-  fields were missing from the JSON output.
-
-Clang Frontend Potentially Breaking Changes
--------------------------------------------
-
-- HIPSPV toolchain: `--offload-targets=spirv{32,64}` option is
-  deprecated and will be removed when the new offload driver becomes
-  default. The replacement for the option is
-  `--offload-targets=spirv{32,64}-unknown-chipstar` when using the new
-  offload driver (`--offload-new-driver`).
-
-
-Clang Python Bindings Potentially Breaking Changes
---------------------------------------------------
-- Remove ``CompletionString.Availability``. No libclang interfaces returned instances of it.
-- ``CompletionString.availability`` now returns instances of ``CompletionString.AvailabilityKindCompat``.
-
-  Instances of ``AvailabilityKindCompat`` have the same ``__str__`` representation
-  as the previous ``CompletionChunk.Kind`` and are equality-comparable with
-  the existing ``AvailabilityKind`` enum. It will be replaced by ``AvailabilityKind``
-  in a future release. When this happens, the return type of ``CompletionString.availability``
-  will change to ``AvailabilityKind``, so it is recommended to use ``AvailabilityKind``
-  to compare with the return values of ``CompletionString.availability``.
-- Remove ``availabilityKinds``. In this release, uses of ``availabilityKinds``
-  need to be replaced by ``CompletionString.AvailabilityKind``.
-- ``CompletionChunk.kind`` now returns instances of ``CompletionChunkKind``.
-
-  Instances of ``CompletionChunkKind`` have the same ``__str__`` representation
-  as the previous ``CompletionChunk.Kind`` for compatibility.
-  These representations will be changed in a future release to match other enums.
-- Remove ``completionChunkKindMap``. In this release, uses of ``completionChunkKindMap``
-  need to be replaced by ``CompletionChunkKind``.
-- Move ``SPELLING_CACHE`` into ``CompletionChunk`` and change it to use
-  ``CompletionChunkKind`` instances as keys, instead of the enum values.
-  An alias is kept in the form of a ``SPELLING_CACHE`` variable, but it only supports
-  ``__getitem__`` and ``__contains__``. It will be removed in a future release.
-  Please migrate to using ``CompletionChunk.SPELLING_CACHE`` instead.
-- ``SourceLocation`` and ``SourceRange`` now use ``NotImplemented`` to delegate
-  equality checks (``__eq__``) to the other object they are compared with when
-  they are of different classes. They previously returned ``False`` when compared
-  with objects of other classes.
-
-What's New in Clang |release|?
-==============================
-
-C++ Language Changes
---------------------
-
-C++2c Feature Support
-^^^^^^^^^^^^^^^^^^^^^
-
-C++23 Feature Support
-^^^^^^^^^^^^^^^^^^^^^
-
-C++20 Feature Support
-^^^^^^^^^^^^^^^^^^^^^
-
-- Clang now supports `P1857R3 <https://wg21.link/p1857r3>`_ Modules Dependency Discovery. (#GH54047)
-
-C++17 Feature Support
-^^^^^^^^^^^^^^^^^^^^^
-
-Resolutions to C++ Defect Reports
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-C Language Changes
-------------------
-
-C2y Feature Support
-^^^^^^^^^^^^^^^^^^^
-
-C23 Feature Support
-^^^^^^^^^^^^^^^^^^^
-
-Non-comprehensive list of changes in this release
--------------------------------------------------
-
-- Added ``__builtin_stdc_rotate_left`` and ``__builtin_stdc_rotate_right``
-  for bit rotation of unsigned integers including ``_BitInt`` types. Rotation
-  counts are normalized modulo the bit-width and support negative values.
-  Usable in constant expressions. Implicit conversion is supported for
-  class/struct types with conversion operators.
-
-New Compiler Flags
-------------------
-- New option ``-fms-anonymous-structs`` / ``-fno-ms-anonymous-structs`` added
-  to enable or disable Microsoft's anonymous struct/union extension without
-  enabling other ``-fms-extensions`` features (#GH177607).
-
-Deprecated Compiler Flags
--------------------------
-
-Modified Compiler Flags
------------------------
-- The `-mno-outline` and `-moutline` compiler flags are now allowed on RISC-V and X86, which both support the machine outliner.
-
-Removed Compiler Flags
-----------------------
-
-Attribute Changes in Clang
---------------------------
-
-- Added new attribute ``stack_protector_ignore`` to opt specific local variables out of
-  the analysis which determines if a function should get a stack protector.  A function
-  will still generate a stack protector if other local variables or command line flags
-  require it.
-
-Improvements to Clang's diagnostics
------------------------------------
-- Added ``-Wlifetime-safety`` to enable lifetime safety analysis,
-  a CFG-based intra-procedural analysis that detects use-after-free and related
-  temporal safety bugs. See the
-  `RFC <https://discourse.llvm.org/t/rfc-intra-procedural-lifetime-analysis-in-clang/86291>`_
-  for more details. By design, this warning is enabled in ``-Weverything``. To disable
-  the analysis, use ``-Wno-lifetime-safety`` or ``-fno-lifetime-safety``.
-
-- Added ``-Wlifetime-safety-suggestions`` to enable lifetime annotation suggestions.
-  This provides suggestions for function parameters that
-  should be marked ``[[clang::lifetimebound]]`` based on lifetime analysis. For
-  example, for the following function:
-
-  .. code-block:: c++
-
-    int* p(int *in) { return in; }
-
-  Clang will suggest:
-
-  .. code-block:: c++
-
-    warning: parameter in intra-TU function should be marked [[clang::lifetimebound]]
-    int* p(int *in) { return in; }
-           ^~~~~~~
-                   [[clang::lifetimebound]]
-    note: param returned here
-    int* p(int *in) { return in; }
-                             ^~
-
-- Added ``-Wlifetime-safety-noescape`` to detect misuse of ``[[clang::noescape]]``
-  annotation where the parameter escapes through return. For example:
-
-  .. code-block:: c++
-
-    int* p(int *in [[clang::noescape]]) { return in; }
-
-  Clang will warn:
-
-  .. code-block:: c++
-
-    warning: parameter is marked [[clang::noescape]] but escapes
-    int* p(int *in [[clang::noescape]]) { return in; }
-           ^~~~~~~
-    note: returned here
-    int* p(int *in [[clang::noescape]]) { return in; }
-                                                 ^~
-
-- Added ``-Wlifetime-safety-dangling-field`` to detect dangling field references
-  when stack memory escapes to class fields. This is part of ``-Wlifetime-safety``
-  and detects cases where local variables or parameters are stored in fields but
-  outlive their scope. For example:
-
-  .. code-block:: c++
-
-    struct DanglingView {
-      std::string_view view;
-      DanglingView(std::string s) : view(s) {}  // warning: address of stack memory escapes to a field
-    };
-
-- Improved ``-Wassign-enum`` performance by caching enum enumerator values. (#GH176454)
-
-- Fixed a false negative in ``-Warray-bounds`` where the warning was suppressed
-  when accessing a member function on a past-the-end array element.
-  (#GH179128)
-
-Improvements to Clang's time-trace
-----------------------------------
-
-Improvements to Coverage Mapping
---------------------------------
-
-- [MC/DC] Nested expressions are handled as individual MC/DC expressions.
-- "Single byte coverage" now supports branch coverage and can be used
-  together with ``-fcoverage-mcdc``.
-
-Bug Fixes in This Version
--------------------------
-
-- Fixed atomic boolean compound assignment; the conversion back to atomic bool would be miscompiled. (#GH33210)
-
-- Fixed a failed assertion in the preprocessor when ``__has_embed`` parameters are missing parentheses. (#GH175088)
-
-- Fix lifetime extension of temporaries in for-range-initializers in templates. (#GH165182)
-- Fixed a preprocessor crash in ``__has_cpp_attribute`` on incomplete scoped attributes. (#GH178098)
-- Fixes an assertion failure when evaluating ``__underlying_type`` on enum redeclarations. (#GH177943)
-
-- Clang now outputs relative paths of embeds for dependency output. (#GH161950)
-
-Bug Fixes to Compiler Builtins
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Bug Fixes to Attribute Support
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-- Fixed a behavioral discrepancy between deleted functions and private members when checking the ``enable_if`` attribute. (#GH175895)
-
-Bug Fixes to C++ Support
-^^^^^^^^^^^^^^^^^^^^^^^^
-- Fixed a crash when instantiating ``requires`` expressions involving substitution failures in C++ concepts. (#GH176402)
-- Fixed a crash when a default argument is passed to an explicit object parameter. (#GH176639)
-- Fixed a crash when diagnosing an invalid static member function with an explicit object parameter (#GH177741)
-
-Bug Fixes to AST Handling
-^^^^^^^^^^^^^^^^^^^^^^^^^
-- Fixed a bug where explicit nullability property attributes were not stored in AST nodes in Objective-C. (#GH179703)
-
-Miscellaneous Bug Fixes
-^^^^^^^^^^^^^^^^^^^^^^^
-- Fixed the arguments of the format attribute on ``__builtin_os_log_format``.  Previously, they were off by 1.
-
-Miscellaneous Clang Crashes Fixed
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-- Fixed a crash when attempting to jump over initialization of a variable with variably modified type. (#GH175540)
-- Fixed a crash when using loop hint with a value dependent argument inside a
-  generic lambda. (#GH172289)
-- Fixed a crash in C++ overload resolution with ``_Atomic``-qualified argument types. (#GH170433)
-
-OpenACC Specific Changes
-------------------------
-
-Target Specific Changes
------------------------
-
-AMDGPU Support
-^^^^^^^^^^^^^^
-
-- Initial support for gfx1310
-
-NVPTX Support
-^^^^^^^^^^^^^^
-
-X86 Support
-^^^^^^^^^^^
-- ``march=znver6`` is now supported.
-
-Arm and AArch64 Support
-^^^^^^^^^^^^^^^^^^^^^^^
-
-Android Support
-^^^^^^^^^^^^^^^
-
-Windows Support
-^^^^^^^^^^^^^^^
-
-LoongArch Support
-^^^^^^^^^^^^^^^^^
-
-- DWARF fission is now compatible with linker relaxations, allowing `-gsplit-dwarf` and `-mrelax`
-  to be used together when building for the LoongArch platform.
-
-RISC-V Support
-^^^^^^^^^^^^^^
-
-- Tenstorrent Ascalon D8 was renamed to Ascalon X. Use `tt-ascalon-x` with `-mcpu` or `-mtune`.
-
-CUDA/HIP Language Changes
-^^^^^^^^^^^^^^^^^^^^^^^^^
-
-CUDA Support
-^^^^^^^^^^^^
-
-AIX Support
-^^^^^^^^^^^
-
-NetBSD Support
-^^^^^^^^^^^^^^
-
-WebAssembly Support
-^^^^^^^^^^^^^^^^^^^
-
-- Fixed a crash when ``__funcref`` is applied to a non-function pointer type.
-  (#GH118233)
-
-AVR Support
-^^^^^^^^^^^
-
-SystemZ Support
-^^^^^^^^^^^^^^^
-
-- Add support for `#pragma export` for z/OS.  This is a pragma used to export functions and variables
-  with external linkage from shared libraries.  It provides compatibility with the IBM XL C/C++
-  compiler.
-
-DWARF Support in Clang
-----------------------
-
-Floating Point Support in Clang
--------------------------------
-
-Fixed Point Support in Clang
-----------------------------
-
-AST Matchers
-------------
-- Add ``functionTypeLoc`` matcher for matching ``FunctionTypeLoc``.
-
-clang-format
-------------
-- Add ``ObjCSpaceAfterMethodDeclarationPrefix`` option to control space between the 
-  '-'/'+' and the return type in Objective-C method declarations
-
-libclang
---------
-
-Code Completion
----------------
-
-Static Analyzer
----------------
-
-.. comment:
-  This is for the Static Analyzer.
-  Using the caret `^^^` underlining for subsections:
-    - Crash and bug fixes
-    - New checkers and features
-    - Improvements
-    - Moved checkers
-
-.. _release-notes-sanitizers:
-
-Sanitizers
-----------
-
-Python Binding Changes
-----------------------
-- Add deprecation warnings to ``CompletionChunk.isKind...`` methods.
-  These will be removed in a future release. Existing uses should be adapted
-  to directly compare equality of the ``CompletionChunk`` kind with
-  the corresponding ``CompletionChunkKind`` variant.
-
-  Affected methods: ``isKindOptional``, ``isKindTypedText``, ``isKindPlaceHolder``,
-  ``isKindInformative`` and ``isKindResultType``.
-- Add a deprecation warning to ``CodeCompletionResults.results``.
-  This property will become an implementation detail with changed behavior in a 
-  future release and should not be used directly.. Existing uses of 
-  ``CodeCompletionResults.results`` should be changed to directly use
-  ``CodeCompletionResults``: it nows supports ``__len__`` and ``__getitem__``,
-  so it can be used the same as ``CodeCompletionResults.results``.
-
-OpenMP Support
---------------
-- Added support for ``transparent`` clause in task and taskloop directives.
-- Added support for ``use_device_ptr`` clause to accept an optional
-  ``fallback`` modifier (``fb_nullify`` or ``fb_preserve``) with OpenMP >= 61.
-
-Improvements
-^^^^^^^^^^^^
-
-Additional Information
-======================
-
-A wide variety of additional information is available on the `Clang web
-page <https://clang.llvm.org/>`_. The web page contains versions of the
-API documentation which are up-to-date with the Git version of
-the source code. You can access versions of these documents specific to
-this release by going into the "``clang/docs/``" directory in the Clang
-tree.
-
-If you have any questions or comments about Clang, please feel free to
-contact us on the `Discourse forums (Clang Frontend category)
-<https://discourse.llvm.org/c/clang/6>`_.
+.. If you want to modify sections/contents permanently, you should modify both
+   ReleaseNotes.rst and ReleaseNotesTemplate.txt.
+
+===========================================
+Clang |release| |ReleaseNotesTitle|
+===========================================
+
+.. contents::
+   :local:
+   :depth: 2
+
+Written by the `LLVM Team <https://llvm.org/>`_
+
+.. only:: PreRelease
+
+  .. warning::
+     These are in-progress notes for the upcoming Clang |version| release.
+     Release notes for previous releases can be found on
+     `the Releases Page <https://llvm.org/releases/>`_.
+
+Introduction
+============
+
+This document contains the release notes for the Clang C/C++/Objective-C
+frontend, part of the LLVM Compiler Infrastructure, release |release|. Here we
+describe the status of Clang in some detail, including major
+improvements from the previous release and new feature work. For the
+general LLVM release notes, see `the LLVM
+documentation <https://llvm.org/docs/ReleaseNotes.html>`_. For the libc++ release notes,
+see `this page <https://libcxx.llvm.org/ReleaseNotes.html>`_. All LLVM releases
+may be downloaded from the `LLVM releases web site <https://llvm.org/releases/>`_.
+
+For more information about Clang or LLVM, including information about the
+latest release, please see the `Clang Web Site <https://clang.llvm.org>`_ or the
+`LLVM Web Site <https://llvm.org>`_.
+
+Potentially Breaking Changes
+============================
+
+C/C++ Language Potentially Breaking Changes
+-------------------------------------------
+
+C++ Specific Potentially Breaking Changes
+-----------------------------------------
+
+- Clang now more aggressively optimizes away stores to objects after they are
+  dead. This behavior can be disabled with ``-fno-lifetime-dse``.
+
+ABI Changes in This Version
+---------------------------
+
+AST Dumping Potentially Breaking Changes
+----------------------------------------
+
+- The JSON AST dump now includes all fields from ``AvailabilityAttr``: ``platform``,
+  ``introduced``, ``deprecated``, ``obsoleted``, ``unavailable``, ``message``,
+  ``strict``, ``replacement``, ``priority``, and ``environment``. Previously, these
+  fields were missing from the JSON output.
+
+Clang Frontend Potentially Breaking Changes
+-------------------------------------------
+
+- HIPSPV toolchain: `--offload-targets=spirv{32,64}` option is
+  deprecated and will be removed when the new offload driver becomes
+  default. The replacement for the option is
+  `--offload-targets=spirv{32,64}-unknown-chipstar` when using the new
+  offload driver (`--offload-new-driver`).
+
+
+Clang Python Bindings Potentially Breaking Changes
+--------------------------------------------------
+- Remove ``CompletionString.Availability``. No libclang interfaces returned instances of it.
+- ``CompletionString.availability`` now returns instances of ``CompletionString.AvailabilityKindCompat``.
+
+  Instances of ``AvailabilityKindCompat`` have the same ``__str__`` representation
+  as the previous ``CompletionChunk.Kind`` and are equality-comparable with
+  the existing ``AvailabilityKind`` enum. It will be replaced by ``AvailabilityKind``
+  in a future release. When this happens, the return type of ``CompletionString.availability``
+  will change to ``AvailabilityKind``, so it is recommended to use ``AvailabilityKind``
+  to compare with the return values of ``CompletionString.availability``.
+- Remove ``availabilityKinds``. In this release, uses of ``availabilityKinds``
+  need to be replaced by ``CompletionString.AvailabilityKind``.
+- ``CompletionChunk.kind`` now returns instances of ``CompletionChunkKind``.
+
+  Instances of ``CompletionChunkKind`` have the same ``__str__`` representation
+  as the previous ``CompletionChunk.Kind`` for compatibility.
+  These representations will be changed in a future release to match other enums.
+- Remove ``completionChunkKindMap``. In this release, uses of ``completionChunkKindMap``
+  need to be replaced by ``CompletionChunkKind``.
+- Move ``SPELLING_CACHE`` into ``CompletionChunk`` and change it to use
+  ``CompletionChunkKind`` instances as keys, instead of the enum values.
+  An alias is kept in the form of a ``SPELLING_CACHE`` variable, but it only supports
+  ``__getitem__`` and ``__contains__``. It will be removed in a future release.
+  Please migrate to using ``CompletionChunk.SPELLING_CACHE`` instead.
+- ``SourceLocation`` and ``SourceRange`` now use ``NotImplemented`` to delegate
+  equality checks (``__eq__``) to the other object they are compared with when
+  they are of different classes. They previously returned ``False`` when compared
+  with objects of other classes.
+
+What's New in Clang |release|?
+==============================
+
+C++ Language Changes
+--------------------
+
+C++2c Feature Support
+^^^^^^^^^^^^^^^^^^^^^
+
+C++23 Feature Support
+^^^^^^^^^^^^^^^^^^^^^
+
+C++20 Feature Support
+^^^^^^^^^^^^^^^^^^^^^
+
+- Clang now supports `P1857R3 <https://wg21.link/p1857r3>`_ Modules Dependency Discovery. (#GH54047)
+
+C++17 Feature Support
+^^^^^^^^^^^^^^^^^^^^^
+
+Resolutions to C++ Defect Reports
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+C Language Changes
+------------------
+
+C2y Feature Support
+^^^^^^^^^^^^^^^^^^^
+
+C23 Feature Support
+^^^^^^^^^^^^^^^^^^^
+
+Non-comprehensive list of changes in this release
+-------------------------------------------------
+
+- Added ``__builtin_stdc_rotate_left`` and ``__builtin_stdc_rotate_right``
+  for bit rotation of unsigned integers including ``_BitInt`` types. Rotation
+  counts are normalized modulo the bit-width and support negative values.
+  Usable in constant expressions. Implicit conversion is supported for
+  class/struct types with conversion operators.
+
+New Compiler Flags
+------------------
+- New option ``-fms-anonymous-structs`` / ``-fno-ms-anonymous-structs`` added
+  to enable or disable Microsoft's anonymous struct/union extension without
+  enabling other ``-fms-extensions`` features (#GH177607).
+
+Deprecated Compiler Flags
+-------------------------
+
+Modified Compiler Flags
+-----------------------
+- The `-mno-outline` and `-moutline` compiler flags are now allowed on RISC-V and X86, which both support the machine outliner.
+
+Removed Compiler Flags
+----------------------
+
+Attribute Changes in Clang
+--------------------------
+
+- Added new attribute ``stack_protector_ignore`` to opt specific local variables out of
+  the analysis which determines if a function should get a stack protector.  A function
+  will still generate a stack protector if other local variables or command line flags
+  require it.
+
+Improvements to Clang's diagnostics
+-----------------------------------
+- Added ``-Wlifetime-safety`` to enable lifetime safety analysis,
+  a CFG-based intra-procedural analysis that detects use-after-free and related
+  temporal safety bugs. See the
+  `RFC <https://discourse.llvm.org/t/rfc-intra-procedural-lifetime-analysis-in-clang/86291>`_
+  for more details. By design, this warning is enabled in ``-Weverything``. To disable
+  the analysis, use ``-Wno-lifetime-safety`` or ``-fno-lifetime-safety``.
+
+- Added ``-Wlifetime-safety-suggestions`` to enable lifetime annotation suggestions.
+  This provides suggestions for function parameters that
+  should be marked ``[[clang::lifetimebound]]`` based on lifetime analysis. For
+  example, for the following function:
+
+  .. code-block:: c++
+
+    int* p(int *in) { return in; }
+
+  Clang will suggest:
+
+  .. code-block:: c++
+
+    warning: parameter in intra-TU function should be marked [[clang::lifetimebound]]
+    int* p(int *in) { return in; }
+           ^~~~~~~
+                   [[clang::lifetimebound]]
+    note: param returned here
+    int* p(int *in) { return in; }
+                             ^~
+
+- Added ``-Wlifetime-safety-noescape`` to detect misuse of ``[[clang::noescape]]``
+  annotation where the parameter escapes through return. For example:
+
+  .. code-block:: c++
+
+    int* p(int *in [[clang::noescape]]) { return in; }
+
+  Clang will warn:
+
+  .. code-block:: c++
+
+    warning: parameter is marked [[clang::noescape]] but escapes
+    int* p(int *in [[clang::noescape]]) { return in; }
+           ^~~~~~~
+    note: returned here
+    int* p(int *in [[clang::noescape]]) { return in; }
+                                                 ^~
+
+- Added ``-Wlifetime-safety-dangling-field`` to detect dangling field references
+  when stack memory escapes to class fields. This is part of ``-Wlifetime-safety``
+  and detects cases where local variables or parameters are stored in fields but
+  outlive their scope. For example:
+
+  .. code-block:: c++
+
+    struct DanglingView {
+      std::string_view view;
+      DanglingView(std::string s) : view(s) {}  // warning: address of stack memory escapes to a field
+    };
+
+- Improved ``-Wassign-enum`` performance by caching enum enumerator values. (#GH176454)
+
+- Fixed a false negative in ``-Warray-bounds`` where the warning was suppressed
+  when accessing a member function on a past-the-end array element.
+  (#GH179128)
+
+- Improved ``-Wunsequenced`` by taking into account the volatile qualifier.
+
+Improvements to Clang's time-trace
+----------------------------------
+
+Improvements to Coverage Mapping
+--------------------------------
+
+- [MC/DC] Nested expressions are handled as individual MC/DC expressions.
+- "Single byte coverage" now supports branch coverage and can be used
+  together with ``-fcoverage-mcdc``.
+
+Bug Fixes in This Version
+-------------------------
+
+- Fixed atomic boolean compound assignment; the conversion back to atomic bool would be miscompiled. (#GH33210)
+
+- Fixed a failed assertion in the preprocessor when ``__has_embed`` parameters are missing parentheses. (#GH175088)
+
+- Fix lifetime extension of temporaries in for-range-initializers in templates. (#GH165182)
+- Fixed a preprocessor crash in ``__has_cpp_attribute`` on incomplete scoped attributes. (#GH178098)
+- Fixes an assertion failure when evaluating ``__underlying_type`` on enum redeclarations. (#GH177943)
+
+- Clang now outputs relative paths of embeds for dependency output. (#GH161950)
+
+Bug Fixes to Compiler Builtins
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Bug Fixes to Attribute Support
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+- Fixed a behavioral discrepancy between deleted functions and private members when checking the ``enable_if`` attribute. (#GH175895)
+
+Bug Fixes to C++ Support
+^^^^^^^^^^^^^^^^^^^^^^^^
+- Fixed a crash when instantiating ``requires`` expressions involving substitution failures in C++ concepts. (#GH176402)
+- Fixed a crash when a default argument is passed to an explicit object parameter. (#GH176639)
+- Fixed a crash when diagnosing an invalid static member function with an explicit object parameter (#GH177741)
+
+Bug Fixes to AST Handling
+^^^^^^^^^^^^^^^^^^^^^^^^^
+- Fixed a bug where explicit nullability property attributes were not stored in AST nodes in Objective-C. (#GH179703)
+
+Miscellaneous Bug Fixes
+^^^^^^^^^^^^^^^^^^^^^^^
+- Fixed the arguments of the format attribute on ``__builtin_os_log_format``.  Previously, they were off by 1.
+
+Miscellaneous Clang Crashes Fixed
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+- Fixed a crash when attempting to jump over initialization of a variable with variably modified type. (#GH175540)
+- Fixed a crash when using loop hint with a value dependent argument inside a
+  generic lambda. (#GH172289)
+- Fixed a crash in C++ overload resolution with ``_Atomic``-qualified argument types. (#GH170433)
+
+OpenACC Specific Changes
+------------------------
+
+Target Specific Changes
+-----------------------
+
+AMDGPU Support
+^^^^^^^^^^^^^^
+
+- Initial support for gfx1310
+
+NVPTX Support
+^^^^^^^^^^^^^^
+
+X86 Support
+^^^^^^^^^^^
+- ``march=znver6`` is now supported.
+
+Arm and AArch64 Support
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Android Support
+^^^^^^^^^^^^^^^
+
+Windows Support
+^^^^^^^^^^^^^^^
+
+LoongArch Support
+^^^^^^^^^^^^^^^^^
+
+- DWARF fission is now compatible with linker relaxations, allowing `-gsplit-dwarf` and `-mrelax`
+  to be used together when building for the LoongArch platform.
+
+RISC-V Support
+^^^^^^^^^^^^^^
+
+- Tenstorrent Ascalon D8 was renamed to Ascalon X. Use `tt-ascalon-x` with `-mcpu` or `-mtune`.
+
+CUDA/HIP Language Changes
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+CUDA Support
+^^^^^^^^^^^^
+
+AIX Support
+^^^^^^^^^^^
+
+NetBSD Support
+^^^^^^^^^^^^^^
+
+WebAssembly Support
+^^^^^^^^^^^^^^^^^^^
+
+- Fixed a crash when ``__funcref`` is applied to a non-function pointer type.
+  (#GH118233)
+
+AVR Support
+^^^^^^^^^^^
+
+SystemZ Support
+^^^^^^^^^^^^^^^
+
+- Add support for `#pragma export` for z/OS.  This is a pragma used to export functions and variables
+  with external linkage from shared libraries.  It provides compatibility with the IBM XL C/C++
+  compiler.
+
+DWARF Support in Clang
+----------------------
+
+Floating Point Support in Clang
+-------------------------------
+
+Fixed Point Support in Clang
+----------------------------
+
+AST Matchers
+------------
+- Add ``functionTypeLoc`` matcher for matching ``FunctionTypeLoc``.
+
+clang-format
+------------
+- Add ``ObjCSpaceAfterMethodDeclarationPrefix`` option to control space between the 
+  '-'/'+' and the return type in Objective-C method declarations
+
+libclang
+--------
+
+Code Completion
+---------------
+
+Static Analyzer
+---------------
+
+.. comment:
+  This is for the Static Analyzer.
+  Using the caret `^^^` underlining for subsections:
+    - Crash and bug fixes
+    - New checkers and features
+    - Improvements
+    - Moved checkers
+
+.. _release-notes-sanitizers:
+
+Sanitizers
+----------
+
+Python Binding Changes
+----------------------
+- Add deprecation warnings to ``CompletionChunk.isKind...`` methods.
+  These will be removed in a future release. Existing uses should be adapted
+  to directly compare equality of the ``CompletionChunk`` kind with
+  the corresponding ``CompletionChunkKind`` variant.
+
+  Affected methods: ``isKindOptional``, ``isKindTypedText``, ``isKindPlaceHolder``,
+  ``isKindInformative`` and ``isKindResultType``.
+- Add a deprecation warning to ``CodeCompletionResults.results``.
+  This property will become an implementation detail with changed behavior in a 
+  future release and should not be used directly.. Existing uses of 
+  ``CodeCompletionResults.results`` should be changed to directly use
+  ``CodeCompletionResults``: it nows supports ``__len__`` and ``__getitem__``,
+  so it can be used the same as ``CodeCompletionResults.results``.
+
+OpenMP Support
+--------------
+- Added support for ``transparent`` clause in task and taskloop directives.
+- Added support for ``use_device_ptr`` clause to accept an optional
+  ``fallback`` modifier (``fb_nullify`` or ``fb_preserve``) with OpenMP >= 61.
+
+Improvements
+^^^^^^^^^^^^
+
+Additional Information
+======================
+
+A wide variety of additional information is available on the `Clang web
+page <https://clang.llvm.org/>`_. The web page contains versions of the
+API documentation which are up-to-date with the Git version of
+the source code. You can access versions of these documents specific to
+this release by going into the "``clang/docs/``" directory in the Clang
+tree.
+
+If you have any questions or comments about Clang, please feel free to
+contact us on the `Discourse forums (Clang Frontend category)
+<https://discourse.llvm.org/c/clang/6>`_.
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 4c2eaad980394..618f678728287 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1,16956 +1,16965 @@
-//===- SemaChecking.cpp - Extra Semantic Checking -------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-//  This file implements extra semantic analysis beyond what is enforced
-//  by the C type system.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CheckExprLifetime.h"
-#include "clang/AST/APValue.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/ASTDiagnostic.h"
-#include "clang/AST/Attr.h"
-#include "clang/AST/AttrIterator.h"
-#include "clang/AST/CharUnits.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclBase.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/DeclarationName.h"
-#include "clang/AST/EvaluatedExprVisitor.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/FormatString.h"
-#include "clang/AST/IgnoreExpr.h"
-#include "clang/AST/NSAPI.h"
-#include "clang/AST/NonTrivialTypeVisitor.h"
-#include "clang/AST/OperationKinds.h"
-#include "clang/AST/RecordLayout.h"
-#include "clang/AST/Stmt.h"
-#include "clang/AST/TemplateBase.h"
-#include "clang/AST/TemplateName.h"
-#include "clang/AST/Type.h"
-#include "clang/AST/TypeBase.h"
-#include "clang/AST/TypeLoc.h"
-#include "clang/AST/UnresolvedSet.h"
-#include "clang/Basic/AddressSpaces.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/DiagnosticSema.h"
-#include "clang/Basic/IdentifierTable.h"
-#include "clang/Basic/LLVM.h"
-#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/OpenCLOptions.h"
-#include "clang/Basic/OperatorKinds.h"
-#include "clang/Basic/PartialDiagnostic.h"
-#include "clang/Basic/SourceLocation.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/Specifiers.h"
-#include "clang/Basic/SyncScope.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/Basic/TypeTraits.h"
-#include "clang/Lex/Lexer.h" // TODO: Extract static functions to fix layering.
-#include "clang/Sema/Initialization.h"
-#include "clang/Sema/Lookup.h"
-#include "clang/Sema/Ownership.h"
-#include "clang/Sema/Scope.h"
-#include "clang/Sema/ScopeInfo.h"
-#include "clang/Sema/Sema.h"
-#include "clang/Sema/SemaAMDGPU.h"
-#include "clang/Sema/SemaARM.h"
-#include "clang/Sema/SemaBPF.h"
-#include "clang/Sema/SemaDirectX.h"
-#include "clang/Sema/SemaHLSL.h"
-#include "clang/Sema/SemaHexagon.h"
-#include "clang/Sema/SemaLoongArch.h"
-#include "clang/Sema/SemaMIPS.h"
-#include "clang/Sema/SemaNVPTX.h"
-#include "clang/Sema/SemaObjC.h"
-#include "clang/Sema/SemaOpenCL.h"
-#include "clang/Sema/SemaPPC.h"
-#include "clang/Sema/SemaRISCV.h"
-#include "clang/Sema/SemaSPIRV.h"
-#include "clang/Sema/SemaSystemZ.h"
-#include "clang/Sema/SemaWasm.h"
-#include "clang/Sema/SemaX86.h"
-#include "llvm/ADT/APFloat.h"
-#include "llvm/ADT/APInt.h"
-#include "llvm/ADT/APSInt.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/STLForwardCompat.h"
-#include "llvm/ADT/SmallBitVector.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSet.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/AtomicOrdering.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/ConvertUTF.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/Locale.h"
-#include "llvm/Support/MathExtras.h"
-#include "llvm/Support/SaveAndRestore.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/TargetParser/RISCVTargetParser.h"
-#include "llvm/TargetParser/Triple.h"
-#include <algorithm>
-#include <cassert>
-#include <cctype>
-#include <cstddef>
-#include <cstdint>
-#include <functional>
-#include <limits>
-#include <optional>
-#include <string>
-#include <tuple>
-#include <utility>
-
-using namespace clang;
-using namespace sema;
-
-SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
-                                                    unsigned ByteNo) const {
-  return SL->getLocationOfByte(ByteNo, getSourceManager(), LangOpts,
-                               Context.getTargetInfo());
-}
-
-static constexpr unsigned short combineFAPK(Sema::FormatArgumentPassingKind A,
-                                            Sema::FormatArgumentPassingKind B) {
-  return (A << 8) | B;
-}
-
-bool Sema::checkArgCountAtLeast(CallExpr *Call, unsigned MinArgCount) {
-  unsigned ArgCount = Call->getNumArgs();
-  if (ArgCount >= MinArgCount)
-    return false;
-
-  return Diag(Call->getEndLoc(), diag::err_typecheck_call_too_few_args)
-         << 0 /*function call*/ << MinArgCount << ArgCount
-         << /*is non object*/ 0 << Call->getSourceRange();
-}
-
-bool Sema::checkArgCountAtMost(CallExpr *Call, unsigned MaxArgCount) {
-  unsigned ArgCount = Call->getNumArgs();
-  if (ArgCount <= MaxArgCount)
-    return false;
-  return Diag(Call->getEndLoc(), diag::err_typecheck_call_too_many_args_at_most)
-         << 0 /*function call*/ << MaxArgCount << ArgCount
-         << /*is non object*/ 0 << Call->getSourceRange();
-}
-
-bool Sema::checkArgCountRange(CallExpr *Call, unsigned MinArgCount,
-                              unsigned MaxArgCount) {
-  return checkArgCountAtLeast(Call, MinArgCount) ||
-         checkArgCountAtMost(Call, MaxArgCount);
-}
-
-bool Sema::checkArgCount(CallExpr *Call, unsigned DesiredArgCount) {
-  unsigned ArgCount = Call->getNumArgs();
-  if (ArgCount == DesiredArgCount)
-    return false;
-
-  if (checkArgCountAtLeast(Call, DesiredArgCount))
-    return true;
-  assert(ArgCount > DesiredArgCount && "should have diagnosed this");
-
-  // Highlight all the excess arguments.
-  SourceRange Range(Call->getArg(DesiredArgCount)->getBeginLoc(),
-                    Call->getArg(ArgCount - 1)->getEndLoc());
-
-  return Diag(Range.getBegin(), diag::err_typecheck_call_too_many_args)
-         << 0 /*function call*/ << DesiredArgCount << ArgCount
-         << /*is non object*/ 0 << Range;
-}
-
-static bool checkBuiltinVerboseTrap(CallExpr *Call, Sema &S) {
-  bool HasError = false;
-
-  for (const Expr *Arg : Call->arguments()) {
-    if (Arg->isValueDependent())
-      continue;
-
-    std::optional<std::string> ArgString = Arg->tryEvaluateString(S.Context);
-    int DiagMsgKind = -1;
-    // Arguments must be pointers to constant strings and cannot use '$'.
-    if (!ArgString.has_value())
-      DiagMsgKind = 0;
-    else if (ArgString->find('$') != std::string::npos)
-      DiagMsgKind = 1;
-
-    if (DiagMsgKind >= 0) {
-      S.Diag(Arg->getBeginLoc(), diag::err_builtin_verbose_trap_arg)
-          << DiagMsgKind << Arg->getSourceRange();
-      HasError = true;
-    }
-  }
-
-  return !HasError;
-}
-
-static bool convertArgumentToType(Sema &S, Expr *&Value, QualType Ty) {
-  if (Value->isTypeDependent())
-    return false;
-
-  InitializedEntity Entity =
-      InitializedEntity::InitializeParameter(S.Context, Ty, false);
-  ExprResult Result =
-      S.PerformCopyInitialization(Entity, SourceLocation(), Value);
-  if (Result.isInvalid())
-    return true;
-  Value = Result.get();
-  return false;
-}
-
-/// Check that the first argument to __builtin_annotation is an integer
-/// and the second argument is a non-wide string literal.
-static bool BuiltinAnnotation(Sema &S, CallExpr *TheCall) {
-  if (S.checkArgCount(TheCall, 2))
-    return true;
-
-  // First argument should be an integer.
-  Expr *ValArg = TheCall->getArg(0);
-  QualType Ty = ValArg->getType();
-  if (!Ty->isIntegerType()) {
-    S.Diag(ValArg->getBeginLoc(), diag::err_builtin_annotation_first_arg)
-        << ValArg->getSourceRange();
-    return true;
-  }
-
-  // Second argument should be a constant string.
-  Expr *StrArg = TheCall->getArg(1)->IgnoreParenCasts();
-  StringLiteral *Literal = dyn_cast<StringLiteral>(StrArg);
-  if (!Literal || !Literal->isOrdinary()) {
-    S.Diag(StrArg->getBeginLoc(), diag::err_builtin_annotation_second_arg)
-        << StrArg->getSourceRange();
-    return true;
-  }
-
-  TheCall->setType(Ty);
-  return false;
-}
-
-static bool BuiltinMSVCAnnotation(Sema &S, CallExpr *TheCall) {
-  // We need at least one argument.
-  if (TheCall->getNumArgs() < 1) {
-    S.Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least)
-        << 0 << 1 << TheCall->getNumArgs() << /*is non object*/ 0
-        << TheCall->getCallee()->getSourceRange();
-    return true;
-  }
-
-  // All arguments should be wide string literals.
-  for (Expr *Arg : TheCall->arguments()) {
-    auto *Literal = dyn_cast<StringLiteral>(Arg->IgnoreParenCasts());
-    if (!Literal || !Literal->isWide()) {
-      S.Diag(Arg->getBeginLoc(), diag::err_msvc_annotation_wide_str)
-          << Arg->getSourceRange();
-      return true;
-    }
-  }
-
-  return false;
-}
-
-/// Check that the argument to __builtin_addressof is a glvalue, and set the
-/// result type to the corresponding pointer type.
-static bool BuiltinAddressof(Sema &S, CallExpr *TheCall) {
-  if (S.checkArgCount(TheCall, 1))
-    return true;
-
-  ExprResult Arg(TheCall->getArg(0));
-  QualType ResultType = S.CheckAddressOfOperand(Arg, TheCall->getBeginLoc());
-  if (ResultType.isNull())
-    return true;
-
-  TheCall->setArg(0, Arg.get());
-  TheCall->setType(ResultType);
-  return false;
-}
-
-/// Check that the argument to __builtin_function_start is a function.
-static bool BuiltinFunctionStart(Sema &S, CallExpr *TheCall) {
-  if (S.checkArgCount(TheCall, 1))
-    return true;
-
-  if (TheCall->getArg(0)->containsErrors())
-    return true;
-
-  ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(0));
-  if (Arg.isInvalid())
-    return true;
-
-  TheCall->setArg(0, Arg.get());
-  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(
-      Arg.get()->getAsBuiltinConstantDeclRef(S.getASTContext()));
-
-  if (!FD) {
-    S.Diag(TheCall->getBeginLoc(), diag::err_function_start_invalid_type)
-        << TheCall->getSourceRange();
-    return true;
-  }
-
-  return !S.checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true,
-                                              TheCall->getBeginLoc());
-}
-
-/// Check the number of arguments and set the result type to
-/// the argument type.
-static bool BuiltinPreserveAI(Sema &S, CallExpr *TheCall) {
-  if (S.checkArgCount(TheCall, 1))
-    return true;
-
-  TheCall->setType(TheCall->getArg(0)->getType());
-  return false;
-}
-
-/// Check that the value argument for __builtin_is_aligned(value, alignment) and
-/// __builtin_aligned_{up,down}(value, alignment) is an integer or a pointer
-/// type (but not a function pointer) and that the alignment is a power-of-two.
-static bool BuiltinAlignment(Sema &S, CallExpr *TheCall, unsigned ID) {
-  if (S.checkArgCount(TheCall, 2))
-    return true;
-
-  clang::Expr *Source = TheCall->getArg(0);
-  bool IsBooleanAlignBuiltin = ID == Builtin::BI__builtin_is_aligned;
-
-  auto IsValidIntegerType = [](QualType Ty) {
-    return Ty->isIntegerType() && !Ty->isEnumeralType() && !Ty->isBooleanType();
-  };
-  QualType SrcTy = Source->getType();
-  // We should also be able to use it with arrays (but not functions!).
-  if (SrcTy->canDecayToPointerType() && SrcTy->isArrayType()) {
-    SrcTy = S.Context.getDecayedType(SrcTy);
-  }
-  if ((!SrcTy->isPointerType() && !IsValidIntegerType(SrcTy)) ||
-      SrcTy->isFunctionPointerType()) {
-    // FIXME: this is not quite the right error message since we don't allow
-    // floating point types, or member pointers.
-    S.Diag(Source->getExprLoc(), diag::err_typecheck_expect_scalar_operand)
-        << SrcTy;
-    return true;
-  }
-
-  clang::Expr *AlignOp = TheCall->getArg(1);
-  if (!IsValidIntegerType(AlignOp->getType())) {
-    S.Diag(AlignOp->getExprLoc(), diag::err_typecheck_expect_int)
-        << AlignOp->getType();
-    return true;
-  }
-  Expr::EvalResult AlignResult;
-  unsigned MaxAlignmentBits = S.Context.getIntWidth(SrcTy) - 1;
-  // We can't check validity of alignment if it is value dependent.
-  if (!AlignOp->isValueDependent() &&
-      AlignOp->EvaluateAsInt(AlignResult, S.Context,
-                             Expr::SE_AllowSideEffects)) {
-    llvm::APSInt AlignValue = AlignResult.Val.getInt();
-    llvm::APSInt MaxValue(
-        llvm::APInt::getOneBitSet(MaxAlignmentBits + 1, MaxAlignmentBits));
-    if (AlignValue < 1) {
-      S.Diag(AlignOp->getExprLoc(), diag::err_alignment_too_small) << 1;
-      return true;
-    }
-    if (llvm::APSInt::compareValues(AlignValue, MaxValue) > 0) {
-      S.Diag(AlignOp->getExprLoc(), diag::err_alignment_too_big)
-          << toString(MaxValue, 10);
-      return true;
-    }
-    if (!AlignValue.isPowerOf2()) {
-      S.Diag(AlignOp->getExprLoc(), diag::err_alignment_not_power_of_two);
-      return true;
-    }
-    if (AlignValue == 1) {
-      S.Diag(AlignOp->getExprLoc(), diag::warn_alignment_builtin_useless)
-          << IsBooleanAlignBuiltin;
-    }
-  }
-
-  ExprResult SrcArg = S.PerformCopyInitialization(
-      InitializedEntity::InitializeParameter(S.Context, SrcTy, false),
-      SourceLocation(), Source);
-  if (SrcArg.isInvalid())
-    return true;
-  TheCall->setArg(0, SrcArg.get());
-  ExprResult AlignArg =
-      S.PerformCopyInitialization(InitializedEntity::InitializeParameter(
-                                      S.Context, AlignOp->getType(), false),
-                                  SourceLocation(), AlignOp);
-  if (AlignArg.isInvalid())
-    return true;
-  TheCall->setArg(1, AlignArg.get());
-  // For align_up/align_down, the return type is the same as the (potentially
-  // decayed) argument type including qualifiers. For is_aligned(), the result
-  // is always bool.
-  TheCall->setType(IsBooleanAlignBuiltin ? S.Context.BoolTy : SrcTy);
-  return false;
-}
-
-static bool BuiltinOverflow(Sema &S, CallExpr *TheCall, unsigned BuiltinID) {
-  if (S.checkArgCount(TheCall, 3))
-    return true;
-
-  std::pair<unsigned, const char *> Builtins[] = {
-    { Builtin::BI__builtin_add_overflow, "ckd_add" },
-    { Builtin::BI__builtin_sub_overflow, "ckd_sub" },
-    { Builtin::BI__builtin_mul_overflow, "ckd_mul" },
-  };
-
-  bool CkdOperation = llvm::any_of(Builtins, [&](const std::pair<unsigned,
-    const char *> &P) {
-    return BuiltinID == P.first && TheCall->getExprLoc().isMacroID() &&
-         Lexer::getImmediateMacroName(TheCall->getExprLoc(),
-         S.getSourceManager(), S.getLangOpts()) == P.second;
-  });
-
-  auto ValidCkdIntType = [](QualType QT) {
-    // A valid checked integer type is an integer type other than a plain char,
-    // bool, a bit-precise type, or an enumeration type.
-    if (const auto *BT = QT.getCanonicalType()->getAs<BuiltinType>())
-      return (BT->getKind() >= BuiltinType::Short &&
-           BT->getKind() <= BuiltinType::Int128) || (
-           BT->getKind() >= BuiltinType::UShort &&
-           BT->getKind() <= BuiltinType::UInt128) ||
-           BT->getKind() == BuiltinType::UChar ||
-           BT->getKind() == BuiltinType::SChar;
-    return false;
-  };
-
-  // First two arguments should be integers.
-  for (unsigned I = 0; I < 2; ++I) {
-    ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(I));
-    if (Arg.isInvalid()) return true;
-    TheCall->setArg(I, Arg.get());
-
-    QualType Ty = Arg.get()->getType();
-    bool IsValid = CkdOperation ? ValidCkdIntType(Ty) : Ty->isIntegerType();
-    if (!IsValid) {
-      S.Diag(Arg.get()->getBeginLoc(), diag::err_overflow_builtin_must_be_int)
-          << CkdOperation << Ty << Arg.get()->getSourceRange();
-      return true;
-    }
-  }
-
-  // Third argument should be a pointer to a non-const integer.
-  // IRGen correctly handles volatile, restrict, and address spaces, and
-  // the other qualifiers aren't possible.
-  {
-    ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(2));
-    if (Arg.isInvalid()) return true;
-    TheCall->setArg(2, Arg.get());
-
-    QualType Ty = Arg.get()->getType();
-    const auto *PtrTy = Ty->getAs<PointerType>();
-    if (!PtrTy ||
-        !PtrTy->getPointeeType()->isIntegerType() ||
-        (!ValidCkdIntType(PtrTy->getPointeeType()) && CkdOperation) ||
-        PtrTy->getPointeeType().isConstQualified()) {
-      S.Diag(Arg.get()->getBeginLoc(),
-             diag::err_overflow_builtin_must_be_ptr_int)
-        << CkdOperation << Ty << Arg.get()->getSourceRange();
-      return true;
-    }
-  }
-
-  // Disallow signed bit-precise integer args larger than 128 bits to mul
-  // function until we improve backend support.
-  if (BuiltinID == Builtin::BI__builtin_mul_overflow) {
-    for (unsigned I = 0; I < 3; ++I) {
-      const auto Arg = TheCall->getArg(I);
-      // Third argument will be a pointer.
-      auto Ty = I < 2 ? Arg->getType() : Arg->getType()->getPointeeType();
-      if (Ty->isBitIntType() && Ty->isSignedIntegerType() &&
-          S.getASTContext().getIntWidth(Ty) > 128)
-        return S.Diag(Arg->getBeginLoc(),
-                      diag::err_overflow_builtin_bit_int_max_size)
-               << 128;
-    }
-  }
-
-  return false;
-}
-
-namespace {
-struct BuiltinDumpStructGenerator {
-  Sema &S;
-  CallExpr *TheCall;
-  SourceLocation Loc = TheCall->getBeginLoc();
-  SmallVector<Expr *, 32> Actions;
-  DiagnosticErrorTrap ErrorTracker;
-  PrintingPolicy Policy;
-
-  BuiltinDumpStructGenerator(Sema &S, CallExpr *TheCall)
-      : S(S), TheCall(TheCall), ErrorTracker(S.getDiagnostics()),
-        Policy(S.Context.getPrintingPolicy()) {
-    Policy.AnonymousTagLocations = false;
-  }
-
-  Expr *makeOpaqueValueExpr(Expr *Inner) {
-    auto *OVE = new (S.Context)
-        OpaqueValueExpr(Loc, Inner->getType(), Inner->getValueKind(),
-                        Inner->getObjectKind(), Inner);
-    Actions.push_back(OVE);
-    return OVE;
-  }
-
-  Expr *getStringLiteral(llvm::StringRef Str) {
-    Expr *Lit = S.Context.getPredefinedStringLiteralFromCache(Str);
-    // Wrap the literal in parentheses to attach a source location.
-    return new (S.Context) ParenExpr(Loc, Loc, Lit);
-  }
-
-  bool callPrintFunction(llvm::StringRef Format,
-                         llvm::ArrayRef<Expr *> Exprs = {}) {
-    SmallVector<Expr *, 8> Args;
-    assert(TheCall->getNumArgs() >= 2);
-    Args.reserve((TheCall->getNumArgs() - 2) + /*Format*/ 1 + Exprs.size());
-    Args.assign(TheCall->arg_begin() + 2, TheCall->arg_end());
-    Args.push_back(getStringLiteral(Format));
-    llvm::append_range(Args, Exprs);
-
-    // Register a note to explain why we're performing the call.
-    Sema::CodeSynthesisContext Ctx;
-    Ctx.Kind = Sema::CodeSynthesisContext::BuildingBuiltinDumpStructCall;
-    Ctx.PointOfInstantiation = Loc;
-    Ctx.CallArgs = Args.data();
-    Ctx.NumCallArgs = Args.size();
-    S.pushCodeSynthesisContext(Ctx);
-
-    ExprResult RealCall =
-        S.BuildCallExpr(/*Scope=*/nullptr, TheCall->getArg(1),
-                        TheCall->getBeginLoc(), Args, TheCall->getRParenLoc());
-
-    S.popCodeSynthesisContext();
-    if (!RealCall.isInvalid())
-      Actions.push_back(RealCall.get());
-    // Bail out if we've hit any errors, even if we managed to build the
-    // call. We don't want to produce more than one error.
-    return RealCall.isInvalid() || ErrorTracker.hasErrorOccurred();
-  }
-
-  Expr *getIndentString(unsigned Depth) {
-    if (!Depth)
-      return nullptr;
-
-    llvm::SmallString<32> Indent;
-    Indent.resize(Depth * Policy.Indentation, ' ');
-    return getStringLiteral(Indent);
-  }
-
-  Expr *getTypeString(QualType T) {
-    return getStringLiteral(T.getAsString(Policy));
-  }
-
-  bool appendFormatSpecifier(QualType T, llvm::SmallVectorImpl<char> &Str) {
-    llvm::raw_svector_ostream OS(Str);
-
-    // Format 'bool', 'char', 'signed char', 'unsigned char' as numbers, rather
-    // than trying to print a single character.
-    if (auto *BT = T->getAs<BuiltinType>()) {
-      switch (BT->getKind()) {
-      case BuiltinType::Bool:
-        OS << "%d";
-        return true;
-      case BuiltinType::Char_U:
-      case BuiltinType::UChar:
-        OS << "%hhu";
-        return true;
-      case BuiltinType::Char_S:
-      case BuiltinType::SChar:
-        OS << "%hhd";
-        return true;
-      default:
-        break;
-      }
-    }
-
-    analyze_printf::PrintfSpecifier Specifier;
-    if (Specifier.fixType(T, S.getLangOpts(), S.Context, /*IsObjCLiteral=*/false)) {
-      // We were able to guess how to format this.
-      if (Specifier.getConversionSpecifier().getKind() ==
-          analyze_printf::PrintfConversionSpecifier::sArg) {
-        // Wrap double-quotes around a '%s' specifier and limit its maximum
-        // length. Ideally we'd also somehow escape special characters in the
-        // contents but printf doesn't support that.
-        // FIXME: '%s' formatting is not safe in general.
-        OS << '"';
-        Specifier.setPrecision(analyze_printf::OptionalAmount(32u));
-        Specifier.toString(OS);
-        OS << '"';
-        // FIXME: It would be nice to include a '...' if the string doesn't fit
-        // in the length limit.
-      } else {
-        Specifier.toString(OS);
-      }
-      return true;
-    }
-
-    if (T->isPointerType()) {
-      // Format all pointers with '%p'.
-      OS << "%p";
-      return true;
-    }
-
-    return false;
-  }
-
-  bool dumpUnnamedRecord(const RecordDecl *RD, Expr *E, unsigned Depth) {
-    Expr *IndentLit = getIndentString(Depth);
-    Expr *TypeLit = getTypeString(S.Context.getCanonicalTagType(RD));
-    if (IndentLit ? callPrintFunction("%s%s", {IndentLit, TypeLit})
-                  : callPrintFunction("%s", {TypeLit}))
-      return true;
-
-    return dumpRecordValue(RD, E, IndentLit, Depth);
-  }
-
-  // Dump a record value. E should be a pointer or lvalue referring to an RD.
-  bool dumpRecordValue(const RecordDecl *RD, Expr *E, Expr *RecordIndent,
-                       unsigned Depth) {
-    // FIXME: Decide what to do if RD is a union. At least we should probably
-    // turn off printing `const char*` members with `%s`, because that is very
-    // likely to crash if that's not the active member. Whatever we decide, we
-    // should document it.
-
-    // Build an OpaqueValueExpr so we can refer to E more than once without
-    // triggering re-evaluation.
-    Expr *RecordArg = makeOpaqueValueExpr(E);
-    bool RecordArgIsPtr = RecordArg->getType()->isPointerType();
-
-    if (callPrintFunction(" {\n"))
-      return true;
-
-    // Dump each base class, regardless of whether they're aggregates.
-    if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
-      for (const auto &Base : CXXRD->bases()) {
-        QualType BaseType =
-            RecordArgIsPtr ? S.Context.getPointerType(Base.getType())
-                           : S.Context.getLValueReferenceType(Base.getType());
-        ExprResult BasePtr = S.BuildCStyleCastExpr(
-            Loc, S.Context.getTrivialTypeSourceInfo(BaseType, Loc), Loc,
-            RecordArg);
-        if (BasePtr.isInvalid() ||
-            dumpUnnamedRecord(Base.getType()->getAsRecordDecl(), BasePtr.get(),
-                              Depth + 1))
-          return true;
-      }
-    }
-
-    Expr *FieldIndentArg = getIndentString(Depth + 1);
-
-    // Dump each field.
-    for (auto *D : RD->decls()) {
-      auto *IFD = dyn_cast<IndirectFieldDecl>(D);
-      auto *FD = IFD ? IFD->getAnonField() : dyn_cast<FieldDecl>(D);
-      if (!FD || FD->isUnnamedBitField() || FD->isAnonymousStructOrUnion())
-        continue;
-
-      llvm::SmallString<20> Format = llvm::StringRef("%s%s %s ");
-      llvm::SmallVector<Expr *, 5> Args = {FieldIndentArg,
-                                           getTypeString(FD->getType()),
-                                           getStringLiteral(FD->getName())};
-
-      if (FD->isBitField()) {
-        Format += ": %zu ";
-        QualType SizeT = S.Context.getSizeType();
-        llvm::APInt BitWidth(S.Context.getIntWidth(SizeT),
-                             FD->getBitWidthValue());
-        Args.push_back(IntegerLiteral::Create(S.Context, BitWidth, SizeT, Loc));
-      }
-
-      Format += "=";
-
-      ExprResult Field =
-          IFD ? S.BuildAnonymousStructUnionMemberReference(
-                    CXXScopeSpec(), Loc, IFD,
-                    DeclAccessPair::make(IFD, AS_public), RecordArg, Loc)
-              : S.BuildFieldReferenceExpr(
-                    RecordArg, RecordArgIsPtr, Loc, CXXScopeSpec(), FD,
-                    DeclAccessPair::make(FD, AS_public),
-                    DeclarationNameInfo(FD->getDeclName(), Loc));
-      if (Field.isInvalid())
-        return true;
-
-      auto *InnerRD = FD->getType()->getAsRecordDecl();
-      auto *InnerCXXRD = dyn_cast_or_null<CXXRecordDecl>(InnerRD);
-      if (InnerRD && (!InnerCXXRD || InnerCXXRD->isAggregate())) {
-        // Recursively print the values of members of aggregate record type.
-        if (callPrintFunction(Format, Args) ||
-            dumpRecordValue(InnerRD, Field.get(), FieldIndentArg, Depth + 1))
-          return true;
-      } else {
-        Format += " ";
-        if (appendFormatSpecifier(FD->getType(), Format)) {
-          // We know how to print this field.
-          Args.push_back(Field.get());
-        } else {
-          // We don't know how to print this field. Print out its address
-          // with a format specifier that a smart tool will be able to
-          // recognize and treat specially.
-          Format += "*%p";
-          ExprResult FieldAddr =
-              S.BuildUnaryOp(nullptr, Loc, UO_AddrOf, Field.get());
-          if (FieldAddr.isInvalid())
-            return true;
-          Args.push_back(FieldAddr.get());
-        }
-        Format += "\n";
-        if (callPrintFunction(Format, Args))
-          return true;
-      }
-    }
-
-    return RecordIndent ? callPrintFunction("%s}\n", RecordIndent)
-                        : callPrintFunction("}\n");
-  }
-
-  Expr *buildWrapper() {
-    auto *Wrapper = PseudoObjectExpr::Create(S.Context, TheCall, Actions,
-                                             PseudoObjectExpr::NoResult);
-    TheCall->setType(Wrapper->getType());
-    TheCall->setValueKind(Wrapper->getValueKind());
-    return Wrapper;
-  }
-};
-} // namespace
-
-static ExprResult BuiltinDumpStruct(Sema &S, CallExpr *TheCall) {
-  if (S.checkArgCountAtLeast(TheCall, 2))
-    return ExprError();
-
-  ExprResult PtrArgResult = S.DefaultLvalueConversion(TheCall->getArg(0));
-  if (PtrArgResult.isInvalid())
-    return ExprError();
-  TheCall->setArg(0, PtrArgResult.get());
-
-  // First argument should be a pointer to a struct.
-  QualType PtrArgType = PtrArgResult.get()->getType();
-  if (!PtrArgType->isPointerType() ||
-      !PtrArgType->getPointeeType()->isRecordType()) {
-    S.Diag(PtrArgResult.get()->getBeginLoc(),
-           diag::err_expected_struct_pointer_argument)
-        << 1 << TheCall->getDirectCallee() << PtrArgType;
-    return ExprError();
-  }
-  QualType Pointee = PtrArgType->getPointeeType();
-  const RecordDecl *RD = Pointee->getAsRecordDecl();
-  // Try to instantiate the class template as appropriate; otherwise, access to
-  // its data() may lead to a crash.
-  if (S.RequireCompleteType(PtrArgResult.get()->getBeginLoc(), Pointee,
-                            diag::err_incomplete_type))
-    return ExprError();
-  // Second argument is a callable, but we can't fully validate it until we try
-  // calling it.
-  QualType FnArgType = TheCall->getArg(1)->getType();
-  if (!FnArgType->isFunctionType() && !FnArgType->isFunctionPointerType() &&
-      !FnArgType->isBlockPointerType() &&
-      !(S.getLangOpts().CPlusPlus && FnArgType->isRecordType())) {
-    auto *BT = FnArgType->getAs<BuiltinType>();
-    switch (BT ? BT->getKind() : BuiltinType::Void) {
-    case BuiltinType::Dependent:
-    case BuiltinType::Overload:
-    case BuiltinType::BoundMember:
-    case BuiltinType::PseudoObject:
-    case BuiltinType::UnknownAny:
-    case BuiltinType::BuiltinFn:
-      // This might be a callable.
-      break;
-
-    default:
-      S.Diag(TheCall->getArg(1)->getBeginLoc(),
-             diag::err_expected_callable_argument)
-          << 2 << TheCall->getDirectCallee() << FnArgType;
-      return ExprError();
-    }
-  }
-
-  BuiltinDumpStructGenerator Generator(S, TheCall);
-
-  // Wrap parentheses around the given pointer. This is not necessary for
-  // correct code generation, but it means that when we pretty-print the call
-  // arguments in our diagnostics we will produce '(&s)->n' instead of the
-  // incorrect '&s->n'.
-  Expr *PtrArg = PtrArgResult.get();
-  PtrArg = new (S.Context)
-      ParenExpr(PtrArg->getBeginLoc(),
-                S.getLocForEndOfToken(PtrArg->getEndLoc()), PtrArg);
-  if (Generator.dumpUnnamedRecord(RD, PtrArg, 0))
-    return ExprError();
-
-  return Generator.buildWrapper();
-}
-
-static bool BuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) {
-  if (S.checkArgCount(BuiltinCall, 2))
-    return true;
-
-  SourceLocation BuiltinLoc = BuiltinCall->getBeginLoc();
-  Expr *Builtin = BuiltinCall->getCallee()->IgnoreImpCasts();
-  Expr *Call = BuiltinCall->getArg(0);
-  Expr *Chain = BuiltinCall->getArg(1);
-
-  if (Call->getStmtClass() != Stmt::CallExprClass) {
-    S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_not_call)
-        << Call->getSourceRange();
-    return true;
-  }
-
-  auto CE = cast<CallExpr>(Call);
-  if (CE->getCallee()->getType()->isBlockPointerType()) {
-    S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_block_call)
-        << Call->getSourceRange();
-    return true;
-  }
-
-  const Decl *TargetDecl = CE->getCalleeDecl();
-  if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl))
-    if (FD->getBuiltinID()) {
-      S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_builtin_call)
-          << Call->getSourceRange();
-      return true;
-    }
-
-  if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens())) {
-    S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_pdtor_call)
-        << Call->getSourceRange();
-    return true;
-  }
-
-  ExprResult ChainResult = S.UsualUnaryConversions(Chain);
-  if (ChainResult.isInvalid())
-    return true;
-  if (!ChainResult.get()->getType()->isPointerType()) {
-    S.Diag(BuiltinLoc, diag::err_second_argument_to_cwsc_not_pointer)
-        << Chain->getSourceRange();
-    return true;
-  }
-
-  QualType ReturnTy = CE->getCallReturnType(S.Context);
-  QualType ArgTys[2] = { ReturnTy, ChainResult.get()->getType() };
-  QualType BuiltinTy = S.Context.getFunctionType(
-      ReturnTy, ArgTys, FunctionProtoType::ExtProtoInfo());
-  QualType BuiltinPtrTy = S.Context.getPointerType(BuiltinTy);
-
-  Builtin =
-      S.ImpCastExprToType(Builtin, BuiltinPtrTy, CK_BuiltinFnToFnPtr).get();
-
-  BuiltinCall->setType(CE->getType());
-  BuiltinCall->setValueKind(CE->getValueKind());
-  BuiltinCall->setObjectKind(CE->getObjectKind());
-  BuiltinCall->setCallee(Builtin);
-  BuiltinCall->setArg(1, ChainResult.get());
-
-  return false;
-}
-
-namespace {
-
-class ScanfDiagnosticFormatHandler
-    : public analyze_format_string::FormatStringHandler {
-  // Accepts the argument index (relative to the first destination index) of the
-  // argument whose size we want.
-  using ComputeSizeFunction =
-      llvm::function_ref<std::optional<llvm::APSInt>(unsigned)>;
-
-  // Accepts the argument index (relative to the first destination index), the
-  // destination size, and the source size).
-  using DiagnoseFunction =
-      llvm::function_ref<void(unsigned, unsigned, unsigned)>;
-
-  ComputeSizeFunction ComputeSizeArgument;
-  DiagnoseFunction Diagnose;
-
-public:
-  ScanfDiagnosticFormatHandler(ComputeSizeFunction ComputeSizeArgument,
-                               DiagnoseFunction Diagnose)
-      : ComputeSizeArgument(ComputeSizeArgument), Diagnose(Diagnose) {}
-
-  bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
-                            const char *StartSpecifier,
-                            unsigned specifierLen) override {
-    if (!FS.consumesDataArgument())
-      return true;
-
-    unsigned NulByte = 0;
-    switch ((FS.getConversionSpecifier().getKind())) {
-    default:
-      return true;
-    case analyze_format_string::ConversionSpecifier::sArg:
-    case analyze_format_string::ConversionSpecifier::ScanListArg:
-      NulByte = 1;
-      break;
-    case analyze_format_string::ConversionSpecifier::cArg:
-      break;
-    }
-
-    analyze_format_string::OptionalAmount FW = FS.getFieldWidth();
-    if (FW.getHowSpecified() !=
-        analyze_format_string::OptionalAmount::HowSpecified::Constant)
-      return true;
-
-    unsigned SourceSize = FW.getConstantAmount() + NulByte;
-
-    std::optional<llvm::APSInt> DestSizeAPS =
-        ComputeSizeArgument(FS.getArgIndex());
-    if (!DestSizeAPS)
-      return true;
-
-    unsigned DestSize = DestSizeAPS->getZExtValue();
-
-    if (DestSize < SourceSize)
-      Diagnose(FS.getArgIndex(), DestSize, SourceSize);
-
-    return true;
-  }
-};
-
-class EstimateSizeFormatHandler
-    : public analyze_format_string::FormatStringHandler {
-  size_t Size;
-  /// Whether the format string contains Linux kernel's format specifier
-  /// extension.
-  bool IsKernelCompatible = true;
-
-public:
-  EstimateSizeFormatHandler(StringRef Format)
-      : Size(std::min(Format.find(0), Format.size()) +
-             1 /* null byte always written by sprintf */) {}
-
-  bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
-                             const char *, unsigned SpecifierLen,
-                             const TargetInfo &) override {
-
-    const size_t FieldWidth = computeFieldWidth(FS);
-    const size_t Precision = computePrecision(FS);
-
-    // The actual format.
-    switch (FS.getConversionSpecifier().getKind()) {
-    // Just a char.
-    case analyze_format_string::ConversionSpecifier::cArg:
-    case analyze_format_string::ConversionSpecifier::CArg:
-      Size += std::max(FieldWidth, (size_t)1);
-      break;
-    // Just an integer.
-    case analyze_format_string::ConversionSpecifier::dArg:
-    case analyze_format_string::ConversionSpecifier::DArg:
-    case analyze_format_string::ConversionSpecifier::iArg:
-    case analyze_format_string::ConversionSpecifier::oArg:
-    case analyze_format_string::ConversionSpecifier::OArg:
-    case analyze_format_string::ConversionSpecifier::uArg:
-    case analyze_format_string::ConversionSpecifier::UArg:
-    case analyze_format_string::ConversionSpecifier::xArg:
-    case analyze_format_string::ConversionSpecifier::XArg:
-      Size += std::max(FieldWidth, Precision);
-      break;
-
-    // %g style conversion switches between %f or %e style dynamically.
-    // %g removes trailing zeros, and does not print decimal point if there are
-    // no digits that follow it. Thus %g can print a single digit.
-    // FIXME: If it is alternative form:
-    // For g and G conversions, trailing zeros are not removed from the result.
-    case analyze_format_string::ConversionSpecifier::gArg:
-    case analyze_format_string::ConversionSpecifier::GArg:
-      Size += 1;
-      break;
-
-    // Floating point number in the form '[+]ddd.ddd'.
-    case analyze_format_string::ConversionSpecifier::fArg:
-    case analyze_format_string::ConversionSpecifier::FArg:
-      Size += std::max(FieldWidth, 1 /* integer part */ +
-                                       (Precision ? 1 + Precision
-                                                  : 0) /* period + decimal */);
-      break;
-
-    // Floating point number in the form '[-]d.ddde[+-]dd'.
-    case analyze_format_string::ConversionSpecifier::eArg:
-    case analyze_format_string::ConversionSpecifier::EArg:
-      Size +=
-          std::max(FieldWidth,
-                   1 /* integer part */ +
-                       (Precision ? 1 + Precision : 0) /* period + decimal */ +
-                       1 /* e or E letter */ + 2 /* exponent */);
-      break;
-
-    // Floating point number in the form '[-]0xh.hhhhp±dd'.
-    case analyze_format_string::ConversionSpecifier::aArg:
-    case analyze_format_string::ConversionSpecifier::AArg:
-      Size +=
-          std::max(FieldWidth,
-                   2 /* 0x */ + 1 /* integer part */ +
-                       (Precision ? 1 + Precision : 0) /* period + decimal */ +
-                       1 /* p or P letter */ + 1 /* + or - */ + 1 /* value */);
-      break;
-
-    // Just a string.
-    case analyze_format_string::ConversionSpecifier::sArg:
-    case analyze_format_string::ConversionSpecifier::SArg:
-      Size += FieldWidth;
-      break;
-
-    // Just a pointer in the form '0xddd'.
-    case analyze_format_string::ConversionSpecifier::pArg:
-      // Linux kernel has its own extesion for `%p` specifier.
-      // Kernel Document:
-      // https://docs.kernel.org/core-api/printk-formats.html#pointer-types
-      IsKernelCompatible = false;
-      Size += std::max(FieldWidth, 2 /* leading 0x */ + Precision);
-      break;
-
-    // A plain percent.
-    case analyze_format_string::ConversionSpecifier::PercentArg:
-      Size += 1;
-      break;
-
-    default:
-      break;
-    }
-
-    // If field width is specified, the sign/space is already accounted for
-    // within the field width, so no additional size is needed.
-    if ((FS.hasPlusPrefix() || FS.hasSpacePrefix()) && FieldWidth == 0)
-      Size += 1;
-
-    if (FS.hasAlternativeForm()) {
-      switch (FS.getConversionSpecifier().getKind()) {
-      // For o conversion, it increases the precision, if and only if necessary,
-      // to force the first digit of the result to be a zero
-      // (if the value and precision are both 0, a single 0 is printed)
-      case analyze_format_string::ConversionSpecifier::oArg:
-      // For b conversion, a nonzero result has 0b prefixed to it.
-      case analyze_format_string::ConversionSpecifier::bArg:
-      // For x (or X) conversion, a nonzero result has 0x (or 0X) prefixed to
-      // it.
-      case analyze_format_string::ConversionSpecifier::xArg:
-      case analyze_format_string::ConversionSpecifier::XArg:
-        // Note: even when the prefix is added, if
-        // (prefix_width <= FieldWidth - formatted_length) holds,
-        // the prefix does not increase the format
-        // size. e.g.(("%#3x", 0xf) is "0xf")
-
-        // If the result is zero, o, b, x, X adds nothing.
-        break;
-      // For a, A, e, E, f, F, g, and G conversions,
-      // the result of converting a floating-point number always contains a
-      // decimal-point
-      case analyze_format_string::ConversionSpecifier::aArg:
-      case analyze_format_string::ConversionSpecifier::AArg:
-      case analyze_format_string::ConversionSpecifier::eArg:
-      case analyze_format_string::ConversionSpecifier::EArg:
-      case analyze_format_string::ConversionSpecifier::fArg:
-      case analyze_format_string::ConversionSpecifier::FArg:
-      case analyze_format_string::ConversionSpecifier::gArg:
-      case analyze_format_string::ConversionSpecifier::GArg:
-        Size += (Precision ? 0 : 1);
-        break;
-      // For other conversions, the behavior is undefined.
-      default:
-        break;
-      }
-    }
-    assert(SpecifierLen <= Size && "no underflow");
-    Size -= SpecifierLen;
-    return true;
-  }
-
-  size_t getSizeLowerBound() const { return Size; }
-  bool isKernelCompatible() const { return IsKernelCompatible; }
-
-private:
-  static size_t computeFieldWidth(const analyze_printf::PrintfSpecifier &FS) {
-    const analyze_format_string::OptionalAmount &FW = FS.getFieldWidth();
-    size_t FieldWidth = 0;
-    if (FW.getHowSpecified() == analyze_format_string::OptionalAmount::Constant)
-      FieldWidth = FW.getConstantAmount();
-    return FieldWidth;
-  }
-
-  static size_t computePrecision(const analyze_printf::PrintfSpecifier &FS) {
-    const analyze_format_string::OptionalAmount &FW = FS.getPrecision();
-    size_t Precision = 0;
-
-    // See man 3 printf for default precision value based on the specifier.
-    switch (FW.getHowSpecified()) {
-    case analyze_format_string::OptionalAmount::NotSpecified:
-      switch (FS.getConversionSpecifier().getKind()) {
-      default:
-        break;
-      case analyze_format_string::ConversionSpecifier::dArg: // %d
-      case analyze_format_string::ConversionSpecifier::DArg: // %D
-      case analyze_format_string::ConversionSpecifier::iArg: // %i
-        Precision = 1;
-        break;
-      case analyze_format_string::ConversionSpecifier::oArg: // %d
-      case analyze_format_string::ConversionSpecifier::OArg: // %D
-      case analyze_format_string::ConversionSpecifier::uArg: // %d
-      case analyze_format_string::ConversionSpecifier::UArg: // %D
-      case analyze_format_string::ConversionSpecifier::xArg: // %d
-      case analyze_format_string::ConversionSpecifier::XArg: // %D
-        Precision = 1;
-        break;
-      case analyze_format_string::ConversionSpecifier::fArg: // %f
-      case analyze_format_string::ConversionSpecifier::FArg: // %F
-      case analyze_format_string::ConversionSpecifier::eArg: // %e
-      case analyze_format_string::ConversionSpecifier::EArg: // %E
-      case analyze_format_string::ConversionSpecifier::gArg: // %g
-      case analyze_format_string::ConversionSpecifier::GArg: // %G
-        Precision = 6;
-        break;
-      case analyze_format_string::ConversionSpecifier::pArg: // %d
-        Precision = 1;
-        break;
-      }
-      break;
-    case analyze_format_string::OptionalAmount::Constant:
-      Precision = FW.getConstantAmount();
-      break;
-    default:
-      break;
-    }
-    return Precision;
-  }
-};
-
-} // namespace
-
-static bool ProcessFormatStringLiteral(const Expr *FormatExpr,
-                                       StringRef &FormatStrRef, size_t &StrLen,
-                                       ASTContext &Context) {
-  if (const auto *Format = dyn_cast<StringLiteral>(FormatExpr);
-      Format && (Format->isOrdinary() || Format->isUTF8())) {
-    FormatStrRef = Format->getString();
-    const ConstantArrayType *T =
-        Context.getAsConstantArrayType(Format->getType());
-    assert(T && "String literal not of constant array type!");
-    size_t TypeSize = T->getZExtSize();
-    // In case there's a null byte somewhere.
-    StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, FormatStrRef.find(0));
-    return true;
-  }
-  return false;
-}
-
-void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
-                                               CallExpr *TheCall) {
-  if (TheCall->isValueDependent() || TheCall->isTypeDependent() ||
-      isConstantEvaluatedContext())
-    return;
-
-  bool UseDABAttr = false;
-  const FunctionDecl *UseDecl = FD;
-
-  const auto *DABAttr = FD->getAttr<DiagnoseAsBuiltinAttr>();
-  if (DABAttr) {
-    UseDecl = DABAttr->getFunction();
-    assert(UseDecl && "Missing FunctionDecl in DiagnoseAsBuiltin attribute!");
-    UseDABAttr = true;
-  }
-
-  unsigned BuiltinID = UseDecl->getBuiltinID(/*ConsiderWrappers=*/true);
-
-  if (!BuiltinID)
-    return;
-
-  const TargetInfo &TI = getASTContext().getTargetInfo();
-  unsigned SizeTypeWidth = TI.getTypeWidth(TI.getSizeType());
-
-  auto TranslateIndex = [&](unsigned Index) -> std::optional<unsigned> {
-    // If we refer to a diagnose_as_builtin attribute, we need to change the
-    // argument index to refer to the arguments of the called function. Unless
-    // the index is out of bounds, which presumably means it's a variadic
-    // function.
-    if (!UseDABAttr)
-      return Index;
-    unsigned DABIndices = DABAttr->argIndices_size();
-    unsigned NewIndex = Index < DABIndices
-                            ? DABAttr->argIndices_begin()[Index]
-                            : Index - DABIndices + FD->getNumParams();
-    if (NewIndex >= TheCall->getNumArgs())
-      return std::nullopt;
-    return NewIndex;
-  };
-
-  auto ComputeExplicitObjectSizeArgument =
-      [&](unsigned Index) -> std::optional<llvm::APSInt> {
-    std::optional<unsigned> IndexOptional = TranslateIndex(Index);
-    if (!IndexOptional)
-      return std::nullopt;
-    unsigned NewIndex = *IndexOptional;
-    Expr::EvalResult Result;
-    Expr *SizeArg = TheCall->getArg(NewIndex);
-    if (!SizeArg->EvaluateAsInt(Result, getASTContext()))
-      return std::nullopt;
-    llvm::APSInt Integer = Result.Val.getInt();
-    Integer.setIsUnsigned(true);
-    return Integer;
-  };
-
-  auto ComputeSizeArgument =
-      [&](unsigned Index) -> std::optional<llvm::APSInt> {
-    // If the parameter has a pass_object_size attribute, then we should use its
-    // (potentially) more strict checking mode. Otherwise, conservatively assume
-    // type 0.
-    int BOSType = 0;
-    // This check can fail for variadic functions.
-    if (Index < FD->getNumParams()) {
-      if (const auto *POS =
-              FD->getParamDecl(Index)->getAttr<PassObjectSizeAttr>())
-        BOSType = POS->getType();
-    }
-
-    std::optional<unsigned> IndexOptional = TranslateIndex(Index);
-    if (!IndexOptional)
-      return std::nullopt;
-    unsigned NewIndex = *IndexOptional;
-
-    if (NewIndex >= TheCall->getNumArgs())
-      return std::nullopt;
-
-    const Expr *ObjArg = TheCall->getArg(NewIndex);
-    if (std::optional<uint64_t> ObjSize =
-            ObjArg->tryEvaluateObjectSize(getASTContext(), BOSType)) {
-      // Get the object size in the target's size_t width.
-      return llvm::APSInt::getUnsigned(*ObjSize).extOrTrunc(SizeTypeWidth);
-    }
-    return std::nullopt;
-  };
-
-  auto ComputeStrLenArgument =
-      [&](unsigned Index) -> std::optional<llvm::APSInt> {
-    std::optional<unsigned> IndexOptional = TranslateIndex(Index);
-    if (!IndexOptional)
-      return std::nullopt;
-    unsigned NewIndex = *IndexOptional;
-
-    const Expr *ObjArg = TheCall->getArg(NewIndex);
-
-    if (std::optional<uint64_t> Result =
-            ObjArg->tryEvaluateStrLen(getASTContext())) {
-      // Add 1 for null byte.
-      return llvm::APSInt::getUnsigned(*Result + 1).extOrTrunc(SizeTypeWidth);
-    }
-    return std::nullopt;
-  };
-
-  std::optional<llvm::APSInt> SourceSize;
-  std::optional<llvm::APSInt> DestinationSize;
-  unsigned DiagID = 0;
-  bool IsChkVariant = false;
-
-  auto GetFunctionName = [&]() {
-    std::string FunctionNameStr =
-        getASTContext().BuiltinInfo.getName(BuiltinID);
-    llvm::StringRef FunctionName = FunctionNameStr;
-    // Skim off the details of whichever builtin was called to produce a better
-    // diagnostic, as it's unlikely that the user wrote the __builtin
-    // explicitly.
-    if (IsChkVariant) {
-      FunctionName = FunctionName.drop_front(std::strlen("__builtin___"));
-      FunctionName = FunctionName.drop_back(std::strlen("_chk"));
-    } else {
-      FunctionName.consume_front("__builtin_");
-    }
-    return FunctionName.str();
-  };
-
-  switch (BuiltinID) {
-  default:
-    return;
-  case Builtin::BI__builtin_strcat:
-  case Builtin::BIstrcat:
-  case Builtin::BI__builtin_stpcpy:
-  case Builtin::BIstpcpy:
-  case Builtin::BI__builtin_strcpy:
-  case Builtin::BIstrcpy: {
-    DiagID = diag::warn_fortify_strlen_overflow;
-    SourceSize = ComputeStrLenArgument(1);
-    DestinationSize = ComputeSizeArgument(0);
-    break;
-  }
-
-  case Builtin::BI__builtin___strcat_chk:
-  case Builtin::BI__builtin___stpcpy_chk:
-  case Builtin::BI__builtin___strcpy_chk: {
-    DiagID = diag::warn_fortify_strlen_overflow;
-    SourceSize = ComputeStrLenArgument(1);
-    DestinationSize = ComputeExplicitObjectSizeArgument(2);
-    IsChkVariant = true;
-    break;
-  }
-
-  case Builtin::BIscanf:
-  case Builtin::BIfscanf:
-  case Builtin::BIsscanf: {
-    unsigned FormatIndex = 1;
-    unsigned DataIndex = 2;
-    if (BuiltinID == Builtin::BIscanf) {
-      FormatIndex = 0;
-      DataIndex = 1;
-    }
-
-    const auto *FormatExpr =
-        TheCall->getArg(FormatIndex)->IgnoreParenImpCasts();
-
-    StringRef FormatStrRef;
-    size_t StrLen;
-    if (!ProcessFormatStringLiteral(FormatExpr, FormatStrRef, StrLen, Context))
-      return;
-
-    auto Diagnose = [&](unsigned ArgIndex, unsigned DestSize,
-                        unsigned SourceSize) {
-      DiagID = diag::warn_fortify_scanf_overflow;
-      unsigned Index = ArgIndex + DataIndex;
-      std::string FunctionName = GetFunctionName();
-      DiagRuntimeBehavior(TheCall->getArg(Index)->getBeginLoc(), TheCall,
-                          PDiag(DiagID) << FunctionName << (Index + 1)
-                                        << DestSize << SourceSize);
-    };
-
-    auto ShiftedComputeSizeArgument = [&](unsigned Index) {
-      return ComputeSizeArgument(Index + DataIndex);
-    };
-    ScanfDiagnosticFormatHandler H(ShiftedComputeSizeArgument, Diagnose);
-    const char *FormatBytes = FormatStrRef.data();
-    analyze_format_string::ParseScanfString(H, FormatBytes,
-                                            FormatBytes + StrLen, getLangOpts(),
-                                            Context.getTargetInfo());
-
-    // Unlike the other cases, in this one we have already issued the diagnostic
-    // here, so no need to continue (because unlike the other cases, here the
-    // diagnostic refers to the argument number).
-    return;
-  }
-
-  case Builtin::BIsprintf:
-  case Builtin::BI__builtin___sprintf_chk: {
-    size_t FormatIndex = BuiltinID == Builtin::BIsprintf ? 1 : 3;
-    auto *FormatExpr = TheCall->getArg(FormatIndex)->IgnoreParenImpCasts();
-
-    StringRef FormatStrRef;
-    size_t StrLen;
-    if (ProcessFormatStringLiteral(FormatExpr, FormatStrRef, StrLen, Context)) {
-      EstimateSizeFormatHandler H(FormatStrRef);
-      const char *FormatBytes = FormatStrRef.data();
-      if (!analyze_format_string::ParsePrintfString(
-              H, FormatBytes, FormatBytes + StrLen, getLangOpts(),
-              Context.getTargetInfo(), false)) {
-        DiagID = H.isKernelCompatible()
-                     ? diag::warn_format_overflow
-                     : diag::warn_format_overflow_non_kprintf;
-        SourceSize = llvm::APSInt::getUnsigned(H.getSizeLowerBound())
-                         .extOrTrunc(SizeTypeWidth);
-        if (BuiltinID == Builtin::BI__builtin___sprintf_chk) {
-          DestinationSize = ComputeExplicitObjectSizeArgument(2);
-          IsChkVariant = true;
-        } else {
-          DestinationSize = ComputeSizeArgument(0);
-        }
-        break;
-      }
-    }
-    return;
-  }
-  case Builtin::BI__builtin___memcpy_chk:
-  case Builtin::BI__builtin___memmove_chk:
-  case Builtin::BI__builtin___memset_chk:
-  case Builtin::BI__builtin___strlcat_chk:
-  case Builtin::BI__builtin___strlcpy_chk:
-  case Builtin::BI__builtin___strncat_chk:
-  case Builtin::BI__builtin___strncpy_chk:
-  case Builtin::BI__builtin___stpncpy_chk:
-  case Builtin::BI__builtin___memccpy_chk:
-  case Builtin::BI__builtin___mempcpy_chk: {
-    DiagID = diag::warn_builtin_chk_overflow;
-    SourceSize = ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 2);
-    DestinationSize =
-        ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1);
-    IsChkVariant = true;
-    break;
-  }
-
-  case Builtin::BI__builtin___snprintf_chk:
-  case Builtin::BI__builtin___vsnprintf_chk: {
-    DiagID = diag::warn_builtin_chk_overflow;
-    SourceSize = ComputeExplicitObjectSizeArgument(1);
-    DestinationSize = ComputeExplicitObjectSizeArgument(3);
-    IsChkVariant = true;
-    break;
-  }
-
-  case Builtin::BIstrncat:
-  case Builtin::BI__builtin_strncat:
-  case Builtin::BIstrncpy:
-  case Builtin::BI__builtin_strncpy:
-  case Builtin::BIstpncpy:
-  case Builtin::BI__builtin_stpncpy: {
-    // Whether these functions overflow depends on the runtime strlen of the
-    // string, not just the buffer size, so emitting the "always overflow"
-    // diagnostic isn't quite right. We should still diagnose passing a buffer
-    // size larger than the destination buffer though; this is a runtime abort
-    // in _FORTIFY_SOURCE mode, and is quite suspicious otherwise.
-    DiagID = diag::warn_fortify_source_size_mismatch;
-    SourceSize = ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1);
-    DestinationSize = ComputeSizeArgument(0);
-    break;
-  }
-
-  case Builtin::BImemcpy:
-  case Builtin::BI__builtin_memcpy:
-  case Builtin::BImemmove:
-  case Builtin::BI__builtin_memmove:
-  case Builtin::BImemset:
-  case Builtin::BI__builtin_memset:
-  case Builtin::BImempcpy:
-  case Builtin::BI__builtin_mempcpy: {
-    DiagID = diag::warn_fortify_source_overflow;
-    SourceSize = ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1);
-    DestinationSize = ComputeSizeArgument(0);
-    break;
-  }
-  case Builtin::BIsnprintf:
-  case Builtin::BI__builtin_snprintf:
-  case Builtin::BIvsnprintf:
-  case Builtin::BI__builtin_vsnprintf: {
-    DiagID = diag::warn_fortify_source_size_mismatch;
-    SourceSize = ComputeExplicitObjectSizeArgument(1);
-    const auto *FormatExpr = TheCall->getArg(2)->IgnoreParenImpCasts();
-    StringRef FormatStrRef;
-    size_t StrLen;
-    if (SourceSize &&
-        ProcessFormatStringLiteral(FormatExpr, FormatStrRef, StrLen, Context)) {
-      EstimateSizeFormatHandler H(FormatStrRef);
-      const char *FormatBytes = FormatStrRef.data();
-      if (!analyze_format_string::ParsePrintfString(
-              H, FormatBytes, FormatBytes + StrLen, getLangOpts(),
-              Context.getTargetInfo(), /*isFreeBSDKPrintf=*/false)) {
-        llvm::APSInt FormatSize =
-            llvm::APSInt::getUnsigned(H.getSizeLowerBound())
-                .extOrTrunc(SizeTypeWidth);
-        if (FormatSize > *SourceSize && *SourceSize != 0) {
-          unsigned TruncationDiagID =
-              H.isKernelCompatible() ? diag::warn_format_truncation
-                                     : diag::warn_format_truncation_non_kprintf;
-          SmallString<16> SpecifiedSizeStr;
-          SmallString<16> FormatSizeStr;
-          SourceSize->toString(SpecifiedSizeStr, /*Radix=*/10);
-          FormatSize.toString(FormatSizeStr, /*Radix=*/10);
-          DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall,
-                              PDiag(TruncationDiagID)
-                                  << GetFunctionName() << SpecifiedSizeStr
-                                  << FormatSizeStr);
-        }
-      }
-    }
-    DestinationSize = ComputeSizeArgument(0);
-  }
-  }
-
-  if (!SourceSize || !DestinationSize ||
-      llvm::APSInt::compareValues(*SourceSize, *DestinationSize) <= 0)
-    return;
-
-  std::string FunctionName = GetFunctionName();
-
-  SmallString<16> DestinationStr;
-  SmallString<16> SourceStr;
-  DestinationSize->toString(DestinationStr, /*Radix=*/10);
-  SourceSize->toString(SourceStr, /*Radix=*/10);
-  DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall,
-                      PDiag(DiagID)
-                          << FunctionName << DestinationStr << SourceStr);
-}
-
-static bool BuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall,
-                                 Scope::ScopeFlags NeededScopeFlags,
-                                 unsigned DiagID) {
-  // Scopes aren't available during instantiation. Fortunately, builtin
-  // functions cannot be template args so they cannot be formed through template
-  // instantiation. Therefore checking once during the parse is sufficient.
-  if (SemaRef.inTemplateInstantiation())
-    return false;
-
-  Scope *S = SemaRef.getCurScope();
-  while (S && !S->isSEHExceptScope())
-    S = S->getParent();
-  if (!S || !(S->getFlags() & NeededScopeFlags)) {
-    auto *DRE = cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
-    SemaRef.Diag(TheCall->getExprLoc(), DiagID)
-        << DRE->getDecl()->getIdentifier();
-    return true;
-  }
-
-  return false;
-}
-
-// In OpenCL, __builtin_alloca_* should return a pointer to address space
-// that corresponds to the stack address space i.e private address space.
-static void builtinAllocaAddrSpace(Sema &S, CallExpr *TheCall) {
-  QualType RT = TheCall->getType();
-  assert((RT->isPointerType() && !(RT->getPointeeType().hasAddressSpace())) &&
-         "__builtin_alloca has invalid address space");
-
-  RT = RT->getPointeeType();
-  RT = S.Context.getAddrSpaceQualType(RT, LangAS::opencl_private);
-  TheCall->setType(S.Context.getPointerType(RT));
-}
-
-static bool checkBuiltinInferAllocToken(Sema &S, CallExpr *TheCall) {
-  if (S.checkArgCountAtLeast(TheCall, 1))
-    return true;
-
-  for (Expr *Arg : TheCall->arguments()) {
-    // If argument is dependent on a template parameter, we can't resolve now.
-    if (Arg->isTypeDependent() || Arg->isValueDependent())
-      continue;
-    // Reject void types.
-    QualType ArgTy = Arg->IgnoreParenImpCasts()->getType();
-    if (ArgTy->isVoidType())
-      return S.Diag(Arg->getBeginLoc(), diag::err_param_with_void_type);
-  }
-
-  TheCall->setType(S.Context.getSizeType());
-  return false;
-}
-
-namespace {
-enum PointerAuthOpKind {
-  PAO_Strip,
-  PAO_Sign,
-  PAO_Auth,
-  PAO_SignGeneric,
-  PAO_Discriminator,
-  PAO_BlendPointer,
-  PAO_BlendInteger
-};
-}
-
-bool Sema::checkPointerAuthEnabled(SourceLocation Loc, SourceRange Range) {
-  if (getLangOpts().PointerAuthIntrinsics)
-    return false;
-
-  Diag(Loc, diag::err_ptrauth_disabled) << Range;
-  return true;
-}
-
-static bool checkPointerAuthEnabled(Sema &S, Expr *E) {
-  return S.checkPointerAuthEnabled(E->getExprLoc(), E->getSourceRange());
-}
-
-static bool checkPointerAuthKey(Sema &S, Expr *&Arg) {
-  // Convert it to type 'int'.
-  if (convertArgumentToType(S, Arg, S.Context.IntTy))
-    return true;
-
-  // Value-dependent expressions are okay; wait for template instantiation.
-  if (Arg->isValueDependent())
-    return false;
-
-  unsigned KeyValue;
-  return S.checkConstantPointerAuthKey(Arg, KeyValue);
-}
-
-bool Sema::checkConstantPointerAuthKey(Expr *Arg, unsigned &Result) {
-  // Attempt to constant-evaluate the expression.
-  std::optional<llvm::APSInt> KeyValue = Arg->getIntegerConstantExpr(Context);
-  if (!KeyValue) {
-    Diag(Arg->getExprLoc(), diag::err_expr_not_ice)
-        << 0 << Arg->getSourceRange();
-    return true;
-  }
-
-  // Ask the target to validate the key parameter.
-  if (!Context.getTargetInfo().validatePointerAuthKey(*KeyValue)) {
-    llvm::SmallString<32> Value;
-    {
-      llvm::raw_svector_ostream Str(Value);
-      Str << *KeyValue;
-    }
-
-    Diag(Arg->getExprLoc(), diag::err_ptrauth_invalid_key)
-        << Value << Arg->getSourceRange();
-    return true;
-  }
-
-  Result = KeyValue->getZExtValue();
-  return false;
-}
-
-bool Sema::checkPointerAuthDiscriminatorArg(Expr *Arg,
-                                            PointerAuthDiscArgKind Kind,
-                                            unsigned &IntVal) {
-  if (!Arg) {
-    IntVal = 0;
-    return true;
-  }
-
-  std::optional<llvm::APSInt> Result = Arg->getIntegerConstantExpr(Context);
-  if (!Result) {
-    Diag(Arg->getExprLoc(), diag::err_ptrauth_arg_not_ice);
-    return false;
-  }
-
-  unsigned Max;
-  bool IsAddrDiscArg = false;
-
-  switch (Kind) {
-  case PointerAuthDiscArgKind::Addr:
-    Max = 1;
-    IsAddrDiscArg = true;
-    break;
-  case PointerAuthDiscArgKind::Extra:
-    Max = PointerAuthQualifier::MaxDiscriminator;
-    break;
-  };
-
-  if (*Result < 0 || *Result > Max) {
-    if (IsAddrDiscArg)
-      Diag(Arg->getExprLoc(), diag::err_ptrauth_address_discrimination_invalid)
-          << Result->getExtValue();
-    else
-      Diag(Arg->getExprLoc(), diag::err_ptrauth_extra_discriminator_invalid)
-          << Result->getExtValue() << Max;
-
-    return false;
-  };
-
-  IntVal = Result->getZExtValue();
-  return true;
-}
-
-static std::pair<const ValueDecl *, CharUnits>
-findConstantBaseAndOffset(Sema &S, Expr *E) {
-  // Must evaluate as a pointer.
-  Expr::EvalResult Result;
-  if (!E->EvaluateAsRValue(Result, S.Context) || !Result.Val.isLValue())
-    return {nullptr, CharUnits()};
-
-  const auto *BaseDecl =
-      Result.Val.getLValueBase().dyn_cast<const ValueDecl *>();
-  if (!BaseDecl)
-    return {nullptr, CharUnits()};
-
-  return {BaseDecl, Result.Val.getLValueOffset()};
-}
-
-static bool checkPointerAuthValue(Sema &S, Expr *&Arg, PointerAuthOpKind OpKind,
-                                  bool RequireConstant = false) {
-  if (Arg->hasPlaceholderType()) {
-    ExprResult R = S.CheckPlaceholderExpr(Arg);
-    if (R.isInvalid())
-      return true;
-    Arg = R.get();
-  }
-
-  auto AllowsPointer = [](PointerAuthOpKind OpKind) {
-    return OpKind != PAO_BlendInteger;
-  };
-  auto AllowsInteger = [](PointerAuthOpKind OpKind) {
-    return OpKind == PAO_Discriminator || OpKind == PAO_BlendInteger ||
-           OpKind == PAO_SignGeneric;
-  };
-
-  // Require the value to have the right range of type.
-  QualType ExpectedTy;
-  if (AllowsPointer(OpKind) && Arg->getType()->isPointerType()) {
-    ExpectedTy = Arg->getType().getUnqualifiedType();
-  } else if (AllowsPointer(OpKind) && Arg->getType()->isNullPtrType()) {
-    ExpectedTy = S.Context.VoidPtrTy;
-  } else if (AllowsInteger(OpKind) &&
-             Arg->getType()->isIntegralOrUnscopedEnumerationType()) {
-    ExpectedTy = S.Context.getUIntPtrType();
-
-  } else {
-    // Diagnose the failures.
-    S.Diag(Arg->getExprLoc(), diag::err_ptrauth_value_bad_type)
-        << unsigned(OpKind == PAO_Discriminator  ? 1
-                    : OpKind == PAO_BlendPointer ? 2
-                    : OpKind == PAO_BlendInteger ? 3
-                                                 : 0)
-        << unsigned(AllowsInteger(OpKind) ? (AllowsPointer(OpKind) ? 2 : 1) : 0)
-        << Arg->getType() << Arg->getSourceRange();
-    return true;
-  }
-
-  // Convert to that type.  This should just be an lvalue-to-rvalue
-  // conversion.
-  if (convertArgumentToType(S, Arg, ExpectedTy))
-    return true;
-
-  if (!RequireConstant) {
-    // Warn about null pointers for non-generic sign and auth operations.
-    if ((OpKind == PAO_Sign || OpKind == PAO_Auth) &&
-        Arg->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull)) {
-      S.Diag(Arg->getExprLoc(), OpKind == PAO_Sign
-                                    ? diag::warn_ptrauth_sign_null_pointer
-                                    : diag::warn_ptrauth_auth_null_pointer)
-          << Arg->getSourceRange();
-    }
-
-    return false;
-  }
-
-  // Perform special checking on the arguments to ptrauth_sign_constant.
-
-  // The main argument.
-  if (OpKind == PAO_Sign) {
-    // Require the value we're signing to have a special form.
-    auto [BaseDecl, Offset] = findConstantBaseAndOffset(S, Arg);
-    bool Invalid;
-
-    // Must be rooted in a declaration reference.
-    if (!BaseDecl)
-      Invalid = true;
-
-    // If it's a function declaration, we can't have an offset.
-    else if (isa<FunctionDecl>(BaseDecl))
-      Invalid = !Offset.isZero();
-
-    // Otherwise we're fine.
-    else
-      Invalid = false;
-
-    if (Invalid)
-      S.Diag(Arg->getExprLoc(), diag::err_ptrauth_bad_constant_pointer);
-    return Invalid;
-  }
-
-  // The discriminator argument.
-  assert(OpKind == PAO_Discriminator);
-
-  // Must be a pointer or integer or blend thereof.
-  Expr *Pointer = nullptr;
-  Expr *Integer = nullptr;
-  if (auto *Call = dyn_cast<CallExpr>(Arg->IgnoreParens())) {
-    if (Call->getBuiltinCallee() ==
-        Builtin::BI__builtin_ptrauth_blend_discriminator) {
-      Pointer = Call->getArg(0);
-      Integer = Call->getArg(1);
-    }
-  }
-  if (!Pointer && !Integer) {
-    if (Arg->getType()->isPointerType())
-      Pointer = Arg;
-    else
-      Integer = Arg;
-  }
-
-  // Check the pointer.
-  bool Invalid = false;
-  if (Pointer) {
-    assert(Pointer->getType()->isPointerType());
-
-    // TODO: if we're initializing a global, check that the address is
-    // somehow related to what we're initializing.  This probably will
-    // never really be feasible and we'll have to catch it at link-time.
-    auto [BaseDecl, Offset] = findConstantBaseAndOffset(S, Pointer);
-    if (!BaseDecl || !isa<VarDecl>(BaseDecl))
-      Invalid = true;
-  }
-
-  // Check the integer.
-  if (Integer) {
-    assert(Integer->getType()->isIntegerType());
-    if (!Integer->isEvaluatable(S.Context))
-      Invalid = true;
-  }
-
-  if (Invalid)
-    S.Diag(Arg->getExprLoc(), diag::err_ptrauth_bad_constant_discriminator);
-  return Invalid;
-}
-
-static ExprResult PointerAuthStrip(Sema &S, CallExpr *Call) {
-  if (S.checkArgCount(Call, 2))
-    return ExprError();
-  if (checkPointerAuthEnabled(S, Call))
-    return ExprError();
-  if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_Strip) ||
-      checkPointerAuthKey(S, Call->getArgs()[1]))
-    return ExprError();
-
-  Call->setType(Call->getArgs()[0]->getType());
-  return Call;
-}
-
-static ExprResult PointerAuthBlendDiscriminator(Sema &S, CallExpr *Call) {
-  if (S.checkArgCount(Call, 2))
-    return ExprError();
-  if (checkPointerAuthEnabled(S, Call))
-    return ExprError();
-  if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_BlendPointer) ||
-      checkPointerAuthValue(S, Call->getArgs()[1], PAO_BlendInteger))
-    return ExprError();
-
-  Call->setType(S.Context.getUIntPtrType());
-  return Call;
-}
-
-static ExprResult PointerAuthSignGenericData(Sema &S, CallExpr *Call) {
-  if (S.checkArgCount(Call, 2))
-    return ExprError();
-  if (checkPointerAuthEnabled(S, Call))
-    return ExprError();
-  if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_SignGeneric) ||
-      checkPointerAuthValue(S, Call->getArgs()[1], PAO_Discriminator))
-    return ExprError();
-
-  Call->setType(S.Context.getUIntPtrType());
-  return Call;
-}
-
-static ExprResult PointerAuthSignOrAuth(Sema &S, CallExpr *Call,
-                                        PointerAuthOpKind OpKind,
-                                        bool RequireConstant) {
-  if (S.checkArgCount(Call, 3))
-    return ExprError();
-  if (checkPointerAuthEnabled(S, Call))
-    return ExprError();
-  if (checkPointerAuthValue(S, Call->getArgs()[0], OpKind, RequireConstant) ||
-      checkPointerAuthKey(S, Call->getArgs()[1]) ||
-      checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator,
-                            RequireConstant))
-    return ExprError();
-
-  Call->setType(Call->getArgs()[0]->getType());
-  return Call;
-}
-
-static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) {
-  if (S.checkArgCount(Call, 5))
-    return ExprError();
-  if (checkPointerAuthEnabled(S, Call))
-    return ExprError();
-  if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_Auth) ||
-      checkPointerAuthKey(S, Call->getArgs()[1]) ||
-      checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator) ||
-      checkPointerAuthKey(S, Call->getArgs()[3]) ||
-      checkPointerAuthValue(S, Call->getArgs()[4], PAO_Discriminator))
-    return ExprError();
-
-  Call->setType(Call->getArgs()[0]->getType());
-  return Call;
-}
-
-static ExprResult PointerAuthAuthLoadRelativeAndSign(Sema &S, CallExpr *Call) {
-  if (S.checkArgCount(Call, 6))
-    return ExprError();
-  if (checkPointerAuthEnabled(S, Call))
-    return ExprError();
-  const Expr *AddendExpr = Call->getArg(5);
-  bool AddendIsConstInt = AddendExpr->isIntegerConstantExpr(S.Context);
-  if (!AddendIsConstInt) {
-    const Expr *Arg = Call->getArg(5)->IgnoreParenImpCasts();
-    DeclRefExpr *DRE = cast<DeclRefExpr>(Call->getCallee()->IgnoreParenCasts());
-    FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl());
-    S.Diag(Arg->getBeginLoc(), diag::err_constant_integer_last_arg_type)
-        << FDecl->getDeclName() << Arg->getSourceRange();
-  }
-  if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_Auth) ||
-      checkPointerAuthKey(S, Call->getArgs()[1]) ||
-      checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator) ||
-      checkPointerAuthKey(S, Call->getArgs()[3]) ||
-      checkPointerAuthValue(S, Call->getArgs()[4], PAO_Discriminator) ||
-      !AddendIsConstInt)
-    return ExprError();
-
-  Call->setType(Call->getArgs()[0]->getType());
-  return Call;
-}
-
-static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *Call) {
-  if (checkPointerAuthEnabled(S, Call))
-    return ExprError();
-
-  // We've already performed normal call type-checking.
-  const Expr *Arg = Call->getArg(0)->IgnoreParenImpCasts();
-
-  // Operand must be an ordinary or UTF-8 string literal.
-  const auto *Literal = dyn_cast<StringLiteral>(Arg);
-  if (!Literal || Literal->getCharByteWidth() != 1) {
-    S.Diag(Arg->getExprLoc(), diag::err_ptrauth_string_not_literal)
-        << (Literal ? 1 : 0) << Arg->getSourceRange();
-    return ExprError();
-  }
-
-  return Call;
-}
-
-static ExprResult GetVTablePointer(Sema &S, CallExpr *Call) {
-  if (S.checkArgCount(Call, 1))
-    return ExprError();
-  Expr *FirstArg = Call->getArg(0);
-  ExprResult FirstValue = S.DefaultFunctionArrayLvalueConversion(FirstArg);
-  if (FirstValue.isInvalid())
-    return ExprError();
-  Call->setArg(0, FirstValue.get());
-  QualType FirstArgType = FirstArg->getType();
-  if (FirstArgType->canDecayToPointerType() && FirstArgType->isArrayType())
-    FirstArgType = S.Context.getDecayedType(FirstArgType);
-
-  const CXXRecordDecl *FirstArgRecord = FirstArgType->getPointeeCXXRecordDecl();
-  if (!FirstArgRecord) {
-    S.Diag(FirstArg->getBeginLoc(), diag::err_get_vtable_pointer_incorrect_type)
-        << /*isPolymorphic=*/0 << FirstArgType;
-    return ExprError();
-  }
-  if (S.RequireCompleteType(
-          FirstArg->getBeginLoc(), FirstArgType->getPointeeType(),
-          diag::err_get_vtable_pointer_requires_complete_type)) {
-    return ExprError();
-  }
-
-  if (!FirstArgRecord->isPolymorphic()) {
-    S.Diag(FirstArg->getBeginLoc(), diag::err_get_vtable_pointer_incorrect_type)
-        << /*isPolymorphic=*/1 << FirstArgRecord;
-    return ExprError();
-  }
-  QualType ReturnType = S.Context.getPointerType(S.Context.VoidTy.withConst());
-  Call->setType(ReturnType);
-  return Call;
-}
-
-static ExprResult BuiltinLaunder(Sema &S, CallExpr *TheCall) {
-  if (S.checkArgCount(TheCall, 1))
-    return ExprError();
-
-  // Compute __builtin_launder's parameter type from the argument.
-  // The parameter type is:
-  //  * The type of the argument if it's not an array or function type,
-  //  Otherwise,
-  //  * The decayed argument type.
-  QualType ParamTy = [&]() {
-    QualType ArgTy = TheCall->getArg(0)->getType();
-    if (const ArrayType *Ty = ArgTy->getAsArrayTypeUnsafe())
-      return S.Context.getPointerType(Ty->getElementType());
-    if (ArgTy->isFunctionType()) {
-      return S.Context.getPointerType(ArgTy);
-    }
-    return ArgTy;
-  }();
-
-  TheCall->setType(ParamTy);
-
-  auto DiagSelect = [&]() -> std::optional<unsigned> {
-    if (!ParamTy->isPointerType())
-      return 0;
-    if (ParamTy->isFunctionPointerType())
-      return 1;
-    if (ParamTy->isVoidPointerType())
-      return 2;
-    return std::optional<unsigned>{};
-  }();
-  if (DiagSelect) {
-    S.Diag(TheCall->getBeginLoc(), diag::err_builtin_launder_invalid_arg)
-        << *DiagSelect << TheCall->getSourceRange();
-    return ExprError();
-  }
-
-  // We either have an incomplete class type, or we have a class template
-  // whose instantiation has not been forced. Example:
-  //
-  //   template <class T> struct Foo { T value; };
-  //   Foo<int> *p = nullptr;
-  //   auto *d = __builtin_launder(p);
-  if (S.RequireCompleteType(TheCall->getBeginLoc(), ParamTy->getPointeeType(),
-                            diag::err_incomplete_type))
-    return ExprError();
-
-  assert(ParamTy->getPointeeType()->isObjectType() &&
-         "Unhandled non-object pointer case");
-
-  InitializedEntity Entity =
-      InitializedEntity::InitializeParameter(S.Context, ParamTy, false);
-  ExprResult Arg =
-      S.PerformCopyInitialization(Entity, SourceLocation(), TheCall->getArg(0));
-  if (Arg.isInvalid())
-    return ExprError();
-  TheCall->setArg(0, Arg.get());
-
-  return TheCall;
-}
-
-static ExprResult BuiltinIsWithinLifetime(Sema &S, CallExpr *TheCall) {
-  if (S.checkArgCount(TheCall, 1))
-    return ExprError();
-
-  ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(0));
-  if (Arg.isInvalid())
-    return ExprError();
-  QualType ParamTy = Arg.get()->getType();
-  TheCall->setArg(0, Arg.get());
-  TheCall->setType(S.Context.BoolTy);
-
-  // Only accept pointers to objects as arguments, which should have object
-  // pointer or void pointer types.
-  if (const auto *PT = ParamTy->getAs<PointerType>()) {
-    // LWG4138: Function pointer types not allowed
-    if (PT->getPointeeType()->isFunctionType()) {
-      S.Diag(TheCall->getArg(0)->getExprLoc(),
-             diag::err_builtin_is_within_lifetime_invalid_arg)
-          << 1;
-      return ExprError();
-    }
-    // Disallow VLAs too since those shouldn't be able to
-    // be a template parameter for `std::is_within_lifetime`
-    if (PT->getPointeeType()->isVariableArrayType()) {
-      S.Diag(TheCall->getArg(0)->getExprLoc(), diag::err_vla_unsupported)
-          << 1 << "__builtin_is_within_lifetime";
-      return ExprError();
-    }
-  } else {
-    S.Diag(TheCall->getArg(0)->getExprLoc(),
-           diag::err_builtin_is_within_lifetime_invalid_arg)
-        << 0;
-    return ExprError();
-  }
-  return TheCall;
-}
-
-static ExprResult BuiltinTriviallyRelocate(Sema &S, CallExpr *TheCall) {
-  if (S.checkArgCount(TheCall, 3))
-    return ExprError();
-
-  QualType Dest = TheCall->getArg(0)->getType();
-  if (!Dest->isPointerType() || Dest.getCVRQualifiers() != 0) {
-    S.Diag(TheCall->getArg(0)->getExprLoc(),
-           diag::err_builtin_trivially_relocate_invalid_arg_type)
-        << /*a pointer*/ 0;
-    return ExprError();
-  }
-
-  QualType T = Dest->getPointeeType();
-  if (S.RequireCompleteType(TheCall->getBeginLoc(), T,
-                            diag::err_incomplete_type))
-    return ExprError();
-
-  if (T.isConstQualified() || !S.IsCXXTriviallyRelocatableType(T) ||
-      T->isIncompleteArrayType()) {
-    S.Diag(TheCall->getArg(0)->getExprLoc(),
-           diag::err_builtin_trivially_relocate_invalid_arg_type)
-        << (T.isConstQualified() ? /*non-const*/ 1 : /*relocatable*/ 2);
-    return ExprError();
-  }
-
-  TheCall->setType(Dest);
-
-  QualType Src = TheCall->getArg(1)->getType();
-  if (Src.getCanonicalType() != Dest.getCanonicalType()) {
-    S.Diag(TheCall->getArg(1)->getExprLoc(),
-           diag::err_builtin_trivially_relocate_invalid_arg_type)
-        << /*the same*/ 3;
-    return ExprError();
-  }
-
-  Expr *SizeExpr = TheCall->getArg(2);
-  ExprResult Size = S.DefaultLvalueConversion(SizeExpr);
-  if (Size.isInvalid())
-    return ExprError();
-
-  Size = S.tryConvertExprToType(Size.get(), S.getASTContext().getSizeType());
-  if (Size.isInvalid())
-    return ExprError();
-  SizeExpr = Size.get();
-  TheCall->setArg(2, SizeExpr);
-
-  return TheCall;
-}
-
-// Emit an error and return true if the current object format type is in the
-// list of unsupported types.
-static bool CheckBuiltinTargetNotInUnsupported(
-    Sema &S, unsigned BuiltinID, CallExpr *TheCall,
-    ArrayRef<llvm::Triple::ObjectFormatType> UnsupportedObjectFormatTypes) {
-  llvm::Triple::ObjectFormatType CurObjFormat =
-      S.getASTContext().getTargetInfo().getTriple().getObjectFormat();
-  if (llvm::is_contained(UnsupportedObjectFormatTypes, CurObjFormat)) {
-    S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
-        << TheCall->getSourceRange();
-    return true;
-  }
-  return false;
-}
-
-// Emit an error and return true if the current architecture is not in the list
-// of supported architectures.
-static bool
-CheckBuiltinTargetInSupported(Sema &S, CallExpr *TheCall,
-                              ArrayRef<llvm::Triple::ArchType> SupportedArchs) {
-  llvm::Triple::ArchType CurArch =
-      S.getASTContext().getTargetInfo().getTriple().getArch();
-  if (llvm::is_contained(SupportedArchs, CurArch))
-    return false;
-  S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
-      << TheCall->getSourceRange();
-  return true;
-}
-
-static void CheckNonNullArgument(Sema &S, const Expr *ArgExpr,
-                                 SourceLocation CallSiteLoc);
-
-bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
-                                      CallExpr *TheCall) {
-  switch (TI.getTriple().getArch()) {
-  default:
-    // Some builtins don't require additional checking, so just consider these
-    // acceptable.
-    return false;
-  case llvm::Triple::arm:
-  case llvm::Triple::armeb:
-  case llvm::Triple::thumb:
-  case llvm::Triple::thumbeb:
-    return ARM().CheckARMBuiltinFunctionCall(TI, BuiltinID, TheCall);
-  case llvm::Triple::aarch64:
-  case llvm::Triple::aarch64_32:
-  case llvm::Triple::aarch64_be:
-    return ARM().CheckAArch64BuiltinFunctionCall(TI, BuiltinID, TheCall);
-  case llvm::Triple::bpfeb:
-  case llvm::Triple::bpfel:
-    return BPF().CheckBPFBuiltinFunctionCall(BuiltinID, TheCall);
-  case llvm::Triple::dxil:
-    return DirectX().CheckDirectXBuiltinFunctionCall(BuiltinID, TheCall);
-  case llvm::Triple::hexagon:
-    return Hexagon().CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall);
-  case llvm::Triple::mips:
-  case llvm::Triple::mipsel:
-  case llvm::Triple::mips64:
-  case llvm::Triple::mips64el:
-    return MIPS().CheckMipsBuiltinFunctionCall(TI, BuiltinID, TheCall);
-  case llvm::Triple::spirv:
-  case llvm::Triple::spirv32:
-  case llvm::Triple::spirv64:
-    if (TI.getTriple().getOS() != llvm::Triple::OSType::AMDHSA)
-      return SPIRV().CheckSPIRVBuiltinFunctionCall(TI, BuiltinID, TheCall);
-    return false;
-  case llvm::Triple::systemz:
-    return SystemZ().CheckSystemZBuiltinFunctionCall(BuiltinID, TheCall);
-  case llvm::Triple::x86:
-  case llvm::Triple::x86_64:
-    return X86().CheckBuiltinFunctionCall(TI, BuiltinID, TheCall);
-  case llvm::Triple::ppc:
-  case llvm::Triple::ppcle:
-  case llvm::Triple::ppc64:
-  case llvm::Triple::ppc64le:
-    return PPC().CheckPPCBuiltinFunctionCall(TI, BuiltinID, TheCall);
-  case llvm::Triple::amdgcn:
-    return AMDGPU().CheckAMDGCNBuiltinFunctionCall(BuiltinID, TheCall);
-  case llvm::Triple::riscv32:
-  case llvm::Triple::riscv64:
-  case llvm::Triple::riscv32be:
-  case llvm::Triple::riscv64be:
-    return RISCV().CheckBuiltinFunctionCall(TI, BuiltinID, TheCall);
-  case llvm::Triple::loongarch32:
-  case llvm::Triple::loongarch64:
-    return LoongArch().CheckLoongArchBuiltinFunctionCall(TI, BuiltinID,
-                                                         TheCall);
-  case llvm::Triple::wasm32:
-  case llvm::Triple::wasm64:
-    return Wasm().CheckWebAssemblyBuiltinFunctionCall(TI, BuiltinID, TheCall);
-  case llvm::Triple::nvptx:
-  case llvm::Triple::nvptx64:
-    return NVPTX().CheckNVPTXBuiltinFunctionCall(TI, BuiltinID, TheCall);
-  }
-}
-
-static bool isValidMathElementType(QualType T) {
-  return T->isDependentType() ||
-         (T->isRealType() && !T->isBooleanType() && !T->isEnumeralType());
-}
-
-// Check if \p Ty is a valid type for the elementwise math builtins. If it is
-// not a valid type, emit an error message and return true. Otherwise return
-// false.
-static bool
-checkMathBuiltinElementType(Sema &S, SourceLocation Loc, QualType ArgTy,
-                            Sema::EltwiseBuiltinArgTyRestriction ArgTyRestr,
-                            int ArgOrdinal) {
-  QualType EltTy = ArgTy;
-  if (auto *VecTy = EltTy->getAs<VectorType>())
-    EltTy = VecTy->getElementType();
-
-  switch (ArgTyRestr) {
-  case Sema::EltwiseBuiltinArgTyRestriction::None:
-    if (!ArgTy->getAs<VectorType>() && !isValidMathElementType(ArgTy)) {
-      return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
-             << ArgOrdinal << /* vector */ 2 << /* integer */ 1 << /* fp */ 1
-             << ArgTy;
-    }
-    break;
-  case Sema::EltwiseBuiltinArgTyRestriction::FloatTy:
-    if (!EltTy->isRealFloatingType()) {
-      return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
-             << ArgOrdinal << /* scalar or vector */ 5 << /* no int */ 0
-             << /* floating-point */ 1 << ArgTy;
-    }
-    break;
-  case Sema::EltwiseBuiltinArgTyRestriction::IntegerTy:
-    if (!EltTy->isIntegerType()) {
-      return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
-             << ArgOrdinal << /* scalar or vector */ 5 << /* integer */ 1
-             << /* no fp */ 0 << ArgTy;
-    }
-    break;
-  case Sema::EltwiseBuiltinArgTyRestriction::SignedIntOrFloatTy:
-    if (!EltTy->isSignedIntegerType() && !EltTy->isRealFloatingType()) {
-      return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
-             << 1 << /* scalar or vector */ 5 << /* signed int */ 2
-             << /* or fp */ 1 << ArgTy;
-    }
-    break;
-  }
-
-  return false;
-}
-
-/// BuiltinCpu{Supports|Is} - Handle __builtin_cpu_{supports|is}(char *).
-/// This checks that the target supports the builtin and that the string
-/// argument is constant and valid.
-static bool BuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall,
-                       const TargetInfo *AuxTI, unsigned BuiltinID) {
-  assert((BuiltinID == Builtin::BI__builtin_cpu_supports ||
-          BuiltinID == Builtin::BI__builtin_cpu_is) &&
-         "Expecting __builtin_cpu_...");
-
-  bool IsCPUSupports = BuiltinID == Builtin::BI__builtin_cpu_supports;
-  const TargetInfo *TheTI = &TI;
-  auto SupportsBI = [=](const TargetInfo *TInfo) {
-    return TInfo && ((IsCPUSupports && TInfo->supportsCpuSupports()) ||
-                     (!IsCPUSupports && TInfo->supportsCpuIs()));
-  };
-  if (!SupportsBI(&TI) && SupportsBI(AuxTI))
-    TheTI = AuxTI;
-
-  if ((!IsCPUSupports && !TheTI->supportsCpuIs()) ||
-      (IsCPUSupports && !TheTI->supportsCpuSupports()))
-    return S.Diag(TheCall->getBeginLoc(),
-                  TI.getTriple().isOSAIX()
-                      ? diag::err_builtin_aix_os_unsupported
-                      : diag::err_builtin_target_unsupported)
-           << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
-
-  Expr *Arg = TheCall->getArg(0)->IgnoreParenImpCasts();
-  // Check if the argument is a string literal.
-  if (!isa<StringLiteral>(Arg))
-    return S.Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
-           << Arg->getSourceRange();
-
-  // Check the contents of the string.
-  StringRef Feature = cast<StringLiteral>(Arg)->getString();
-  if (IsCPUSupports && !TheTI->validateCpuSupports(Feature)) {
-    S.Diag(TheCall->getBeginLoc(), diag::warn_invalid_cpu_supports)
-        << Arg->getSourceRange();
-    return false;
-  }
-  if (!IsCPUSupports && !TheTI->validateCpuIs(Feature))
-    return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_is)
-           << Arg->getSourceRange();
-  return false;
-}
-
-/// Checks that __builtin_bswapg was called with a single argument, which is an
-/// unsigned integer, and overrides the return value type to the integer type.
-static bool BuiltinBswapg(Sema &S, CallExpr *TheCall) {
-  if (S.checkArgCount(TheCall, 1))
-    return true;
-  ExprResult ArgRes = S.DefaultLvalueConversion(TheCall->getArg(0));
-  if (ArgRes.isInvalid())
-    return true;
-
-  Expr *Arg = ArgRes.get();
-  TheCall->setArg(0, Arg);
-  if (Arg->isTypeDependent())
-    return false;
-
-  QualType ArgTy = Arg->getType();
-
-  if (!ArgTy->isIntegerType()) {
-    S.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
-        << 1 << /*scalar=*/1 << /*unsigned integer=*/1 << /*floating point=*/0
-        << ArgTy;
-    return true;
-  }
-  if (const auto *BT = dyn_cast<BitIntType>(ArgTy)) {
-    if (BT->getNumBits() % 16 != 0 && BT->getNumBits() != 8 &&
-        BT->getNumBits() != 1) {
-      S.Diag(Arg->getBeginLoc(), diag::err_bswapg_invalid_bit_width)
-          << ArgTy << BT->getNumBits();
-      return true;
-    }
-  }
-  TheCall->setType(ArgTy);
-  return false;
-}
-
-/// Checks that __builtin_popcountg was called with a single argument, which is
-/// an unsigned integer.
-static bool BuiltinPopcountg(Sema &S, CallExpr *TheCall) {
-  if (S.checkArgCount(TheCall, 1))
-    return true;
-
-  ExprResult ArgRes = S.DefaultLvalueConversion(TheCall->getArg(0));
-  if (ArgRes.isInvalid())
-    return true;
-
-  Expr *Arg = ArgRes.get();
-  TheCall->setArg(0, Arg);
-
-  QualType ArgTy = Arg->getType();
-
-  if (!ArgTy->isUnsignedIntegerType() && !ArgTy->isExtVectorBoolType()) {
-    S.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
-        << 1 << /* scalar */ 1 << /* unsigned integer ty */ 3 << /* no fp */ 0
-        << ArgTy;
-    return true;
-  }
-  return false;
-}
-
-/// Checks that __builtin_{clzg,ctzg} was called with a first argument, which is
-/// an unsigned integer, and an optional second argument, which is promoted to
-/// an 'int'.
-static bool BuiltinCountZeroBitsGeneric(Sema &S, CallExpr *TheCall) {
-  if (S.checkArgCountRange(TheCall, 1, 2))
-    return true;
-
-  ExprResult Arg0Res = S.DefaultLvalueConversion(TheCall->getArg(0));
-  if (Arg0Res.isInvalid())
-    return true;
-
-  Expr *Arg0 = Arg0Res.get();
-  TheCall->setArg(0, Arg0);
-
-  QualType Arg0Ty = Arg0->getType();
-
-  if (!Arg0Ty->isUnsignedIntegerType() && !Arg0Ty->isExtVectorBoolType()) {
-    S.Diag(Arg0->getBeginLoc(), diag::err_builtin_invalid_arg_type)
-        << 1 << /* scalar */ 1 << /* unsigned integer ty */ 3 << /* no fp */ 0
-        << Arg0Ty;
-    return true;
-  }
-
-  if (TheCall->getNumArgs() > 1) {
-    ExprResult Arg1Res = S.UsualUnaryConversions(TheCall->getArg(1));
-    if (Arg1Res.isInvalid())
-      return true;
-
-    Expr *Arg1 = Arg1Res.get();
-    TheCall->setArg(1, Arg1);
-
-    QualType Arg1Ty = Arg1->getType();
-
-    if (!Arg1Ty->isSpecificBuiltinType(BuiltinType::Int)) {
-      S.Diag(Arg1->getBeginLoc(), diag::err_builtin_invalid_arg_type)
-          << 2 << /* scalar */ 1 << /* 'int' ty */ 4 << /* no fp */ 0 << Arg1Ty;
-      return true;
-    }
-  }
-
-  return false;
-}
-
-class RotateIntegerConverter : public Sema::ContextualImplicitConverter {
-  unsigned ArgIndex;
-  bool OnlyUnsigned;
-
-  Sema::SemaDiagnosticBuilder emitError(Sema &S, SourceLocation Loc,
-                                        QualType T) {
-    return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
-           << ArgIndex << /*scalar*/ 1
-           << (OnlyUnsigned ? /*unsigned integer*/ 3 : /*integer*/ 1)
-           << /*no fp*/ 0 << T;
-  }
-
-public:
-  RotateIntegerConverter(unsigned ArgIndex, bool OnlyUnsigned)
-      : ContextualImplicitConverter(/*Suppress=*/false,
-                                    /*SuppressConversion=*/true),
-        ArgIndex(ArgIndex), OnlyUnsigned(OnlyUnsigned) {}
-
-  bool match(QualType T) override {
-    return OnlyUnsigned ? T->isUnsignedIntegerType() : T->isIntegerType();
-  }
-
-  Sema::SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc,
-                                              QualType T) override {
-    return emitError(S, Loc, T);
-  }
-
-  Sema::SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc,
-                                                 QualType T) override {
-    return emitError(S, Loc, T);
-  }
-
-  Sema::SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc,
-                                                   QualType T,
-                                                   QualType ConvTy) override {
-    return emitError(S, Loc, T);
-  }
-
-  Sema::SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv,
-                                               QualType ConvTy) override {
-    return S.Diag(Conv->getLocation(), diag::note_conv_function_declared_at);
-  }
-
-  Sema::SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
-                                                QualType T) override {
-    return emitError(S, Loc, T);
-  }
-
-  Sema::SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv,
-                                            QualType ConvTy) override {
-    return S.Diag(Conv->getLocation(), diag::note_conv_function_declared_at);
-  }
-
-  Sema::SemaDiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc,
-                                                 QualType T,
-                                                 QualType ConvTy) override {
-    llvm_unreachable("conversion functions are permitted");
-  }
-};
-
-/// Checks that __builtin_stdc_rotate_{left,right} was called with two
-/// arguments, that the first argument is an unsigned integer type, and that
-/// the second argument is an integer type.
-static bool BuiltinRotateGeneric(Sema &S, CallExpr *TheCall) {
-  if (S.checkArgCount(TheCall, 2))
-    return true;
-
-  // First argument (value to rotate) must be unsigned integer type.
-  RotateIntegerConverter Arg0Converter(1, /*OnlyUnsigned=*/true);
-  ExprResult Arg0Res = S.PerformContextualImplicitConversion(
-      TheCall->getArg(0)->getBeginLoc(), TheCall->getArg(0), Arg0Converter);
-  if (Arg0Res.isInvalid())
-    return true;
-
-  Expr *Arg0 = Arg0Res.get();
-  TheCall->setArg(0, Arg0);
-
-  QualType Arg0Ty = Arg0->getType();
-  if (!Arg0Ty->isUnsignedIntegerType())
-    return true;
-
-  // Second argument (rotation count) must be integer type.
-  RotateIntegerConverter Arg1Converter(2, /*OnlyUnsigned=*/false);
-  ExprResult Arg1Res = S.PerformContextualImplicitConversion(
-      TheCall->getArg(1)->getBeginLoc(), TheCall->getArg(1), Arg1Converter);
-  if (Arg1Res.isInvalid())
-    return true;
-
-  Expr *Arg1 = Arg1Res.get();
-  TheCall->setArg(1, Arg1);
-
-  QualType Arg1Ty = Arg1->getType();
-  if (!Arg1Ty->isIntegerType())
-    return true;
-
-  TheCall->setType(Arg0Ty);
-  return false;
-}
-
-static bool CheckMaskedBuiltinArgs(Sema &S, Expr *MaskArg, Expr *PtrArg,
-                                   unsigned Pos, bool AllowConst,
-                                   bool AllowAS) {
-  QualType MaskTy = MaskArg->getType();
-  if (!MaskTy->isExtVectorBoolType())
-    return S.Diag(MaskArg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
-           << 1 << /* vector of */ 4 << /* booleans */ 6 << /* no fp */ 0
-           << MaskTy;
-
-  QualType PtrTy = PtrArg->getType();
-  if (!PtrTy->isPointerType() || PtrTy->getPointeeType()->isVectorType())
-    return S.Diag(PtrArg->getExprLoc(), diag::err_vec_masked_load_store_ptr)
-           << Pos << "scalar pointer";
-
-  QualType PointeeTy = PtrTy->getPointeeType();
-  if (PointeeTy.isVolatileQualified() || PointeeTy->isAtomicType() ||
-      (!AllowConst && PointeeTy.isConstQualified()) ||
-      (!AllowAS && PointeeTy.hasAddressSpace())) {
-    QualType Target =
-        S.Context.getPointerType(PointeeTy.getAtomicUnqualifiedType());
-    return S.Diag(PtrArg->getExprLoc(),
-                  diag::err_typecheck_convert_incompatible)
-           << PtrTy << Target << /*different qualifiers=*/5
-           << /*qualifier difference=*/0 << /*parameter mismatch=*/3 << 2
-           << PtrTy << Target;
-  }
-  return false;
-}
-
-static bool ConvertMaskedBuiltinArgs(Sema &S, CallExpr *TheCall) {
-  bool TypeDependent = false;
-  for (unsigned Arg = 0, E = TheCall->getNumArgs(); Arg != E; ++Arg) {
-    ExprResult Converted =
-        S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(Arg));
-    if (Converted.isInvalid())
-      return true;
-    TheCall->setArg(Arg, Converted.get());
-    TypeDependent |= Converted.get()->isTypeDependent();
-  }
-
-  if (TypeDependent)
-    TheCall->setType(S.Context.DependentTy);
-  return false;
-}
-
-static ExprResult BuiltinMaskedLoad(Sema &S, CallExpr *TheCall) {
-  if (S.checkArgCountRange(TheCall, 2, 3))
-    return ExprError();
-
-  if (ConvertMaskedBuiltinArgs(S, TheCall))
-    return ExprError();
-
-  Expr *MaskArg = TheCall->getArg(0);
-  Expr *PtrArg = TheCall->getArg(1);
-  if (TheCall->isTypeDependent())
-    return TheCall;
-
-  if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 2, /*AllowConst=*/true,
-                             TheCall->getBuiltinCallee() ==
-                                 Builtin::BI__builtin_masked_load))
-    return ExprError();
-
-  QualType MaskTy = MaskArg->getType();
-  QualType PtrTy = PtrArg->getType();
-  QualType PointeeTy = PtrTy->getPointeeType();
-  const VectorType *MaskVecTy = MaskTy->getAs<VectorType>();
-
-  QualType RetTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(),
-                                              MaskVecTy->getNumElements());
-  if (TheCall->getNumArgs() == 3) {
-    Expr *PassThruArg = TheCall->getArg(2);
-    QualType PassThruTy = PassThruArg->getType();
-    if (!S.Context.hasSameType(PassThruTy, RetTy))
-      return S.Diag(PtrArg->getExprLoc(), diag::err_vec_masked_load_store_ptr)
-             << /* third argument */ 3 << RetTy;
-  }
-
-  TheCall->setType(RetTy);
-  return TheCall;
-}
-
-static ExprResult BuiltinMaskedStore(Sema &S, CallExpr *TheCall) {
-  if (S.checkArgCount(TheCall, 3))
-    return ExprError();
-
-  if (ConvertMaskedBuiltinArgs(S, TheCall))
-    return ExprError();
-
-  Expr *MaskArg = TheCall->getArg(0);
-  Expr *ValArg = TheCall->getArg(1);
-  Expr *PtrArg = TheCall->getArg(2);
-  if (TheCall->isTypeDependent())
-    return TheCall;
-
-  if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 3, /*AllowConst=*/false,
-                             TheCall->getBuiltinCallee() ==
-                                 Builtin::BI__builtin_masked_store))
-    return ExprError();
-
-  QualType MaskTy = MaskArg->getType();
-  QualType PtrTy = PtrArg->getType();
-  QualType ValTy = ValArg->getType();
-  if (!ValTy->isVectorType())
-    return ExprError(
-        S.Diag(ValArg->getExprLoc(), diag::err_vec_masked_load_store_ptr)
-        << 2 << "vector");
-
-  QualType PointeeTy = PtrTy->getPointeeType();
-  const VectorType *MaskVecTy = MaskTy->getAs<VectorType>();
-  QualType MemoryTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(),
-                                                 MaskVecTy->getNumElements());
-  if (!S.Context.hasSameType(ValTy.getUnqualifiedType(),
-                             MemoryTy.getUnqualifiedType()))
-    return ExprError(S.Diag(TheCall->getBeginLoc(),
-                            diag::err_vec_builtin_incompatible_vector)
-                     << TheCall->getDirectCallee() << /*isMorethantwoArgs*/ 2
-                     << SourceRange(TheCall->getArg(1)->getBeginLoc(),
-                                    TheCall->getArg(1)->getEndLoc()));
-
-  TheCall->setType(S.Context.VoidTy);
-  return TheCall;
-}
-
-static ExprResult BuiltinMaskedGather(Sema &S, CallExpr *TheCall) {
-  if (S.checkArgCountRange(TheCall, 3, 4))
-    return ExprError();
-
-  if (ConvertMaskedBuiltinArgs(S, TheCall))
-    return ExprError();
-
-  Expr *MaskArg = TheCall->getArg(0);
-  Expr *IdxArg = TheCall->getArg(1);
-  Expr *PtrArg = TheCall->getArg(2);
-  if (TheCall->isTypeDependent())
-    return TheCall;
-
-  if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 3, /*AllowConst=*/true,
-                             /*AllowAS=*/true))
-    return ExprError();
-
-  QualType IdxTy = IdxArg->getType();
-  const VectorType *IdxVecTy = IdxTy->getAs<VectorType>();
-  if (!IdxTy->isExtVectorType() || !IdxVecTy->getElementType()->isIntegerType())
-    return S.Diag(MaskArg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
-           << 1 << /* vector of */ 4 << /* integer */ 1 << /* no fp */ 0
-           << IdxTy;
-
-  QualType MaskTy = MaskArg->getType();
-  QualType PtrTy = PtrArg->getType();
-  QualType PointeeTy = PtrTy->getPointeeType();
-  const VectorType *MaskVecTy = MaskTy->getAs<VectorType>();
-  if (MaskVecTy->getNumElements() != IdxVecTy->getNumElements())
-    return ExprError(
-        S.Diag(TheCall->getBeginLoc(), diag::err_vec_masked_load_store_size)
-        << S.getASTContext().BuiltinInfo.getQuotedName(
-               TheCall->getBuiltinCallee())
-        << MaskTy << IdxTy);
-
-  QualType RetTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(),
-                                              MaskVecTy->getNumElements());
-  if (TheCall->getNumArgs() == 4) {
-    Expr *PassThruArg = TheCall->getArg(3);
-    QualType PassThruTy = PassThruArg->getType();
-    if (!S.Context.hasSameType(PassThruTy, RetTy))
-      return S.Diag(PassThruArg->getExprLoc(),
-                    diag::err_vec_masked_load_store_ptr)
-             << /* fourth argument */ 4 << RetTy;
-  }
-
-  TheCall->setType(RetTy);
-  return TheCall;
-}
-
-static ExprResult BuiltinMaskedScatter(Sema &S, CallExpr *TheCall) {
-  if (S.checkArgCount(TheCall, 4))
-    return ExprError();
-
-  if (ConvertMaskedBuiltinArgs(S, TheCall))
-    return ExprError();
-
-  Expr *MaskArg = TheCall->getArg(0);
-  Expr *IdxArg = TheCall->getArg(1);
-  Expr *ValArg = TheCall->getArg(2);
-  Expr *PtrArg = TheCall->getArg(3);
-  if (TheCall->isTypeDependent())
-    return TheCall;
-
-  if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 4, /*AllowConst=*/false,
-                             /*AllowAS=*/true))
-    return ExprError();
-
-  QualType IdxTy = IdxArg->getType();
-  const VectorType *IdxVecTy = IdxTy->getAs<VectorType>();
-  if (!IdxTy->isExtVectorType() || !IdxVecTy->getElementType()->isIntegerType())
-    return S.Diag(MaskArg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
-           << 2 << /* vector of */ 4 << /* integer */ 1 << /* no fp */ 0
-           << IdxTy;
-
-  QualType ValTy = ValArg->getType();
-  QualType MaskTy = MaskArg->getType();
-  QualType PtrTy = PtrArg->getType();
-  QualType PointeeTy = PtrTy->getPointeeType();
-
-  const VectorType *MaskVecTy = MaskTy->castAs<VectorType>();
-  const VectorType *ValVecTy = ValTy->castAs<VectorType>();
-  if (MaskVecTy->getNumElements() != IdxVecTy->getNumElements())
-    return ExprError(
-        S.Diag(TheCall->getBeginLoc(), diag::err_vec_masked_load_store_size)
-        << S.getASTContext().BuiltinInfo.getQuotedName(
-               TheCall->getBuiltinCallee())
-        << MaskTy << IdxTy);
-  if (MaskVecTy->getNumElements() != ValVecTy->getNumElements())
-    return ExprError(
-        S.Diag(TheCall->getBeginLoc(), diag::err_vec_masked_load_store_size)
-        << S.getASTContext().BuiltinInfo.getQuotedName(
-               TheCall->getBuiltinCallee())
-        << MaskTy << ValTy);
-
-  QualType ArgTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(),
-                                              MaskVecTy->getNumElements());
-  if (!S.Context.hasSameType(ValTy.getUnqualifiedType(), ArgTy))
-    return ExprError(S.Diag(TheCall->getBeginLoc(),
-                            diag::err_vec_builtin_incompatible_vector)
-                     << TheCall->getDirectCallee() << /*isMoreThanTwoArgs*/ 2
-                     << SourceRange(TheCall->getArg(1)->getBeginLoc(),
-                                    TheCall->getArg(1)->getEndLoc()));
-
-  TheCall->setType(S.Context.VoidTy);
-  return TheCall;
-}
-
-static ExprResult BuiltinInvoke(Sema &S, CallExpr *TheCall) {
-  SourceLocation Loc = TheCall->getBeginLoc();
-  MutableArrayRef Args(TheCall->getArgs(), TheCall->getNumArgs());
-  assert(llvm::none_of(Args, [](Expr *Arg) { return Arg->isTypeDependent(); }));
-
-  if (Args.size() == 0) {
-    S.Diag(TheCall->getBeginLoc(),
-           diag::err_typecheck_call_too_few_args_at_least)
-        << /*callee_type=*/0 << /*min_arg_count=*/1 << /*actual_arg_count=*/0
-        << /*is_non_object=*/0 << TheCall->getSourceRange();
-    return ExprError();
-  }
-
-  QualType FuncT = Args[0]->getType();
-
-  if (const auto *MPT = FuncT->getAs<MemberPointerType>()) {
-    if (Args.size() < 2) {
-      S.Diag(TheCall->getBeginLoc(),
-             diag::err_typecheck_call_too_few_args_at_least)
-          << /*callee_type=*/0 << /*min_arg_count=*/2 << /*actual_arg_count=*/1
-          << /*is_non_object=*/0 << TheCall->getSourceRange();
-      return ExprError();
-    }
-
-    const Type *MemPtrClass = MPT->getQualifier().getAsType();
-    QualType ObjectT = Args[1]->getType();
-
-    if (MPT->isMemberDataPointer() && S.checkArgCount(TheCall, 2))
-      return ExprError();
-
-    ExprResult ObjectArg = [&]() -> ExprResult {
-      // (1.1): (t1.*f)(t2, ..., tN) when f is a pointer to a member function of
-      // a class T and is_same_v<T, remove_cvref_t<decltype(t1)>> ||
-      // is_base_of_v<T, remove_cvref_t<decltype(t1)>> is true;
-      // (1.4): t1.*f when N=1 and f is a pointer to data member of a class T
-      // and is_same_v<T, remove_cvref_t<decltype(t1)>> ||
-      // is_base_of_v<T, remove_cvref_t<decltype(t1)>> is true;
-      if (S.Context.hasSameType(QualType(MemPtrClass, 0),
-                                S.BuiltinRemoveCVRef(ObjectT, Loc)) ||
-          S.BuiltinIsBaseOf(Args[1]->getBeginLoc(), QualType(MemPtrClass, 0),
-                            S.BuiltinRemoveCVRef(ObjectT, Loc))) {
-        return Args[1];
-      }
-
-      // (t1.get().*f)(t2, ..., tN) when f is a pointer to a member function of
-      // a class T and remove_cvref_t<decltype(t1)> is a specialization of
-      // reference_wrapper;
-      if (const auto *RD = ObjectT->getAsCXXRecordDecl()) {
-        if (RD->isInStdNamespace() &&
-            RD->getDeclName().getAsString() == "reference_wrapper") {
-          CXXScopeSpec SS;
-          IdentifierInfo *GetName = &S.Context.Idents.get("get");
-          UnqualifiedId GetID;
-          GetID.setIdentifier(GetName, Loc);
-
-          ExprResult MemExpr = S.ActOnMemberAccessExpr(
-              S.getCurScope(), Args[1], Loc, tok::period, SS,
-              /*TemplateKWLoc=*/SourceLocation(), GetID, nullptr);
-
-          if (MemExpr.isInvalid())
-            return ExprError();
-
-          return S.ActOnCallExpr(S.getCurScope(), MemExpr.get(), Loc, {}, Loc);
-        }
-      }
-
-      // ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a
-      // class T and t1 does not satisfy the previous two items;
-
-      return S.ActOnUnaryOp(S.getCurScope(), Loc, tok::star, Args[1]);
-    }();
-
-    if (ObjectArg.isInvalid())
-      return ExprError();
-
-    ExprResult BinOp = S.ActOnBinOp(S.getCurScope(), TheCall->getBeginLoc(),
-                                    tok::periodstar, ObjectArg.get(), Args[0]);
-    if (BinOp.isInvalid())
-      return ExprError();
-
-    if (MPT->isMemberDataPointer())
-      return BinOp;
-
-    auto *MemCall = new (S.Context)
-        ParenExpr(SourceLocation(), SourceLocation(), BinOp.get());
-
-    return S.ActOnCallExpr(S.getCurScope(), MemCall, TheCall->getBeginLoc(),
-                           Args.drop_front(2), TheCall->getRParenLoc());
-  }
-  return S.ActOnCallExpr(S.getCurScope(), Args.front(), TheCall->getBeginLoc(),
-                         Args.drop_front(), TheCall->getRParenLoc());
-}
-
-// Performs a similar job to Sema::UsualUnaryConversions, but without any
-// implicit promotion of integral/enumeration types.
-static ExprResult BuiltinVectorMathConversions(Sema &S, Expr *E) {
-  // First, convert to an r-value.
-  ExprResult Res = S.DefaultFunctionArrayLvalueConversion(E);
-  if (Res.isInvalid())
-    return ExprError();
-
-  // Promote floating-point types.
-  return S.UsualUnaryFPConversions(Res.get());
-}
-
-ExprResult
-Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
-                               CallExpr *TheCall) {
-  ExprResult TheCallResult(TheCall);
-
-  // Find out if any arguments are required to be integer constant expressions.
-  unsigned ICEArguments = 0;
-  ASTContext::GetBuiltinTypeError Error;
-  Context.GetBuiltinType(BuiltinID, Error, &ICEArguments);
-  if (Error != ASTContext::GE_None)
-    ICEArguments = 0;  // Don't diagnose previously diagnosed errors.
-
-  // If any arguments are required to be ICE's, check and diagnose.
-  for (unsigned ArgNo = 0; ICEArguments != 0; ++ArgNo) {
-    // Skip arguments not required to be ICE's.
-    if ((ICEArguments & (1 << ArgNo)) == 0) continue;
-
-    llvm::APSInt Result;
-    // If we don't have enough arguments, continue so we can issue better
-    // diagnostic in checkArgCount(...)
-    if (ArgNo < TheCall->getNumArgs() &&
-        BuiltinConstantArg(TheCall, ArgNo, Result))
-      return true;
-    ICEArguments &= ~(1 << ArgNo);
-  }
-
-  FPOptions FPO;
-  switch (BuiltinID) {
-  case Builtin::BI__builtin_cpu_supports:
-  case Builtin::BI__builtin_cpu_is:
-    if (BuiltinCpu(*this, Context.getTargetInfo(), TheCall,
-                   Context.getAuxTargetInfo(), BuiltinID))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_cpu_init:
-    if (!Context.getTargetInfo().supportsCpuInit()) {
-      Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
-          << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
-      return ExprError();
-    }
-    break;
-  case Builtin::BI__builtin___CFStringMakeConstantString:
-    // CFStringMakeConstantString is currently not implemented for GOFF (i.e.,
-    // on z/OS) and for XCOFF (i.e., on AIX). Emit unsupported
-    if (CheckBuiltinTargetNotInUnsupported(
-            *this, BuiltinID, TheCall,
-            {llvm::Triple::GOFF, llvm::Triple::XCOFF}))
-      return ExprError();
-    assert(TheCall->getNumArgs() == 1 &&
-           "Wrong # arguments to builtin CFStringMakeConstantString");
-    if (ObjC().CheckObjCString(TheCall->getArg(0)))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_ms_va_start:
-  case Builtin::BI__builtin_stdarg_start:
-  case Builtin::BI__builtin_va_start:
-  case Builtin::BI__builtin_c23_va_start:
-    if (BuiltinVAStart(BuiltinID, TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__va_start: {
-    switch (Context.getTargetInfo().getTriple().getArch()) {
-    case llvm::Triple::aarch64:
-    case llvm::Triple::arm:
-    case llvm::Triple::thumb:
-      if (BuiltinVAStartARMMicrosoft(TheCall))
-        return ExprError();
-      break;
-    default:
-      if (BuiltinVAStart(BuiltinID, TheCall))
-        return ExprError();
-      break;
-    }
-    break;
-  }
-
-  // The acquire, release, and no fence variants are ARM and AArch64 only.
-  case Builtin::BI_interlockedbittestandset_acq:
-  case Builtin::BI_interlockedbittestandset_rel:
-  case Builtin::BI_interlockedbittestandset_nf:
-  case Builtin::BI_interlockedbittestandreset_acq:
-  case Builtin::BI_interlockedbittestandreset_rel:
-  case Builtin::BI_interlockedbittestandreset_nf:
-    if (CheckBuiltinTargetInSupported(
-            *this, TheCall,
-            {llvm::Triple::arm, llvm::Triple::thumb, llvm::Triple::aarch64}))
-      return ExprError();
-    break;
-
-  // The 64-bit bittest variants are x64, ARM, and AArch64 only.
-  case Builtin::BI_bittest64:
-  case Builtin::BI_bittestandcomplement64:
-  case Builtin::BI_bittestandreset64:
-  case Builtin::BI_bittestandset64:
-  case Builtin::BI_interlockedbittestandreset64:
-  case Builtin::BI_interlockedbittestandset64:
-    if (CheckBuiltinTargetInSupported(
-            *this, TheCall,
-            {llvm::Triple::x86_64, llvm::Triple::arm, llvm::Triple::thumb,
-             llvm::Triple::aarch64, llvm::Triple::amdgcn}))
-      return ExprError();
-    break;
-
-  // The 64-bit acquire, release, and no fence variants are AArch64 only.
-  case Builtin::BI_interlockedbittestandreset64_acq:
-  case Builtin::BI_interlockedbittestandreset64_rel:
-  case Builtin::BI_interlockedbittestandreset64_nf:
-  case Builtin::BI_interlockedbittestandset64_acq:
-  case Builtin::BI_interlockedbittestandset64_rel:
-  case Builtin::BI_interlockedbittestandset64_nf:
-    if (CheckBuiltinTargetInSupported(*this, TheCall, {llvm::Triple::aarch64}))
-      return ExprError();
-    break;
-
-  case Builtin::BI__builtin_set_flt_rounds:
-    if (CheckBuiltinTargetInSupported(
-            *this, TheCall,
-            {llvm::Triple::x86, llvm::Triple::x86_64, llvm::Triple::arm,
-             llvm::Triple::thumb, llvm::Triple::aarch64, llvm::Triple::amdgcn,
-             llvm::Triple::ppc, llvm::Triple::ppc64, llvm::Triple::ppcle,
-             llvm::Triple::ppc64le}))
-      return ExprError();
-    break;
-
-  case Builtin::BI__builtin_isgreater:
-  case Builtin::BI__builtin_isgreaterequal:
-  case Builtin::BI__builtin_isless:
-  case Builtin::BI__builtin_islessequal:
-  case Builtin::BI__builtin_islessgreater:
-  case Builtin::BI__builtin_isunordered:
-    if (BuiltinUnorderedCompare(TheCall, BuiltinID))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_fpclassify:
-    if (BuiltinFPClassification(TheCall, 6, BuiltinID))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_isfpclass:
-    if (BuiltinFPClassification(TheCall, 2, BuiltinID))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_isfinite:
-  case Builtin::BI__builtin_isinf:
-  case Builtin::BI__builtin_isinf_sign:
-  case Builtin::BI__builtin_isnan:
-  case Builtin::BI__builtin_issignaling:
-  case Builtin::BI__builtin_isnormal:
-  case Builtin::BI__builtin_issubnormal:
-  case Builtin::BI__builtin_iszero:
-  case Builtin::BI__builtin_signbit:
-  case Builtin::BI__builtin_signbitf:
-  case Builtin::BI__builtin_signbitl:
-    if (BuiltinFPClassification(TheCall, 1, BuiltinID))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_shufflevector:
-    return BuiltinShuffleVector(TheCall);
-    // TheCall will be freed by the smart pointer here, but that's fine, since
-    // BuiltinShuffleVector guts it, but then doesn't release it.
-  case Builtin::BI__builtin_masked_load:
-  case Builtin::BI__builtin_masked_expand_load:
-    return BuiltinMaskedLoad(*this, TheCall);
-  case Builtin::BI__builtin_masked_store:
-  case Builtin::BI__builtin_masked_compress_store:
-    return BuiltinMaskedStore(*this, TheCall);
-  case Builtin::BI__builtin_masked_gather:
-    return BuiltinMaskedGather(*this, TheCall);
-  case Builtin::BI__builtin_masked_scatter:
-    return BuiltinMaskedScatter(*this, TheCall);
-  case Builtin::BI__builtin_invoke:
-    return BuiltinInvoke(*this, TheCall);
-  case Builtin::BI__builtin_prefetch:
-    if (BuiltinPrefetch(TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_alloca_with_align:
-  case Builtin::BI__builtin_alloca_with_align_uninitialized:
-    if (BuiltinAllocaWithAlign(TheCall))
-      return ExprError();
-    [[fallthrough]];
-  case Builtin::BI__builtin_alloca:
-  case Builtin::BI__builtin_alloca_uninitialized:
-    Diag(TheCall->getBeginLoc(), diag::warn_alloca)
-        << TheCall->getDirectCallee();
-    if (getLangOpts().OpenCL) {
-      builtinAllocaAddrSpace(*this, TheCall);
-    }
-    break;
-  case Builtin::BI__builtin_infer_alloc_token:
-    if (checkBuiltinInferAllocToken(*this, TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__arithmetic_fence:
-    if (BuiltinArithmeticFence(TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__assume:
-  case Builtin::BI__builtin_assume:
-    if (BuiltinAssume(TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_assume_aligned:
-    if (BuiltinAssumeAligned(TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_dynamic_object_size:
-  case Builtin::BI__builtin_object_size:
-    if (BuiltinConstantArgRange(TheCall, 1, 0, 3))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_longjmp:
-    if (BuiltinLongjmp(TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_setjmp:
-    if (BuiltinSetjmp(TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_classify_type:
-    if (checkArgCount(TheCall, 1))
-      return true;
-    TheCall->setType(Context.IntTy);
-    break;
-  case Builtin::BI__builtin_complex:
-    if (BuiltinComplex(TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_constant_p: {
-    if (checkArgCount(TheCall, 1))
-      return true;
-    ExprResult Arg = DefaultFunctionArrayLvalueConversion(TheCall->getArg(0));
-    if (Arg.isInvalid()) return true;
-    TheCall->setArg(0, Arg.get());
-    TheCall->setType(Context.IntTy);
-    break;
-  }
-  case Builtin::BI__builtin_launder:
-    return BuiltinLaunder(*this, TheCall);
-  case Builtin::BI__builtin_is_within_lifetime:
-    return BuiltinIsWithinLifetime(*this, TheCall);
-  case Builtin::BI__builtin_trivially_relocate:
-    return BuiltinTriviallyRelocate(*this, TheCall);
-
-  case Builtin::BI__sync_fetch_and_add:
-  case Builtin::BI__sync_fetch_and_add_1:
-  case Builtin::BI__sync_fetch_and_add_2:
-  case Builtin::BI__sync_fetch_and_add_4:
-  case Builtin::BI__sync_fetch_and_add_8:
-  case Builtin::BI__sync_fetch_and_add_16:
-  case Builtin::BI__sync_fetch_and_sub:
-  case Builtin::BI__sync_fetch_and_sub_1:
-  case Builtin::BI__sync_fetch_and_sub_2:
-  case Builtin::BI__sync_fetch_and_sub_4:
-  case Builtin::BI__sync_fetch_and_sub_8:
-  case Builtin::BI__sync_fetch_and_sub_16:
-  case Builtin::BI__sync_fetch_and_or:
-  case Builtin::BI__sync_fetch_and_or_1:
-  case Builtin::BI__sync_fetch_and_or_2:
-  case Builtin::BI__sync_fetch_and_or_4:
-  case Builtin::BI__sync_fetch_and_or_8:
-  case Builtin::BI__sync_fetch_and_or_16:
-  case Builtin::BI__sync_fetch_and_and:
-  case Builtin::BI__sync_fetch_and_and_1:
-  case Builtin::BI__sync_fetch_and_and_2:
-  case Builtin::BI__sync_fetch_and_and_4:
-  case Builtin::BI__sync_fetch_and_and_8:
-  case Builtin::BI__sync_fetch_and_and_16:
-  case Builtin::BI__sync_fetch_and_xor:
-  case Builtin::BI__sync_fetch_and_xor_1:
-  case Builtin::BI__sync_fetch_and_xor_2:
-  case Builtin::BI__sync_fetch_and_xor_4:
-  case Builtin::BI__sync_fetch_and_xor_8:
-  case Builtin::BI__sync_fetch_and_xor_16:
-  case Builtin::BI__sync_fetch_and_nand:
-  case Builtin::BI__sync_fetch_and_nand_1:
-  case Builtin::BI__sync_fetch_and_nand_2:
-  case Builtin::BI__sync_fetch_and_nand_4:
-  case Builtin::BI__sync_fetch_and_nand_8:
-  case Builtin::BI__sync_fetch_and_nand_16:
-  case Builtin::BI__sync_add_and_fetch:
-  case Builtin::BI__sync_add_and_fetch_1:
-  case Builtin::BI__sync_add_and_fetch_2:
-  case Builtin::BI__sync_add_and_fetch_4:
-  case Builtin::BI__sync_add_and_fetch_8:
-  case Builtin::BI__sync_add_and_fetch_16:
-  case Builtin::BI__sync_sub_and_fetch:
-  case Builtin::BI__sync_sub_and_fetch_1:
-  case Builtin::BI__sync_sub_and_fetch_2:
-  case Builtin::BI__sync_sub_and_fetch_4:
-  case Builtin::BI__sync_sub_and_fetch_8:
-  case Builtin::BI__sync_sub_and_fetch_16:
-  case Builtin::BI__sync_and_and_fetch:
-  case Builtin::BI__sync_and_and_fetch_1:
-  case Builtin::BI__sync_and_and_fetch_2:
-  case Builtin::BI__sync_and_and_fetch_4:
-  case Builtin::BI__sync_and_and_fetch_8:
-  case Builtin::BI__sync_and_and_fetch_16:
-  case Builtin::BI__sync_or_and_fetch:
-  case Builtin::BI__sync_or_and_fetch_1:
-  case Builtin::BI__sync_or_and_fetch_2:
-  case Builtin::BI__sync_or_and_fetch_4:
-  case Builtin::BI__sync_or_and_fetch_8:
-  case Builtin::BI__sync_or_and_fetch_16:
-  case Builtin::BI__sync_xor_and_fetch:
-  case Builtin::BI__sync_xor_and_fetch_1:
-  case Builtin::BI__sync_xor_and_fetch_2:
-  case Builtin::BI__sync_xor_and_fetch_4:
-  case Builtin::BI__sync_xor_and_fetch_8:
-  case Builtin::BI__sync_xor_and_fetch_16:
-  case Builtin::BI__sync_nand_and_fetch:
-  case Builtin::BI__sync_nand_and_fetch_1:
-  case Builtin::BI__sync_nand_and_fetch_2:
-  case Builtin::BI__sync_nand_and_fetch_4:
-  case Builtin::BI__sync_nand_and_fetch_8:
-  case Builtin::BI__sync_nand_and_fetch_16:
-  case Builtin::BI__sync_val_compare_and_swap:
-  case Builtin::BI__sync_val_compare_and_swap_1:
-  case Builtin::BI__sync_val_compare_and_swap_2:
-  case Builtin::BI__sync_val_compare_and_swap_4:
-  case Builtin::BI__sync_val_compare_and_swap_8:
-  case Builtin::BI__sync_val_compare_and_swap_16:
-  case Builtin::BI__sync_bool_compare_and_swap:
-  case Builtin::BI__sync_bool_compare_and_swap_1:
-  case Builtin::BI__sync_bool_compare_and_swap_2:
-  case Builtin::BI__sync_bool_compare_and_swap_4:
-  case Builtin::BI__sync_bool_compare_and_swap_8:
-  case Builtin::BI__sync_bool_compare_and_swap_16:
-  case Builtin::BI__sync_lock_test_and_set:
-  case Builtin::BI__sync_lock_test_and_set_1:
-  case Builtin::BI__sync_lock_test_and_set_2:
-  case Builtin::BI__sync_lock_test_and_set_4:
-  case Builtin::BI__sync_lock_test_and_set_8:
-  case Builtin::BI__sync_lock_test_and_set_16:
-  case Builtin::BI__sync_lock_release:
-  case Builtin::BI__sync_lock_release_1:
-  case Builtin::BI__sync_lock_release_2:
-  case Builtin::BI__sync_lock_release_4:
-  case Builtin::BI__sync_lock_release_8:
-  case Builtin::BI__sync_lock_release_16:
-  case Builtin::BI__sync_swap:
-  case Builtin::BI__sync_swap_1:
-  case Builtin::BI__sync_swap_2:
-  case Builtin::BI__sync_swap_4:
-  case Builtin::BI__sync_swap_8:
-  case Builtin::BI__sync_swap_16:
-    return BuiltinAtomicOverloaded(TheCallResult);
-  case Builtin::BI__sync_synchronize:
-    Diag(TheCall->getBeginLoc(), diag::warn_atomic_implicit_seq_cst)
-        << TheCall->getCallee()->getSourceRange();
-    break;
-  case Builtin::BI__builtin_nontemporal_load:
-  case Builtin::BI__builtin_nontemporal_store:
-    return BuiltinNontemporalOverloaded(TheCallResult);
-  case Builtin::BI__builtin_memcpy_inline: {
-    clang::Expr *SizeOp = TheCall->getArg(2);
-    // We warn about copying to or from `nullptr` pointers when `size` is
-    // greater than 0. When `size` is value dependent we cannot evaluate its
-    // value so we bail out.
-    if (SizeOp->isValueDependent())
-      break;
-    if (!SizeOp->EvaluateKnownConstInt(Context).isZero()) {
-      CheckNonNullArgument(*this, TheCall->getArg(0), TheCall->getExprLoc());
-      CheckNonNullArgument(*this, TheCall->getArg(1), TheCall->getExprLoc());
-    }
-    break;
-  }
-  case Builtin::BI__builtin_memset_inline: {
-    clang::Expr *SizeOp = TheCall->getArg(2);
-    // We warn about filling to `nullptr` pointers when `size` is greater than
-    // 0. When `size` is value dependent we cannot evaluate its value so we bail
-    // out.
-    if (SizeOp->isValueDependent())
-      break;
-    if (!SizeOp->EvaluateKnownConstInt(Context).isZero())
-      CheckNonNullArgument(*this, TheCall->getArg(0), TheCall->getExprLoc());
-    break;
-  }
-#define ATOMIC_BUILTIN(ID, TYPE, ATTRS)                                        \
-  case Builtin::BI##ID:                                                        \
-    return AtomicOpsOverloaded(TheCallResult, AtomicExpr::AO##ID);
-#include "clang/Basic/Builtins.inc"
-  case Builtin::BI__annotation:
-    if (BuiltinMSVCAnnotation(*this, TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_annotation:
-    if (BuiltinAnnotation(*this, TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_addressof:
-    if (BuiltinAddressof(*this, TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_function_start:
-    if (BuiltinFunctionStart(*this, TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_is_aligned:
-  case Builtin::BI__builtin_align_up:
-  case Builtin::BI__builtin_align_down:
-    if (BuiltinAlignment(*this, TheCall, BuiltinID))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_add_overflow:
-  case Builtin::BI__builtin_sub_overflow:
-  case Builtin::BI__builtin_mul_overflow:
-    if (BuiltinOverflow(*this, TheCall, BuiltinID))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_operator_new:
-  case Builtin::BI__builtin_operator_delete: {
-    bool IsDelete = BuiltinID == Builtin::BI__builtin_operator_delete;
-    ExprResult Res =
-        BuiltinOperatorNewDeleteOverloaded(TheCallResult, IsDelete);
-    return Res;
-  }
-  case Builtin::BI__builtin_dump_struct:
-    return BuiltinDumpStruct(*this, TheCall);
-  case Builtin::BI__builtin_expect_with_probability: {
-    // We first want to ensure we are called with 3 arguments
-    if (checkArgCount(TheCall, 3))
-      return ExprError();
-    // then check probability is constant float in range [0.0, 1.0]
-    const Expr *ProbArg = TheCall->getArg(2);
-    SmallVector<PartialDiagnosticAt, 8> Notes;
-    Expr::EvalResult Eval;
-    Eval.Diag = &Notes;
-    if ((!ProbArg->EvaluateAsConstantExpr(Eval, Context)) ||
-        !Eval.Val.isFloat()) {
-      Diag(ProbArg->getBeginLoc(), diag::err_probability_not_constant_float)
-          << ProbArg->getSourceRange();
-      for (const PartialDiagnosticAt &PDiag : Notes)
-        Diag(PDiag.first, PDiag.second);
-      return ExprError();
-    }
-    llvm::APFloat Probability = Eval.Val.getFloat();
-    bool LoseInfo = false;
-    Probability.convert(llvm::APFloat::IEEEdouble(),
-                        llvm::RoundingMode::Dynamic, &LoseInfo);
-    if (!(Probability >= llvm::APFloat(0.0) &&
-          Probability <= llvm::APFloat(1.0))) {
-      Diag(ProbArg->getBeginLoc(), diag::err_probability_out_of_range)
-          << ProbArg->getSourceRange();
-      return ExprError();
-    }
-    break;
-  }
-  case Builtin::BI__builtin_preserve_access_index:
-    if (BuiltinPreserveAI(*this, TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_call_with_static_chain:
-    if (BuiltinCallWithStaticChain(*this, TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__exception_code:
-  case Builtin::BI_exception_code:
-    if (BuiltinSEHScopeCheck(*this, TheCall, Scope::SEHExceptScope,
-                             diag::err_seh___except_block))
-      return ExprError();
-    break;
-  case Builtin::BI__exception_info:
-  case Builtin::BI_exception_info:
-    if (BuiltinSEHScopeCheck(*this, TheCall, Scope::SEHFilterScope,
-                             diag::err_seh___except_filter))
-      return ExprError();
-    break;
-  case Builtin::BI__GetExceptionInfo:
-    if (checkArgCount(TheCall, 1))
-      return ExprError();
-
-    if (CheckCXXThrowOperand(
-            TheCall->getBeginLoc(),
-            Context.getExceptionObjectType(FDecl->getParamDecl(0)->getType()),
-            TheCall))
-      return ExprError();
-
-    TheCall->setType(Context.VoidPtrTy);
-    break;
-  case Builtin::BIaddressof:
-  case Builtin::BI__addressof:
-  case Builtin::BIforward:
-  case Builtin::BIforward_like:
-  case Builtin::BImove:
-  case Builtin::BImove_if_noexcept:
-  case Builtin::BIas_const: {
-    // These are all expected to be of the form
-    //   T &/&&/* f(U &/&&)
-    // where T and U only differ in qualification.
-    if (checkArgCount(TheCall, 1))
-      return ExprError();
-    QualType Param = FDecl->getParamDecl(0)->getType();
-    QualType Result = FDecl->getReturnType();
-    bool ReturnsPointer = BuiltinID == Builtin::BIaddressof ||
-                          BuiltinID == Builtin::BI__addressof;
-    if (!(Param->isReferenceType() &&
-          (ReturnsPointer ? Result->isAnyPointerType()
-                          : Result->isReferenceType()) &&
-          Context.hasSameUnqualifiedType(Param->getPointeeType(),
-                                         Result->getPointeeType()))) {
-      Diag(TheCall->getBeginLoc(), diag::err_builtin_move_forward_unsupported)
-          << FDecl;
-      return ExprError();
-    }
-    break;
-  }
-  case Builtin::BI__builtin_ptrauth_strip:
-    return PointerAuthStrip(*this, TheCall);
-  case Builtin::BI__builtin_ptrauth_blend_discriminator:
-    return PointerAuthBlendDiscriminator(*this, TheCall);
-  case Builtin::BI__builtin_ptrauth_sign_constant:
-    return PointerAuthSignOrAuth(*this, TheCall, PAO_Sign,
-                                 /*RequireConstant=*/true);
-  case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
-    return PointerAuthSignOrAuth(*this, TheCall, PAO_Sign,
-                                 /*RequireConstant=*/false);
-  case Builtin::BI__builtin_ptrauth_auth:
-    return PointerAuthSignOrAuth(*this, TheCall, PAO_Auth,
-                                 /*RequireConstant=*/false);
-  case Builtin::BI__builtin_ptrauth_sign_generic_data:
-    return PointerAuthSignGenericData(*this, TheCall);
-  case Builtin::BI__builtin_ptrauth_auth_and_resign:
-    return PointerAuthAuthAndResign(*this, TheCall);
-  case Builtin::BI__builtin_ptrauth_auth_load_relative_and_sign:
-    return PointerAuthAuthLoadRelativeAndSign(*this, TheCall);
-  case Builtin::BI__builtin_ptrauth_string_discriminator:
-    return PointerAuthStringDiscriminator(*this, TheCall);
-
-  case Builtin::BI__builtin_get_vtable_pointer:
-    return GetVTablePointer(*this, TheCall);
-
-  // OpenCL v2.0, s6.13.16 - Pipe functions
-  case Builtin::BIread_pipe:
-  case Builtin::BIwrite_pipe:
-    // Since those two functions are declared with var args, we need a semantic
-    // check for the argument.
-    if (OpenCL().checkBuiltinRWPipe(TheCall))
-      return ExprError();
-    break;
-  case Builtin::BIreserve_read_pipe:
-  case Builtin::BIreserve_write_pipe:
-  case Builtin::BIwork_group_reserve_read_pipe:
-  case Builtin::BIwork_group_reserve_write_pipe:
-    if (OpenCL().checkBuiltinReserveRWPipe(TheCall))
-      return ExprError();
-    break;
-  case Builtin::BIsub_group_reserve_read_pipe:
-  case Builtin::BIsub_group_reserve_write_pipe:
-    if (OpenCL().checkSubgroupExt(TheCall) ||
-        OpenCL().checkBuiltinReserveRWPipe(TheCall))
-      return ExprError();
-    break;
-  case Builtin::BIcommit_read_pipe:
-  case Builtin::BIcommit_write_pipe:
-  case Builtin::BIwork_group_commit_read_pipe:
-  case Builtin::BIwork_group_commit_write_pipe:
-    if (OpenCL().checkBuiltinCommitRWPipe(TheCall))
-      return ExprError();
-    break;
-  case Builtin::BIsub_group_commit_read_pipe:
-  case Builtin::BIsub_group_commit_write_pipe:
-    if (OpenCL().checkSubgroupExt(TheCall) ||
-        OpenCL().checkBuiltinCommitRWPipe(TheCall))
-      return ExprError();
-    break;
-  case Builtin::BIget_pipe_num_packets:
-  case Builtin::BIget_pipe_max_packets:
-    if (OpenCL().checkBuiltinPipePackets(TheCall))
-      return ExprError();
-    break;
-  case Builtin::BIto_global:
-  case Builtin::BIto_local:
-  case Builtin::BIto_private:
-    if (OpenCL().checkBuiltinToAddr(BuiltinID, TheCall))
-      return ExprError();
-    break;
-  // OpenCL v2.0, s6.13.17 - Enqueue kernel functions.
-  case Builtin::BIenqueue_kernel:
-    if (OpenCL().checkBuiltinEnqueueKernel(TheCall))
-      return ExprError();
-    break;
-  case Builtin::BIget_kernel_work_group_size:
-  case Builtin::BIget_kernel_preferred_work_group_size_multiple:
-    if (OpenCL().checkBuiltinKernelWorkGroupSize(TheCall))
-      return ExprError();
-    break;
-  case Builtin::BIget_kernel_max_sub_group_size_for_ndrange:
-  case Builtin::BIget_kernel_sub_group_count_for_ndrange:
-    if (OpenCL().checkBuiltinNDRangeAndBlock(TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_os_log_format:
-    Cleanup.setExprNeedsCleanups(true);
-    [[fallthrough]];
-  case Builtin::BI__builtin_os_log_format_buffer_size:
-    if (BuiltinOSLogFormat(TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_frame_address:
-  case Builtin::BI__builtin_return_address: {
-    if (BuiltinConstantArgRange(TheCall, 0, 0, 0xFFFF))
-      return ExprError();
-
-    // -Wframe-address warning if non-zero passed to builtin
-    // return/frame address.
-    Expr::EvalResult Result;
-    if (!TheCall->getArg(0)->isValueDependent() &&
-        TheCall->getArg(0)->EvaluateAsInt(Result, getASTContext()) &&
-        Result.Val.getInt() != 0)
-      Diag(TheCall->getBeginLoc(), diag::warn_frame_address)
-          << ((BuiltinID == Builtin::BI__builtin_return_address)
-                  ? "__builtin_return_address"
-                  : "__builtin_frame_address")
-          << TheCall->getSourceRange();
-    break;
-  }
-
-  case Builtin::BI__builtin_nondeterministic_value: {
-    if (BuiltinNonDeterministicValue(TheCall))
-      return ExprError();
-    break;
-  }
-
-  // __builtin_elementwise_abs restricts the element type to signed integers or
-  // floating point types only.
-  case Builtin::BI__builtin_elementwise_abs:
-    if (PrepareBuiltinElementwiseMathOneArgCall(
-            TheCall, EltwiseBuiltinArgTyRestriction::SignedIntOrFloatTy))
-      return ExprError();
-    break;
-
-  // These builtins restrict the element type to floating point
-  // types only.
-  case Builtin::BI__builtin_elementwise_acos:
-  case Builtin::BI__builtin_elementwise_asin:
-  case Builtin::BI__builtin_elementwise_atan:
-  case Builtin::BI__builtin_elementwise_ceil:
-  case Builtin::BI__builtin_elementwise_cos:
-  case Builtin::BI__builtin_elementwise_cosh:
-  case Builtin::BI__builtin_elementwise_exp:
-  case Builtin::BI__builtin_elementwise_exp2:
-  case Builtin::BI__builtin_elementwise_exp10:
-  case Builtin::BI__builtin_elementwise_floor:
-  case Builtin::BI__builtin_elementwise_log:
-  case Builtin::BI__builtin_elementwise_log2:
-  case Builtin::BI__builtin_elementwise_log10:
-  case Builtin::BI__builtin_elementwise_roundeven:
-  case Builtin::BI__builtin_elementwise_round:
-  case Builtin::BI__builtin_elementwise_rint:
-  case Builtin::BI__builtin_elementwise_nearbyint:
-  case Builtin::BI__builtin_elementwise_sin:
-  case Builtin::BI__builtin_elementwise_sinh:
-  case Builtin::BI__builtin_elementwise_sqrt:
-  case Builtin::BI__builtin_elementwise_tan:
-  case Builtin::BI__builtin_elementwise_tanh:
-  case Builtin::BI__builtin_elementwise_trunc:
-  case Builtin::BI__builtin_elementwise_canonicalize:
-    if (PrepareBuiltinElementwiseMathOneArgCall(
-            TheCall, EltwiseBuiltinArgTyRestriction::FloatTy))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_elementwise_fma:
-    if (BuiltinElementwiseTernaryMath(TheCall))
-      return ExprError();
-    break;
-
-  case Builtin::BI__builtin_elementwise_ldexp: {
-    if (checkArgCount(TheCall, 2))
-      return ExprError();
-
-    ExprResult A = BuiltinVectorMathConversions(*this, TheCall->getArg(0));
-    if (A.isInvalid())
-      return ExprError();
-    QualType TyA = A.get()->getType();
-    if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA,
-                                    EltwiseBuiltinArgTyRestriction::FloatTy, 1))
-      return ExprError();
-
-    ExprResult Exp = UsualUnaryConversions(TheCall->getArg(1));
-    if (Exp.isInvalid())
-      return ExprError();
-    QualType TyExp = Exp.get()->getType();
-    if (checkMathBuiltinElementType(*this, Exp.get()->getBeginLoc(), TyExp,
-                                    EltwiseBuiltinArgTyRestriction::IntegerTy,
-                                    2))
-      return ExprError();
-
-    // Check the two arguments are either scalars or vectors of equal length.
-    const auto *Vec0 = TyA->getAs<VectorType>();
-    const auto *Vec1 = TyExp->getAs<VectorType>();
-    unsigned Arg0Length = Vec0 ? Vec0->getNumElements() : 0;
-    unsigned Arg1Length = Vec1 ? Vec1->getNumElements() : 0;
-    if (Arg0Length != Arg1Length) {
-      Diag(Exp.get()->getBeginLoc(),
-           diag::err_typecheck_vector_lengths_not_equal)
-          << TyA << TyExp << A.get()->getSourceRange()
-          << Exp.get()->getSourceRange();
-      return ExprError();
-    }
-
-    TheCall->setArg(0, A.get());
-    TheCall->setArg(1, Exp.get());
-    TheCall->setType(TyA);
-    break;
-  }
-
-  // These builtins restrict the element type to floating point
-  // types only, and take in two arguments.
-  case Builtin::BI__builtin_elementwise_minnum:
-  case Builtin::BI__builtin_elementwise_maxnum:
-  case Builtin::BI__builtin_elementwise_minimum:
-  case Builtin::BI__builtin_elementwise_maximum:
-  case Builtin::BI__builtin_elementwise_minimumnum:
-  case Builtin::BI__builtin_elementwise_maximumnum:
-  case Builtin::BI__builtin_elementwise_atan2:
-  case Builtin::BI__builtin_elementwise_fmod:
-  case Builtin::BI__builtin_elementwise_pow:
-    if (BuiltinElementwiseMath(TheCall,
-                               EltwiseBuiltinArgTyRestriction::FloatTy))
-      return ExprError();
-    break;
-  // These builtins restrict the element type to integer
-  // types only.
-  case Builtin::BI__builtin_elementwise_add_sat:
-  case Builtin::BI__builtin_elementwise_sub_sat:
-    if (BuiltinElementwiseMath(TheCall,
-                               EltwiseBuiltinArgTyRestriction::IntegerTy))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_elementwise_fshl:
-  case Builtin::BI__builtin_elementwise_fshr:
-    if (BuiltinElementwiseTernaryMath(
-            TheCall, EltwiseBuiltinArgTyRestriction::IntegerTy))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_elementwise_min:
-  case Builtin::BI__builtin_elementwise_max:
-    if (BuiltinElementwiseMath(TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_elementwise_popcount:
-  case Builtin::BI__builtin_elementwise_bitreverse:
-    if (PrepareBuiltinElementwiseMathOneArgCall(
-            TheCall, EltwiseBuiltinArgTyRestriction::IntegerTy))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_elementwise_copysign: {
-    if (checkArgCount(TheCall, 2))
-      return ExprError();
-
-    ExprResult Magnitude = UsualUnaryConversions(TheCall->getArg(0));
-    ExprResult Sign = UsualUnaryConversions(TheCall->getArg(1));
-    if (Magnitude.isInvalid() || Sign.isInvalid())
-      return ExprError();
-
-    QualType MagnitudeTy = Magnitude.get()->getType();
-    QualType SignTy = Sign.get()->getType();
-    if (checkMathBuiltinElementType(
-            *this, TheCall->getArg(0)->getBeginLoc(), MagnitudeTy,
-            EltwiseBuiltinArgTyRestriction::FloatTy, 1) ||
-        checkMathBuiltinElementType(
-            *this, TheCall->getArg(1)->getBeginLoc(), SignTy,
-            EltwiseBuiltinArgTyRestriction::FloatTy, 2)) {
-      return ExprError();
-    }
-
-    if (MagnitudeTy.getCanonicalType() != SignTy.getCanonicalType()) {
-      return Diag(Sign.get()->getBeginLoc(),
-                  diag::err_typecheck_call_different_arg_types)
-             << MagnitudeTy << SignTy;
-    }
-
-    TheCall->setArg(0, Magnitude.get());
-    TheCall->setArg(1, Sign.get());
-    TheCall->setType(Magnitude.get()->getType());
-    break;
-  }
-  case Builtin::BI__builtin_elementwise_clzg:
-  case Builtin::BI__builtin_elementwise_ctzg:
-    // These builtins can be unary or binary. Note for empty calls we call the
-    // unary checker in order to not emit an error that says the function
-    // expects 2 arguments, which would be misleading.
-    if (TheCall->getNumArgs() <= 1) {
-      if (PrepareBuiltinElementwiseMathOneArgCall(
-              TheCall, EltwiseBuiltinArgTyRestriction::IntegerTy))
-        return ExprError();
-    } else if (BuiltinElementwiseMath(
-                   TheCall, EltwiseBuiltinArgTyRestriction::IntegerTy))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_reduce_max:
-  case Builtin::BI__builtin_reduce_min: {
-    if (PrepareBuiltinReduceMathOneArgCall(TheCall))
-      return ExprError();
-
-    const Expr *Arg = TheCall->getArg(0);
-    const auto *TyA = Arg->getType()->getAs<VectorType>();
-
-    QualType ElTy;
-    if (TyA)
-      ElTy = TyA->getElementType();
-    else if (Arg->getType()->isSizelessVectorType())
-      ElTy = Arg->getType()->getSizelessVectorEltType(Context);
-
-    if (ElTy.isNull()) {
-      Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
-          << 1 << /* vector ty */ 2 << /* no int */ 0 << /* no fp */ 0
-          << Arg->getType();
-      return ExprError();
-    }
-
-    TheCall->setType(ElTy);
-    break;
-  }
-  case Builtin::BI__builtin_reduce_maximum:
-  case Builtin::BI__builtin_reduce_minimum: {
-    if (PrepareBuiltinReduceMathOneArgCall(TheCall))
-      return ExprError();
-
-    const Expr *Arg = TheCall->getArg(0);
-    const auto *TyA = Arg->getType()->getAs<VectorType>();
-
-    QualType ElTy;
-    if (TyA)
-      ElTy = TyA->getElementType();
-    else if (Arg->getType()->isSizelessVectorType())
-      ElTy = Arg->getType()->getSizelessVectorEltType(Context);
-
-    if (ElTy.isNull() || !ElTy->isFloatingType()) {
-      Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
-          << 1 << /* vector of */ 4 << /* no int */ 0 << /* fp */ 1
-          << Arg->getType();
-      return ExprError();
-    }
-
-    TheCall->setType(ElTy);
-    break;
-  }
-
-  // These builtins support vectors of integers only.
-  // TODO: ADD/MUL should support floating-point types.
-  case Builtin::BI__builtin_reduce_add:
-  case Builtin::BI__builtin_reduce_mul:
-  case Builtin::BI__builtin_reduce_xor:
-  case Builtin::BI__builtin_reduce_or:
-  case Builtin::BI__builtin_reduce_and: {
-    if (PrepareBuiltinReduceMathOneArgCall(TheCall))
-      return ExprError();
-
-    const Expr *Arg = TheCall->getArg(0);
-    const auto *TyA = Arg->getType()->getAs<VectorType>();
-
-    QualType ElTy;
-    if (TyA)
-      ElTy = TyA->getElementType();
-    else if (Arg->getType()->isSizelessVectorType())
-      ElTy = Arg->getType()->getSizelessVectorEltType(Context);
-
-    if (ElTy.isNull() || !ElTy->isIntegerType()) {
-      Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
-          << 1 << /* vector of */ 4 << /* int */ 1 << /* no fp */ 0
-          << Arg->getType();
-      return ExprError();
-    }
-
-    TheCall->setType(ElTy);
-    break;
-  }
-
-  case Builtin::BI__builtin_matrix_transpose:
-    return BuiltinMatrixTranspose(TheCall, TheCallResult);
-
-  case Builtin::BI__builtin_matrix_column_major_load:
-    return BuiltinMatrixColumnMajorLoad(TheCall, TheCallResult);
-
-  case Builtin::BI__builtin_matrix_column_major_store:
-    return BuiltinMatrixColumnMajorStore(TheCall, TheCallResult);
-
-  case Builtin::BI__builtin_verbose_trap:
-    if (!checkBuiltinVerboseTrap(TheCall, *this))
-      return ExprError();
-    break;
-
-  case Builtin::BI__builtin_get_device_side_mangled_name: {
-    auto Check = [](CallExpr *TheCall) {
-      if (TheCall->getNumArgs() != 1)
-        return false;
-      auto *DRE = dyn_cast<DeclRefExpr>(TheCall->getArg(0)->IgnoreImpCasts());
-      if (!DRE)
-        return false;
-      auto *D = DRE->getDecl();
-      if (!isa<FunctionDecl>(D) && !isa<VarDecl>(D))
-        return false;
-      return D->hasAttr<CUDAGlobalAttr>() || D->hasAttr<CUDADeviceAttr>() ||
-             D->hasAttr<CUDAConstantAttr>() || D->hasAttr<HIPManagedAttr>();
-    };
-    if (!Check(TheCall)) {
-      Diag(TheCall->getBeginLoc(),
-           diag::err_hip_invalid_args_builtin_mangled_name);
-      return ExprError();
-    }
-    break;
-  }
-  case Builtin::BI__builtin_bswapg:
-    if (BuiltinBswapg(*this, TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_popcountg:
-    if (BuiltinPopcountg(*this, TheCall))
-      return ExprError();
-    break;
-  case Builtin::BI__builtin_clzg:
-  case Builtin::BI__builtin_ctzg:
-    if (BuiltinCountZeroBitsGeneric(*this, TheCall))
-      return ExprError();
-    break;
-
-  case Builtin::BI__builtin_stdc_rotate_left:
-  case Builtin::BI__builtin_stdc_rotate_right:
-    if (BuiltinRotateGeneric(*this, TheCall))
-      return ExprError();
-    break;
-
-  case Builtin::BI__builtin_allow_runtime_check: {
-    Expr *Arg = TheCall->getArg(0);
-    // Check if the argument is a string literal.
-    if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts())) {
-      Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
-          << Arg->getSourceRange();
-      return ExprError();
-    }
-    break;
-  }
-
-  case Builtin::BI__builtin_allow_sanitize_check: {
-    Expr *Arg = TheCall->getArg(0);
-    // Check if the argument is a string literal.
-    const StringLiteral *SanitizerName =
-        dyn_cast<StringLiteral>(Arg->IgnoreParenImpCasts());
-    if (!SanitizerName) {
-      Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
-          << Arg->getSourceRange();
-      return ExprError();
-    }
-    // Validate the sanitizer name.
-    if (!llvm::StringSwitch<bool>(SanitizerName->getString())
-             .Cases({"address", "thread", "memory", "hwaddress",
-                     "kernel-address", "kernel-memory", "kernel-hwaddress"},
-                    true)
-             .Default(false)) {
-      Diag(TheCall->getBeginLoc(), diag::err_invalid_builtin_argument)
-          << SanitizerName->getString() << "__builtin_allow_sanitize_check"
-          << Arg->getSourceRange();
-      return ExprError();
-    }
-    break;
-  }
-  case Builtin::BI__builtin_counted_by_ref:
-    if (BuiltinCountedByRef(TheCall))
-      return ExprError();
-    break;
-  }
-
-  if (getLangOpts().HLSL && HLSL().CheckBuiltinFunctionCall(BuiltinID, TheCall))
-    return ExprError();
-
-  // Since the target specific builtins for each arch overlap, only check those
-  // of the arch we are compiling for.
-  if (Context.BuiltinInfo.isTSBuiltin(BuiltinID)) {
-    if (Context.BuiltinInfo.isAuxBuiltinID(BuiltinID)) {
-      assert(Context.getAuxTargetInfo() &&
-             "Aux Target Builtin, but not an aux target?");
-
-      if (CheckTSBuiltinFunctionCall(
-              *Context.getAuxTargetInfo(),
-              Context.BuiltinInfo.getAuxBuiltinID(BuiltinID), TheCall))
-        return ExprError();
-    } else {
-      if (CheckTSBuiltinFunctionCall(Context.getTargetInfo(), BuiltinID,
-                                     TheCall))
-        return ExprError();
-    }
-  }
-
-  return TheCallResult;
-}
-
-bool Sema::ValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum) {
-  llvm::APSInt Result;
-  // We can't check the value of a dependent argument.
-  Expr *Arg = TheCall->getArg(ArgNum);
-  if (Arg->isTypeDependent() || Arg->isValueDependent())
-    return false;
-
-  // Check constant-ness first.
-  if (BuiltinConstantArg(TheCall, ArgNum, Result))
-    return true;
-
-  // Check contiguous run of 1s, 0xFF0000FF is also a run of 1s.
-  if (Result.isShiftedMask() || (~Result).isShiftedMask())
-    return false;
-
-  return Diag(TheCall->getBeginLoc(),
-              diag::err_argument_not_contiguous_bit_field)
-         << ArgNum << Arg->getSourceRange();
-}
-
-bool Sema::getFormatStringInfo(const Decl *D, unsigned FormatIdx,
-                               unsigned FirstArg, FormatStringInfo *FSI) {
-  bool HasImplicitThisParam = hasImplicitObjectParameter(D);
-  bool IsVariadic = false;
-  if (const FunctionType *FnTy = D->getFunctionType())
-    IsVariadic = cast<FunctionProtoType>(FnTy)->isVariadic();
-  else if (const auto *BD = dyn_cast<BlockDecl>(D))
-    IsVariadic = BD->isVariadic();
-  else if (const auto *OMD = dyn_cast<ObjCMethodDecl>(D))
-    IsVariadic = OMD->isVariadic();
-
-  return getFormatStringInfo(FormatIdx, FirstArg, HasImplicitThisParam,
-                             IsVariadic, FSI);
-}
-
-bool Sema::getFormatStringInfo(unsigned FormatIdx, unsigned FirstArg,
-                               bool HasImplicitThisParam, bool IsVariadic,
-                               FormatStringInfo *FSI) {
-  if (FirstArg == 0)
-    FSI->ArgPassingKind = FAPK_VAList;
-  else if (IsVariadic)
-    FSI->ArgPassingKind = FAPK_Variadic;
-  else
-    FSI->ArgPassingKind = FAPK_Fixed;
-  FSI->FormatIdx = FormatIdx - 1;
-  FSI->FirstDataArg = FSI->ArgPassingKind == FAPK_VAList ? 0 : FirstArg - 1;
-
-  // The way the format attribute works in GCC, the implicit this argument
-  // of member functions is counted. However, it doesn't appear in our own
-  // lists, so decrement format_idx in that case.
-  if (HasImplicitThisParam) {
-    if(FSI->FormatIdx == 0)
-      return false;
-    --FSI->FormatIdx;
-    if (FSI->FirstDataArg != 0)
-      --FSI->FirstDataArg;
-  }
-  return true;
-}
-
-/// Checks if a the given expression evaluates to null.
-///
-/// Returns true if the value evaluates to null.
-static bool CheckNonNullExpr(Sema &S, const Expr *Expr) {
-  // Treat (smart) pointers constructed from nullptr as null, whether we can
-  // const-evaluate them or not.
-  // This must happen first: the smart pointer expr might have _Nonnull type!
-  if (isa<CXXNullPtrLiteralExpr>(
-          IgnoreExprNodes(Expr, IgnoreImplicitAsWrittenSingleStep,
-                          IgnoreElidableImplicitConstructorSingleStep)))
-    return true;
-
-  // If the expression has non-null type, it doesn't evaluate to null.
-  if (auto nullability = Expr->IgnoreImplicit()->getType()->getNullability()) {
-    if (*nullability == NullabilityKind::NonNull)
-      return false;
-  }
-
-  // As a special case, transparent unions initialized with zero are
-  // considered null for the purposes of the nonnull attribute.
-  if (const RecordType *UT = Expr->getType()->getAsUnionType();
-      UT &&
-      UT->getDecl()->getMostRecentDecl()->hasAttr<TransparentUnionAttr>()) {
-    if (const auto *CLE = dyn_cast<CompoundLiteralExpr>(Expr))
-      if (const auto *ILE = dyn_cast<InitListExpr>(CLE->getInitializer()))
-        Expr = ILE->getInit(0);
-  }
-
-  bool Result;
-  return (!Expr->isValueDependent() &&
-          Expr->EvaluateAsBooleanCondition(Result, S.Context) &&
-          !Result);
-}
-
-static void CheckNonNullArgument(Sema &S,
-                                 const Expr *ArgExpr,
-                                 SourceLocation CallSiteLoc) {
-  if (CheckNonNullExpr(S, ArgExpr))
-    S.DiagRuntimeBehavior(CallSiteLoc, ArgExpr,
-                          S.PDiag(diag::warn_null_arg)
-                              << ArgExpr->getSourceRange());
-}
-
-/// Determine whether the given type has a non-null nullability annotation.
-static bool isNonNullType(QualType type) {
-  if (auto nullability = type->getNullability())
-    return *nullability == NullabilityKind::NonNull;
-
-  return false;
-}
-
-static void CheckNonNullArguments(Sema &S,
-                                  const NamedDecl *FDecl,
-                                  const FunctionProtoType *Proto,
-                                  ArrayRef<const Expr *> Args,
-                                  SourceLocation CallSiteLoc) {
-  assert((FDecl || Proto) && "Need a function declaration or prototype");
-
-  // Already checked by constant evaluator.
-  if (S.isConstantEvaluatedContext())
-    return;
-  // Check the attributes attached to the method/function itself.
-  llvm::SmallBitVector NonNullArgs;
-  if (FDecl) {
-    // Handle the nonnull attribute on the function/method declaration itself.
-    for (const auto *NonNull : FDecl->specific_attrs<NonNullAttr>()) {
-      if (!NonNull->args_size()) {
-        // Easy case: all pointer arguments are nonnull.
-        for (const auto *Arg : Args)
-          if (S.isValidPointerAttrType(Arg->getType()))
-            CheckNonNullArgument(S, Arg, CallSiteLoc);
-        return;
-      }
-
-      for (const ParamIdx &Idx : NonNull->args()) {
-        unsigned IdxAST = Idx.getASTIndex();
-        if (IdxAST >= Args.size())
-          continue;
-        if (NonNullArgs.empty())
-          NonNullArgs.resize(Args.size());
-        NonNullArgs.set(IdxAST);
-      }
-    }
-  }
-
-  if (FDecl && (isa<FunctionDecl>(FDecl) || isa<ObjCMethodDecl>(FDecl))) {
-    // Handle the nonnull attribute on the parameters of the
-    // function/method.
-    ArrayRef<ParmVarDecl*> parms;
-    if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(FDecl))
-      parms = FD->parameters();
-    else
-      parms = cast<ObjCMethodDecl>(FDecl)->parameters();
-
-    unsigned ParamIndex = 0;
-    for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end();
-         I != E; ++I, ++ParamIndex) {
-      const ParmVarDecl *PVD = *I;
-      if (PVD->hasAttr<NonNullAttr>() || isNonNullType(PVD->getType())) {
-        if (NonNullArgs.empty())
-          NonNullArgs.resize(Args.size());
-
-        NonNullArgs.set(ParamIndex);
-      }
-    }
-  } else {
-    // If we have a non-function, non-method declaration but no
-    // function prototype, try to dig out the function prototype.
-    if (!Proto) {
-      if (const ValueDecl *VD = dyn_cast<ValueDecl>(FDecl)) {
-        QualType type = VD->getType().getNonReferenceType();
-        if (auto pointerType = type->getAs<PointerType>())
-          type = pointerType->getPointeeType();
-        else if (auto blockType = type->getAs<BlockPointerType>())
-          type = blockType->getPointeeType();
-        // FIXME: data member pointers?
-
-        // Dig out the function prototype, if there is one.
-        Proto = type->getAs<FunctionProtoType>();
-      }
-    }
-
-    // Fill in non-null argument information from the nullability
-    // information on the parameter types (if we have them).
-    if (Proto) {
-      unsigned Index = 0;
-      for (auto paramType : Proto->getParamTypes()) {
-        if (isNonNullType(paramType)) {
-          if (NonNullArgs.empty())
-            NonNullArgs.resize(Args.size());
-
-          NonNullArgs.set(Index);
-        }
-
-        ++Index;
-      }
-    }
-  }
-
-  // Check for non-null arguments.
-  for (unsigned ArgIndex = 0, ArgIndexEnd = NonNullArgs.size();
-       ArgIndex != ArgIndexEnd; ++ArgIndex) {
-    if (NonNullArgs[ArgIndex])
-      CheckNonNullArgument(S, Args[ArgIndex], Args[ArgIndex]->getExprLoc());
-  }
-}
-
-void Sema::CheckArgAlignment(SourceLocation Loc, NamedDecl *FDecl,
-                             StringRef ParamName, QualType ArgTy,
-                             QualType ParamTy) {
-
-  // If a function accepts a pointer or reference type
-  if (!ParamTy->isPointerType() && !ParamTy->isReferenceType())
-    return;
-
-  // If the parameter is a pointer type, get the pointee type for the
-  // argument too. If the parameter is a reference type, don't try to get
-  // the pointee type for the argument.
-  if (ParamTy->isPointerType())
-    ArgTy = ArgTy->getPointeeType();
-
-  // Remove reference or pointer
-  ParamTy = ParamTy->getPointeeType();
-
-  // Find expected alignment, and the actual alignment of the passed object.
-  // getTypeAlignInChars requires complete types
-  if (ArgTy.isNull() || ParamTy->isDependentType() ||
-      ParamTy->isIncompleteType() || ArgTy->isIncompleteType() ||
-      ParamTy->isUndeducedType() || ArgTy->isUndeducedType())
-    return;
-
-  CharUnits ParamAlign = Context.getTypeAlignInChars(ParamTy);
-  CharUnits ArgAlign = Context.getTypeAlignInChars(ArgTy);
-
-  // If the argument is less aligned than the parameter, there is a
-  // potential alignment issue.
-  if (ArgAlign < ParamAlign)
-    Diag(Loc, diag::warn_param_mismatched_alignment)
-        << (int)ArgAlign.getQuantity() << (int)ParamAlign.getQuantity()
-        << ParamName << (FDecl != nullptr) << FDecl;
-}
-
-void Sema::checkLifetimeCaptureBy(FunctionDecl *FD, bool IsMemberFunction,
-                                  const Expr *ThisArg,
-                                  ArrayRef<const Expr *> Args) {
-  if (!FD || Args.empty())
-    return;
-  auto GetArgAt = [&](int Idx) -> const Expr * {
-    if (Idx == LifetimeCaptureByAttr::Global ||
-        Idx == LifetimeCaptureByAttr::Unknown)
-      return nullptr;
-    if (IsMemberFunction && Idx == 0)
-      return ThisArg;
-    return Args[Idx - IsMemberFunction];
-  };
-  auto HandleCaptureByAttr = [&](const LifetimeCaptureByAttr *Attr,
-                                 unsigned ArgIdx) {
-    if (!Attr)
-      return;
-
-    Expr *Captured = const_cast<Expr *>(GetArgAt(ArgIdx));
-    for (int CapturingParamIdx : Attr->params()) {
-      // lifetime_capture_by(this) case is handled in the lifetimebound expr
-      // initialization codepath.
-      if (CapturingParamIdx == LifetimeCaptureByAttr::This &&
-          isa<CXXConstructorDecl>(FD))
-        continue;
-      Expr *Capturing = const_cast<Expr *>(GetArgAt(CapturingParamIdx));
-      CapturingEntity CE{Capturing};
-      // Ensure that 'Captured' outlives the 'Capturing' entity.
-      checkCaptureByLifetime(*this, CE, Captured);
-    }
-  };
-  for (unsigned I = 0; I < FD->getNumParams(); ++I)
-    HandleCaptureByAttr(FD->getParamDecl(I)->getAttr<LifetimeCaptureByAttr>(),
-                        I + IsMemberFunction);
-  // Check when the implicit object param is captured.
-  if (IsMemberFunction) {
-    TypeSourceInfo *TSI = FD->getTypeSourceInfo();
-    if (!TSI)
-      return;
-    AttributedTypeLoc ATL;
-    for (TypeLoc TL = TSI->getTypeLoc();
-         (ATL = TL.getAsAdjusted<AttributedTypeLoc>());
-         TL = ATL.getModifiedLoc())
-      HandleCaptureByAttr(ATL.getAttrAs<LifetimeCaptureByAttr>(), 0);
-  }
-}
-
-void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
-                     const Expr *ThisArg, ArrayRef<const Expr *> Args,
-                     bool IsMemberFunction, SourceLocation Loc,
-                     SourceRange Range, VariadicCallType CallType) {
-  // FIXME: We should check as much as we can in the template definition.
-  if (CurContext->isDependentContext())
-    return;
-
-  // Printf and scanf checking.
-  llvm::SmallBitVector CheckedVarArgs;
-  if (FDecl) {
-    for (const auto *I : FDecl->specific_attrs<FormatMatchesAttr>()) {
-      // Only create vector if there are format attributes.
-      CheckedVarArgs.resize(Args.size());
-      CheckFormatString(I, Args, IsMemberFunction, CallType, Loc, Range,
-                        CheckedVarArgs);
-    }
-
-    for (const auto *I : FDecl->specific_attrs<FormatAttr>()) {
-      CheckedVarArgs.resize(Args.size());
-      CheckFormatArguments(I, Args, IsMemberFunction, CallType, Loc, Range,
-                           CheckedVarArgs);
-    }
-  }
-
-  // Refuse POD arguments that weren't caught by the format string
-  // checks above.
-  auto *FD = dyn_cast_or_null<FunctionDecl>(FDecl);
-  if (CallType != VariadicCallType::DoesNotApply &&
-      (!FD || FD->getBuiltinID() != Builtin::BI__noop)) {
-    unsigned NumParams = Proto ? Proto->getNumParams()
-                         : isa_and_nonnull<FunctionDecl>(FDecl)
-                             ? cast<FunctionDecl>(FDecl)->getNumParams()
-                         : isa_and_nonnull<ObjCMethodDecl>(FDecl)
-                             ? cast<ObjCMethodDecl>(FDecl)->param_size()
-                             : 0;
-
-    for (unsigned ArgIdx = NumParams; ArgIdx < Args.size(); ++ArgIdx) {
-      // Args[ArgIdx] can be null in malformed code.
-      if (const Expr *Arg = Args[ArgIdx]) {
-        if (CheckedVarArgs.empty() || !CheckedVarArgs[ArgIdx])
-          checkVariadicArgument(Arg, CallType);
-      }
-    }
-  }
-  if (FD)
-    checkLifetimeCaptureBy(FD, IsMemberFunction, ThisArg, Args);
-  if (FDecl || Proto) {
-    CheckNonNullArguments(*this, FDecl, Proto, Args, Loc);
-
-    // Type safety checking.
-    if (FDecl) {
-      for (const auto *I : FDecl->specific_attrs<ArgumentWithTypeTagAttr>())
-        CheckArgumentWithTypeTag(I, Args, Loc);
-    }
-  }
-
-  // Check that passed arguments match the alignment of original arguments.
-  // Try to get the missing prototype from the declaration.
-  if (!Proto && FDecl) {
-    const auto *FT = FDecl->getFunctionType();
-    if (isa_and_nonnull<FunctionProtoType>(FT))
-      Proto = cast<FunctionProtoType>(FDecl->getFunctionType());
-  }
-  if (Proto) {
-    // For variadic functions, we may have more args than parameters.
-    // For some K&R functions, we may have less args than parameters.
-    const auto N = std::min<unsigned>(Proto->getNumParams(), Args.size());
-    bool IsScalableRet = Proto->getReturnType()->isSizelessVectorType();
-    bool IsScalableArg = false;
-    for (unsigned ArgIdx = 0; ArgIdx < N; ++ArgIdx) {
-      // Args[ArgIdx] can be null in malformed code.
-      if (const Expr *Arg = Args[ArgIdx]) {
-        if (Arg->containsErrors())
-          continue;
-
-        if (Context.getTargetInfo().getTriple().isOSAIX() && FDecl && Arg &&
-            FDecl->hasLinkage() &&
-            FDecl->getFormalLinkage() != Linkage::Internal &&
-            CallType == VariadicCallType::DoesNotApply)
-          PPC().checkAIXMemberAlignment((Arg->getExprLoc()), Arg);
-
-        QualType ParamTy = Proto->getParamType(ArgIdx);
-        if (ParamTy->isSizelessVectorType())
-          IsScalableArg = true;
-        QualType ArgTy = Arg->getType();
-        CheckArgAlignment(Arg->getExprLoc(), FDecl, std::to_string(ArgIdx + 1),
-                          ArgTy, ParamTy);
-      }
-    }
-
-    // If the callee has an AArch64 SME attribute to indicate that it is an
-    // __arm_streaming function, then the caller requires SME to be available.
-    FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
-    if (ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask) {
-      if (auto *CallerFD = dyn_cast<FunctionDecl>(CurContext)) {
-        llvm::StringMap<bool> CallerFeatureMap;
-        Context.getFunctionFeatureMap(CallerFeatureMap, CallerFD);
-        if (!CallerFeatureMap.contains("sme"))
-          Diag(Loc, diag::err_sme_call_in_non_sme_target);
-      } else if (!Context.getTargetInfo().hasFeature("sme")) {
-        Diag(Loc, diag::err_sme_call_in_non_sme_target);
-      }
-    }
-
-    // If the call requires a streaming-mode change and has scalable vector
-    // arguments or return values, then warn the user that the streaming and
-    // non-streaming vector lengths may be different.
-    // When both streaming and non-streaming vector lengths are defined and
-    // mismatched, produce an error.
-    const auto *CallerFD = dyn_cast<FunctionDecl>(CurContext);
-    if (CallerFD && (!FD || !FD->getBuiltinID()) &&
-        (IsScalableArg || IsScalableRet)) {
-      bool IsCalleeStreaming =
-          ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask;
-      bool IsCalleeStreamingCompatible =
-          ExtInfo.AArch64SMEAttributes &
-          FunctionType::SME_PStateSMCompatibleMask;
-      SemaARM::ArmStreamingType CallerFnType = getArmStreamingFnType(CallerFD);
-      if (!IsCalleeStreamingCompatible &&
-          (CallerFnType == SemaARM::ArmStreamingCompatible ||
-           ((CallerFnType == SemaARM::ArmStreaming) ^ IsCalleeStreaming))) {
-        const LangOptions &LO = getLangOpts();
-        unsigned VL = LO.VScaleMin * 128;
-        unsigned SVL = LO.VScaleStreamingMin * 128;
-        bool IsVLMismatch = VL && SVL && VL != SVL;
-
-        auto EmitDiag = [&](bool IsArg) {
-          if (IsVLMismatch) {
-            if (CallerFnType == SemaARM::ArmStreamingCompatible)
-              // Emit warning for streaming-compatible callers
-              Diag(Loc, diag::warn_sme_streaming_compatible_vl_mismatch)
-                  << IsArg << IsCalleeStreaming << SVL << VL;
-            else
-              // Emit error otherwise
-              Diag(Loc, diag::err_sme_streaming_transition_vl_mismatch)
-                  << IsArg << SVL << VL;
-          } else
-            Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming)
-                << IsArg;
-        };
-
-        if (IsScalableArg)
-          EmitDiag(true);
-        if (IsScalableRet)
-          EmitDiag(false);
-      }
-    }
-
-    FunctionType::ArmStateValue CalleeArmZAState =
-        FunctionType::getArmZAState(ExtInfo.AArch64SMEAttributes);
-    FunctionType::ArmStateValue CalleeArmZT0State =
-        FunctionType::getArmZT0State(ExtInfo.AArch64SMEAttributes);
-    if (CalleeArmZAState != FunctionType::ARM_None ||
-        CalleeArmZT0State != FunctionType::ARM_None) {
-      bool CallerHasZAState = false;
-      bool CallerHasZT0State = false;
-      if (CallerFD) {
-        auto *Attr = CallerFD->getAttr<ArmNewAttr>();
-        if (Attr && Attr->isNewZA())
-          CallerHasZAState = true;
-        if (Attr && Attr->isNewZT0())
-          CallerHasZT0State = true;
-        if (const auto *FPT = CallerFD->getType()->getAs<FunctionProtoType>()) {
-          CallerHasZAState |=
-              FunctionType::getArmZAState(
-                  FPT->getExtProtoInfo().AArch64SMEAttributes) !=
-              FunctionType::ARM_None;
-          CallerHasZT0State |=
-              FunctionType::getArmZT0State(
-                  FPT->getExtProtoInfo().AArch64SMEAttributes) !=
-              FunctionType::ARM_None;
-        }
-      }
-
-      if (CalleeArmZAState != FunctionType::ARM_None && !CallerHasZAState)
-        Diag(Loc, diag::err_sme_za_call_no_za_state);
-
-      if (CalleeArmZT0State != FunctionType::ARM_None && !CallerHasZT0State)
-        Diag(Loc, diag::err_sme_zt0_call_no_zt0_state);
-
-      if (CallerHasZAState && CalleeArmZAState == FunctionType::ARM_None &&
-          CalleeArmZT0State != FunctionType::ARM_None) {
-        Diag(Loc, diag::err_sme_unimplemented_za_save_restore);
-        Diag(Loc, diag::note_sme_use_preserves_za);
-      }
-    }
-  }
-
-  if (FDecl && FDecl->hasAttr<AllocAlignAttr>()) {
-    auto *AA = FDecl->getAttr<AllocAlignAttr>();
-    const Expr *Arg = Args[AA->getParamIndex().getASTIndex()];
-    if (!Arg->isValueDependent()) {
-      Expr::EvalResult Align;
-      if (Arg->EvaluateAsInt(Align, Context)) {
-        const llvm::APSInt &I = Align.Val.getInt();
-        if (!I.isPowerOf2())
-          Diag(Arg->getExprLoc(), diag::warn_alignment_not_power_of_two)
-              << Arg->getSourceRange();
-
-        if (I > Sema::MaximumAlignment)
-          Diag(Arg->getExprLoc(), diag::warn_assume_aligned_too_great)
-              << Arg->getSourceRange() << Sema::MaximumAlignment;
-      }
-    }
-  }
-
-  if (FD)
-    diagnoseArgDependentDiagnoseIfAttrs(FD, ThisArg, Args, Loc);
-}
-
-void Sema::CheckConstrainedAuto(const AutoType *AutoT, SourceLocation Loc) {
-  if (TemplateDecl *Decl = AutoT->getTypeConstraintConcept()) {
-    DiagnoseUseOfDecl(Decl, Loc);
-  }
-}
-
-void Sema::CheckConstructorCall(FunctionDecl *FDecl, QualType ThisType,
-                                ArrayRef<const Expr *> Args,
-                                const FunctionProtoType *Proto,
-                                SourceLocation Loc) {
-  VariadicCallType CallType = Proto->isVariadic()
-                                  ? VariadicCallType::Constructor
-                                  : VariadicCallType::DoesNotApply;
-
-  auto *Ctor = cast<CXXConstructorDecl>(FDecl);
-  CheckArgAlignment(
-      Loc, FDecl, "'this'", Context.getPointerType(ThisType),
-      Context.getPointerType(Ctor->getFunctionObjectParameterType()));
-
-  checkCall(FDecl, Proto, /*ThisArg=*/nullptr, Args, /*IsMemberFunction=*/true,
-            Loc, SourceRange(), CallType);
-}
-
-bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
-                             const FunctionProtoType *Proto) {
-  bool IsMemberOperatorCall = isa<CXXOperatorCallExpr>(TheCall) &&
-                              isa<CXXMethodDecl>(FDecl);
-  bool IsMemberFunction = isa<CXXMemberCallExpr>(TheCall) ||
-                          IsMemberOperatorCall;
-  VariadicCallType CallType = getVariadicCallType(FDecl, Proto,
-                                                  TheCall->getCallee());
-  Expr** Args = TheCall->getArgs();
-  unsigned NumArgs = TheCall->getNumArgs();
-
-  Expr *ImplicitThis = nullptr;
-  if (IsMemberOperatorCall && !FDecl->hasCXXExplicitFunctionObjectParameter()) {
-    // If this is a call to a member operator, hide the first
-    // argument from checkCall.
-    // FIXME: Our choice of AST representation here is less than ideal.
-    ImplicitThis = Args[0];
-    ++Args;
-    --NumArgs;
-  } else if (IsMemberFunction && !FDecl->isStatic() &&
-             !FDecl->hasCXXExplicitFunctionObjectParameter())
-    ImplicitThis =
-        cast<CXXMemberCallExpr>(TheCall)->getImplicitObjectArgument();
-
-  if (ImplicitThis) {
-    // ImplicitThis may or may not be a pointer, depending on whether . or -> is
-    // used.
-    QualType ThisType = ImplicitThis->getType();
-    if (!ThisType->isPointerType()) {
-      assert(!ThisType->isReferenceType());
-      ThisType = Context.getPointerType(ThisType);
-    }
-
-    QualType ThisTypeFromDecl = Context.getPointerType(
-        cast<CXXMethodDecl>(FDecl)->getFunctionObjectParameterType());
-
-    CheckArgAlignment(TheCall->getRParenLoc(), FDecl, "'this'", ThisType,
-                      ThisTypeFromDecl);
-  }
-
-  checkCall(FDecl, Proto, ImplicitThis, llvm::ArrayRef(Args, NumArgs),
-            IsMemberFunction, TheCall->getRParenLoc(),
-            TheCall->getCallee()->getSourceRange(), CallType);
-
-  IdentifierInfo *FnInfo = FDecl->getIdentifier();
-  // None of the checks below are needed for functions that don't have
-  // simple names (e.g., C++ conversion functions).
-  if (!FnInfo)
-    return false;
-
-  // Enforce TCB except for builtin calls, which are always allowed.
-  if (FDecl->getBuiltinID() == 0)
-    CheckTCBEnforcement(TheCall->getExprLoc(), FDecl);
-
-  CheckAbsoluteValueFunction(TheCall, FDecl);
-  CheckMaxUnsignedZero(TheCall, FDecl);
-  CheckInfNaNFunction(TheCall, FDecl);
-
-  if (getLangOpts().ObjC)
-    ObjC().DiagnoseCStringFormatDirectiveInCFAPI(FDecl, Args, NumArgs);
-
-  unsigned CMId = FDecl->getMemoryFunctionKind();
-
-  // Handle memory setting and copying functions.
-  switch (CMId) {
-  case 0:
-    return false;
-  case Builtin::BIstrlcpy: // fallthrough
-  case Builtin::BIstrlcat:
-    CheckStrlcpycatArguments(TheCall, FnInfo);
-    break;
-  case Builtin::BIstrncat:
-    CheckStrncatArguments(TheCall, FnInfo);
-    break;
-  case Builtin::BIfree:
-    CheckFreeArguments(TheCall);
-    break;
-  default:
-    CheckMemaccessArguments(TheCall, CMId, FnInfo);
-  }
-
-  return false;
-}
-
-bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall,
-                            const FunctionProtoType *Proto) {
-  QualType Ty;
-  if (const auto *V = dyn_cast<VarDecl>(NDecl))
-    Ty = V->getType().getNonReferenceType();
-  else if (const auto *F = dyn_cast<FieldDecl>(NDecl))
-    Ty = F->getType().getNonReferenceType();
-  else
-    return false;
-
-  if (!Ty->isBlockPointerType() && !Ty->isFunctionPointerType() &&
-      !Ty->isFunctionProtoType())
-    return false;
-
-  VariadicCallType CallType;
-  if (!Proto || !Proto->isVariadic()) {
-    CallType = VariadicCallType::DoesNotApply;
-  } else if (Ty->isBlockPointerType()) {
-    CallType = VariadicCallType::Block;
-  } else { // Ty->isFunctionPointerType()
-    CallType = VariadicCallType::Function;
-  }
-
-  checkCall(NDecl, Proto, /*ThisArg=*/nullptr,
-            llvm::ArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
-            /*IsMemberFunction=*/false, TheCall->getRParenLoc(),
-            TheCall->getCallee()->getSourceRange(), CallType);
-
-  return false;
-}
-
-bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) {
-  VariadicCallType CallType = getVariadicCallType(/*FDecl=*/nullptr, Proto,
-                                                  TheCall->getCallee());
-  checkCall(/*FDecl=*/nullptr, Proto, /*ThisArg=*/nullptr,
-            llvm::ArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
-            /*IsMemberFunction=*/false, TheCall->getRParenLoc(),
-            TheCall->getCallee()->getSourceRange(), CallType);
-
-  return false;
-}
-
-static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) {
-  if (!llvm::isValidAtomicOrderingCABI(Ordering))
-    return false;
-
-  auto OrderingCABI = (llvm::AtomicOrderingCABI)Ordering;
-  switch (Op) {
-  case AtomicExpr::AO__c11_atomic_init:
-  case AtomicExpr::AO__opencl_atomic_init:
-    llvm_unreachable("There is no ordering argument for an init");
-
-  case AtomicExpr::AO__c11_atomic_load:
-  case AtomicExpr::AO__opencl_atomic_load:
-  case AtomicExpr::AO__hip_atomic_load:
-  case AtomicExpr::AO__atomic_load_n:
-  case AtomicExpr::AO__atomic_load:
-  case AtomicExpr::AO__scoped_atomic_load_n:
-  case AtomicExpr::AO__scoped_atomic_load:
-    return OrderingCABI != llvm::AtomicOrderingCABI::release &&
-           OrderingCABI != llvm::AtomicOrderingCABI::acq_rel;
-
-  case AtomicExpr::AO__c11_atomic_store:
-  case AtomicExpr::AO__opencl_atomic_store:
-  case AtomicExpr::AO__hip_atomic_store:
-  case AtomicExpr::AO__atomic_store:
-  case AtomicExpr::AO__atomic_store_n:
-  case AtomicExpr::AO__scoped_atomic_store:
-  case AtomicExpr::AO__scoped_atomic_store_n:
-  case AtomicExpr::AO__atomic_clear:
-    return OrderingCABI != llvm::AtomicOrderingCABI::consume &&
-           OrderingCABI != llvm::AtomicOrderingCABI::acquire &&
-           OrderingCABI != llvm::AtomicOrderingCABI::acq_rel;
-
-  default:
-    return true;
-  }
-}
-
-ExprResult Sema::AtomicOpsOverloaded(ExprResult TheCallResult,
-                                     AtomicExpr::AtomicOp Op) {
-  CallExpr *TheCall = cast<CallExpr>(TheCallResult.get());
-  DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
-  MultiExprArg Args{TheCall->getArgs(), TheCall->getNumArgs()};
-  return BuildAtomicExpr({TheCall->getBeginLoc(), TheCall->getEndLoc()},
-                         DRE->getSourceRange(), TheCall->getRParenLoc(), Args,
-                         Op);
-}
-
-ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
-                                 SourceLocation RParenLoc, MultiExprArg Args,
-                                 AtomicExpr::AtomicOp Op,
-                                 AtomicArgumentOrder ArgOrder) {
-  // All the non-OpenCL operations take one of the following forms.
-  // The OpenCL operations take the __c11 forms with one extra argument for
-  // synchronization scope.
-  enum {
-    // C    __c11_atomic_init(A *, C)
-    Init,
-
-    // C    __c11_atomic_load(A *, int)
-    Load,
-
-    // void __atomic_load(A *, CP, int)
-    LoadCopy,
-
-    // void __atomic_store(A *, CP, int)
-    Copy,
-
-    // C    __c11_atomic_add(A *, M, int)
-    Arithmetic,
-
-    // C    __atomic_exchange_n(A *, CP, int)
-    Xchg,
-
-    // void __atomic_exchange(A *, C *, CP, int)
-    GNUXchg,
-
-    // bool __c11_atomic_compare_exchange_strong(A *, C *, CP, int, int)
-    C11CmpXchg,
-
-    // bool __atomic_compare_exchange(A *, C *, CP, bool, int, int)
-    GNUCmpXchg,
-
-    // bool __atomic_test_and_set(A *, int)
-    TestAndSetByte,
-
-    // void __atomic_clear(A *, int)
-    ClearByte,
-  } Form = Init;
-
-  const unsigned NumForm = ClearByte + 1;
-  const unsigned NumArgs[] = {2, 2, 3, 3, 3, 3, 4, 5, 6, 2, 2};
-  const unsigned NumVals[] = {1, 0, 1, 1, 1, 1, 2, 2, 3, 0, 0};
-  // where:
-  //   C is an appropriate type,
-  //   A is volatile _Atomic(C) for __c11 builtins and is C for GNU builtins,
-  //   CP is C for __c11 builtins and GNU _n builtins and is C * otherwise,
-  //   M is C if C is an integer, and ptrdiff_t if C is a pointer, and
-  //   the int parameters are for orderings.
-
-  static_assert(sizeof(NumArgs)/sizeof(NumArgs[0]) == NumForm
-      && sizeof(NumVals)/sizeof(NumVals[0]) == NumForm,
-      "need to update code for modified forms");
-  static_assert(AtomicExpr::AO__atomic_add_fetch == 0 &&
-                    AtomicExpr::AO__atomic_xor_fetch + 1 ==
-                        AtomicExpr::AO__c11_atomic_compare_exchange_strong,
-                "need to update code for modified C11 atomics");
-  bool IsOpenCL = Op >= AtomicExpr::AO__opencl_atomic_compare_exchange_strong &&
-                  Op <= AtomicExpr::AO__opencl_atomic_store;
-  bool IsHIP = Op >= AtomicExpr::AO__hip_atomic_compare_exchange_strong &&
-               Op <= AtomicExpr::AO__hip_atomic_store;
-  bool IsScoped = Op >= AtomicExpr::AO__scoped_atomic_add_fetch &&
-                  Op <= AtomicExpr::AO__scoped_atomic_xor_fetch;
-  bool IsC11 = (Op >= AtomicExpr::AO__c11_atomic_compare_exchange_strong &&
-                Op <= AtomicExpr::AO__c11_atomic_store) ||
-               IsOpenCL;
-  bool IsN = Op == AtomicExpr::AO__atomic_load_n ||
-             Op == AtomicExpr::AO__atomic_store_n ||
-             Op == AtomicExpr::AO__atomic_exchange_n ||
-             Op == AtomicExpr::AO__atomic_compare_exchange_n ||
-             Op == AtomicExpr::AO__scoped_atomic_load_n ||
-             Op == AtomicExpr::AO__scoped_atomic_store_n ||
-             Op == AtomicExpr::AO__scoped_atomic_exchange_n ||
-             Op == AtomicExpr::AO__scoped_atomic_compare_exchange_n;
-  // Bit mask for extra allowed value types other than integers for atomic
-  // arithmetic operations. Add/sub allow pointer and floating point. Min/max
-  // allow floating point.
-  enum ArithOpExtraValueType {
-    AOEVT_None = 0,
-    AOEVT_Pointer = 1,
-    AOEVT_FP = 2,
-  };
-  unsigned ArithAllows = AOEVT_None;
-
-  switch (Op) {
-  case AtomicExpr::AO__c11_atomic_init:
-  case AtomicExpr::AO__opencl_atomic_init:
-    Form = Init;
-    break;
-
-  case AtomicExpr::AO__c11_atomic_load:
-  case AtomicExpr::AO__opencl_atomic_load:
-  case AtomicExpr::AO__hip_atomic_load:
-  case AtomicExpr::AO__atomic_load_n:
-  case AtomicExpr::AO__scoped_atomic_load_n:
-    Form = Load;
-    break;
-
-  case AtomicExpr::AO__atomic_load:
-  case AtomicExpr::AO__scoped_atomic_load:
-    Form = LoadCopy;
-    break;
-
-  case AtomicExpr::AO__c11_atomic_store:
-  case AtomicExpr::AO__opencl_atomic_store:
-  case AtomicExpr::AO__hip_atomic_store:
-  case AtomicExpr::AO__atomic_store:
-  case AtomicExpr::AO__atomic_store_n:
-  case AtomicExpr::AO__scoped_atomic_store:
-  case AtomicExpr::AO__scoped_atomic_store_n:
-    Form = Copy;
-    break;
-  case AtomicExpr::AO__atomic_fetch_add:
-  case AtomicExpr::AO__atomic_fetch_sub:
-  case AtomicExpr::AO__atomic_add_fetch:
-  case AtomicExpr::AO__atomic_sub_fetch:
-  case AtomicExpr::AO__scoped_atomic_fetch_add:
-  case AtomicExpr::AO__scoped_atomic_fetch_sub:
-  case AtomicExpr::AO__scoped_atomic_add_fetch:
-  case AtomicExpr::AO__scoped_atomic_sub_fetch:
-  case AtomicExpr::AO__c11_atomic_fetch_add:
-  case AtomicExpr::AO__c11_atomic_fetch_sub:
-  case AtomicExpr::AO__opencl_atomic_fetch_add:
-  case AtomicExpr::AO__opencl_atomic_fetch_sub:
-  case AtomicExpr::AO__hip_atomic_fetch_add:
-  case AtomicExpr::AO__hip_atomic_fetch_sub:
-    ArithAllows = AOEVT_Pointer | AOEVT_FP;
-    Form = Arithmetic;
-    break;
-  case AtomicExpr::AO__atomic_fetch_max:
-  case AtomicExpr::AO__atomic_fetch_min:
-  case AtomicExpr::AO__atomic_max_fetch:
-  case AtomicExpr::AO__atomic_min_fetch:
-  case AtomicExpr::AO__scoped_atomic_fetch_max:
-  case AtomicExpr::AO__scoped_atomic_fetch_min:
-  case AtomicExpr::AO__scoped_atomic_max_fetch:
-  case AtomicExpr::AO__scoped_atomic_min_fetch:
-  case AtomicExpr::AO__c11_atomic_fetch_max:
-  case AtomicExpr::AO__c11_atomic_fetch_min:
-  case AtomicExpr::AO__opencl_atomic_fetch_max:
-  case AtomicExpr::AO__opencl_atomic_fetch_min:
-  case AtomicExpr::AO__hip_atomic_fetch_max:
-  case AtomicExpr::AO__hip_atomic_fetch_min:
-    ArithAllows = AOEVT_FP;
-    Form = Arithmetic;
-    break;
-  case AtomicExpr::AO__c11_atomic_fetch_and:
-  case AtomicExpr::AO__c11_atomic_fetch_or:
-  case AtomicExpr::AO__c11_atomic_fetch_xor:
-  case AtomicExpr::AO__hip_atomic_fetch_and:
-  case AtomicExpr::AO__hip_atomic_fetch_or:
-  case AtomicExpr::AO__hip_atomic_fetch_xor:
-  case AtomicExpr::AO__c11_atomic_fetch_nand:
-  case AtomicExpr::AO__opencl_atomic_fetch_and:
-  case AtomicExpr::AO__opencl_atomic_fetch_or:
-  case AtomicExpr::AO__opencl_atomic_fetch_xor:
-  case AtomicExpr::AO__atomic_fetch_and:
-  case AtomicExpr::AO__atomic_fetch_or:
-  case AtomicExpr::AO__atomic_fetch_xor:
-  case AtomicExpr::AO__atomic_fetch_nand:
-  case AtomicExpr::AO__atomic_and_fetch:
-  case AtomicExpr::AO__atomic_or_fetch:
-  case AtomicExpr::AO__atomic_xor_fetch:
-  case AtomicExpr::AO__atomic_nand_fetch:
-  case AtomicExpr::AO__atomic_fetch_uinc:
-  case AtomicExpr::AO__atomic_fetch_udec:
-  case AtomicExpr::AO__scoped_atomic_fetch_and:
-  case AtomicExpr::AO__scoped_atomic_fetch_or:
-  case AtomicExpr::AO__scoped_atomic_fetch_xor:
-  case AtomicExpr::AO__scoped_atomic_fetch_nand:
-  case AtomicExpr::AO__scoped_atomic_and_fetch:
-  case AtomicExpr::AO__scoped_atomic_or_fetch:
-  case AtomicExpr::AO__scoped_atomic_xor_fetch:
-  case AtomicExpr::AO__scoped_atomic_nand_fetch:
-  case AtomicExpr::AO__scoped_atomic_fetch_uinc:
-  case AtomicExpr::AO__scoped_atomic_fetch_udec:
-    Form = Arithmetic;
-    break;
-
-  case AtomicExpr::AO__c11_atomic_exchange:
-  case AtomicExpr::AO__hip_atomic_exchange:
-  case AtomicExpr::AO__opencl_atomic_exchange:
-  case AtomicExpr::AO__atomic_exchange_n:
-  case AtomicExpr::AO__scoped_atomic_exchange_n:
-    Form = Xchg;
-    break;
-
-  case AtomicExpr::AO__atomic_exchange:
-  case AtomicExpr::AO__scoped_atomic_exchange:
-    Form = GNUXchg;
-    break;
-
-  case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
-  case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
-  case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
-  case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
-  case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
-  case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
-    Form = C11CmpXchg;
-    break;
-
-  case AtomicExpr::AO__atomic_compare_exchange:
-  case AtomicExpr::AO__atomic_compare_exchange_n:
-  case AtomicExpr::AO__scoped_atomic_compare_exchange:
-  case AtomicExpr::AO__scoped_atomic_compare_exchange_n:
-    Form = GNUCmpXchg;
-    break;
-
-  case AtomicExpr::AO__atomic_test_and_set:
-    Form = TestAndSetByte;
-    break;
-
-  case AtomicExpr::AO__atomic_clear:
-    Form = ClearByte;
-    break;
-  }
-
-  unsigned AdjustedNumArgs = NumArgs[Form];
-  if ((IsOpenCL || IsHIP || IsScoped) &&
-      Op != AtomicExpr::AO__opencl_atomic_init)
-    ++AdjustedNumArgs;
-  // Check we have the right number of arguments.
-  if (Args.size() < AdjustedNumArgs) {
-    Diag(CallRange.getEnd(), diag::err_typecheck_call_too_few_args)
-        << 0 << AdjustedNumArgs << static_cast<unsigned>(Args.size())
-        << /*is non object*/ 0 << ExprRange;
-    return ExprError();
-  } else if (Args.size() > AdjustedNumArgs) {
-    Diag(Args[AdjustedNumArgs]->getBeginLoc(),
-         diag::err_typecheck_call_too_many_args)
-        << 0 << AdjustedNumArgs << static_cast<unsigned>(Args.size())
-        << /*is non object*/ 0 << ExprRange;
-    return ExprError();
-  }
-
-  // Inspect the first argument of the atomic operation.
-  Expr *Ptr = Args[0];
-  ExprResult ConvertedPtr = DefaultFunctionArrayLvalueConversion(Ptr);
-  if (ConvertedPtr.isInvalid())
-    return ExprError();
-
-  Ptr = ConvertedPtr.get();
-  const PointerType *pointerType = Ptr->getType()->getAs<PointerType>();
-  if (!pointerType) {
-    Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer)
-        << Ptr->getType() << 0 << Ptr->getSourceRange();
-    return ExprError();
-  }
-
-  // For a __c11 builtin, this should be a pointer to an _Atomic type.
-  QualType AtomTy = pointerType->getPointeeType(); // 'A'
-  QualType ValType = AtomTy; // 'C'
-  if (IsC11) {
-    if (!AtomTy->isAtomicType()) {
-      Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic)
-          << Ptr->getType() << Ptr->getSourceRange();
-      return ExprError();
-    }
-    if ((Form != Load && Form != LoadCopy && AtomTy.isConstQualified()) ||
-        AtomTy.getAddressSpace() == LangAS::opencl_constant) {
-      Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_non_const_atomic)
-          << (AtomTy.isConstQualified() ? 0 : 1) << Ptr->getType()
-          << Ptr->getSourceRange();
-      return ExprError();
-    }
-    ValType = AtomTy->castAs<AtomicType>()->getValueType();
-  } else if (Form != Load && Form != LoadCopy) {
-    if (ValType.isConstQualified()) {
-      Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_non_const_pointer)
-          << Ptr->getType() << Ptr->getSourceRange();
-      return ExprError();
-    }
-  }
-
-  if (Form != TestAndSetByte && Form != ClearByte) {
-    // Pointer to object of size zero is not allowed.
-    if (RequireCompleteType(Ptr->getBeginLoc(), AtomTy,
-                            diag::err_incomplete_type))
-      return ExprError();
-
-    if (Context.getTypeInfoInChars(AtomTy).Width.isZero()) {
-      Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer)
-          << Ptr->getType() << 1 << Ptr->getSourceRange();
-      return ExprError();
-    }
-  } else {
-    // The __atomic_clear and __atomic_test_and_set intrinsics accept any
-    // non-const pointer type, including void* and pointers to incomplete
-    // structs, but only access the first byte.
-    AtomTy = Context.CharTy;
-    AtomTy = AtomTy.withCVRQualifiers(
-        pointerType->getPointeeType().getCVRQualifiers());
-    QualType PointerQT = Context.getPointerType(AtomTy);
-    pointerType = PointerQT->getAs<PointerType>();
-    Ptr = ImpCastExprToType(Ptr, PointerQT, CK_BitCast).get();
-    ValType = AtomTy;
-  }
-
-  PointerAuthQualifier PointerAuth = AtomTy.getPointerAuth();
-  if (PointerAuth && PointerAuth.isAddressDiscriminated()) {
-    Diag(ExprRange.getBegin(),
-         diag::err_atomic_op_needs_non_address_discriminated_pointer)
-        << 0 << Ptr->getType() << Ptr->getSourceRange();
-    return ExprError();
-  }
-
-  // For an arithmetic operation, the implied arithmetic must be well-formed.
-  if (Form == Arithmetic) {
-    // GCC does not enforce these rules for GNU atomics, but we do to help catch
-    // trivial type errors.
-    auto IsAllowedValueType = [&](QualType ValType,
-                                  unsigned AllowedType) -> bool {
-      if (ValType->isIntegerType())
-        return true;
-      if (ValType->isPointerType())
-        return AllowedType & AOEVT_Pointer;
-      if (!(ValType->isFloatingType() && (AllowedType & AOEVT_FP)))
-        return false;
-      // LLVM Parser does not allow atomicrmw with x86_fp80 type.
-      if (ValType->isSpecificBuiltinType(BuiltinType::LongDouble) &&
-          &Context.getTargetInfo().getLongDoubleFormat() ==
-              &llvm::APFloat::x87DoubleExtended())
-        return false;
-      return true;
-    };
-    if (!IsAllowedValueType(ValType, ArithAllows)) {
-      auto DID = ArithAllows & AOEVT_FP
-                     ? (ArithAllows & AOEVT_Pointer
-                            ? diag::err_atomic_op_needs_atomic_int_ptr_or_fp
-                            : diag::err_atomic_op_needs_atomic_int_or_fp)
-                     : diag::err_atomic_op_needs_atomic_int;
-      Diag(ExprRange.getBegin(), DID)
-          << IsC11 << Ptr->getType() << Ptr->getSourceRange();
-      return ExprError();
-    }
-    if (IsC11 && ValType->isPointerType() &&
-        RequireCompleteType(Ptr->getBeginLoc(), ValType->getPointeeType(),
-                            diag::err_incomplete_type)) {
-      return ExprError();
-    }
-  } else if (IsN && !ValType->isIntegerType() && !ValType->isPointerType()) {
-    // For __atomic_*_n operations, the value type must be a scalar integral or
-    // pointer type which is 1, 2, 4, 8 or 16 bytes in length.
-    Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int_or_ptr)
-        << IsC11 << Ptr->getType() << Ptr->getSourceRange();
-    return ExprError();
-  }
-
-  if (!IsC11 && !AtomTy.isTriviallyCopyableType(Context) &&
-      !AtomTy->isScalarType()) {
-    // For GNU atomics, require a trivially-copyable type. This is not part of
-    // the GNU atomics specification but we enforce it for consistency with
-    // other atomics which generally all require a trivially-copyable type. This
-    // is because atomics just copy bits.
-    Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_trivial_copy)
-        << Ptr->getType() << Ptr->getSourceRange();
-    return ExprError();
-  }
-
-  switch (ValType.getObjCLifetime()) {
-  case Qualifiers::OCL_None:
-  case Qualifiers::OCL_ExplicitNone:
-    // okay
-    break;
-
-  case Qualifiers::OCL_Weak:
-  case Qualifiers::OCL_Strong:
-  case Qualifiers::OCL_Autoreleasing:
-    // FIXME: Can this happen? By this point, ValType should be known
-    // to be trivially copyable.
-    Diag(ExprRange.getBegin(), diag::err_arc_atomic_ownership)
-        << ValType << Ptr->getSourceRange();
-    return ExprError();
-  }
-
-  // All atomic operations have an overload which takes a pointer to a volatile
-  // 'A'.  We shouldn't let the volatile-ness of the pointee-type inject itself
-  // into the result or the other operands. Similarly atomic_load takes a
-  // pointer to a const 'A'.
-  ValType.removeLocalVolatile();
-  ValType.removeLocalConst();
-  QualType ResultType = ValType;
-  if (Form == Copy || Form == LoadCopy || Form == GNUXchg || Form == Init ||
-      Form == ClearByte)
-    ResultType = Context.VoidTy;
-  else if (Form == C11CmpXchg || Form == GNUCmpXchg || Form == TestAndSetByte)
-    ResultType = Context.BoolTy;
-
-  // The type of a parameter passed 'by value'. In the GNU atomics, such
-  // arguments are actually passed as pointers.
-  QualType ByValType = ValType; // 'CP'
-  bool IsPassedByAddress = false;
-  if (!IsC11 && !IsHIP && !IsN) {
-    ByValType = Ptr->getType();
-    IsPassedByAddress = true;
-  }
-
-  SmallVector<Expr *, 5> APIOrderedArgs;
-  if (ArgOrder == Sema::AtomicArgumentOrder::AST) {
-    APIOrderedArgs.push_back(Args[0]);
-    switch (Form) {
-    case Init:
-    case Load:
-      APIOrderedArgs.push_back(Args[1]); // Val1/Order
-      break;
-    case LoadCopy:
-    case Copy:
-    case Arithmetic:
-    case Xchg:
-      APIOrderedArgs.push_back(Args[2]); // Val1
-      APIOrderedArgs.push_back(Args[1]); // Order
-      break;
-    case GNUXchg:
-      APIOrderedArgs.push_back(Args[2]); // Val1
-      APIOrderedArgs.push_back(Args[3]); // Val2
-      APIOrderedArgs.push_back(Args[1]); // Order
-      break;
-    case C11CmpXchg:
-      APIOrderedArgs.push_back(Args[2]); // Val1
-      APIOrderedArgs.push_back(Args[4]); // Val2
-      APIOrderedArgs.push_back(Args[1]); // Order
-      APIOrderedArgs.push_back(Args[3]); // OrderFail
-      break;
-    case GNUCmpXchg:
-      APIOrderedArgs.push_back(Args[2]); // Val1
-      APIOrderedArgs.push_back(Args[4]); // Val2
-      APIOrderedArgs.push_back(Args[5]); // Weak
-      APIOrderedArgs.push_back(Args[1]); // Order
-      APIOrderedArgs.push_back(Args[3]); // OrderFail
-      break;
-    case TestAndSetByte:
-    case ClearByte:
-      APIOrderedArgs.push_back(Args[1]); // Order
-      break;
-    }
-  } else
-    APIOrderedArgs.append(Args.begin(), Args.end());
-
-  // The first argument's non-CV pointer type is used to deduce the type of
-  // subsequent arguments, except for:
-  //  - weak flag (always converted to bool)
-  //  - memory order (always converted to int)
-  //  - scope  (always converted to int)
-  for (unsigned i = 0; i != APIOrderedArgs.size(); ++i) {
-    QualType Ty;
-    if (i < NumVals[Form] + 1) {
-      switch (i) {
-      case 0:
-        // The first argument is always a pointer. It has a fixed type.
-        // It is always dereferenced, a nullptr is undefined.
-        CheckNonNullArgument(*this, APIOrderedArgs[i], ExprRange.getBegin());
-        // Nothing else to do: we already know all we want about this pointer.
-        continue;
-      case 1:
-        // The second argument is the non-atomic operand. For arithmetic, this
-        // is always passed by value, and for a compare_exchange it is always
-        // passed by address. For the rest, GNU uses by-address and C11 uses
-        // by-value.
-        assert(Form != Load);
-        if (Form == Arithmetic && ValType->isPointerType())
-          Ty = Context.getPointerDiffType();
-        else if (Form == Init || Form == Arithmetic)
-          Ty = ValType;
-        else if (Form == Copy || Form == Xchg) {
-          if (IsPassedByAddress) {
-            // The value pointer is always dereferenced, a nullptr is undefined.
-            CheckNonNullArgument(*this, APIOrderedArgs[i],
-                                 ExprRange.getBegin());
-          }
-          Ty = ByValType;
-        } else {
-          Expr *ValArg = APIOrderedArgs[i];
-          // The value pointer is always dereferenced, a nullptr is undefined.
-          CheckNonNullArgument(*this, ValArg, ExprRange.getBegin());
-          LangAS AS = LangAS::Default;
-          // Keep address space of non-atomic pointer type.
-          if (const PointerType *PtrTy =
-                  ValArg->getType()->getAs<PointerType>()) {
-            AS = PtrTy->getPointeeType().getAddressSpace();
-          }
-          Ty = Context.getPointerType(
-              Context.getAddrSpaceQualType(ValType.getUnqualifiedType(), AS));
-        }
-        break;
-      case 2:
-        // The third argument to compare_exchange / GNU exchange is the desired
-        // value, either by-value (for the C11 and *_n variant) or as a pointer.
-        if (IsPassedByAddress)
-          CheckNonNullArgument(*this, APIOrderedArgs[i], ExprRange.getBegin());
-        Ty = ByValType;
-        break;
-      case 3:
-        // The fourth argument to GNU compare_exchange is a 'weak' flag.
-        Ty = Context.BoolTy;
-        break;
-      }
-    } else {
-      // The order(s) and scope are always converted to int.
-      Ty = Context.IntTy;
-    }
-
-    InitializedEntity Entity =
-        InitializedEntity::InitializeParameter(Context, Ty, false);
-    ExprResult Arg = APIOrderedArgs[i];
-    Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg);
-    if (Arg.isInvalid())
-      return true;
-    APIOrderedArgs[i] = Arg.get();
-  }
-
-  // Permute the arguments into a 'consistent' order.
-  SmallVector<Expr*, 5> SubExprs;
-  SubExprs.push_back(Ptr);
-  switch (Form) {
-  case Init:
-    // Note, AtomicExpr::getVal1() has a special case for this atomic.
-    SubExprs.push_back(APIOrderedArgs[1]); // Val1
-    break;
-  case Load:
-  case TestAndSetByte:
-  case ClearByte:
-    SubExprs.push_back(APIOrderedArgs[1]); // Order
-    break;
-  case LoadCopy:
-  case Copy:
-  case Arithmetic:
-  case Xchg:
-    SubExprs.push_back(APIOrderedArgs[2]); // Order
-    SubExprs.push_back(APIOrderedArgs[1]); // Val1
-    break;
-  case GNUXchg:
-    // Note, AtomicExpr::getVal2() has a special case for this atomic.
-    SubExprs.push_back(APIOrderedArgs[3]); // Order
-    SubExprs.push_back(APIOrderedArgs[1]); // Val1
-    SubExprs.push_back(APIOrderedArgs[2]); // Val2
-    break;
-  case C11CmpXchg:
-    SubExprs.push_back(APIOrderedArgs[3]); // Order
-    SubExprs.push_back(APIOrderedArgs[1]); // Val1
-    SubExprs.push_back(APIOrderedArgs[4]); // OrderFail
-    SubExprs.push_back(APIOrderedArgs[2]); // Val2
-    break;
-  case GNUCmpXchg:
-    SubExprs.push_back(APIOrderedArgs[4]); // Order
-    SubExprs.push_back(APIOrderedArgs[1]); // Val1
-    SubExprs.push_back(APIOrderedArgs[5]); // OrderFail
-    SubExprs.push_back(APIOrderedArgs[2]); // Val2
-    SubExprs.push_back(APIOrderedArgs[3]); // Weak
-    break;
-  }
-
-  // If the memory orders are constants, check they are valid.
-  if (SubExprs.size() >= 2 && Form != Init) {
-    std::optional<llvm::APSInt> Success =
-        SubExprs[1]->getIntegerConstantExpr(Context);
-    if (Success && !isValidOrderingForOp(Success->getSExtValue(), Op)) {
-      Diag(SubExprs[1]->getBeginLoc(),
-           diag::warn_atomic_op_has_invalid_memory_order)
-          << /*success=*/(Form == C11CmpXchg || Form == GNUCmpXchg)
-          << SubExprs[1]->getSourceRange();
-    }
-    if (SubExprs.size() >= 5) {
-      if (std::optional<llvm::APSInt> Failure =
-              SubExprs[3]->getIntegerConstantExpr(Context)) {
-        if (!llvm::is_contained(
-                {llvm::AtomicOrderingCABI::relaxed,
-                 llvm::AtomicOrderingCABI::consume,
-                 llvm::AtomicOrderingCABI::acquire,
-                 llvm::AtomicOrderingCABI::seq_cst},
-                (llvm::AtomicOrderingCABI)Failure->getSExtValue())) {
-          Diag(SubExprs[3]->getBeginLoc(),
-               diag::warn_atomic_op_has_invalid_memory_order)
-              << /*failure=*/2 << SubExprs[3]->getSourceRange();
-        }
-      }
-    }
-  }
-
-  if (auto ScopeModel = AtomicExpr::getScopeModel(Op)) {
-    auto *Scope = Args[Args.size() - 1];
-    if (std::optional<llvm::APSInt> Result =
-            Scope->getIntegerConstantExpr(Context)) {
-      if (!ScopeModel->isValid(Result->getZExtValue()))
-        Diag(Scope->getBeginLoc(), diag::err_atomic_op_has_invalid_sync_scope)
-            << Scope->getSourceRange();
-    }
-    SubExprs.push_back(Scope);
-  }
-
-  AtomicExpr *AE = new (Context)
-      AtomicExpr(ExprRange.getBegin(), SubExprs, ResultType, Op, RParenLoc);
-
-  if ((Op == AtomicExpr::AO__c11_atomic_load ||
-       Op == AtomicExpr::AO__c11_atomic_store ||
-       Op == AtomicExpr::AO__opencl_atomic_load ||
-       Op == AtomicExpr::AO__hip_atomic_load ||
-       Op == AtomicExpr::AO__opencl_atomic_store ||
-       Op == AtomicExpr::AO__hip_atomic_store) &&
-      Context.AtomicUsesUnsupportedLibcall(AE))
-    Diag(AE->getBeginLoc(), diag::err_atomic_load_store_uses_lib)
-        << ((Op == AtomicExpr::AO__c11_atomic_load ||
-             Op == AtomicExpr::AO__opencl_atomic_load ||
-             Op == AtomicExpr::AO__hip_atomic_load)
-                ? 0
-                : 1);
-
-  if (ValType->isBitIntType()) {
-    Diag(Ptr->getExprLoc(), diag::err_atomic_builtin_bit_int_prohibit);
-    return ExprError();
-  }
-
-  return AE;
-}
-
-/// checkBuiltinArgument - Given a call to a builtin function, perform
-/// normal type-checking on the given argument, updating the call in
-/// place.  This is useful when a builtin function requires custom
-/// type-checking for some of its arguments but not necessarily all of
-/// them.
-///
-/// Returns true on error.
-static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) {
-  FunctionDecl *Fn = E->getDirectCallee();
-  assert(Fn && "builtin call without direct callee!");
-
-  ParmVarDecl *Param = Fn->getParamDecl(ArgIndex);
-  InitializedEntity Entity =
-    InitializedEntity::InitializeParameter(S.Context, Param);
-
-  ExprResult Arg = E->getArg(ArgIndex);
-  Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg);
-  if (Arg.isInvalid())
-    return true;
-
-  E->setArg(ArgIndex, Arg.get());
-  return false;
-}
-
-ExprResult Sema::BuiltinAtomicOverloaded(ExprResult TheCallResult) {
-  CallExpr *TheCall = static_cast<CallExpr *>(TheCallResult.get());
-  Expr *Callee = TheCall->getCallee();
-  DeclRefExpr *DRE = cast<DeclRefExpr>(Callee->IgnoreParenCasts());
-  FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl());
-
-  // Ensure that we have at least one argument to do type inference from.
-  if (TheCall->getNumArgs() < 1) {
-    Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least)
-        << 0 << 1 << TheCall->getNumArgs() << /*is non object*/ 0
-        << Callee->getSourceRange();
-    return ExprError();
-  }
-
-  // Inspect the first argument of the atomic builtin.  This should always be
-  // a pointer type, whose element is an integral scalar or pointer type.
-  // Because it is a pointer type, we don't have to worry about any implicit
-  // casts here.
-  // FIXME: We don't allow floating point scalars as input.
-  Expr *FirstArg = TheCall->getArg(0);
-  ExprResult FirstArgResult = DefaultFunctionArrayLvalueConversion(FirstArg);
-  if (FirstArgResult.isInvalid())
-    return ExprError();
-  FirstArg = FirstArgResult.get();
-  TheCall->setArg(0, FirstArg);
-
-  const PointerType *pointerType = FirstArg->getType()->getAs<PointerType>();
-  if (!pointerType) {
-    Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer)
-        << FirstArg->getType() << 0 << FirstArg->getSourceRange();
-    return ExprError();
-  }
-
-  QualType ValType = pointerType->getPointeeType();
-  if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
-      !ValType->isBlockPointerType()) {
-    Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer_intptr)
-        << FirstArg->getType() << 0 << FirstArg->getSourceRange();
-    return ExprError();
-  }
-  PointerAuthQualifier PointerAuth = ValType.getPointerAuth();
-  if (PointerAuth && PointerAuth.isAddressDiscriminated()) {
-    Diag(FirstArg->getBeginLoc(),
-         diag::err_atomic_op_needs_non_address_discriminated_pointer)
-        << 1 << ValType << FirstArg->getSourceRange();
-    return ExprError();
-  }
-
-  if (ValType.isConstQualified()) {
-    Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_cannot_be_const)
-        << FirstArg->getType() << FirstArg->getSourceRange();
-    return ExprError();
-  }
-
-  switch (ValType.getObjCLifetime()) {
-  case Qualifiers::OCL_None:
-  case Qualifiers::OCL_ExplicitNone:
-    // okay
-    break;
-
-  case Qualifiers::OCL_Weak:
-  case Qualifiers::OCL_Strong:
-  case Qualifiers::OCL_Autoreleasing:
-    Diag(DRE->getBeginLoc(), diag::err_arc_atomic_ownership)
-        << ValType << FirstArg->getSourceRange();
-    return ExprError();
-  }
-
-  // Strip any qualifiers off ValType.
-  ValType = ValType.getUnqualifiedType();
-
-  // The majority of builtins return a value, but a few have special return
-  // types, so allow them to override appropriately below.
-  QualType ResultType = ValType;
-
-  // We need to figure out which concrete builtin this maps onto.  For example,
-  // __sync_fetch_and_add with a 2 byte object turns into
-  // __sync_fetch_and_add_2.
-#define BUILTIN_ROW(x) \
-  { Builtin::BI##x##_1, Builtin::BI##x##_2, Builtin::BI##x##_4, \
-    Builtin::BI##x##_8, Builtin::BI##x##_16 }
-
-  static const unsigned BuiltinIndices[][5] = {
-    BUILTIN_ROW(__sync_fetch_and_add),
-    BUILTIN_ROW(__sync_fetch_and_sub),
-    BUILTIN_ROW(__sync_fetch_and_or),
-    BUILTIN_ROW(__sync_fetch_and_and),
-    BUILTIN_ROW(__sync_fetch_and_xor),
-    BUILTIN_ROW(__sync_fetch_and_nand),
-
-    BUILTIN_ROW(__sync_add_and_fetch),
-    BUILTIN_ROW(__sync_sub_and_fetch),
-    BUILTIN_ROW(__sync_and_and_fetch),
-    BUILTIN_ROW(__sync_or_and_fetch),
-    BUILTIN_ROW(__sync_xor_and_fetch),
-    BUILTIN_ROW(__sync_nand_and_fetch),
-
-    BUILTIN_ROW(__sync_val_compare_and_swap),
-    BUILTIN_ROW(__sync_bool_compare_and_swap),
-    BUILTIN_ROW(__sync_lock_test_and_set),
-    BUILTIN_ROW(__sync_lock_release),
-    BUILTIN_ROW(__sync_swap)
-  };
-#undef BUILTIN_ROW
-
-  // Determine the index of the size.
-  unsigned SizeIndex;
-  switch (Context.getTypeSizeInChars(ValType).getQuantity()) {
-  case 1: SizeIndex = 0; break;
-  case 2: SizeIndex = 1; break;
-  case 4: SizeIndex = 2; break;
-  case 8: SizeIndex = 3; break;
-  case 16: SizeIndex = 4; break;
-  default:
-    Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_pointer_size)
-        << FirstArg->getType() << FirstArg->getSourceRange();
-    return ExprError();
-  }
-
-  // Each of these builtins has one pointer argument, followed by some number of
-  // values (0, 1 or 2) followed by a potentially empty varags list of stuff
-  // that we ignore.  Find out which row of BuiltinIndices to read from as well
-  // as the number of fixed args.
-  unsigned BuiltinID = FDecl->getBuiltinID();
-  unsigned BuiltinIndex, NumFixed = 1;
-  bool WarnAboutSemanticsChange = false;
-  switch (BuiltinID) {
-  default: llvm_unreachable("Unknown overloaded atomic builtin!");
-  case Builtin::BI__sync_fetch_and_add:
-  case Builtin::BI__sync_fetch_and_add_1:
-  case Builtin::BI__sync_fetch_and_add_2:
-  case Builtin::BI__sync_fetch_and_add_4:
-  case Builtin::BI__sync_fetch_and_add_8:
-  case Builtin::BI__sync_fetch_and_add_16:
-    BuiltinIndex = 0;
-    break;
-
-  case Builtin::BI__sync_fetch_and_sub:
-  case Builtin::BI__sync_fetch_and_sub_1:
-  case Builtin::BI__sync_fetch_and_sub_2:
-  case Builtin::BI__sync_fetch_and_sub_4:
-  case Builtin::BI__sync_fetch_and_sub_8:
-  case Builtin::BI__sync_fetch_and_sub_16:
-    BuiltinIndex = 1;
-    break;
-
-  case Builtin::BI__sync_fetch_and_or:
-  case Builtin::BI__sync_fetch_and_or_1:
-  case Builtin::BI__sync_fetch_and_or_2:
-  case Builtin::BI__sync_fetch_and_or_4:
-  case Builtin::BI__sync_fetch_and_or_8:
-  case Builtin::BI__sync_fetch_and_or_16:
-    BuiltinIndex = 2;
-    break;
-
-  case Builtin::BI__sync_fetch_and_and:
-  case Builtin::BI__sync_fetch_and_and_1:
-  case Builtin::BI__sync_fetch_and_and_2:
-  case Builtin::BI__sync_fetch_and_and_4:
-  case Builtin::BI__sync_fetch_and_and_8:
-  case Builtin::BI__sync_fetch_and_and_16:
-    BuiltinIndex = 3;
-    break;
-
-  case Builtin::BI__sync_fetch_and_xor:
-  case Builtin::BI__sync_fetch_and_xor_1:
-  case Builtin::BI__sync_fetch_and_xor_2:
-  case Builtin::BI__sync_fetch_and_xor_4:
-  case Builtin::BI__sync_fetch_and_xor_8:
-  case Builtin::BI__sync_fetch_and_xor_16:
-    BuiltinIndex = 4;
-    break;
-
-  case Builtin::BI__sync_fetch_and_nand:
-  case Builtin::BI__sync_fetch_and_nand_1:
-  case Builtin::BI__sync_fetch_and_nand_2:
-  case Builtin::BI__sync_fetch_and_nand_4:
-  case Builtin::BI__sync_fetch_and_nand_8:
-  case Builtin::BI__sync_fetch_and_nand_16:
-    BuiltinIndex = 5;
-    WarnAboutSemanticsChange = true;
-    break;
-
-  case Builtin::BI__sync_add_and_fetch:
-  case Builtin::BI__sync_add_and_fetch_1:
-  case Builtin::BI__sync_add_and_fetch_2:
-  case Builtin::BI__sync_add_and_fetch_4:
-  case Builtin::BI__sync_add_and_fetch_8:
-  case Builtin::BI__sync_add_and_fetch_16:
-    BuiltinIndex = 6;
-    break;
-
-  case Builtin::BI__sync_sub_and_fetch:
-  case Builtin::BI__sync_sub_and_fetch_1:
-  case Builtin::BI__sync_sub_and_fetch_2:
-  case Builtin::BI__sync_sub_and_fetch_4:
-  case Builtin::BI__sync_sub_and_fetch_8:
-  case Builtin::BI__sync_sub_and_fetch_16:
-    BuiltinIndex = 7;
-    break;
-
-  case Builtin::BI__sync_and_and_fetch:
-  case Builtin::BI__sync_and_and_fetch_1:
-  case Builtin::BI__sync_and_and_fetch_2:
-  case Builtin::BI__sync_and_and_fetch_4:
-  case Builtin::BI__sync_and_and_fetch_8:
-  case Builtin::BI__sync_and_and_fetch_16:
-    BuiltinIndex = 8;
-    break;
-
-  case Builtin::BI__sync_or_and_fetch:
-  case Builtin::BI__sync_or_and_fetch_1:
-  case Builtin::BI__sync_or_and_fetch_2:
-  case Builtin::BI__sync_or_and_fetch_4:
-  case Builtin::BI__sync_or_and_fetch_8:
-  case Builtin::BI__sync_or_and_fetch_16:
-    BuiltinIndex = 9;
-    break;
-
-  case Builtin::BI__sync_xor_and_fetch:
-  case Builtin::BI__sync_xor_and_fetch_1:
-  case Builtin::BI__sync_xor_and_fetch_2:
-  case Builtin::BI__sync_xor_and_fetch_4:
-  case Builtin::BI__sync_xor_and_fetch_8:
-  case Builtin::BI__sync_xor_and_fetch_16:
-    BuiltinIndex = 10;
-    break;
-
-  case Builtin::BI__sync_nand_and_fetch:
-  case Builtin::BI__sync_nand_and_fetch_1:
-  case Builtin::BI__sync_nand_and_fetch_2:
-  case Builtin::BI__sync_nand_and_fetch_4:
-  case Builtin::BI__sync_nand_and_fetch_8:
-  case Builtin::BI__sync_nand_and_fetch_16:
-    BuiltinIndex = 11;
-    WarnAboutSemanticsChange = true;
-    break;
-
-  case Builtin::BI__sync_val_compare_and_swap:
-  case Builtin::BI__sync_val_compare_and_swap_1:
-  case Builtin::BI__sync_val_compare_and_swap_2:
-  case Builtin::BI__sync_val_compare_and_swap_4:
-  case Builtin::BI__sync_val_compare_and_swap_8:
-  case Builtin::BI__sync_val_compare_and_swap_16:
-    BuiltinIndex = 12;
-    NumFixed = 2;
-    break;
-
-  case Builtin::BI__sync_bool_compare_and_swap:
-  case Builtin::BI__sync_bool_compare_and_swap_1:
-  case Builtin::BI__sync_bool_compare_and_swap_2:
-  case Builtin::BI__sync_bool_compare_and_swap_4:
-  case Builtin::BI__sync_bool_compare_and_swap_8:
-  case Builtin::BI__sync_bool_compare_and_swap_16:
-    BuiltinIndex = 13;
-    NumFixed = 2;
-    ResultType = Context.BoolTy;
-    break;
-
-  case Builtin::BI__sync_lock_test_and_set:
-  case Builtin::BI__sync_lock_test_and_set_1:
-  case Builtin::BI__sync_lock_test_and_set_2:
-  case Builtin::BI__sync_lock_test_and_set_4:
-  case Builtin::BI__sync_lock_test_and_set_8:
-  case Builtin::BI__sync_lock_test_and_set_16:
-    BuiltinIndex = 14;
-    break;
-
-  case Builtin::BI__sync_lock_release:
-  case Builtin::BI__sync_lock_release_1:
-  case Builtin::BI__sync_lock_release_2:
-  case Builtin::BI__sync_lock_release_4:
-  case Builtin::BI__sync_lock_release_8:
-  case Builtin::BI__sync_lock_release_16:
-    BuiltinIndex = 15;
-    NumFixed = 0;
-    ResultType = Context.VoidTy;
-    break;
-
-  case Builtin::BI__sync_swap:
-  case Builtin::BI__sync_swap_1:
-  case Builtin::BI__sync_swap_2:
-  case Builtin::BI__sync_swap_4:
-  case Builtin::BI__sync_swap_8:
-  case Builtin::BI__sync_swap_16:
-    BuiltinIndex = 16;
-    break;
-  }
-
-  // Now that we know how many fixed arguments we expect, first check that we
-  // have at least that many.
-  if (TheCall->getNumArgs() < 1+NumFixed) {
-    Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least)
-        << 0 << 1 + NumFixed << TheCall->getNumArgs() << /*is non object*/ 0
-        << Callee->getSourceRange();
-    return ExprError();
-  }
-
-  Diag(TheCall->getEndLoc(), diag::warn_atomic_implicit_seq_cst)
-      << Callee->getSourceRange();
-
-  if (WarnAboutSemanticsChange) {
-    Diag(TheCall->getEndLoc(), diag::warn_sync_fetch_and_nand_semantics_change)
-        << Callee->getSourceRange();
-  }
-
-  // Get the decl for the concrete builtin from this, we can tell what the
-  // concrete integer type we should convert to is.
-  unsigned NewBuiltinID = BuiltinIndices[BuiltinIndex][SizeIndex];
-  std::string NewBuiltinName = Context.BuiltinInfo.getName(NewBuiltinID);
-  FunctionDecl *NewBuiltinDecl;
-  if (NewBuiltinID == BuiltinID)
-    NewBuiltinDecl = FDecl;
-  else {
-    // Perform builtin lookup to avoid redeclaring it.
-    DeclarationName DN(&Context.Idents.get(NewBuiltinName));
-    LookupResult Res(*this, DN, DRE->getBeginLoc(), LookupOrdinaryName);
-    LookupName(Res, TUScope, /*AllowBuiltinCreation=*/true);
-    assert(Res.getFoundDecl());
-    NewBuiltinDecl = dyn_cast<FunctionDecl>(Res.getFoundDecl());
-    if (!NewBuiltinDecl)
-      return ExprError();
-  }
-
-  // The first argument --- the pointer --- has a fixed type; we
-  // deduce the types of the rest of the arguments accordingly.  Walk
-  // the remaining arguments, converting them to the deduced value type.
-  for (unsigned i = 0; i != NumFixed; ++i) {
-    ExprResult Arg = TheCall->getArg(i+1);
-
-    // GCC does an implicit conversion to the pointer or integer ValType.  This
-    // can fail in some cases (1i -> int**), check for this error case now.
-    // Initialize the argument.
-    InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
-                                                   ValType, /*consume*/ false);
-    Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg);
-    if (Arg.isInvalid())
-      return ExprError();
-
-    // Okay, we have something that *can* be converted to the right type.  Check
-    // to see if there is a potentially weird extension going on here.  This can
-    // happen when you do an atomic operation on something like an char* and
-    // pass in 42.  The 42 gets converted to char.  This is even more strange
-    // for things like 45.123 -> char, etc.
-    // FIXME: Do this check.
-    TheCall->setArg(i+1, Arg.get());
-  }
-
-  // Create a new DeclRefExpr to refer to the new decl.
-  DeclRefExpr *NewDRE = DeclRefExpr::Create(
-      Context, DRE->getQualifierLoc(), SourceLocation(), NewBuiltinDecl,
-      /*enclosing*/ false, DRE->getLocation(), Context.BuiltinFnTy,
-      DRE->getValueKind(), nullptr, nullptr, DRE->isNonOdrUse());
-
-  // Set the callee in the CallExpr.
-  // FIXME: This loses syntactic information.
-  QualType CalleePtrTy = Context.getPointerType(NewBuiltinDecl->getType());
-  ExprResult PromotedCall = ImpCastExprToType(NewDRE, CalleePtrTy,
-                                              CK_BuiltinFnToFnPtr);
-  TheCall->setCallee(PromotedCall.get());
-
-  // Change the result type of the call to match the original value type. This
-  // is arbitrary, but the codegen for these builtins ins design to handle it
-  // gracefully.
-  TheCall->setType(ResultType);
-
-  // Prohibit problematic uses of bit-precise integer types with atomic
-  // builtins. The arguments would have already been converted to the first
-  // argument's type, so only need to check the first argument.
-  const auto *BitIntValType = ValType->getAs<BitIntType>();
-  if (BitIntValType && !llvm::isPowerOf2_64(BitIntValType->getNumBits())) {
-    Diag(FirstArg->getExprLoc(), diag::err_atomic_builtin_ext_int_size);
-    return ExprError();
-  }
-
-  return TheCallResult;
-}
-
-ExprResult Sema::BuiltinNontemporalOverloaded(ExprResult TheCallResult) {
-  CallExpr *TheCall = (CallExpr *)TheCallResult.get();
-  DeclRefExpr *DRE =
-      cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
-  FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl());
-  unsigned BuiltinID = FDecl->getBuiltinID();
-  assert((BuiltinID == Builtin::BI__builtin_nontemporal_store ||
-          BuiltinID == Builtin::BI__builtin_nontemporal_load) &&
-         "Unexpected nontemporal load/store builtin!");
-  bool isStore = BuiltinID == Builtin::BI__builtin_nontemporal_store;
-  unsigned numArgs = isStore ? 2 : 1;
-
-  // Ensure that we have the proper number of arguments.
-  if (checkArgCount(TheCall, numArgs))
-    return ExprError();
-
-  // Inspect the last argument of the nontemporal builtin.  This should always
-  // be a pointer type, from which we imply the type of the memory access.
-  // Because it is a pointer type, we don't have to worry about any implicit
-  // casts here.
-  Expr *PointerArg = TheCall->getArg(numArgs - 1);
-  ExprResult PointerArgResult =
-      DefaultFunctionArrayLvalueConversion(PointerArg);
-
-  if (PointerArgResult.isInvalid())
-    return ExprError();
-  PointerArg = PointerArgResult.get();
-  TheCall->setArg(numArgs - 1, PointerArg);
-
-  const PointerType *pointerType = PointerArg->getType()->getAs<PointerType>();
-  if (!pointerType) {
-    Diag(DRE->getBeginLoc(), diag::err_nontemporal_builtin_must_be_pointer)
-        << PointerArg->getType() << PointerArg->getSourceRange();
-    return ExprError();
-  }
-
-  QualType ValType = pointerType->getPointeeType();
-
-  // Strip any qualifiers off ValType.
-  ValType = ValType.getUnqualifiedType();
-  if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
-      !ValType->isBlockPointerType() && !ValType->isFloatingType() &&
-      !ValType->isVectorType()) {
-    Diag(DRE->getBeginLoc(),
-         diag::err_nontemporal_builtin_must_be_pointer_intfltptr_or_vector)
-        << PointerArg->getType() << PointerArg->getSourceRange();
-    return ExprError();
-  }
-
-  if (!isStore) {
-    TheCall->setType(ValType);
-    return TheCallResult;
-  }
-
-  ExprResult ValArg = TheCall->getArg(0);
-  InitializedEntity Entity = InitializedEntity::InitializeParameter(
-      Context, ValType, /*consume*/ false);
-  ValArg = PerformCopyInitialization(Entity, SourceLocation(), ValArg);
-  if (ValArg.isInvalid())
-    return ExprError();
-
-  TheCall->setArg(0, ValArg.get());
-  TheCall->setType(Context.VoidTy);
-  return TheCallResult;
-}
-
-/// CheckObjCString - Checks that the format string argument to the os_log()
-/// and os_trace() functions is correct, and converts it to const char *.
-ExprResult Sema::CheckOSLogFormatStringArg(Expr *Arg) {
-  Arg = Arg->IgnoreParenCasts();
-  auto *Literal = dyn_cast<StringLiteral>(Arg);
-  if (!Literal) {
-    if (auto *ObjcLiteral = dyn_cast<ObjCStringLiteral>(Arg)) {
-      Literal = ObjcLiteral->getString();
-    }
-  }
-
-  if (!Literal || (!Literal->isOrdinary() && !Literal->isUTF8())) {
-    return ExprError(
-        Diag(Arg->getBeginLoc(), diag::err_os_log_format_not_string_constant)
-        << Arg->getSourceRange());
-  }
-
-  ExprResult Result(Literal);
-  QualType ResultTy = Context.getPointerType(Context.CharTy.withConst());
-  InitializedEntity Entity =
-      InitializedEntity::InitializeParameter(Context, ResultTy, false);
-  Result = PerformCopyInitialization(Entity, SourceLocation(), Result);
-  return Result;
-}
-
-/// Check that the user is calling the appropriate va_start builtin for the
-/// target and calling convention.
-static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) {
-  const llvm::Triple &TT = S.Context.getTargetInfo().getTriple();
-  bool IsX64 = TT.getArch() == llvm::Triple::x86_64;
-  bool IsAArch64 = (TT.getArch() == llvm::Triple::aarch64 ||
-                    TT.getArch() == llvm::Triple::aarch64_32);
-  bool IsWindowsOrUEFI = TT.isOSWindows() || TT.isUEFI();
-  bool IsMSVAStart = BuiltinID == Builtin::BI__builtin_ms_va_start;
-  if (IsX64 || IsAArch64) {
-    CallingConv CC = CC_C;
-    if (const FunctionDecl *FD = S.getCurFunctionDecl())
-      CC = FD->getType()->castAs<FunctionType>()->getCallConv();
-    if (IsMSVAStart) {
-      // Don't allow this in System V ABI functions.
-      if (CC == CC_X86_64SysV || (!IsWindowsOrUEFI && CC != CC_Win64))
-        return S.Diag(Fn->getBeginLoc(),
-                      diag::err_ms_va_start_used_in_sysv_function);
-    } else {
-      // On x86-64/AArch64 Unix, don't allow this in Win64 ABI functions.
-      // On x64 Windows, don't allow this in System V ABI functions.
-      // (Yes, that means there's no corresponding way to support variadic
-      // System V ABI functions on Windows.)
-      if ((IsWindowsOrUEFI && CC == CC_X86_64SysV) ||
-          (!IsWindowsOrUEFI && CC == CC_Win64))
-        return S.Diag(Fn->getBeginLoc(),
-                      diag::err_va_start_used_in_wrong_abi_function)
-               << !IsWindowsOrUEFI;
-    }
-    return false;
-  }
-
-  if (IsMSVAStart)
-    return S.Diag(Fn->getBeginLoc(), diag::err_builtin_x64_aarch64_only);
-  return false;
-}
-
-static bool checkVAStartIsInVariadicFunction(Sema &S, Expr *Fn,
-                                             ParmVarDecl **LastParam = nullptr) {
-  // Determine whether the current function, block, or obj-c method is variadic
-  // and get its parameter list.
-  bool IsVariadic = false;
-  ArrayRef<ParmVarDecl *> Params;
-  DeclContext *Caller = S.CurContext;
-  if (auto *Block = dyn_cast<BlockDecl>(Caller)) {
-    IsVariadic = Block->isVariadic();
-    Params = Block->parameters();
-  } else if (auto *FD = dyn_cast<FunctionDecl>(Caller)) {
-    IsVariadic = FD->isVariadic();
-    Params = FD->parameters();
-  } else if (auto *MD = dyn_cast<ObjCMethodDecl>(Caller)) {
-    IsVariadic = MD->isVariadic();
-    // FIXME: This isn't correct for methods (results in bogus warning).
-    Params = MD->parameters();
-  } else if (isa<CapturedDecl>(Caller)) {
-    // We don't support va_start in a CapturedDecl.
-    S.Diag(Fn->getBeginLoc(), diag::err_va_start_captured_stmt);
-    return true;
-  } else {
-    // This must be some other declcontext that parses exprs.
-    S.Diag(Fn->getBeginLoc(), diag::err_va_start_outside_function);
-    return true;
-  }
-
-  if (!IsVariadic) {
-    S.Diag(Fn->getBeginLoc(), diag::err_va_start_fixed_function);
-    return true;
-  }
-
-  if (LastParam)
-    *LastParam = Params.empty() ? nullptr : Params.back();
-
-  return false;
-}
-
-bool Sema::BuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
-  Expr *Fn = TheCall->getCallee();
-  if (checkVAStartABI(*this, BuiltinID, Fn))
-    return true;
-
-  if (BuiltinID == Builtin::BI__builtin_c23_va_start) {
-    // This builtin requires one argument (the va_list), allows two arguments,
-    // but diagnoses more than two arguments. e.g.,
-    //   __builtin_c23_va_start(); // error
-    //   __builtin_c23_va_start(list); // ok
-    //   __builtin_c23_va_start(list, param); // ok
-    //   __builtin_c23_va_start(list, anything, anything); // error
-    // This differs from the GCC behavior in that they accept the last case
-    // with a warning, but it doesn't seem like a useful behavior to allow.
-    if (checkArgCountRange(TheCall, 1, 2))
-      return true;
-  } else {
-    // In C23 mode, va_start only needs one argument. However, the builtin still
-    // requires two arguments (which matches the behavior of the GCC builtin),
-    // <stdarg.h> passes `0` as the second argument in C23 mode.
-    if (checkArgCount(TheCall, 2))
-      return true;
-  }
-
-  // Type-check the first argument normally.
-  if (checkBuiltinArgument(*this, TheCall, 0))
-    return true;
-
-  // Check that the current function is variadic, and get its last parameter.
-  ParmVarDecl *LastParam;
-  if (checkVAStartIsInVariadicFunction(*this, Fn, &LastParam))
-    return true;
-
-  // Verify that the second argument to the builtin is the last non-variadic
-  // argument of the current function or method. In C23 mode, if the call is
-  // not to __builtin_c23_va_start, and the second argument is an integer
-  // constant expression with value 0, then we don't bother with this check.
-  // For __builtin_c23_va_start, we only perform the check for the second
-  // argument being the last argument to the current function if there is a
-  // second argument present.
-  if (BuiltinID == Builtin::BI__builtin_c23_va_start &&
-      TheCall->getNumArgs() < 2) {
-    Diag(TheCall->getExprLoc(), diag::warn_c17_compat_va_start_one_arg);
-    return false;
-  }
-
-  const Expr *Arg = TheCall->getArg(1)->IgnoreParenCasts();
-  if (std::optional<llvm::APSInt> Val =
-          TheCall->getArg(1)->getIntegerConstantExpr(Context);
-      Val && LangOpts.C23 && *Val == 0 &&
-      BuiltinID != Builtin::BI__builtin_c23_va_start) {
-    Diag(TheCall->getExprLoc(), diag::warn_c17_compat_va_start_one_arg);
-    return false;
-  }
-
-  // These are valid if SecondArgIsLastNonVariadicArgument is false after the
-  // next block.
-  QualType Type;
-  SourceLocation ParamLoc;
-  bool IsCRegister = false;
-  bool SecondArgIsLastNonVariadicArgument = false;
-  if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Arg)) {
-    if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(DR->getDecl())) {
-      SecondArgIsLastNonVariadicArgument = PV == LastParam;
-
-      Type = PV->getType();
-      ParamLoc = PV->getLocation();
-      IsCRegister =
-          PV->getStorageClass() == SC_Register && !getLangOpts().CPlusPlus;
-    }
-  }
-
-  if (!SecondArgIsLastNonVariadicArgument)
-    Diag(TheCall->getArg(1)->getBeginLoc(),
-         diag::warn_second_arg_of_va_start_not_last_non_variadic_param);
-  else if (IsCRegister || Type->isReferenceType() ||
-           Type->isSpecificBuiltinType(BuiltinType::Float) || [=] {
-             // Promotable integers are UB, but enumerations need a bit of
-             // extra checking to see what their promotable type actually is.
-             if (!Context.isPromotableIntegerType(Type))
-               return false;
-             const auto *ED = Type->getAsEnumDecl();
-             if (!ED)
-               return true;
-             return !Context.typesAreCompatible(ED->getPromotionType(), Type);
-           }()) {
-    unsigned Reason = 0;
-    if (Type->isReferenceType())  Reason = 1;
-    else if (IsCRegister)         Reason = 2;
-    Diag(Arg->getBeginLoc(), diag::warn_va_start_type_is_undefined) << Reason;
-    Diag(ParamLoc, diag::note_parameter_type) << Type;
-  }
-
-  return false;
-}
-
-bool Sema::BuiltinVAStartARMMicrosoft(CallExpr *Call) {
-  auto IsSuitablyTypedFormatArgument = [this](const Expr *Arg) -> bool {
-    const LangOptions &LO = getLangOpts();
-
-    if (LO.CPlusPlus)
-      return Arg->getType()
-                 .getCanonicalType()
-                 .getTypePtr()
-                 ->getPointeeType()
-                 .withoutLocalFastQualifiers() == Context.CharTy;
-
-    // In C, allow aliasing through `char *`, this is required for AArch64 at
-    // least.
-    return true;
-  };
-
-  // void __va_start(va_list *ap, const char *named_addr, size_t slot_size,
-  //                 const char *named_addr);
-
-  Expr *Func = Call->getCallee();
-
-  if (Call->getNumArgs() < 3)
-    return Diag(Call->getEndLoc(),
-                diag::err_typecheck_call_too_few_args_at_least)
-           << 0 /*function call*/ << 3 << Call->getNumArgs()
-           << /*is non object*/ 0;
-
-  // Type-check the first argument normally.
-  if (checkBuiltinArgument(*this, Call, 0))
-    return true;
-
-  // Check that the current function is variadic.
-  if (checkVAStartIsInVariadicFunction(*this, Func))
-    return true;
-
-  // __va_start on Windows does not validate the parameter qualifiers
-
-  const Expr *Arg1 = Call->getArg(1)->IgnoreParens();
-  const Type *Arg1Ty = Arg1->getType().getCanonicalType().getTypePtr();
-
-  const Expr *Arg2 = Call->getArg(2)->IgnoreParens();
-  const Type *Arg2Ty = Arg2->getType().getCanonicalType().getTypePtr();
-
-  const QualType &ConstCharPtrTy =
-      Context.getPointerType(Context.CharTy.withConst());
-  if (!Arg1Ty->isPointerType() || !IsSuitablyTypedFormatArgument(Arg1))
-    Diag(Arg1->getBeginLoc(), diag::err_typecheck_convert_incompatible)
-        << Arg1->getType() << ConstCharPtrTy << 1 /* different class */
-        << 0                                      /* qualifier difference */
-        << 3                                      /* parameter mismatch */
-        << 2 << Arg1->getType() << ConstCharPtrTy;
-
-  const QualType SizeTy = Context.getSizeType();
-  if (!Context.hasSameType(
-          Arg2Ty->getCanonicalTypeInternal().withoutLocalFastQualifiers(),
-          SizeTy))
-    Diag(Arg2->getBeginLoc(), diag::err_typecheck_convert_incompatible)
-        << Arg2->getType() << SizeTy << 1 /* different class */
-        << 0                              /* qualifier difference */
-        << 3                              /* parameter mismatch */
-        << 3 << Arg2->getType() << SizeTy;
-
-  return false;
-}
-
-bool Sema::BuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID) {
-  if (checkArgCount(TheCall, 2))
-    return true;
-
-  if (BuiltinID == Builtin::BI__builtin_isunordered &&
-      TheCall->getFPFeaturesInEffect(getLangOpts()).getNoHonorNaNs())
-    Diag(TheCall->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled)
-        << 1 << 0 << TheCall->getSourceRange();
-
-  ExprResult OrigArg0 = TheCall->getArg(0);
-  ExprResult OrigArg1 = TheCall->getArg(1);
-
-  // Do standard promotions between the two arguments, returning their common
-  // type.
-  QualType Res = UsualArithmeticConversions(
-      OrigArg0, OrigArg1, TheCall->getExprLoc(), ArithConvKind::Comparison);
-  if (OrigArg0.isInvalid() || OrigArg1.isInvalid())
-    return true;
-
-  // Make sure any conversions are pushed back into the call; this is
-  // type safe since unordered compare builtins are declared as "_Bool
-  // foo(...)".
-  TheCall->setArg(0, OrigArg0.get());
-  TheCall->setArg(1, OrigArg1.get());
-
-  if (OrigArg0.get()->isTypeDependent() || OrigArg1.get()->isTypeDependent())
-    return false;
-
-  // If the common type isn't a real floating type, then the arguments were
-  // invalid for this operation.
-  if (Res.isNull() || !Res->isRealFloatingType())
-    return Diag(OrigArg0.get()->getBeginLoc(),
-                diag::err_typecheck_call_invalid_ordered_compare)
-           << OrigArg0.get()->getType() << OrigArg1.get()->getType()
-           << SourceRange(OrigArg0.get()->getBeginLoc(),
-                          OrigArg1.get()->getEndLoc());
-
-  return false;
-}
-
-bool Sema::BuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs,
-                                   unsigned BuiltinID) {
-  if (checkArgCount(TheCall, NumArgs))
-    return true;
-
-  FPOptions FPO = TheCall->getFPFeaturesInEffect(getLangOpts());
-  if (FPO.getNoHonorInfs() && (BuiltinID == Builtin::BI__builtin_isfinite ||
-                               BuiltinID == Builtin::BI__builtin_isinf ||
-                               BuiltinID == Builtin::BI__builtin_isinf_sign))
-    Diag(TheCall->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled)
-        << 0 << 0 << TheCall->getSourceRange();
-
-  if (FPO.getNoHonorNaNs() && (BuiltinID == Builtin::BI__builtin_isnan ||
-                               BuiltinID == Builtin::BI__builtin_isunordered))
-    Diag(TheCall->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled)
-        << 1 << 0 << TheCall->getSourceRange();
-
-  bool IsFPClass = NumArgs == 2;
-
-  // Find out position of floating-point argument.
-  unsigned FPArgNo = IsFPClass ? 0 : NumArgs - 1;
-
-  // We can count on all parameters preceding the floating-point just being int.
-  // Try all of those.
-  for (unsigned i = 0; i < FPArgNo; ++i) {
-    Expr *Arg = TheCall->getArg(i);
-
-    if (Arg->isTypeDependent())
-      return false;
-
-    ExprResult Res = PerformImplicitConversion(Arg, Context.IntTy,
-                                               AssignmentAction::Passing);
-
-    if (Res.isInvalid())
-      return true;
-    TheCall->setArg(i, Res.get());
-  }
-
-  Expr *OrigArg = TheCall->getArg(FPArgNo);
-
-  if (OrigArg->isTypeDependent())
-    return false;
-
-  // Usual Unary Conversions will convert half to float, which we want for
-  // machines that use fp16 conversion intrinsics. Else, we wnat to leave the
-  // type how it is, but do normal L->Rvalue conversions.
-  if (Context.getTargetInfo().useFP16ConversionIntrinsics()) {
-    ExprResult Res = UsualUnaryConversions(OrigArg);
-
-    if (!Res.isUsable())
-      return true;
-    OrigArg = Res.get();
-  } else {
-    ExprResult Res = DefaultFunctionArrayLvalueConversion(OrigArg);
-
-    if (!Res.isUsable())
-      return true;
-    OrigArg = Res.get();
-  }
-  TheCall->setArg(FPArgNo, OrigArg);
-
-  QualType VectorResultTy;
-  QualType ElementTy = OrigArg->getType();
-  // TODO: When all classification function are implemented with is_fpclass,
-  // vector argument can be supported in all of them.
-  if (ElementTy->isVectorType() && IsFPClass) {
-    VectorResultTy = GetSignedVectorType(ElementTy);
-    ElementTy = ElementTy->castAs<VectorType>()->getElementType();
-  }
-
-  // This operation requires a non-_Complex floating-point number.
-  if (!ElementTy->isRealFloatingType())
-    return Diag(OrigArg->getBeginLoc(),
-                diag::err_typecheck_call_invalid_unary_fp)
-           << OrigArg->getType() << OrigArg->getSourceRange();
-
-  // __builtin_isfpclass has integer parameter that specify test mask. It is
-  // passed in (...), so it should be analyzed completely here.
-  if (IsFPClass)
-    if (BuiltinConstantArgRange(TheCall, 1, 0, llvm::fcAllFlags))
-      return true;
-
-  // TODO: enable this code to all classification functions.
-  if (IsFPClass) {
-    QualType ResultTy;
-    if (!VectorResultTy.isNull())
-      ResultTy = VectorResultTy;
-    else
-      ResultTy = Context.IntTy;
-    TheCall->setType(ResultTy);
-  }
-
-  return false;
-}
-
-bool Sema::BuiltinComplex(CallExpr *TheCall) {
-  if (checkArgCount(TheCall, 2))
-    return true;
-
-  bool Dependent = false;
-  for (unsigned I = 0; I != 2; ++I) {
-    Expr *Arg = TheCall->getArg(I);
-    QualType T = Arg->getType();
-    if (T->isDependentType()) {
-      Dependent = true;
-      continue;
-    }
-
-    // Despite supporting _Complex int, GCC requires a real floating point type
-    // for the operands of __builtin_complex.
-    if (!T->isRealFloatingType()) {
-      return Diag(Arg->getBeginLoc(), diag::err_typecheck_call_requires_real_fp)
-             << Arg->getType() << Arg->getSourceRange();
-    }
-
-    ExprResult Converted = DefaultLvalueConversion(Arg);
-    if (Converted.isInvalid())
-      return true;
-    TheCall->setArg(I, Converted.get());
-  }
-
-  if (Dependent) {
-    TheCall->setType(Context.DependentTy);
-    return false;
-  }
-
-  Expr *Real = TheCall->getArg(0);
-  Expr *Imag = TheCall->getArg(1);
-  if (!Context.hasSameType(Real->getType(), Imag->getType())) {
-    return Diag(Real->getBeginLoc(),
-                diag::err_typecheck_call_different_arg_types)
-           << Real->getType() << Imag->getType()
-           << Real->getSourceRange() << Imag->getSourceRange();
-  }
-
-  TheCall->setType(Context.getComplexType(Real->getType()));
-  return false;
-}
-
-/// BuiltinShuffleVector - Handle __builtin_shufflevector.
-// This is declared to take (...), so we have to check everything.
-ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) {
-  unsigned NumArgs = TheCall->getNumArgs();
-  if (NumArgs < 2)
-    return ExprError(Diag(TheCall->getEndLoc(),
-                          diag::err_typecheck_call_too_few_args_at_least)
-                     << 0 /*function call*/ << 2 << NumArgs
-                     << /*is non object*/ 0 << TheCall->getSourceRange());
-
-  // Determine which of the following types of shufflevector we're checking:
-  // 1) unary, vector mask: (lhs, mask)
-  // 2) binary, scalar mask: (lhs, rhs, index, ..., index)
-  QualType ResType = TheCall->getArg(0)->getType();
-  unsigned NumElements = 0;
-
-  if (!TheCall->getArg(0)->isTypeDependent() &&
-      !TheCall->getArg(1)->isTypeDependent()) {
-    QualType LHSType = TheCall->getArg(0)->getType();
-    QualType RHSType = TheCall->getArg(1)->getType();
-
-    if (!LHSType->isVectorType() || !RHSType->isVectorType())
-      return ExprError(
-          Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_non_vector)
-          << TheCall->getDirectCallee() << /*isMoreThanTwoArgs*/ false
-          << SourceRange(TheCall->getArg(0)->getBeginLoc(),
-                         TheCall->getArg(1)->getEndLoc()));
-
-    NumElements = LHSType->castAs<VectorType>()->getNumElements();
-    unsigned NumResElements = NumArgs - 2;
-
-    // Check to see if we have a call with 2 vector arguments, the unary shuffle
-    // with mask.  If so, verify that RHS is an integer vector type with the
-    // same number of elts as lhs.
-    if (NumArgs == 2) {
-      if (!RHSType->hasIntegerRepresentation() ||
-          RHSType->castAs<VectorType>()->getNumElements() != NumElements)
-        return ExprError(Diag(TheCall->getBeginLoc(),
-                              diag::err_vec_builtin_incompatible_vector)
-                         << TheCall->getDirectCallee()
-                         << /*isMoreThanTwoArgs*/ false
-                         << SourceRange(TheCall->getArg(1)->getBeginLoc(),
-                                        TheCall->getArg(1)->getEndLoc()));
-    } else if (!Context.hasSameUnqualifiedType(LHSType, RHSType)) {
-      return ExprError(Diag(TheCall->getBeginLoc(),
-                            diag::err_vec_builtin_incompatible_vector)
-                       << TheCall->getDirectCallee()
-                       << /*isMoreThanTwoArgs*/ false
-                       << SourceRange(TheCall->getArg(0)->getBeginLoc(),
-                                      TheCall->getArg(1)->getEndLoc()));
-    } else if (NumElements != NumResElements) {
-      QualType EltType = LHSType->castAs<VectorType>()->getElementType();
-      ResType = ResType->isExtVectorType()
-                    ? Context.getExtVectorType(EltType, NumResElements)
-                    : Context.getVectorType(EltType, NumResElements,
-                                            VectorKind::Generic);
-    }
-  }
-
-  for (unsigned I = 2; I != NumArgs; ++I) {
-    Expr *Arg = TheCall->getArg(I);
-    if (Arg->isTypeDependent() || Arg->isValueDependent())
-      continue;
-
-    std::optional<llvm::APSInt> Result = Arg->getIntegerConstantExpr(Context);
-    if (!Result)
-      return ExprError(Diag(TheCall->getBeginLoc(),
-                            diag::err_shufflevector_nonconstant_argument)
-                       << Arg->getSourceRange());
-
-    // Allow -1 which will be translated to undef in the IR.
-    if (Result->isSigned() && Result->isAllOnes())
-      ;
-    else if (Result->getActiveBits() > 64 ||
-             Result->getZExtValue() >= NumElements * 2)
-      return ExprError(Diag(TheCall->getBeginLoc(),
-                            diag::err_shufflevector_argument_too_large)
-                       << Arg->getSourceRange());
-
-    TheCall->setArg(I, ConstantExpr::Create(Context, Arg, APValue(*Result)));
-  }
-
-  auto *Result = new (Context) ShuffleVectorExpr(
-      Context, ArrayRef(TheCall->getArgs(), NumArgs), ResType,
-      TheCall->getCallee()->getBeginLoc(), TheCall->getRParenLoc());
-
-  // All moved to Result.
-  TheCall->shrinkNumArgs(0);
-  return Result;
-}
-
-ExprResult Sema::ConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo,
-                                   SourceLocation BuiltinLoc,
-                                   SourceLocation RParenLoc) {
-  ExprValueKind VK = VK_PRValue;
-  ExprObjectKind OK = OK_Ordinary;
-  QualType DstTy = TInfo->getType();
-  QualType SrcTy = E->getType();
-
-  if (!SrcTy->isVectorType() && !SrcTy->isDependentType())
-    return ExprError(Diag(BuiltinLoc,
-                          diag::err_convertvector_non_vector)
-                     << E->getSourceRange());
-  if (!DstTy->isVectorType() && !DstTy->isDependentType())
-    return ExprError(Diag(BuiltinLoc, diag::err_builtin_non_vector_type)
-                     << "second"
-                     << "__builtin_convertvector");
-
-  if (!SrcTy->isDependentType() && !DstTy->isDependentType()) {
-    unsigned SrcElts = SrcTy->castAs<VectorType>()->getNumElements();
-    unsigned DstElts = DstTy->castAs<VectorType>()->getNumElements();
-    if (SrcElts != DstElts)
-      return ExprError(Diag(BuiltinLoc,
-                            diag::err_convertvector_incompatible_vector)
-                       << E->getSourceRange());
-  }
-
-  return ConvertVectorExpr::Create(Context, E, TInfo, DstTy, VK, OK, BuiltinLoc,
-                                   RParenLoc, CurFPFeatureOverrides());
-}
-
-bool Sema::BuiltinPrefetch(CallExpr *TheCall) {
-  unsigned NumArgs = TheCall->getNumArgs();
-
-  if (NumArgs > 3)
-    return Diag(TheCall->getEndLoc(),
-                diag::err_typecheck_call_too_many_args_at_most)
-           << 0 /*function call*/ << 3 << NumArgs << /*is non object*/ 0
-           << TheCall->getSourceRange();
-
-  // Argument 0 is checked for us and the remaining arguments must be
-  // constant integers.
-  for (unsigned i = 1; i != NumArgs; ++i)
-    if (BuiltinConstantArgRange(TheCall, i, 0, i == 1 ? 1 : 3))
-      return true;
-
-  return false;
-}
-
-bool Sema::BuiltinArithmeticFence(CallExpr *TheCall) {
-  if (!Context.getTargetInfo().checkArithmeticFenceSupported())
-    return Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
-           << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
-  if (checkArgCount(TheCall, 1))
-    return true;
-  Expr *Arg = TheCall->getArg(0);
-  if (Arg->isInstantiationDependent())
-    return false;
-
-  QualType ArgTy = Arg->getType();
-  if (!ArgTy->hasFloatingRepresentation())
-    return Diag(TheCall->getEndLoc(), diag::err_typecheck_expect_flt_or_vector)
-           << ArgTy;
-  if (Arg->isLValue()) {
-    ExprResult FirstArg = DefaultLvalueConversion(Arg);
-    TheCall->setArg(0, FirstArg.get());
-  }
-  TheCall->setType(TheCall->getArg(0)->getType());
-  return false;
-}
-
-bool Sema::BuiltinAssume(CallExpr *TheCall) {
-  Expr *Arg = TheCall->getArg(0);
-  if (Arg->isInstantiationDependent()) return false;
-
-  if (Arg->HasSideEffects(Context))
-    Diag(Arg->getBeginLoc(), diag::warn_assume_side_effects)
-        << Arg->getSourceRange()
-        << cast<FunctionDecl>(TheCall->getCalleeDecl())->getIdentifier();
-
-  return false;
-}
-
-bool Sema::BuiltinAllocaWithAlign(CallExpr *TheCall) {
-  // The alignment must be a constant integer.
-  Expr *Arg = TheCall->getArg(1);
-
-  // We can't check the value of a dependent argument.
-  if (!Arg->isTypeDependent() && !Arg->isValueDependent()) {
-    if (const auto *UE =
-            dyn_cast<UnaryExprOrTypeTraitExpr>(Arg->IgnoreParenImpCasts()))
-      if (UE->getKind() == UETT_AlignOf ||
-          UE->getKind() == UETT_PreferredAlignOf)
-        Diag(TheCall->getBeginLoc(), diag::warn_alloca_align_alignof)
-            << Arg->getSourceRange();
-
-    llvm::APSInt Result = Arg->EvaluateKnownConstInt(Context);
-
-    if (!Result.isPowerOf2())
-      return Diag(TheCall->getBeginLoc(), diag::err_alignment_not_power_of_two)
-             << Arg->getSourceRange();
-
-    if (Result < Context.getCharWidth())
-      return Diag(TheCall->getBeginLoc(), diag::err_alignment_too_small)
-             << (unsigned)Context.getCharWidth() << Arg->getSourceRange();
-
-    if (Result > std::numeric_limits<int32_t>::max())
-      return Diag(TheCall->getBeginLoc(), diag::err_alignment_too_big)
-             << std::numeric_limits<int32_t>::max() << Arg->getSourceRange();
-  }
-
-  return false;
-}
-
-bool Sema::BuiltinAssumeAligned(CallExpr *TheCall) {
-  if (checkArgCountRange(TheCall, 2, 3))
-    return true;
-
-  unsigned NumArgs = TheCall->getNumArgs();
-  Expr *FirstArg = TheCall->getArg(0);
-
-  {
-    ExprResult FirstArgResult =
-        DefaultFunctionArrayLvalueConversion(FirstArg);
-    if (!FirstArgResult.get()->getType()->isPointerType()) {
-      Diag(TheCall->getBeginLoc(), diag::err_builtin_assume_aligned_invalid_arg)
-          << TheCall->getSourceRange();
-      return true;
-    }
-    TheCall->setArg(0, FirstArgResult.get());
-  }
-
-  // The alignment must be a constant integer.
-  Expr *SecondArg = TheCall->getArg(1);
-
-  // We can't check the value of a dependent argument.
-  if (!SecondArg->isValueDependent()) {
-    llvm::APSInt Result;
-    if (BuiltinConstantArg(TheCall, 1, Result))
-      return true;
-
-    if (!Result.isPowerOf2())
-      return Diag(TheCall->getBeginLoc(), diag::err_alignment_not_power_of_two)
-             << SecondArg->getSourceRange();
-
-    if (Result > Sema::MaximumAlignment)
-      Diag(TheCall->getBeginLoc(), diag::warn_assume_aligned_too_great)
-          << SecondArg->getSourceRange() << Sema::MaximumAlignment;
-
-    TheCall->setArg(1,
-                    ConstantExpr::Create(Context, SecondArg, APValue(Result)));
-  }
-
-  if (NumArgs > 2) {
-    Expr *ThirdArg = TheCall->getArg(2);
-    if (convertArgumentToType(*this, ThirdArg, Context.getSizeType()))
-      return true;
-    TheCall->setArg(2, ThirdArg);
-  }
-
-  return false;
-}
-
-bool Sema::BuiltinOSLogFormat(CallExpr *TheCall) {
-  unsigned BuiltinID =
-      cast<FunctionDecl>(TheCall->getCalleeDecl())->getBuiltinID();
-  bool IsSizeCall = BuiltinID == Builtin::BI__builtin_os_log_format_buffer_size;
-
-  unsigned NumArgs = TheCall->getNumArgs();
-  unsigned NumRequiredArgs = IsSizeCall ? 1 : 2;
-  if (NumArgs < NumRequiredArgs) {
-    return Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args)
-           << 0 /* function call */ << NumRequiredArgs << NumArgs
-           << /*is non object*/ 0 << TheCall->getSourceRange();
-  }
-  if (NumArgs >= NumRequiredArgs + 0x100) {
-    return Diag(TheCall->getEndLoc(),
-                diag::err_typecheck_call_too_many_args_at_most)
-           << 0 /* function call */ << (NumRequiredArgs + 0xff) << NumArgs
-           << /*is non object*/ 0 << TheCall->getSourceRange();
-  }
-  unsigned i = 0;
-
-  // For formatting call, check buffer arg.
-  if (!IsSizeCall) {
-    ExprResult Arg(TheCall->getArg(i));
-    InitializedEntity Entity = InitializedEntity::InitializeParameter(
-        Context, Context.VoidPtrTy, false);
-    Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg);
-    if (Arg.isInvalid())
-      return true;
-    TheCall->setArg(i, Arg.get());
-    i++;
-  }
-
-  // Check string literal arg.
-  unsigned FormatIdx = i;
-  {
-    ExprResult Arg = CheckOSLogFormatStringArg(TheCall->getArg(i));
-    if (Arg.isInvalid())
-      return true;
-    TheCall->setArg(i, Arg.get());
-    i++;
-  }
-
-  // Make sure variadic args are scalar.
-  unsigned FirstDataArg = i;
-  while (i < NumArgs) {
-    ExprResult Arg = DefaultVariadicArgumentPromotion(
-        TheCall->getArg(i), VariadicCallType::Function, nullptr);
-    if (Arg.isInvalid())
-      return true;
-    CharUnits ArgSize = Context.getTypeSizeInChars(Arg.get()->getType());
-    if (ArgSize.getQuantity() >= 0x100) {
-      return Diag(Arg.get()->getEndLoc(), diag::err_os_log_argument_too_big)
-             << i << (int)ArgSize.getQuantity() << 0xff
-             << TheCall->getSourceRange();
-    }
-    TheCall->setArg(i, Arg.get());
-    i++;
-  }
-
-  // Check formatting specifiers. NOTE: We're only doing this for the non-size
-  // call to avoid duplicate diagnostics.
-  if (!IsSizeCall) {
-    llvm::SmallBitVector CheckedVarArgs(NumArgs, false);
-    ArrayRef<const Expr *> Args(TheCall->getArgs(), TheCall->getNumArgs());
-    bool Success = CheckFormatArguments(
-        Args, FAPK_Variadic, nullptr, FormatIdx, FirstDataArg,
-        FormatStringType::OSLog, VariadicCallType::Function,
-        TheCall->getBeginLoc(), SourceRange(), CheckedVarArgs);
-    if (!Success)
-      return true;
-  }
-
-  if (IsSizeCall) {
-    TheCall->setType(Context.getSizeType());
-  } else {
-    TheCall->setType(Context.VoidPtrTy);
-  }
-  return false;
-}
-
-bool Sema::BuiltinConstantArg(CallExpr *TheCall, unsigned ArgNum,
-                              llvm::APSInt &Result) {
-  Expr *Arg = TheCall->getArg(ArgNum);
-
-  if (Arg->isTypeDependent() || Arg->isValueDependent())
-    return false;
-
-  std::optional<llvm::APSInt> R = Arg->getIntegerConstantExpr(Context);
-  if (!R) {
-    auto *DRE = cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
-    auto *FDecl = cast<FunctionDecl>(DRE->getDecl());
-    return Diag(TheCall->getBeginLoc(), diag::err_constant_integer_arg_type)
-           << FDecl->getDeclName() << Arg->getSourceRange();
-  }
-  Result = *R;
-
-  return false;
-}
-
-bool Sema::BuiltinConstantArgRange(CallExpr *TheCall, unsigned ArgNum, int Low,
-                                   int High, bool RangeIsError) {
-  if (isConstantEvaluatedContext())
-    return false;
-  llvm::APSInt Result;
-
-  // We can't check the value of a dependent argument.
-  Expr *Arg = TheCall->getArg(ArgNum);
-  if (Arg->isTypeDependent() || Arg->isValueDependent())
-    return false;
-
-  // Check constant-ness first.
-  if (BuiltinConstantArg(TheCall, ArgNum, Result))
-    return true;
-
-  if (Result.getSExtValue() < Low || Result.getSExtValue() > High) {
-    if (RangeIsError)
-      return Diag(TheCall->getBeginLoc(), diag::err_argument_invalid_range)
-             << toString(Result, 10) << Low << High << Arg->getSourceRange();
-    else
-      // Defer the warning until we know if the code will be emitted so that
-      // dead code can ignore this.
-      DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall,
-                          PDiag(diag::warn_argument_invalid_range)
-                              << toString(Result, 10) << Low << High
-                              << Arg->getSourceRange());
-  }
-
-  return false;
-}
-
-bool Sema::BuiltinConstantArgMultiple(CallExpr *TheCall, unsigned ArgNum,
-                                      unsigned Num) {
-  llvm::APSInt Result;
-
-  // We can't check the value of a dependent argument.
-  Expr *Arg = TheCall->getArg(ArgNum);
-  if (Arg->isTypeDependent() || Arg->isValueDependent())
-    return false;
-
-  // Check constant-ness first.
-  if (BuiltinConstantArg(TheCall, ArgNum, Result))
-    return true;
-
-  if (Result.getSExtValue() % Num != 0)
-    return Diag(TheCall->getBeginLoc(), diag::err_argument_not_multiple)
-           << Num << Arg->getSourceRange();
-
-  return false;
-}
-
-bool Sema::BuiltinConstantArgPower2(CallExpr *TheCall, unsigned ArgNum) {
-  llvm::APSInt Result;
-
-  // We can't check the value of a dependent argument.
-  Expr *Arg = TheCall->getArg(ArgNum);
-  if (Arg->isTypeDependent() || Arg->isValueDependent())
-    return false;
-
-  // Check constant-ness first.
-  if (BuiltinConstantArg(TheCall, ArgNum, Result))
-    return true;
-
-  if (Result.isPowerOf2())
-    return false;
-
-  return Diag(TheCall->getBeginLoc(), diag::err_argument_not_power_of_2)
-         << Arg->getSourceRange();
-}
-
-static bool IsShiftedByte(llvm::APSInt Value) {
-  if (Value.isNegative())
-    return false;
-
-  // Check if it's a shifted byte, by shifting it down
-  while (true) {
-    // If the value fits in the bottom byte, the check passes.
-    if (Value < 0x100)
-      return true;
-
-    // Otherwise, if the value has _any_ bits in the bottom byte, the check
-    // fails.
-    if ((Value & 0xFF) != 0)
-      return false;
-
-    // If the bottom 8 bits are all 0, but something above that is nonzero,
-    // then shifting the value right by 8 bits won't affect whether it's a
-    // shifted byte or not. So do that, and go round again.
-    Value >>= 8;
-  }
-}
-
-bool Sema::BuiltinConstantArgShiftedByte(CallExpr *TheCall, unsigned ArgNum,
-                                         unsigned ArgBits) {
-  llvm::APSInt Result;
-
-  // We can't check the value of a dependent argument.
-  Expr *Arg = TheCall->getArg(ArgNum);
-  if (Arg->isTypeDependent() || Arg->isValueDependent())
-    return false;
-
-  // Check constant-ness first.
-  if (BuiltinConstantArg(TheCall, ArgNum, Result))
-    return true;
-
-  // Truncate to the given size.
-  Result = Result.getLoBits(ArgBits);
-  Result.setIsUnsigned(true);
-
-  if (IsShiftedByte(Result))
-    return false;
-
-  return Diag(TheCall->getBeginLoc(), diag::err_argument_not_shifted_byte)
-         << Arg->getSourceRange();
-}
-
-bool Sema::BuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall,
-                                               unsigned ArgNum,
-                                               unsigned ArgBits) {
-  llvm::APSInt Result;
-
-  // We can't check the value of a dependent argument.
-  Expr *Arg = TheCall->getArg(ArgNum);
-  if (Arg->isTypeDependent() || Arg->isValueDependent())
-    return false;
-
-  // Check constant-ness first.
-  if (BuiltinConstantArg(TheCall, ArgNum, Result))
-    return true;
-
-  // Truncate to the given size.
-  Result = Result.getLoBits(ArgBits);
-  Result.setIsUnsigned(true);
-
-  // Check to see if it's in either of the required forms.
-  if (IsShiftedByte(Result) ||
-      (Result > 0 && Result < 0x10000 && (Result & 0xFF) == 0xFF))
-    return false;
-
-  return Diag(TheCall->getBeginLoc(),
-              diag::err_argument_not_shifted_byte_or_xxff)
-         << Arg->getSourceRange();
-}
-
-bool Sema::BuiltinLongjmp(CallExpr *TheCall) {
-  if (!Context.getTargetInfo().hasSjLjLowering())
-    return Diag(TheCall->getBeginLoc(), diag::err_builtin_longjmp_unsupported)
-           << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
-
-  Expr *Arg = TheCall->getArg(1);
-  llvm::APSInt Result;
-
-  // TODO: This is less than ideal. Overload this to take a value.
-  if (BuiltinConstantArg(TheCall, 1, Result))
-    return true;
-
-  if (Result != 1)
-    return Diag(TheCall->getBeginLoc(), diag::err_builtin_longjmp_invalid_val)
-           << SourceRange(Arg->getBeginLoc(), Arg->getEndLoc());
-
-  return false;
-}
-
-bool Sema::BuiltinSetjmp(CallExpr *TheCall) {
-  if (!Context.getTargetInfo().hasSjLjLowering())
-    return Diag(TheCall->getBeginLoc(), diag::err_builtin_setjmp_unsupported)
-           << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
-  return false;
-}
-
-bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
-  if (checkArgCount(TheCall, 1))
-    return true;
-
-  ExprResult ArgRes = UsualUnaryConversions(TheCall->getArg(0));
-  if (ArgRes.isInvalid())
-    return true;
-
-  // For simplicity, we support only limited expressions for the argument.
-  // Specifically a flexible array member or a pointer with counted_by:
-  // 'ptr->array' or 'ptr->pointer'. This allows us to reject arguments with
-  // complex casting, which really shouldn't be a huge problem.
-  const Expr *Arg = ArgRes.get()->IgnoreParenImpCasts();
-  if (!Arg->getType()->isPointerType() && !Arg->getType()->isArrayType())
-    return Diag(Arg->getBeginLoc(),
-                diag::err_builtin_counted_by_ref_invalid_arg)
-           << Arg->getSourceRange();
-
-  if (Arg->HasSideEffects(Context))
-    return Diag(Arg->getBeginLoc(),
-                diag::err_builtin_counted_by_ref_has_side_effects)
-           << Arg->getSourceRange();
-
-  if (const auto *ME = dyn_cast<MemberExpr>(Arg)) {
-    const auto *CATy =
-        ME->getMemberDecl()->getType()->getAs<CountAttributedType>();
-
-    if (CATy && CATy->getKind() == CountAttributedType::CountedBy) {
-      // Member has counted_by attribute - return pointer to count field
-      const auto *MemberDecl = cast<FieldDecl>(ME->getMemberDecl());
-      if (const FieldDecl *CountFD = MemberDecl->findCountedByField()) {
-        TheCall->setType(Context.getPointerType(CountFD->getType()));
-        return false;
-      }
-    }
-
-    // FAMs and pointers without counted_by return void*
-    QualType MemberTy = ME->getMemberDecl()->getType();
-    if (!MemberTy->isArrayType() && !MemberTy->isPointerType())
-      return Diag(Arg->getBeginLoc(),
-                  diag::err_builtin_counted_by_ref_invalid_arg)
-             << Arg->getSourceRange();
-  } else {
-    return Diag(Arg->getBeginLoc(),
-                diag::err_builtin_counted_by_ref_invalid_arg)
-           << Arg->getSourceRange();
-  }
-
-  TheCall->setType(Context.getPointerType(Context.VoidTy));
-  return false;
-}
-
-/// The result of __builtin_counted_by_ref cannot be assigned to a variable.
-/// It allows leaking and modification of bounds safety information.
-bool Sema::CheckInvalidBuiltinCountedByRef(const Expr *E,
-                                           BuiltinCountedByRefKind K) {
-  const CallExpr *CE =
-      E ? dyn_cast<CallExpr>(E->IgnoreParenImpCasts()) : nullptr;
-  if (!CE || CE->getBuiltinCallee() != Builtin::BI__builtin_counted_by_ref)
-    return false;
-
-  switch (K) {
-  case BuiltinCountedByRefKind::Assignment:
-  case BuiltinCountedByRefKind::Initializer:
-    Diag(E->getExprLoc(),
-         diag::err_builtin_counted_by_ref_cannot_leak_reference)
-        << 0 << E->getSourceRange();
-    break;
-  case BuiltinCountedByRefKind::FunctionArg:
-    Diag(E->getExprLoc(),
-         diag::err_builtin_counted_by_ref_cannot_leak_reference)
-        << 1 << E->getSourceRange();
-    break;
-  case BuiltinCountedByRefKind::ReturnArg:
-    Diag(E->getExprLoc(),
-         diag::err_builtin_counted_by_ref_cannot_leak_reference)
-        << 2 << E->getSourceRange();
-    break;
-  case BuiltinCountedByRefKind::ArraySubscript:
-    Diag(E->getExprLoc(), diag::err_builtin_counted_by_ref_invalid_use)
-        << 0 << E->getSourceRange();
-    break;
-  case BuiltinCountedByRefKind::BinaryExpr:
-    Diag(E->getExprLoc(), diag::err_builtin_counted_by_ref_invalid_use)
-        << 1 << E->getSourceRange();
-    break;
-  }
-
-  return true;
-}
-
-namespace {
-
-class UncoveredArgHandler {
-  enum { Unknown = -1, AllCovered = -2 };
-
-  signed FirstUncoveredArg = Unknown;
-  SmallVector<const Expr *, 4> DiagnosticExprs;
-
-public:
-  UncoveredArgHandler() = default;
-
-  bool hasUncoveredArg() const {
-    return (FirstUncoveredArg >= 0);
-  }
-
-  unsigned getUncoveredArg() const {
-    assert(hasUncoveredArg() && "no uncovered argument");
-    return FirstUncoveredArg;
-  }
-
-  void setAllCovered() {
-    // A string has been found with all arguments covered, so clear out
-    // the diagnostics.
-    DiagnosticExprs.clear();
-    FirstUncoveredArg = AllCovered;
-  }
-
-  void Update(signed NewFirstUncoveredArg, const Expr *StrExpr) {
-    assert(NewFirstUncoveredArg >= 0 && "Outside range");
-
-    // Don't update if a previous string covers all arguments.
-    if (FirstUncoveredArg == AllCovered)
-      return;
-
-    // UncoveredArgHandler tracks the highest uncovered argument index
-    // and with it all the strings that match this index.
-    if (NewFirstUncoveredArg == FirstUncoveredArg)
-      DiagnosticExprs.push_back(StrExpr);
-    else if (NewFirstUncoveredArg > FirstUncoveredArg) {
-      DiagnosticExprs.clear();
-      DiagnosticExprs.push_back(StrExpr);
-      FirstUncoveredArg = NewFirstUncoveredArg;
-    }
-  }
-
-  void Diagnose(Sema &S, bool IsFunctionCall, const Expr *ArgExpr);
-};
-
-enum StringLiteralCheckType {
-  SLCT_NotALiteral,
-  SLCT_UncheckedLiteral,
-  SLCT_CheckedLiteral
-};
-
-} // namespace
-
-static void sumOffsets(llvm::APSInt &Offset, llvm::APSInt Addend,
-                                     BinaryOperatorKind BinOpKind,
-                                     bool AddendIsRight) {
-  unsigned BitWidth = Offset.getBitWidth();
-  unsigned AddendBitWidth = Addend.getBitWidth();
-  // There might be negative interim results.
-  if (Addend.isUnsigned()) {
-    Addend = Addend.zext(++AddendBitWidth);
-    Addend.setIsSigned(true);
-  }
-  // Adjust the bit width of the APSInts.
-  if (AddendBitWidth > BitWidth) {
-    Offset = Offset.sext(AddendBitWidth);
-    BitWidth = AddendBitWidth;
-  } else if (BitWidth > AddendBitWidth) {
-    Addend = Addend.sext(BitWidth);
-  }
-
-  bool Ov = false;
-  llvm::APSInt ResOffset = Offset;
-  if (BinOpKind == BO_Add)
-    ResOffset = Offset.sadd_ov(Addend, Ov);
-  else {
-    assert(AddendIsRight && BinOpKind == BO_Sub &&
-           "operator must be add or sub with addend on the right");
-    ResOffset = Offset.ssub_ov(Addend, Ov);
-  }
-
-  // We add an offset to a pointer here so we should support an offset as big as
-  // possible.
-  if (Ov) {
-    assert(BitWidth <= std::numeric_limits<unsigned>::max() / 2 &&
-           "index (intermediate) result too big");
-    Offset = Offset.sext(2 * BitWidth);
-    sumOffsets(Offset, Addend, BinOpKind, AddendIsRight);
-    return;
-  }
-
-  Offset = ResOffset;
-}
-
-namespace {
-
-// This is a wrapper class around StringLiteral to support offsetted string
-// literals as format strings. It takes the offset into account when returning
-// the string and its length or the source locations to display notes correctly.
-class FormatStringLiteral {
-  const StringLiteral *FExpr;
-  int64_t Offset;
-
-public:
-  FormatStringLiteral(const StringLiteral *fexpr, int64_t Offset = 0)
-      : FExpr(fexpr), Offset(Offset) {}
-
-  const StringLiteral *getFormatString() const { return FExpr; }
-
-  StringRef getString() const { return FExpr->getString().drop_front(Offset); }
-
-  unsigned getByteLength() const {
-    return FExpr->getByteLength() - getCharByteWidth() * Offset;
-  }
-
-  unsigned getLength() const { return FExpr->getLength() - Offset; }
-  unsigned getCharByteWidth() const { return FExpr->getCharByteWidth(); }
-
-  StringLiteralKind getKind() const { return FExpr->getKind(); }
-
-  QualType getType() const { return FExpr->getType(); }
-
-  bool isAscii() const { return FExpr->isOrdinary(); }
-  bool isWide() const { return FExpr->isWide(); }
-  bool isUTF8() const { return FExpr->isUTF8(); }
-  bool isUTF16() const { return FExpr->isUTF16(); }
-  bool isUTF32() const { return FExpr->isUTF32(); }
-  bool isPascal() const { return FExpr->isPascal(); }
-
-  SourceLocation getLocationOfByte(
-      unsigned ByteNo, const SourceManager &SM, const LangOptions &Features,
-      const TargetInfo &Target, unsigned *StartToken = nullptr,
-      unsigned *StartTokenByteOffset = nullptr) const {
-    return FExpr->getLocationOfByte(ByteNo + Offset, SM, Features, Target,
-                                    StartToken, StartTokenByteOffset);
-  }
-
-  SourceLocation getBeginLoc() const LLVM_READONLY {
-    return FExpr->getBeginLoc().getLocWithOffset(Offset);
-  }
-
-  SourceLocation getEndLoc() const LLVM_READONLY { return FExpr->getEndLoc(); }
-};
-
-} // namespace
-
-static void CheckFormatString(
-    Sema &S, const FormatStringLiteral *FExpr,
-    const StringLiteral *ReferenceFormatString, const Expr *OrigFormatExpr,
-    ArrayRef<const Expr *> Args, Sema::FormatArgumentPassingKind APK,
-    unsigned format_idx, unsigned firstDataArg, FormatStringType Type,
-    bool inFunctionCall, VariadicCallType CallType,
-    llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg,
-    bool IgnoreStringsWithoutSpecifiers);
-
-static const Expr *maybeConstEvalStringLiteral(ASTContext &Context,
-                                               const Expr *E);
-
-// Determine if an expression is a string literal or constant string.
-// If this function returns false on the arguments to a function expecting a
-// format string, we will usually need to emit a warning.
-// True string literals are then checked by CheckFormatString.
-static StringLiteralCheckType
-checkFormatStringExpr(Sema &S, const StringLiteral *ReferenceFormatString,
-                      const Expr *E, ArrayRef<const Expr *> Args,
-                      Sema::FormatArgumentPassingKind APK, unsigned format_idx,
-                      unsigned firstDataArg, FormatStringType Type,
-                      VariadicCallType CallType, bool InFunctionCall,
-                      llvm::SmallBitVector &CheckedVarArgs,
-                      UncoveredArgHandler &UncoveredArg, llvm::APSInt Offset,
-                      std::optional<unsigned> *CallerFormatParamIdx = nullptr,
-                      bool IgnoreStringsWithoutSpecifiers = false) {
-  if (S.isConstantEvaluatedContext())
-    return SLCT_NotALiteral;
-tryAgain:
-  assert(Offset.isSigned() && "invalid offset");
-
-  if (E->isTypeDependent() || E->isValueDependent())
-    return SLCT_NotALiteral;
-
-  E = E->IgnoreParenCasts();
-
-  if (E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull))
-    // Technically -Wformat-nonliteral does not warn about this case.
-    // The behavior of printf and friends in this case is implementation
-    // dependent.  Ideally if the format string cannot be null then
-    // it should have a 'nonnull' attribute in the function prototype.
-    return SLCT_UncheckedLiteral;
-
-  switch (E->getStmtClass()) {
-  case Stmt::InitListExprClass:
-    // Handle expressions like {"foobar"}.
-    if (const clang::Expr *SLE = maybeConstEvalStringLiteral(S.Context, E)) {
-      return checkFormatStringExpr(S, ReferenceFormatString, SLE, Args, APK,
-                                   format_idx, firstDataArg, Type, CallType,
-                                   /*InFunctionCall*/ false, CheckedVarArgs,
-                                   UncoveredArg, Offset, CallerFormatParamIdx,
-                                   IgnoreStringsWithoutSpecifiers);
-    }
-    return SLCT_NotALiteral;
-  case Stmt::BinaryConditionalOperatorClass:
-  case Stmt::ConditionalOperatorClass: {
-    // The expression is a literal if both sub-expressions were, and it was
-    // completely checked only if both sub-expressions were checked.
-    const AbstractConditionalOperator *C =
-        cast<AbstractConditionalOperator>(E);
-
-    // Determine whether it is necessary to check both sub-expressions, for
-    // example, because the condition expression is a constant that can be
-    // evaluated at compile time.
-    bool CheckLeft = true, CheckRight = true;
-
-    bool Cond;
-    if (C->getCond()->EvaluateAsBooleanCondition(
-            Cond, S.getASTContext(), S.isConstantEvaluatedContext())) {
-      if (Cond)
-        CheckRight = false;
-      else
-        CheckLeft = false;
-    }
-
-    // We need to maintain the offsets for the right and the left hand side
-    // separately to check if every possible indexed expression is a valid
-    // string literal. They might have different offsets for different string
-    // literals in the end.
-    StringLiteralCheckType Left;
-    if (!CheckLeft)
-      Left = SLCT_UncheckedLiteral;
-    else {
-      Left = checkFormatStringExpr(S, ReferenceFormatString, C->getTrueExpr(),
-                                   Args, APK, format_idx, firstDataArg, Type,
-                                   CallType, InFunctionCall, CheckedVarArgs,
-                                   UncoveredArg, Offset, CallerFormatParamIdx,
-                                   IgnoreStringsWithoutSpecifiers);
-      if (Left == SLCT_NotALiteral || !CheckRight) {
-        return Left;
-      }
-    }
-
-    StringLiteralCheckType Right = checkFormatStringExpr(
-        S, ReferenceFormatString, C->getFalseExpr(), Args, APK, format_idx,
-        firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs,
-        UncoveredArg, Offset, CallerFormatParamIdx,
-        IgnoreStringsWithoutSpecifiers);
-
-    return (CheckLeft && Left < Right) ? Left : Right;
-  }
-
-  case Stmt::ImplicitCastExprClass:
-    E = cast<ImplicitCastExpr>(E)->getSubExpr();
-    goto tryAgain;
-
-  case Stmt::OpaqueValueExprClass:
-    if (const Expr *src = cast<OpaqueValueExpr>(E)->getSourceExpr()) {
-      E = src;
-      goto tryAgain;
-    }
-    return SLCT_NotALiteral;
-
-  case Stmt::PredefinedExprClass:
-    // While __func__, etc., are technically not string literals, they
-    // cannot contain format specifiers and thus are not a security
-    // liability.
-    return SLCT_UncheckedLiteral;
-
-  case Stmt::DeclRefExprClass: {
-    const DeclRefExpr *DR = cast<DeclRefExpr>(E);
-
-    // As an exception, do not flag errors for variables binding to
-    // const string literals.
-    if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
-      bool isConstant = false;
-      QualType T = DR->getType();
-
-      if (const ArrayType *AT = S.Context.getAsArrayType(T)) {
-        isConstant = AT->getElementType().isConstant(S.Context);
-      } else if (const PointerType *PT = T->getAs<PointerType>()) {
-        isConstant = T.isConstant(S.Context) &&
-                     PT->getPointeeType().isConstant(S.Context);
-      } else if (T->isObjCObjectPointerType()) {
-        // In ObjC, there is usually no "const ObjectPointer" type,
-        // so don't check if the pointee type is constant.
-        isConstant = T.isConstant(S.Context);
-      }
-
-      if (isConstant) {
-        if (const Expr *Init = VD->getAnyInitializer()) {
-          // Look through initializers like const char c[] = { "foo" }
-          if (const InitListExpr *InitList = dyn_cast<InitListExpr>(Init)) {
-            if (InitList->isStringLiteralInit())
-              Init = InitList->getInit(0)->IgnoreParenImpCasts();
-          }
-          return checkFormatStringExpr(
-              S, ReferenceFormatString, Init, Args, APK, format_idx,
-              firstDataArg, Type, CallType, /*InFunctionCall=*/false,
-              CheckedVarArgs, UncoveredArg, Offset, CallerFormatParamIdx);
-        }
-      }
-
-      // When the format argument is an argument of this function, and this
-      // function also has the format attribute, there are several interactions
-      // for which there shouldn't be a warning. For instance, when calling
-      // v*printf from a function that has the printf format attribute, we
-      // should not emit a warning about using `fmt`, even though it's not
-      // constant, because the arguments have already been checked for the
-      // caller of `logmessage`:
-      //
-      //  __attribute__((format(printf, 1, 2)))
-      //  void logmessage(char const *fmt, ...) {
-      //    va_list ap;
-      //    va_start(ap, fmt);
-      //    vprintf(fmt, ap);  /* do not emit a warning about "fmt" */
-      //    ...
-      // }
-      //
-      // Another interaction that we need to support is using a format string
-      // specified by the format_matches attribute:
-      //
-      //  __attribute__((format_matches(printf, 1, "%s %d")))
-      //  void logmessage(char const *fmt, const char *a, int b) {
-      //    printf(fmt, a, b); /* do not emit a warning about "fmt" */
-      //    printf(fmt, 123.4); /* emit warnings that "%s %d" is incompatible */
-      //    ...
-      // }
-      //
-      // Yet another interaction that we need to support is calling a variadic
-      // format function from a format function that has fixed arguments. For
-      // instance:
-      //
-      //  __attribute__((format(printf, 1, 2)))
-      //  void logstring(char const *fmt, char const *str) {
-      //    printf(fmt, str);  /* do not emit a warning about "fmt" */
-      //  }
-      //
-      // Same (and perhaps more relatably) for the variadic template case:
-      //
-      //  template<typename... Args>
-      //  __attribute__((format(printf, 1, 2)))
-      //  void log(const char *fmt, Args&&... args) {
-      //    printf(fmt, forward<Args>(args)...);
-      //           /* do not emit a warning about "fmt" */
-      //  }
-      //
-      // Due to implementation difficulty, we only check the format, not the
-      // format arguments, in all cases.
-      //
-      if (const auto *PV = dyn_cast<ParmVarDecl>(VD)) {
-        if (CallerFormatParamIdx)
-          *CallerFormatParamIdx = PV->getFunctionScopeIndex();
-        if (const auto *D = dyn_cast<Decl>(PV->getDeclContext())) {
-          for (const auto *PVFormatMatches :
-               D->specific_attrs<FormatMatchesAttr>()) {
-            Sema::FormatStringInfo CalleeFSI;
-            if (!Sema::getFormatStringInfo(D, PVFormatMatches->getFormatIdx(),
-                                           0, &CalleeFSI))
-              continue;
-            if (PV->getFunctionScopeIndex() == CalleeFSI.FormatIdx) {
-              // If using the wrong type of format string, emit a diagnostic
-              // here and stop checking to avoid irrelevant diagnostics.
-              if (Type != S.GetFormatStringType(PVFormatMatches)) {
-                S.Diag(Args[format_idx]->getBeginLoc(),
-                       diag::warn_format_string_type_incompatible)
-                    << PVFormatMatches->getType()->getName()
-                    << S.GetFormatStringTypeName(Type);
-                if (!InFunctionCall) {
-                  S.Diag(PVFormatMatches->getFormatString()->getBeginLoc(),
-                         diag::note_format_string_defined);
-                }
-                return SLCT_UncheckedLiteral;
-              }
-              return checkFormatStringExpr(
-                  S, ReferenceFormatString, PVFormatMatches->getFormatString(),
-                  Args, APK, format_idx, firstDataArg, Type, CallType,
-                  /*InFunctionCall*/ false, CheckedVarArgs, UncoveredArg,
-                  Offset, CallerFormatParamIdx, IgnoreStringsWithoutSpecifiers);
-            }
-          }
-
-          for (const auto *PVFormat : D->specific_attrs<FormatAttr>()) {
-            Sema::FormatStringInfo CallerFSI;
-            if (!Sema::getFormatStringInfo(D, PVFormat->getFormatIdx(),
-                                           PVFormat->getFirstArg(), &CallerFSI))
-              continue;
-            if (PV->getFunctionScopeIndex() == CallerFSI.FormatIdx) {
-              // We also check if the formats are compatible.
-              // We can't pass a 'scanf' string to a 'printf' function.
-              if (Type != S.GetFormatStringType(PVFormat)) {
-                S.Diag(Args[format_idx]->getBeginLoc(),
-                       diag::warn_format_string_type_incompatible)
-                    << PVFormat->getType()->getName()
-                    << S.GetFormatStringTypeName(Type);
-                if (!InFunctionCall) {
-                  S.Diag(E->getBeginLoc(), diag::note_format_string_defined);
-                }
-                return SLCT_UncheckedLiteral;
-              }
-              // Lastly, check that argument passing kinds transition in a
-              // way that makes sense:
-              // from a caller with FAPK_VAList, allow FAPK_VAList
-              // from a caller with FAPK_Fixed, allow FAPK_Fixed
-              // from a caller with FAPK_Fixed, allow FAPK_Variadic
-              // from a caller with FAPK_Variadic, allow FAPK_VAList
-              switch (combineFAPK(CallerFSI.ArgPassingKind, APK)) {
-              case combineFAPK(Sema::FAPK_VAList, Sema::FAPK_VAList):
-              case combineFAPK(Sema::FAPK_Fixed, Sema::FAPK_Fixed):
-              case combineFAPK(Sema::FAPK_Fixed, Sema::FAPK_Variadic):
-              case combineFAPK(Sema::FAPK_Variadic, Sema::FAPK_VAList):
-                return SLCT_UncheckedLiteral;
-              }
-            }
-          }
-        }
-      }
-    }
-
-    return SLCT_NotALiteral;
-  }
-
-  case Stmt::CallExprClass:
-  case Stmt::CXXMemberCallExprClass: {
-    const CallExpr *CE = cast<CallExpr>(E);
-    if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
-      bool IsFirst = true;
-      StringLiteralCheckType CommonResult;
-      for (const auto *FA : ND->specific_attrs<FormatArgAttr>()) {
-        const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex());
-        StringLiteralCheckType Result = checkFormatStringExpr(
-            S, ReferenceFormatString, Arg, Args, APK, format_idx, firstDataArg,
-            Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg,
-            Offset, CallerFormatParamIdx, IgnoreStringsWithoutSpecifiers);
-        if (IsFirst) {
-          CommonResult = Result;
-          IsFirst = false;
-        }
-      }
-      if (!IsFirst)
-        return CommonResult;
-
-      if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
-        unsigned BuiltinID = FD->getBuiltinID();
-        if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
-            BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {
-          const Expr *Arg = CE->getArg(0);
-          return checkFormatStringExpr(
-              S, ReferenceFormatString, Arg, Args, APK, format_idx,
-              firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs,
-              UncoveredArg, Offset, CallerFormatParamIdx,
-              IgnoreStringsWithoutSpecifiers);
-        }
-      }
-    }
-    if (const Expr *SLE = maybeConstEvalStringLiteral(S.Context, E))
-      return checkFormatStringExpr(S, ReferenceFormatString, SLE, Args, APK,
-                                   format_idx, firstDataArg, Type, CallType,
-                                   /*InFunctionCall*/ false, CheckedVarArgs,
-                                   UncoveredArg, Offset, CallerFormatParamIdx,
-                                   IgnoreStringsWithoutSpecifiers);
-    return SLCT_NotALiteral;
-  }
-  case Stmt::ObjCMessageExprClass: {
-    const auto *ME = cast<ObjCMessageExpr>(E);
-    if (const auto *MD = ME->getMethodDecl()) {
-      if (const auto *FA = MD->getAttr<FormatArgAttr>()) {
-        // As a special case heuristic, if we're using the method -[NSBundle
-        // localizedStringForKey:value:table:], ignore any key strings that lack
-        // format specifiers. The idea is that if the key doesn't have any
-        // format specifiers then its probably just a key to map to the
-        // localized strings. If it does have format specifiers though, then its
-        // likely that the text of the key is the format string in the
-        // programmer's language, and should be checked.
-        const ObjCInterfaceDecl *IFace;
-        if (MD->isInstanceMethod() && (IFace = MD->getClassInterface()) &&
-            IFace->getIdentifier()->isStr("NSBundle") &&
-            MD->getSelector().isKeywordSelector(
-                {"localizedStringForKey", "value", "table"})) {
-          IgnoreStringsWithoutSpecifiers = true;
-        }
-
-        const Expr *Arg = ME->getArg(FA->getFormatIdx().getASTIndex());
-        return checkFormatStringExpr(
-            S, ReferenceFormatString, Arg, Args, APK, format_idx, firstDataArg,
-            Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg,
-            Offset, CallerFormatParamIdx, IgnoreStringsWithoutSpecifiers);
-      }
-    }
-
-    return SLCT_NotALiteral;
-  }
-  case Stmt::ObjCStringLiteralClass:
-  case Stmt::StringLiteralClass: {
-    const StringLiteral *StrE = nullptr;
-
-    if (const ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(E))
-      StrE = ObjCFExpr->getString();
-    else
-      StrE = cast<StringLiteral>(E);
-
-    if (StrE) {
-      if (Offset.isNegative() || Offset > StrE->getLength()) {
-        // TODO: It would be better to have an explicit warning for out of
-        // bounds literals.
-        return SLCT_NotALiteral;
-      }
-      FormatStringLiteral FStr(StrE, Offset.sextOrTrunc(64).getSExtValue());
-      CheckFormatString(S, &FStr, ReferenceFormatString, E, Args, APK,
-                        format_idx, firstDataArg, Type, InFunctionCall,
-                        CallType, CheckedVarArgs, UncoveredArg,
-                        IgnoreStringsWithoutSpecifiers);
-      return SLCT_CheckedLiteral;
-    }
-
-    return SLCT_NotALiteral;
-  }
-  case Stmt::BinaryOperatorClass: {
-    const BinaryOperator *BinOp = cast<BinaryOperator>(E);
-
-    // A string literal + an int offset is still a string literal.
-    if (BinOp->isAdditiveOp()) {
-      Expr::EvalResult LResult, RResult;
-
-      bool LIsInt = BinOp->getLHS()->EvaluateAsInt(
-          LResult, S.Context, Expr::SE_NoSideEffects,
-          S.isConstantEvaluatedContext());
-      bool RIsInt = BinOp->getRHS()->EvaluateAsInt(
-          RResult, S.Context, Expr::SE_NoSideEffects,
-          S.isConstantEvaluatedContext());
-
-      if (LIsInt != RIsInt) {
-        BinaryOperatorKind BinOpKind = BinOp->getOpcode();
-
-        if (LIsInt) {
-          if (BinOpKind == BO_Add) {
-            sumOffsets(Offset, LResult.Val.getInt(), BinOpKind, RIsInt);
-            E = BinOp->getRHS();
-            goto tryAgain;
-          }
-        } else {
-          sumOffsets(Offset, RResult.Val.getInt(), BinOpKind, RIsInt);
-          E = BinOp->getLHS();
-          goto tryAgain;
-        }
-      }
-    }
-
-    return SLCT_NotALiteral;
-  }
-  case Stmt::UnaryOperatorClass: {
-    const UnaryOperator *UnaOp = cast<UnaryOperator>(E);
-    auto ASE = dyn_cast<ArraySubscriptExpr>(UnaOp->getSubExpr());
-    if (UnaOp->getOpcode() == UO_AddrOf && ASE) {
-      Expr::EvalResult IndexResult;
-      if (ASE->getRHS()->EvaluateAsInt(IndexResult, S.Context,
-                                       Expr::SE_NoSideEffects,
-                                       S.isConstantEvaluatedContext())) {
-        sumOffsets(Offset, IndexResult.Val.getInt(), BO_Add,
-                   /*RHS is int*/ true);
-        E = ASE->getBase();
-        goto tryAgain;
-      }
-    }
-
-    return SLCT_NotALiteral;
-  }
-
-  default:
-    return SLCT_NotALiteral;
-  }
-}
-
-// If this expression can be evaluated at compile-time,
-// check if the result is a StringLiteral and return it
-// otherwise return nullptr
-static const Expr *maybeConstEvalStringLiteral(ASTContext &Context,
-                                               const Expr *E) {
-  Expr::EvalResult Result;
-  if (E->EvaluateAsRValue(Result, Context) && Result.Val.isLValue()) {
-    const auto *LVE = Result.Val.getLValueBase().dyn_cast<const Expr *>();
-    if (isa_and_nonnull<StringLiteral>(LVE))
-      return LVE;
-  }
-  return nullptr;
-}
-
-StringRef Sema::GetFormatStringTypeName(FormatStringType FST) {
-  switch (FST) {
-  case FormatStringType::Scanf:
-    return "scanf";
-  case FormatStringType::Printf:
-    return "printf";
-  case FormatStringType::NSString:
-    return "NSString";
-  case FormatStringType::Strftime:
-    return "strftime";
-  case FormatStringType::Strfmon:
-    return "strfmon";
-  case FormatStringType::Kprintf:
-    return "kprintf";
-  case FormatStringType::FreeBSDKPrintf:
-    return "freebsd_kprintf";
-  case FormatStringType::OSLog:
-    return "os_log";
-  default:
-    return "<unknown>";
-  }
-}
-
-FormatStringType Sema::GetFormatStringType(StringRef Flavor) {
-  return llvm::StringSwitch<FormatStringType>(Flavor)
-      .Cases({"gnu_scanf", "scanf"}, FormatStringType::Scanf)
-      .Cases({"gnu_printf", "printf", "printf0", "syslog"},
-             FormatStringType::Printf)
-      .Cases({"NSString", "CFString"}, FormatStringType::NSString)
-      .Cases({"gnu_strftime", "strftime"}, FormatStringType::Strftime)
-      .Cases({"gnu_strfmon", "strfmon"}, FormatStringType::Strfmon)
-      .Cases({"kprintf", "cmn_err", "vcmn_err", "zcmn_err"},
-             FormatStringType::Kprintf)
-      .Case("freebsd_kprintf", FormatStringType::FreeBSDKPrintf)
-      .Case("os_trace", FormatStringType::OSLog)
-      .Case("os_log", FormatStringType::OSLog)
-      .Default(FormatStringType::Unknown);
-}
-
-FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
-  return GetFormatStringType(Format->getType()->getName());
-}
-
-FormatStringType Sema::GetFormatStringType(const FormatMatchesAttr *Format) {
-  return GetFormatStringType(Format->getType()->getName());
-}
-
-bool Sema::CheckFormatArguments(const FormatAttr *Format,
-                                ArrayRef<const Expr *> Args, bool IsCXXMember,
-                                VariadicCallType CallType, SourceLocation Loc,
-                                SourceRange Range,
-                                llvm::SmallBitVector &CheckedVarArgs) {
-  FormatStringInfo FSI;
-  if (getFormatStringInfo(Format->getFormatIdx(), Format->getFirstArg(),
-                          IsCXXMember,
-                          CallType != VariadicCallType::DoesNotApply, &FSI))
-    return CheckFormatArguments(
-        Args, FSI.ArgPassingKind, nullptr, FSI.FormatIdx, FSI.FirstDataArg,
-        GetFormatStringType(Format), CallType, Loc, Range, CheckedVarArgs);
-  return false;
-}
-
-bool Sema::CheckFormatString(const FormatMatchesAttr *Format,
-                             ArrayRef<const Expr *> Args, bool IsCXXMember,
-                             VariadicCallType CallType, SourceLocation Loc,
-                             SourceRange Range,
-                             llvm::SmallBitVector &CheckedVarArgs) {
-  FormatStringInfo FSI;
-  if (getFormatStringInfo(Format->getFormatIdx(), 0, IsCXXMember, false,
-                          &FSI)) {
-    FSI.ArgPassingKind = Sema::FAPK_Elsewhere;
-    return CheckFormatArguments(Args, FSI.ArgPassingKind,
-                                Format->getFormatString(), FSI.FormatIdx,
-                                FSI.FirstDataArg, GetFormatStringType(Format),
-                                CallType, Loc, Range, CheckedVarArgs);
-  }
-  return false;
-}
-
-static bool CheckMissingFormatAttribute(
-    Sema *S, ArrayRef<const Expr *> Args, Sema::FormatArgumentPassingKind APK,
-    StringLiteral *ReferenceFormatString, unsigned FormatIdx,
-    unsigned FirstDataArg, FormatStringType FormatType, unsigned CallerParamIdx,
-    SourceLocation Loc) {
-  if (S->getDiagnostics().isIgnored(diag::warn_missing_format_attribute, Loc))
-    return false;
-
-  DeclContext *DC = S->CurContext;
-  if (!isa<ObjCMethodDecl>(DC) && !isa<FunctionDecl>(DC) && !isa<BlockDecl>(DC))
-    return false;
-  Decl *Caller = cast<Decl>(DC)->getCanonicalDecl();
-
-  unsigned NumCallerParams = getFunctionOrMethodNumParams(Caller);
-
-  // Find the offset to convert between attribute and parameter indexes.
-  unsigned CallerArgumentIndexOffset =
-      hasImplicitObjectParameter(Caller) ? 2 : 1;
-
-  unsigned FirstArgumentIndex = -1;
-  switch (APK) {
-  case Sema::FormatArgumentPassingKind::FAPK_Fixed:
-  case Sema::FormatArgumentPassingKind::FAPK_Variadic: {
-    // As an extension, clang allows the format attribute on non-variadic
-    // functions.
-    // Caller must have fixed arguments to pass them to a fixed or variadic
-    // function. Try to match caller and callee arguments. If successful, then
-    // emit a diag with the caller idx, otherwise we can't determine the callee
-    // arguments.
-    unsigned NumCalleeArgs = Args.size() - FirstDataArg;
-    if (NumCalleeArgs == 0 || NumCallerParams < NumCalleeArgs) {
-      // There aren't enough arguments in the caller to pass to callee.
-      return false;
-    }
-    for (unsigned CalleeIdx = Args.size() - 1, CallerIdx = NumCallerParams - 1;
-         CalleeIdx >= FirstDataArg; --CalleeIdx, --CallerIdx) {
-      const auto *Arg =
-          dyn_cast<DeclRefExpr>(Args[CalleeIdx]->IgnoreParenCasts());
-      if (!Arg)
-        return false;
-      const auto *Param = dyn_cast<ParmVarDecl>(Arg->getDecl());
-      if (!Param || Param->getFunctionScopeIndex() != CallerIdx)
-        return false;
-    }
-    FirstArgumentIndex =
-        NumCallerParams + CallerArgumentIndexOffset - NumCalleeArgs;
-    break;
-  }
-  case Sema::FormatArgumentPassingKind::FAPK_VAList:
-    // Caller arguments are either variadic or a va_list.
-    FirstArgumentIndex = isFunctionOrMethodVariadic(Caller)
-                             ? (NumCallerParams + CallerArgumentIndexOffset)
-                             : 0;
-    break;
-  case Sema::FormatArgumentPassingKind::FAPK_Elsewhere:
-    // The callee has a format_matches attribute. We will emit that instead.
-    if (!ReferenceFormatString)
-      return false;
-    break;
-  }
-
-  // Emit the diagnostic and fixit.
-  unsigned FormatStringIndex = CallerParamIdx + CallerArgumentIndexOffset;
-  StringRef FormatTypeName = S->GetFormatStringTypeName(FormatType);
-  NamedDecl *ND = dyn_cast<NamedDecl>(Caller);
-  do {
-    std::string Attr, Fixit;
-    llvm::raw_string_ostream AttrOS(Attr);
-    if (APK != Sema::FormatArgumentPassingKind::FAPK_Elsewhere) {
-      AttrOS << "format(" << FormatTypeName << ", " << FormatStringIndex << ", "
-             << FirstArgumentIndex << ")";
-    } else {
-      AttrOS << "format_matches(" << FormatTypeName << ", " << FormatStringIndex
-             << ", \"";
-      AttrOS.write_escaped(ReferenceFormatString->getString());
-      AttrOS << "\")";
-    }
-    AttrOS.flush();
-    auto DB = S->Diag(Loc, diag::warn_missing_format_attribute) << Attr;
-    if (ND)
-      DB << ND;
-    else
-      DB << "block";
-
-    // Blocks don't provide a correct end loc, so skip emitting a fixit.
-    if (isa<BlockDecl>(Caller))
-      break;
-
-    SourceLocation SL;
-    llvm::raw_string_ostream IS(Fixit);
-    // The attribute goes at the start of the declaration in C/C++ functions
-    // and methods, but after the declaration for Objective-C methods.
-    if (isa<ObjCMethodDecl>(Caller)) {
-      IS << ' ';
-      SL = Caller->getEndLoc();
-    }
-    const LangOptions &LO = S->getLangOpts();
-    if (LO.C23 || LO.CPlusPlus11)
-      IS << "[[gnu::" << Attr << "]]";
-    else if (LO.ObjC || LO.GNUMode)
-      IS << "__attribute__((" << Attr << "))";
-    else
-      break;
-    if (!isa<ObjCMethodDecl>(Caller)) {
-      IS << ' ';
-      SL = Caller->getBeginLoc();
-    }
-    IS.flush();
-
-    DB << FixItHint::CreateInsertion(SL, Fixit);
-  } while (false);
-
-  // Add implicit format or format_matches attribute.
-  if (APK != Sema::FormatArgumentPassingKind::FAPK_Elsewhere) {
-    Caller->addAttr(FormatAttr::CreateImplicit(
-        S->getASTContext(), &S->getASTContext().Idents.get(FormatTypeName),
-        FormatStringIndex, FirstArgumentIndex));
-  } else {
-    Caller->addAttr(FormatMatchesAttr::CreateImplicit(
-        S->getASTContext(), &S->getASTContext().Idents.get(FormatTypeName),
-        FormatStringIndex, ReferenceFormatString));
-  }
-
-  {
-    auto DB = S->Diag(Caller->getLocation(), diag::note_entity_declared_at);
-    if (ND)
-      DB << ND;
-    else
-      DB << "block";
-  }
-  return true;
-}
-
-bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
-                                Sema::FormatArgumentPassingKind APK,
-                                StringLiteral *ReferenceFormatString,
-                                unsigned format_idx, unsigned firstDataArg,
-                                FormatStringType Type,
-                                VariadicCallType CallType, SourceLocation Loc,
-                                SourceRange Range,
-                                llvm::SmallBitVector &CheckedVarArgs) {
-  // CHECK: printf/scanf-like function is called with no format string.
-  if (format_idx >= Args.size()) {
-    Diag(Loc, diag::warn_missing_format_string) << Range;
-    return false;
-  }
-
-  const Expr *OrigFormatExpr = Args[format_idx]->IgnoreParenCasts();
-
-  // CHECK: format string is not a string literal.
-  //
-  // Dynamically generated format strings are difficult to
-  // automatically vet at compile time.  Requiring that format strings
-  // are string literals: (1) permits the checking of format strings by
-  // the compiler and thereby (2) can practically remove the source of
-  // many format string exploits.
-
-  // Format string can be either ObjC string (e.g. @"%d") or
-  // C string (e.g. "%d")
-  // ObjC string uses the same format specifiers as C string, so we can use
-  // the same format string checking logic for both ObjC and C strings.
-  UncoveredArgHandler UncoveredArg;
-  std::optional<unsigned> CallerParamIdx;
-  StringLiteralCheckType CT = checkFormatStringExpr(
-      *this, ReferenceFormatString, OrigFormatExpr, Args, APK, format_idx,
-      firstDataArg, Type, CallType,
-      /*IsFunctionCall*/ true, CheckedVarArgs, UncoveredArg,
-      /*no string offset*/ llvm::APSInt(64, false) = 0, &CallerParamIdx);
-
-  // Generate a diagnostic where an uncovered argument is detected.
-  if (UncoveredArg.hasUncoveredArg()) {
-    unsigned ArgIdx = UncoveredArg.getUncoveredArg() + firstDataArg;
-    assert(ArgIdx < Args.size() && "ArgIdx outside bounds");
-    UncoveredArg.Diagnose(*this, /*IsFunctionCall*/true, Args[ArgIdx]);
-  }
-
-  if (CT != SLCT_NotALiteral)
-    // Literal format string found, check done!
-    return CT == SLCT_CheckedLiteral;
-
-  // Do not emit diag when the string param is a macro expansion and the
-  // format is either NSString or CFString. This is a hack to prevent
-  // diag when using the NSLocalizedString and CFCopyLocalizedString macros
-  // which are usually used in place of NS and CF string literals.
-  SourceLocation FormatLoc = Args[format_idx]->getBeginLoc();
-  if (Type == FormatStringType::NSString &&
-      SourceMgr.isInSystemMacro(FormatLoc))
-    return false;
-
-  if (CallerParamIdx && CheckMissingFormatAttribute(
-                            this, Args, APK, ReferenceFormatString, format_idx,
-                            firstDataArg, Type, *CallerParamIdx, Loc))
-    return false;
-
-  // Strftime is particular as it always uses a single 'time' argument,
-  // so it is safe to pass a non-literal string.
-  if (Type == FormatStringType::Strftime)
-    return false;
-
-  // If there are no arguments specified, warn with -Wformat-security, otherwise
-  // warn only with -Wformat-nonliteral.
-  if (Args.size() == firstDataArg) {
-    Diag(FormatLoc, diag::warn_format_nonliteral_noargs)
-      << OrigFormatExpr->getSourceRange();
-    switch (Type) {
-    default:
-      break;
-    case FormatStringType::Kprintf:
-    case FormatStringType::FreeBSDKPrintf:
-    case FormatStringType::Printf:
-      Diag(FormatLoc, diag::note_format_security_fixit)
-        << FixItHint::CreateInsertion(FormatLoc, "\"%s\", ");
-      break;
-    case FormatStringType::NSString:
-      Diag(FormatLoc, diag::note_format_security_fixit)
-        << FixItHint::CreateInsertion(FormatLoc, "@\"%@\", ");
-      break;
-    }
-  } else {
-    Diag(FormatLoc, diag::warn_format_nonliteral)
-      << OrigFormatExpr->getSourceRange();
-  }
-  return false;
-}
-
-namespace {
-
-class CheckFormatHandler : public analyze_format_string::FormatStringHandler {
-protected:
-  Sema &S;
-  const FormatStringLiteral *FExpr;
-  const Expr *OrigFormatExpr;
-  const FormatStringType FSType;
-  const unsigned FirstDataArg;
-  const unsigned NumDataArgs;
-  const char *Beg; // Start of format string.
-  const Sema::FormatArgumentPassingKind ArgPassingKind;
-  ArrayRef<const Expr *> Args;
-  unsigned FormatIdx;
-  llvm::SmallBitVector CoveredArgs;
-  bool usesPositionalArgs = false;
-  bool atFirstArg = true;
-  bool inFunctionCall;
-  VariadicCallType CallType;
-  llvm::SmallBitVector &CheckedVarArgs;
-  UncoveredArgHandler &UncoveredArg;
-
-public:
-  CheckFormatHandler(Sema &s, const FormatStringLiteral *fexpr,
-                     const Expr *origFormatExpr, const FormatStringType type,
-                     unsigned firstDataArg, unsigned numDataArgs,
-                     const char *beg, Sema::FormatArgumentPassingKind APK,
-                     ArrayRef<const Expr *> Args, unsigned formatIdx,
-                     bool inFunctionCall, VariadicCallType callType,
-                     llvm::SmallBitVector &CheckedVarArgs,
-                     UncoveredArgHandler &UncoveredArg)
-      : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), FSType(type),
-        FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), Beg(beg),
-        ArgPassingKind(APK), Args(Args), FormatIdx(formatIdx),
-        inFunctionCall(inFunctionCall), CallType(callType),
-        CheckedVarArgs(CheckedVarArgs), UncoveredArg(UncoveredArg) {
-    CoveredArgs.resize(numDataArgs);
-    CoveredArgs.reset();
-  }
-
-  bool HasFormatArguments() const {
-    return ArgPassingKind == Sema::FAPK_Fixed ||
-           ArgPassingKind == Sema::FAPK_Variadic;
-  }
-
-  void DoneProcessing();
-
-  void HandleIncompleteSpecifier(const char *startSpecifier,
-                                 unsigned specifierLen) override;
-
-  void HandleInvalidLengthModifier(
-                           const analyze_format_string::FormatSpecifier &FS,
-                           const analyze_format_string::ConversionSpecifier &CS,
-                           const char *startSpecifier, unsigned specifierLen,
-                           unsigned DiagID);
-
-  void HandleNonStandardLengthModifier(
-                    const analyze_format_string::FormatSpecifier &FS,
-                    const char *startSpecifier, unsigned specifierLen);
-
-  void HandleNonStandardConversionSpecifier(
-                    const analyze_format_string::ConversionSpecifier &CS,
-                    const char *startSpecifier, unsigned specifierLen);
-
-  void HandlePosition(const char *startPos, unsigned posLen) override;
-
-  void HandleInvalidPosition(const char *startSpecifier,
-                             unsigned specifierLen,
-                             analyze_format_string::PositionContext p) override;
-
-  void HandleZeroPosition(const char *startPos, unsigned posLen) override;
-
-  void HandleNullChar(const char *nullCharacter) override;
-
-  template <typename Range>
-  static void
-  EmitFormatDiagnostic(Sema &S, bool inFunctionCall, const Expr *ArgumentExpr,
-                       const PartialDiagnostic &PDiag, SourceLocation StringLoc,
-                       bool IsStringLocation, Range StringRange,
-                       ArrayRef<FixItHint> Fixit = {});
-
-protected:
-  bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc,
-                                        const char *startSpec,
-                                        unsigned specifierLen,
-                                        const char *csStart, unsigned csLen);
-
-  void HandlePositionalNonpositionalArgs(SourceLocation Loc,
-                                         const char *startSpec,
-                                         unsigned specifierLen);
-
-  SourceRange getFormatStringRange();
-  CharSourceRange getSpecifierRange(const char *startSpecifier,
-                                    unsigned specifierLen);
-  SourceLocation getLocationOfByte(const char *x);
-
-  const Expr *getDataArg(unsigned i) const;
-
-  bool CheckNumArgs(const analyze_format_string::FormatSpecifier &FS,
-                    const analyze_format_string::ConversionSpecifier &CS,
-                    const char *startSpecifier, unsigned specifierLen,
-                    unsigned argIndex);
-
-  template <typename Range>
-  void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc,
-                            bool IsStringLocation, Range StringRange,
-                            ArrayRef<FixItHint> Fixit = {});
-};
-
-} // namespace
-
-SourceRange CheckFormatHandler::getFormatStringRange() {
-  return OrigFormatExpr->getSourceRange();
-}
-
-CharSourceRange CheckFormatHandler::
-getSpecifierRange(const char *startSpecifier, unsigned specifierLen) {
-  SourceLocation Start = getLocationOfByte(startSpecifier);
-  SourceLocation End   = getLocationOfByte(startSpecifier + specifierLen - 1);
-
-  // Advance the end SourceLocation by one due to half-open ranges.
-  End = End.getLocWithOffset(1);
-
-  return CharSourceRange::getCharRange(Start, End);
-}
-
-SourceLocation CheckFormatHandler::getLocationOfByte(const char *x) {
-  return FExpr->getLocationOfByte(x - Beg, S.getSourceManager(),
-                                  S.getLangOpts(), S.Context.getTargetInfo());
-}
-
-void CheckFormatHandler::HandleIncompleteSpecifier(const char *startSpecifier,
-                                                   unsigned specifierLen){
-  EmitFormatDiagnostic(S.PDiag(diag::warn_printf_incomplete_specifier),
-                       getLocationOfByte(startSpecifier),
-                       /*IsStringLocation*/true,
-                       getSpecifierRange(startSpecifier, specifierLen));
-}
-
-void CheckFormatHandler::HandleInvalidLengthModifier(
-    const analyze_format_string::FormatSpecifier &FS,
-    const analyze_format_string::ConversionSpecifier &CS,
-    const char *startSpecifier, unsigned specifierLen, unsigned DiagID) {
-  using namespace analyze_format_string;
-
-  const LengthModifier &LM = FS.getLengthModifier();
-  CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength());
-
-  // See if we know how to fix this length modifier.
-  std::optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
-  if (FixedLM) {
-    EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(),
-                         getLocationOfByte(LM.getStart()),
-                         /*IsStringLocation*/true,
-                         getSpecifierRange(startSpecifier, specifierLen));
-
-    S.Diag(getLocationOfByte(LM.getStart()), diag::note_format_fix_specifier)
-      << FixedLM->toString()
-      << FixItHint::CreateReplacement(LMRange, FixedLM->toString());
-
-  } else {
-    FixItHint Hint;
-    if (DiagID == diag::warn_format_nonsensical_length)
-      Hint = FixItHint::CreateRemoval(LMRange);
-
-    EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(),
-                         getLocationOfByte(LM.getStart()),
-                         /*IsStringLocation*/true,
-                         getSpecifierRange(startSpecifier, specifierLen),
-                         Hint);
-  }
-}
-
-void CheckFormatHandler::HandleNonStandardLengthModifier(
-    const analyze_format_string::FormatSpecifier &FS,
-    const char *startSpecifier, unsigned specifierLen) {
-  using namespace analyze_format_string;
-
-  const LengthModifier &LM = FS.getLengthModifier();
-  CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength());
-
-  // See if we know how to fix this length modifier.
-  std::optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
-  if (FixedLM) {
-    EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
-                           << LM.toString() << 0,
-                         getLocationOfByte(LM.getStart()),
-                         /*IsStringLocation*/true,
-                         getSpecifierRange(startSpecifier, specifierLen));
-
-    S.Diag(getLocationOfByte(LM.getStart()), diag::note_format_fix_specifier)
-      << FixedLM->toString()
-      << FixItHint::CreateReplacement(LMRange, FixedLM->toString());
-
-  } else {
-    EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
-                           << LM.toString() << 0,
-                         getLocationOfByte(LM.getStart()),
-                         /*IsStringLocation*/true,
-                         getSpecifierRange(startSpecifier, specifierLen));
-  }
-}
-
-void CheckFormatHandler::HandleNonStandardConversionSpecifier(
-    const analyze_format_string::ConversionSpecifier &CS,
-    const char *startSpecifier, unsigned specifierLen) {
-  using namespace analyze_format_string;
-
-  // See if we know how to fix this conversion specifier.
-  std::optional<ConversionSpecifier> FixedCS = CS.getStandardSpecifier();
-  if (FixedCS) {
-    EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
-                          << CS.toString() << /*conversion specifier*/1,
-                         getLocationOfByte(CS.getStart()),
-                         /*IsStringLocation*/true,
-                         getSpecifierRange(startSpecifier, specifierLen));
-
-    CharSourceRange CSRange = getSpecifierRange(CS.getStart(), CS.getLength());
-    S.Diag(getLocationOfByte(CS.getStart()), diag::note_format_fix_specifier)
-      << FixedCS->toString()
-      << FixItHint::CreateReplacement(CSRange, FixedCS->toString());
-  } else {
-    EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
-                          << CS.toString() << /*conversion specifier*/1,
-                         getLocationOfByte(CS.getStart()),
-                         /*IsStringLocation*/true,
-                         getSpecifierRange(startSpecifier, specifierLen));
-  }
-}
-
-void CheckFormatHandler::HandlePosition(const char *startPos,
-                                        unsigned posLen) {
-  if (!S.getDiagnostics().isIgnored(
-          diag::warn_format_non_standard_positional_arg, SourceLocation()))
-    EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard_positional_arg),
-                         getLocationOfByte(startPos),
-                         /*IsStringLocation*/ true,
-                         getSpecifierRange(startPos, posLen));
-}
-
-void CheckFormatHandler::HandleInvalidPosition(
-    const char *startSpecifier, unsigned specifierLen,
-    analyze_format_string::PositionContext p) {
-  if (!S.getDiagnostics().isIgnored(
-          diag::warn_format_invalid_positional_specifier, SourceLocation()))
-    EmitFormatDiagnostic(
-        S.PDiag(diag::warn_format_invalid_positional_specifier) << (unsigned)p,
-        getLocationOfByte(startSpecifier), /*IsStringLocation*/ true,
-        getSpecifierRange(startSpecifier, specifierLen));
-}
-
-void CheckFormatHandler::HandleZeroPosition(const char *startPos,
-                                            unsigned posLen) {
-  if (!S.getDiagnostics().isIgnored(diag::warn_format_zero_positional_specifier,
-                                    SourceLocation()))
-    EmitFormatDiagnostic(S.PDiag(diag::warn_format_zero_positional_specifier),
-                         getLocationOfByte(startPos),
-                         /*IsStringLocation*/ true,
-                         getSpecifierRange(startPos, posLen));
-}
-
-void CheckFormatHandler::HandleNullChar(const char *nullCharacter) {
-  if (!isa<ObjCStringLiteral>(OrigFormatExpr)) {
-    // The presence of a null character is likely an error.
-    EmitFormatDiagnostic(
-      S.PDiag(diag::warn_printf_format_string_contains_null_char),
-      getLocationOfByte(nullCharacter), /*IsStringLocation*/true,
-      getFormatStringRange());
-  }
-}
-
-// Note that this may return NULL if there was an error parsing or building
-// one of the argument expressions.
-const Expr *CheckFormatHandler::getDataArg(unsigned i) const {
-  return Args[FirstDataArg + i];
-}
-
-void CheckFormatHandler::DoneProcessing() {
-  // Does the number of data arguments exceed the number of
-  // format conversions in the format string?
-  if (HasFormatArguments()) {
-    // Find any arguments that weren't covered.
-    CoveredArgs.flip();
-    signed notCoveredArg = CoveredArgs.find_first();
-    if (notCoveredArg >= 0) {
-      assert((unsigned)notCoveredArg < NumDataArgs);
-      UncoveredArg.Update(notCoveredArg, OrigFormatExpr);
-    } else {
-      UncoveredArg.setAllCovered();
-    }
-  }
-}
-
-void UncoveredArgHandler::Diagnose(Sema &S, bool IsFunctionCall,
-                                   const Expr *ArgExpr) {
-  assert(hasUncoveredArg() && !DiagnosticExprs.empty() &&
-         "Invalid state");
-
-  if (!ArgExpr)
-    return;
-
-  SourceLocation Loc = ArgExpr->getBeginLoc();
-
-  if (S.getSourceManager().isInSystemMacro(Loc))
-    return;
-
-  PartialDiagnostic PDiag = S.PDiag(diag::warn_printf_data_arg_not_used);
-  for (auto E : DiagnosticExprs)
-    PDiag << E->getSourceRange();
-
-  CheckFormatHandler::EmitFormatDiagnostic(
-                                  S, IsFunctionCall, DiagnosticExprs[0],
-                                  PDiag, Loc, /*IsStringLocation*/false,
-                                  DiagnosticExprs[0]->getSourceRange());
-}
-
-bool
-CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex,
-                                                     SourceLocation Loc,
-                                                     const char *startSpec,
-                                                     unsigned specifierLen,
-                                                     const char *csStart,
-                                                     unsigned csLen) {
-  bool keepGoing = true;
-  if (argIndex < NumDataArgs) {
-    // Consider the argument coverered, even though the specifier doesn't
-    // make sense.
-    CoveredArgs.set(argIndex);
-  }
-  else {
-    // If argIndex exceeds the number of data arguments we
-    // don't issue a warning because that is just a cascade of warnings (and
-    // they may have intended '%%' anyway). We don't want to continue processing
-    // the format string after this point, however, as we will like just get
-    // gibberish when trying to match arguments.
-    keepGoing = false;
-  }
-
-  StringRef Specifier(csStart, csLen);
-
-  // If the specifier in non-printable, it could be the first byte of a UTF-8
-  // sequence. In that case, print the UTF-8 code point. If not, print the byte
-  // hex value.
-  std::string CodePointStr;
-  if (!llvm::sys::locale::isPrint(*csStart)) {
-    llvm::UTF32 CodePoint;
-    const llvm::UTF8 **B = reinterpret_cast<const llvm::UTF8 **>(&csStart);
-    const llvm::UTF8 *E =
-        reinterpret_cast<const llvm::UTF8 *>(csStart + csLen);
-    llvm::ConversionResult Result =
-        llvm::convertUTF8Sequence(B, E, &CodePoint, llvm::strictConversion);
-
-    if (Result != llvm::conversionOK) {
-      unsigned char FirstChar = *csStart;
-      CodePoint = (llvm::UTF32)FirstChar;
-    }
-
-    llvm::raw_string_ostream OS(CodePointStr);
-    if (CodePoint < 256)
-      OS << "\\x" << llvm::format("%02x", CodePoint);
-    else if (CodePoint <= 0xFFFF)
-      OS << "\\u" << llvm::format("%04x", CodePoint);
-    else
-      OS << "\\U" << llvm::format("%08x", CodePoint);
-    Specifier = CodePointStr;
-  }
-
-  EmitFormatDiagnostic(
-      S.PDiag(diag::warn_format_invalid_conversion) << Specifier, Loc,
-      /*IsStringLocation*/ true, getSpecifierRange(startSpec, specifierLen));
-
-  return keepGoing;
-}
-
-void
-CheckFormatHandler::HandlePositionalNonpositionalArgs(SourceLocation Loc,
-                                                      const char *startSpec,
-                                                      unsigned specifierLen) {
-  EmitFormatDiagnostic(
-    S.PDiag(diag::warn_format_mix_positional_nonpositional_args),
-    Loc, /*isStringLoc*/true, getSpecifierRange(startSpec, specifierLen));
-}
-
-bool
-CheckFormatHandler::CheckNumArgs(
-  const analyze_format_string::FormatSpecifier &FS,
-  const analyze_format_string::ConversionSpecifier &CS,
-  const char *startSpecifier, unsigned specifierLen, unsigned argIndex) {
-
-  if (HasFormatArguments() && argIndex >= NumDataArgs) {
-    PartialDiagnostic PDiag = FS.usesPositionalArg()
-      ? (S.PDiag(diag::warn_printf_positional_arg_exceeds_data_args)
-           << (argIndex+1) << NumDataArgs)
-      : S.PDiag(diag::warn_printf_insufficient_data_args);
-    EmitFormatDiagnostic(
-      PDiag, getLocationOfByte(CS.getStart()), /*IsStringLocation*/true,
-      getSpecifierRange(startSpecifier, specifierLen));
-
-    // Since more arguments than conversion tokens are given, by extension
-    // all arguments are covered, so mark this as so.
-    UncoveredArg.setAllCovered();
-    return false;
-  }
-  return true;
-}
-
-template<typename Range>
-void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag,
-                                              SourceLocation Loc,
-                                              bool IsStringLocation,
-                                              Range StringRange,
-                                              ArrayRef<FixItHint> FixIt) {
-  EmitFormatDiagnostic(S, inFunctionCall, Args[FormatIdx], PDiag,
-                       Loc, IsStringLocation, StringRange, FixIt);
-}
-
-/// If the format string is not within the function call, emit a note
-/// so that the function call and string are in diagnostic messages.
-///
-/// \param InFunctionCall if true, the format string is within the function
-/// call and only one diagnostic message will be produced.  Otherwise, an
-/// extra note will be emitted pointing to location of the format string.
-///
-/// \param ArgumentExpr the expression that is passed as the format string
-/// argument in the function call.  Used for getting locations when two
-/// diagnostics are emitted.
-///
-/// \param PDiag the callee should already have provided any strings for the
-/// diagnostic message.  This function only adds locations and fixits
-/// to diagnostics.
-///
-/// \param Loc primary location for diagnostic.  If two diagnostics are
-/// required, one will be at Loc and a new SourceLocation will be created for
-/// the other one.
-///
-/// \param IsStringLocation if true, Loc points to the format string should be
-/// used for the note.  Otherwise, Loc points to the argument list and will
-/// be used with PDiag.
-///
-/// \param StringRange some or all of the string to highlight.  This is
-/// templated so it can accept either a CharSourceRange or a SourceRange.
-///
-/// \param FixIt optional fix it hint for the format string.
-template <typename Range>
-void CheckFormatHandler::EmitFormatDiagnostic(
-    Sema &S, bool InFunctionCall, const Expr *ArgumentExpr,
-    const PartialDiagnostic &PDiag, SourceLocation Loc, bool IsStringLocation,
-    Range StringRange, ArrayRef<FixItHint> FixIt) {
-  if (InFunctionCall) {
-    const Sema::SemaDiagnosticBuilder &D = S.Diag(Loc, PDiag);
-    D << StringRange;
-    D << FixIt;
-  } else {
-    S.Diag(IsStringLocation ? ArgumentExpr->getExprLoc() : Loc, PDiag)
-      << ArgumentExpr->getSourceRange();
-
-    const Sema::SemaDiagnosticBuilder &Note =
-      S.Diag(IsStringLocation ? Loc : StringRange.getBegin(),
-             diag::note_format_string_defined);
-
-    Note << StringRange;
-    Note << FixIt;
-  }
-}
-
-//===--- CHECK: Printf format string checking -----------------------------===//
-
-namespace {
-
-class CheckPrintfHandler : public CheckFormatHandler {
-public:
-  CheckPrintfHandler(Sema &s, const FormatStringLiteral *fexpr,
-                     const Expr *origFormatExpr, const FormatStringType type,
-                     unsigned firstDataArg, unsigned numDataArgs, bool isObjC,
-                     const char *beg, Sema::FormatArgumentPassingKind APK,
-                     ArrayRef<const Expr *> Args, unsigned formatIdx,
-                     bool inFunctionCall, VariadicCallType CallType,
-                     llvm::SmallBitVector &CheckedVarArgs,
-                     UncoveredArgHandler &UncoveredArg)
-      : CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg,
-                           numDataArgs, beg, APK, Args, formatIdx,
-                           inFunctionCall, CallType, CheckedVarArgs,
-                           UncoveredArg) {}
-
-  bool isObjCContext() const { return FSType == FormatStringType::NSString; }
-
-  /// Returns true if '%@' specifiers are allowed in the format string.
-  bool allowsObjCArg() const {
-    return FSType == FormatStringType::NSString ||
-           FSType == FormatStringType::OSLog ||
-           FSType == FormatStringType::OSTrace;
-  }
-
-  bool HandleInvalidPrintfConversionSpecifier(
-                                      const analyze_printf::PrintfSpecifier &FS,
-                                      const char *startSpecifier,
-                                      unsigned specifierLen) override;
-
-  void handleInvalidMaskType(StringRef MaskType) override;
-
-  bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
-                             const char *startSpecifier, unsigned specifierLen,
-                             const TargetInfo &Target) override;
-  bool checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
-                       const char *StartSpecifier,
-                       unsigned SpecifierLen,
-                       const Expr *E);
-
-  bool HandleAmount(const analyze_format_string::OptionalAmount &Amt, unsigned k,
-                    const char *startSpecifier, unsigned specifierLen);
-  void HandleInvalidAmount(const analyze_printf::PrintfSpecifier &FS,
-                           const analyze_printf::OptionalAmount &Amt,
-                           unsigned type,
-                           const char *startSpecifier, unsigned specifierLen);
-  void HandleFlag(const analyze_printf::PrintfSpecifier &FS,
-                  const analyze_printf::OptionalFlag &flag,
-                  const char *startSpecifier, unsigned specifierLen);
-  void HandleIgnoredFlag(const analyze_printf::PrintfSpecifier &FS,
-                         const analyze_printf::OptionalFlag &ignoredFlag,
-                         const analyze_printf::OptionalFlag &flag,
-                         const char *startSpecifier, unsigned specifierLen);
-  bool checkForCStrMembers(const analyze_printf::ArgType &AT,
-                           const Expr *E);
-
-  void HandleEmptyObjCModifierFlag(const char *startFlag,
-                                   unsigned flagLen) override;
-
-  void HandleInvalidObjCModifierFlag(const char *startFlag,
-                                            unsigned flagLen) override;
-
-  void
-  HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,
-                                       const char *flagsEnd,
-                                       const char *conversionPosition) override;
-};
-
-/// Keeps around the information needed to verify that two specifiers are
-/// compatible.
-class EquatableFormatArgument {
-public:
-  enum SpecifierSensitivity : unsigned {
-    SS_None,
-    SS_Private,
-    SS_Public,
-    SS_Sensitive
-  };
-
-  enum FormatArgumentRole : unsigned {
-    FAR_Data,
-    FAR_FieldWidth,
-    FAR_Precision,
-    FAR_Auxiliary, // FreeBSD kernel %b and %D
-  };
-
-private:
-  analyze_format_string::ArgType ArgType;
-  analyze_format_string::LengthModifier::Kind LengthMod;
-  StringRef SpecifierLetter;
-  CharSourceRange Range;
-  SourceLocation ElementLoc;
-  FormatArgumentRole Role : 2;
-  SpecifierSensitivity Sensitivity : 2; // only set for FAR_Data
-  unsigned Position : 14;
-  unsigned ModifierFor : 14; // not set for FAR_Data
-
-  void EmitDiagnostic(Sema &S, PartialDiagnostic PDiag, const Expr *FmtExpr,
-                      bool InFunctionCall) const;
-
-public:
-  EquatableFormatArgument(CharSourceRange Range, SourceLocation ElementLoc,
-                          analyze_format_string::LengthModifier::Kind LengthMod,
-                          StringRef SpecifierLetter,
-                          analyze_format_string::ArgType ArgType,
-                          FormatArgumentRole Role,
-                          SpecifierSensitivity Sensitivity, unsigned Position,
-                          unsigned ModifierFor)
-      : ArgType(ArgType), LengthMod(LengthMod),
-        SpecifierLetter(SpecifierLetter), Range(Range), ElementLoc(ElementLoc),
-        Role(Role), Sensitivity(Sensitivity), Position(Position),
-        ModifierFor(ModifierFor) {}
-
-  unsigned getPosition() const { return Position; }
-  SourceLocation getSourceLocation() const { return ElementLoc; }
-  CharSourceRange getSourceRange() const { return Range; }
-  analyze_format_string::LengthModifier getLengthModifier() const {
-    return analyze_format_string::LengthModifier(nullptr, LengthMod);
-  }
-  void setModifierFor(unsigned V) { ModifierFor = V; }
-
-  std::string buildFormatSpecifier() const {
-    std::string result;
-    llvm::raw_string_ostream(result)
-        << getLengthModifier().toString() << SpecifierLetter;
-    return result;
-  }
-
-  bool VerifyCompatible(Sema &S, const EquatableFormatArgument &Other,
-                        const Expr *FmtExpr, bool InFunctionCall) const;
-};
-
-/// Turns format strings into lists of EquatableSpecifier objects.
-class DecomposePrintfHandler : public CheckPrintfHandler {
-  llvm::SmallVectorImpl<EquatableFormatArgument> &Specs;
-  bool HadError;
-
-  DecomposePrintfHandler(Sema &s, const FormatStringLiteral *fexpr,
-                         const Expr *origFormatExpr,
-                         const FormatStringType type, unsigned firstDataArg,
-                         unsigned numDataArgs, bool isObjC, const char *beg,
-                         Sema::FormatArgumentPassingKind APK,
-                         ArrayRef<const Expr *> Args, unsigned formatIdx,
-                         bool inFunctionCall, VariadicCallType CallType,
-                         llvm::SmallBitVector &CheckedVarArgs,
-                         UncoveredArgHandler &UncoveredArg,
-                         llvm::SmallVectorImpl<EquatableFormatArgument> &Specs)
-      : CheckPrintfHandler(s, fexpr, origFormatExpr, type, firstDataArg,
-                           numDataArgs, isObjC, beg, APK, Args, formatIdx,
-                           inFunctionCall, CallType, CheckedVarArgs,
-                           UncoveredArg),
-        Specs(Specs), HadError(false) {}
-
-public:
-  static bool
-  GetSpecifiers(Sema &S, const FormatStringLiteral *FSL, const Expr *FmtExpr,
-                FormatStringType type, bool IsObjC, bool InFunctionCall,
-                llvm::SmallVectorImpl<EquatableFormatArgument> &Args);
-
-  virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
-                                     const char *startSpecifier,
-                                     unsigned specifierLen,
-                                     const TargetInfo &Target) override;
-};
-
-} // namespace
-
-bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier(
-    const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier,
-    unsigned specifierLen) {
-  const analyze_printf::PrintfConversionSpecifier &CS =
-    FS.getConversionSpecifier();
-
-  return HandleInvalidConversionSpecifier(FS.getArgIndex(),
-                                          getLocationOfByte(CS.getStart()),
-                                          startSpecifier, specifierLen,
-                                          CS.getStart(), CS.getLength());
-}
-
-void CheckPrintfHandler::handleInvalidMaskType(StringRef MaskType) {
-  S.Diag(getLocationOfByte(MaskType.data()), diag::err_invalid_mask_type_size);
-}
-
-// Error out if struct or complex type argments are passed to os_log.
-static bool isInvalidOSLogArgTypeForCodeGen(FormatStringType FSType,
-                                            QualType T) {
-  if (FSType != FormatStringType::OSLog)
-    return false;
-  return T->isRecordType() || T->isComplexType();
-}
-
-bool CheckPrintfHandler::HandleAmount(
-    const analyze_format_string::OptionalAmount &Amt, unsigned k,
-    const char *startSpecifier, unsigned specifierLen) {
-  if (Amt.hasDataArgument()) {
-    if (HasFormatArguments()) {
-      unsigned argIndex = Amt.getArgIndex();
-      if (argIndex >= NumDataArgs) {
-        EmitFormatDiagnostic(S.PDiag(diag::warn_printf_asterisk_missing_arg)
-                                 << k,
-                             getLocationOfByte(Amt.getStart()),
-                             /*IsStringLocation*/ true,
-                             getSpecifierRange(startSpecifier, specifierLen));
-        // Don't do any more checking.  We will just emit
-        // spurious errors.
-        return false;
-      }
-
-      // Type check the data argument.  It should be an 'int'.
-      // Although not in conformance with C99, we also allow the argument to be
-      // an 'unsigned int' as that is a reasonably safe case.  GCC also
-      // doesn't emit a warning for that case.
-      CoveredArgs.set(argIndex);
-      const Expr *Arg = getDataArg(argIndex);
-      if (!Arg)
-        return false;
-
-      QualType T = Arg->getType();
-
-      const analyze_printf::ArgType &AT = Amt.getArgType(S.Context);
-      assert(AT.isValid());
-
-      if (!AT.matchesType(S.Context, T)) {
-        unsigned DiagID = isInvalidOSLogArgTypeForCodeGen(FSType, T)
-                              ? diag::err_printf_asterisk_wrong_type
-                              : diag::warn_printf_asterisk_wrong_type;
-        EmitFormatDiagnostic(S.PDiag(DiagID)
-                                 << k << AT.getRepresentativeTypeName(S.Context)
-                                 << T << Arg->getSourceRange(),
-                             getLocationOfByte(Amt.getStart()),
-                             /*IsStringLocation*/ true,
-                             getSpecifierRange(startSpecifier, specifierLen));
-        // Don't do any more checking.  We will just emit
-        // spurious errors.
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-void CheckPrintfHandler::HandleInvalidAmount(
-                                      const analyze_printf::PrintfSpecifier &FS,
-                                      const analyze_printf::OptionalAmount &Amt,
-                                      unsigned type,
-                                      const char *startSpecifier,
-                                      unsigned specifierLen) {
-  const analyze_printf::PrintfConversionSpecifier &CS =
-    FS.getConversionSpecifier();
-
-  FixItHint fixit =
-    Amt.getHowSpecified() == analyze_printf::OptionalAmount::Constant
-      ? FixItHint::CreateRemoval(getSpecifierRange(Amt.getStart(),
-                                 Amt.getConstantLength()))
-      : FixItHint();
-
-  EmitFormatDiagnostic(S.PDiag(diag::warn_printf_nonsensical_optional_amount)
-                         << type << CS.toString(),
-                       getLocationOfByte(Amt.getStart()),
-                       /*IsStringLocation*/true,
-                       getSpecifierRange(startSpecifier, specifierLen),
-                       fixit);
-}
-
-void CheckPrintfHandler::HandleFlag(const analyze_printf::PrintfSpecifier &FS,
-                                    const analyze_printf::OptionalFlag &flag,
-                                    const char *startSpecifier,
-                                    unsigned specifierLen) {
-  // Warn about pointless flag with a fixit removal.
-  const analyze_printf::PrintfConversionSpecifier &CS =
-    FS.getConversionSpecifier();
-  EmitFormatDiagnostic(S.PDiag(diag::warn_printf_nonsensical_flag)
-                         << flag.toString() << CS.toString(),
-                       getLocationOfByte(flag.getPosition()),
-                       /*IsStringLocation*/true,
-                       getSpecifierRange(startSpecifier, specifierLen),
-                       FixItHint::CreateRemoval(
-                         getSpecifierRange(flag.getPosition(), 1)));
-}
-
-void CheckPrintfHandler::HandleIgnoredFlag(
-                                const analyze_printf::PrintfSpecifier &FS,
-                                const analyze_printf::OptionalFlag &ignoredFlag,
-                                const analyze_printf::OptionalFlag &flag,
-                                const char *startSpecifier,
-                                unsigned specifierLen) {
-  // Warn about ignored flag with a fixit removal.
-  EmitFormatDiagnostic(S.PDiag(diag::warn_printf_ignored_flag)
-                         << ignoredFlag.toString() << flag.toString(),
-                       getLocationOfByte(ignoredFlag.getPosition()),
-                       /*IsStringLocation*/true,
-                       getSpecifierRange(startSpecifier, specifierLen),
-                       FixItHint::CreateRemoval(
-                         getSpecifierRange(ignoredFlag.getPosition(), 1)));
-}
-
-void CheckPrintfHandler::HandleEmptyObjCModifierFlag(const char *startFlag,
-                                                     unsigned flagLen) {
-  // Warn about an empty flag.
-  EmitFormatDiagnostic(S.PDiag(diag::warn_printf_empty_objc_flag),
-                       getLocationOfByte(startFlag),
-                       /*IsStringLocation*/true,
-                       getSpecifierRange(startFlag, flagLen));
-}
-
-void CheckPrintfHandler::HandleInvalidObjCModifierFlag(const char *startFlag,
-                                                       unsigned flagLen) {
-  // Warn about an invalid flag.
-  auto Range = getSpecifierRange(startFlag, flagLen);
-  StringRef flag(startFlag, flagLen);
-  EmitFormatDiagnostic(S.PDiag(diag::warn_printf_invalid_objc_flag) << flag,
-                      getLocationOfByte(startFlag),
-                      /*IsStringLocation*/true,
-                      Range, FixItHint::CreateRemoval(Range));
-}
-
-void CheckPrintfHandler::HandleObjCFlagsWithNonObjCConversion(
-    const char *flagsStart, const char *flagsEnd, const char *conversionPosition) {
-    // Warn about using '[...]' without a '@' conversion.
-    auto Range = getSpecifierRange(flagsStart, flagsEnd - flagsStart + 1);
-    auto diag = diag::warn_printf_ObjCflags_without_ObjCConversion;
-    EmitFormatDiagnostic(S.PDiag(diag) << StringRef(conversionPosition, 1),
-                         getLocationOfByte(conversionPosition),
-                         /*IsStringLocation*/ true, Range,
-                         FixItHint::CreateRemoval(Range));
-}
-
-void EquatableFormatArgument::EmitDiagnostic(Sema &S, PartialDiagnostic PDiag,
-                                             const Expr *FmtExpr,
-                                             bool InFunctionCall) const {
-  CheckFormatHandler::EmitFormatDiagnostic(S, InFunctionCall, FmtExpr, PDiag,
-                                           ElementLoc, true, Range);
-}
-
-bool EquatableFormatArgument::VerifyCompatible(
-    Sema &S, const EquatableFormatArgument &Other, const Expr *FmtExpr,
-    bool InFunctionCall) const {
-  using MK = analyze_format_string::ArgType::MatchKind;
-  if (Role != Other.Role) {
-    // diagnose and stop
-    EmitDiagnostic(
-        S, S.PDiag(diag::warn_format_cmp_role_mismatch) << Role << Other.Role,
-        FmtExpr, InFunctionCall);
-    S.Diag(Other.ElementLoc, diag::note_format_cmp_with) << 0 << Other.Range;
-    return false;
-  }
-
-  if (Role != FAR_Data) {
-    if (ModifierFor != Other.ModifierFor) {
-      // diagnose and stop
-      EmitDiagnostic(S,
-                     S.PDiag(diag::warn_format_cmp_modifierfor_mismatch)
-                         << (ModifierFor + 1) << (Other.ModifierFor + 1),
-                     FmtExpr, InFunctionCall);
-      S.Diag(Other.ElementLoc, diag::note_format_cmp_with) << 0 << Other.Range;
-      return false;
-    }
-    return true;
-  }
-
-  bool HadError = false;
-  if (Sensitivity != Other.Sensitivity) {
-    // diagnose and continue
-    EmitDiagnostic(S,
-                   S.PDiag(diag::warn_format_cmp_sensitivity_mismatch)
-                       << Sensitivity << Other.Sensitivity,
-                   FmtExpr, InFunctionCall);
-    HadError = S.Diag(Other.ElementLoc, diag::note_format_cmp_with)
-               << 0 << Other.Range;
-  }
-
-  switch (ArgType.matchesArgType(S.Context, Other.ArgType)) {
-  case MK::Match:
-    break;
-
-  case MK::MatchPromotion:
-    // Per consensus reached at https://discourse.llvm.org/t/-/83076/12,
-    // MatchPromotion is treated as a failure by format_matches.
-  case MK::NoMatch:
-  case MK::NoMatchTypeConfusion:
-  case MK::NoMatchPromotionTypeConfusion:
-    EmitDiagnostic(S,
-                   S.PDiag(diag::warn_format_cmp_specifier_mismatch)
-                       << buildFormatSpecifier()
-                       << Other.buildFormatSpecifier(),
-                   FmtExpr, InFunctionCall);
-    HadError = S.Diag(Other.ElementLoc, diag::note_format_cmp_with)
-               << 0 << Other.Range;
-    break;
-
-  case MK::NoMatchPedantic:
-    EmitDiagnostic(S,
-                   S.PDiag(diag::warn_format_cmp_specifier_mismatch_pedantic)
-                       << buildFormatSpecifier()
-                       << Other.buildFormatSpecifier(),
-                   FmtExpr, InFunctionCall);
-    HadError = S.Diag(Other.ElementLoc, diag::note_format_cmp_with)
-               << 0 << Other.Range;
-    break;
-
-  case MK::NoMatchSignedness:
-    EmitDiagnostic(S,
-                   S.PDiag(diag::warn_format_cmp_specifier_sign_mismatch)
-                       << buildFormatSpecifier()
-                       << Other.buildFormatSpecifier(),
-                   FmtExpr, InFunctionCall);
-    HadError = S.Diag(Other.ElementLoc, diag::note_format_cmp_with)
-               << 0 << Other.Range;
-    break;
-  }
-  return !HadError;
-}
-
-bool DecomposePrintfHandler::GetSpecifiers(
-    Sema &S, const FormatStringLiteral *FSL, const Expr *FmtExpr,
-    FormatStringType Type, bool IsObjC, bool InFunctionCall,
-    llvm::SmallVectorImpl<EquatableFormatArgument> &Args) {
-  StringRef Data = FSL->getString();
-  const char *Str = Data.data();
-  llvm::SmallBitVector BV;
-  UncoveredArgHandler UA;
-  const Expr *PrintfArgs[] = {FSL->getFormatString()};
-  DecomposePrintfHandler H(S, FSL, FSL->getFormatString(), Type, 0, 0, IsObjC,
-                           Str, Sema::FAPK_Elsewhere, PrintfArgs, 0,
-                           InFunctionCall, VariadicCallType::DoesNotApply, BV,
-                           UA, Args);
-
-  if (!analyze_format_string::ParsePrintfString(
-          H, Str, Str + Data.size(), S.getLangOpts(), S.Context.getTargetInfo(),
-          Type == FormatStringType::FreeBSDKPrintf))
-    H.DoneProcessing();
-  if (H.HadError)
-    return false;
-
-  llvm::stable_sort(Args, [](const EquatableFormatArgument &A,
-                             const EquatableFormatArgument &B) {
-    return A.getPosition() < B.getPosition();
-  });
-  return true;
-}
-
-bool DecomposePrintfHandler::HandlePrintfSpecifier(
-    const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier,
-    unsigned specifierLen, const TargetInfo &Target) {
-  if (!CheckPrintfHandler::HandlePrintfSpecifier(FS, startSpecifier,
-                                                 specifierLen, Target)) {
-    HadError = true;
-    return false;
-  }
-
-  // Do not add any specifiers to the list for %%. This is possibly incorrect
-  // if using a precision/width with a data argument, but that combination is
-  // meaningless and we wouldn't know which format to attach the
-  // precision/width to.
-  const auto &CS = FS.getConversionSpecifier();
-  if (CS.getKind() == analyze_format_string::ConversionSpecifier::PercentArg)
-    return true;
-
-  // have to patch these to have the right ModifierFor if they are used
-  const unsigned Unset = ~0;
-  unsigned FieldWidthIndex = Unset;
-  unsigned PrecisionIndex = Unset;
-
-  // field width?
-  const auto &FieldWidth = FS.getFieldWidth();
-  if (!FieldWidth.isInvalid() && FieldWidth.hasDataArgument()) {
-    FieldWidthIndex = Specs.size();
-    Specs.emplace_back(getSpecifierRange(startSpecifier, specifierLen),
-                       getLocationOfByte(FieldWidth.getStart()),
-                       analyze_format_string::LengthModifier::None, "*",
-                       FieldWidth.getArgType(S.Context),
-                       EquatableFormatArgument::FAR_FieldWidth,
-                       EquatableFormatArgument::SS_None,
-                       FieldWidth.usesPositionalArg()
-                           ? FieldWidth.getPositionalArgIndex() - 1
-                           : FieldWidthIndex,
-                       0);
-  }
-  // precision?
-  const auto &Precision = FS.getPrecision();
-  if (!Precision.isInvalid() && Precision.hasDataArgument()) {
-    PrecisionIndex = Specs.size();
-    Specs.emplace_back(
-        getSpecifierRange(startSpecifier, specifierLen),
-        getLocationOfByte(Precision.getStart()),
-        analyze_format_string::LengthModifier::None, ".*",
-        Precision.getArgType(S.Context), EquatableFormatArgument::FAR_Precision,
-        EquatableFormatArgument::SS_None,
-        Precision.usesPositionalArg() ? Precision.getPositionalArgIndex() - 1
-                                      : PrecisionIndex,
-        0);
-  }
-
-  // this specifier
-  unsigned SpecIndex =
-      FS.usesPositionalArg() ? FS.getPositionalArgIndex() - 1 : Specs.size();
-  if (FieldWidthIndex != Unset)
-    Specs[FieldWidthIndex].setModifierFor(SpecIndex);
-  if (PrecisionIndex != Unset)
-    Specs[PrecisionIndex].setModifierFor(SpecIndex);
-
-  EquatableFormatArgument::SpecifierSensitivity Sensitivity;
-  if (FS.isPrivate())
-    Sensitivity = EquatableFormatArgument::SS_Private;
-  else if (FS.isPublic())
-    Sensitivity = EquatableFormatArgument::SS_Public;
-  else if (FS.isSensitive())
-    Sensitivity = EquatableFormatArgument::SS_Sensitive;
-  else
-    Sensitivity = EquatableFormatArgument::SS_None;
-
-  Specs.emplace_back(
-      getSpecifierRange(startSpecifier, specifierLen),
-      getLocationOfByte(CS.getStart()), FS.getLengthModifier().getKind(),
-      CS.getCharacters(), FS.getArgType(S.Context, isObjCContext()),
-      EquatableFormatArgument::FAR_Data, Sensitivity, SpecIndex, 0);
-
-  // auxiliary argument?
-  if (CS.getKind() == analyze_format_string::ConversionSpecifier::FreeBSDbArg ||
-      CS.getKind() == analyze_format_string::ConversionSpecifier::FreeBSDDArg) {
-    Specs.emplace_back(getSpecifierRange(startSpecifier, specifierLen),
-                       getLocationOfByte(CS.getStart()),
-                       analyze_format_string::LengthModifier::None,
-                       CS.getCharacters(),
-                       analyze_format_string::ArgType::CStrTy,
-                       EquatableFormatArgument::FAR_Auxiliary, Sensitivity,
-                       SpecIndex + 1, SpecIndex);
-  }
-  return true;
-}
-
-// Determines if the specified is a C++ class or struct containing
-// a member with the specified name and kind (e.g. a CXXMethodDecl named
-// "c_str()").
-template<typename MemberKind>
-static llvm::SmallPtrSet<MemberKind*, 1>
-CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) {
-  auto *RD = Ty->getAsCXXRecordDecl();
-  llvm::SmallPtrSet<MemberKind*, 1> Results;
-
-  if (!RD || !(RD->isBeingDefined() || RD->isCompleteDefinition()))
-    return Results;
-
-  LookupResult R(S, &S.Context.Idents.get(Name), SourceLocation(),
-                 Sema::LookupMemberName);
-  R.suppressDiagnostics();
-
-  // We just need to include all members of the right kind turned up by the
-  // filter, at this point.
-  if (S.LookupQualifiedName(R, RD))
-    for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
-      NamedDecl *decl = (*I)->getUnderlyingDecl();
-      if (MemberKind *FK = dyn_cast<MemberKind>(decl))
-        Results.insert(FK);
-    }
-  return Results;
-}
-
-/// Check if we could call '.c_str()' on an object.
-///
-/// FIXME: This returns the wrong results in some cases (if cv-qualifiers don't
-/// allow the call, or if it would be ambiguous).
-bool Sema::hasCStrMethod(const Expr *E) {
-  using MethodSet = llvm::SmallPtrSet<CXXMethodDecl *, 1>;
-
-  MethodSet Results =
-      CXXRecordMembersNamed<CXXMethodDecl>("c_str", *this, E->getType());
-  for (MethodSet::iterator MI = Results.begin(), ME = Results.end();
-       MI != ME; ++MI)
-    if ((*MI)->getMinRequiredArguments() == 0)
-      return true;
-  return false;
-}
-
-// Check if a (w)string was passed when a (w)char* was needed, and offer a
-// better diagnostic if so. AT is assumed to be valid.
-// Returns true when a c_str() conversion method is found.
-bool CheckPrintfHandler::checkForCStrMembers(
-    const analyze_printf::ArgType &AT, const Expr *E) {
-  using MethodSet = llvm::SmallPtrSet<CXXMethodDecl *, 1>;
-
-  MethodSet Results =
-      CXXRecordMembersNamed<CXXMethodDecl>("c_str", S, E->getType());
-
-  for (MethodSet::iterator MI = Results.begin(), ME = Results.end();
-       MI != ME; ++MI) {
-    const CXXMethodDecl *Method = *MI;
-    if (Method->getMinRequiredArguments() == 0 &&
-        AT.matchesType(S.Context, Method->getReturnType())) {
-      // FIXME: Suggest parens if the expression needs them.
-      SourceLocation EndLoc = S.getLocForEndOfToken(E->getEndLoc());
-      S.Diag(E->getBeginLoc(), diag::note_printf_c_str)
-          << "c_str()" << FixItHint::CreateInsertion(EndLoc, ".c_str()");
-      return true;
-    }
-  }
-
-  return false;
-}
-
-bool CheckPrintfHandler::HandlePrintfSpecifier(
-    const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier,
-    unsigned specifierLen, const TargetInfo &Target) {
-  using namespace analyze_format_string;
-  using namespace analyze_printf;
-
-  const PrintfConversionSpecifier &CS = FS.getConversionSpecifier();
-
-  if (FS.consumesDataArgument()) {
-    if (atFirstArg) {
-        atFirstArg = false;
-        usesPositionalArgs = FS.usesPositionalArg();
-    }
-    else if (usesPositionalArgs != FS.usesPositionalArg()) {
-      HandlePositionalNonpositionalArgs(getLocationOfByte(CS.getStart()),
-                                        startSpecifier, specifierLen);
-      return false;
-    }
-  }
-
-  // First check if the field width, precision, and conversion specifier
-  // have matching data arguments.
-  if (!HandleAmount(FS.getFieldWidth(), /* field width */ 0,
-                    startSpecifier, specifierLen)) {
-    return false;
-  }
-
-  if (!HandleAmount(FS.getPrecision(), /* precision */ 1,
-                    startSpecifier, specifierLen)) {
-    return false;
-  }
-
-  if (!CS.consumesDataArgument()) {
-    // FIXME: Technically specifying a precision or field width here
-    // makes no sense.  Worth issuing a warning at some point.
-    return true;
-  }
-
-  // Consume the argument.
-  unsigned argIndex = FS.getArgIndex();
-  if (argIndex < NumDataArgs) {
-    // The check to see if the argIndex is valid will come later.
-    // We set the bit here because we may exit early from this
-    // function if we encounter some other error.
-    CoveredArgs.set(argIndex);
-  }
-
-  // FreeBSD kernel extensions.
-  if (CS.getKind() == ConversionSpecifier::FreeBSDbArg ||
-      CS.getKind() == ConversionSpecifier::FreeBSDDArg) {
-    // We need at least two arguments.
-    if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex + 1))
-      return false;
-
-    if (HasFormatArguments()) {
-      // Claim the second argument.
-      CoveredArgs.set(argIndex + 1);
-
-      // Type check the first argument (int for %b, pointer for %D)
-      const Expr *Ex = getDataArg(argIndex);
-      const analyze_printf::ArgType &AT =
-          (CS.getKind() == ConversionSpecifier::FreeBSDbArg)
-              ? ArgType(S.Context.IntTy)
-              : ArgType::CPointerTy;
-      if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType()))
-        EmitFormatDiagnostic(
-            S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
-                << AT.getRepresentativeTypeName(S.Context) << Ex->getType()
-                << false << Ex->getSourceRange(),
-            Ex->getBeginLoc(), /*IsStringLocation*/ false,
-            getSpecifierRange(startSpecifier, specifierLen));
-
-      // Type check the second argument (char * for both %b and %D)
-      Ex = getDataArg(argIndex + 1);
-      const analyze_printf::ArgType &AT2 = ArgType::CStrTy;
-      if (AT2.isValid() && !AT2.matchesType(S.Context, Ex->getType()))
-        EmitFormatDiagnostic(
-            S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
-                << AT2.getRepresentativeTypeName(S.Context) << Ex->getType()
-                << false << Ex->getSourceRange(),
-            Ex->getBeginLoc(), /*IsStringLocation*/ false,
-            getSpecifierRange(startSpecifier, specifierLen));
-    }
-    return true;
-  }
-
-  // Check for using an Objective-C specific conversion specifier
-  // in a non-ObjC literal.
-  if (!allowsObjCArg() && CS.isObjCArg()) {
-    return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier,
-                                                  specifierLen);
-  }
-
-  // %P can only be used with os_log.
-  if (FSType != FormatStringType::OSLog &&
-      CS.getKind() == ConversionSpecifier::PArg) {
-    return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier,
-                                                  specifierLen);
-  }
-
-  // %n is not allowed with os_log.
-  if (FSType == FormatStringType::OSLog &&
-      CS.getKind() == ConversionSpecifier::nArg) {
-    EmitFormatDiagnostic(S.PDiag(diag::warn_os_log_format_narg),
-                         getLocationOfByte(CS.getStart()),
-                         /*IsStringLocation*/ false,
-                         getSpecifierRange(startSpecifier, specifierLen));
-
-    return true;
-  }
-
-  // Only scalars are allowed for os_trace.
-  if (FSType == FormatStringType::OSTrace &&
-      (CS.getKind() == ConversionSpecifier::PArg ||
-       CS.getKind() == ConversionSpecifier::sArg ||
-       CS.getKind() == ConversionSpecifier::ObjCObjArg)) {
-    return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier,
-                                                  specifierLen);
-  }
-
-  // Check for use of public/private annotation outside of os_log().
-  if (FSType != FormatStringType::OSLog) {
-    if (FS.isPublic().isSet()) {
-      EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_annotation)
-                               << "public",
-                           getLocationOfByte(FS.isPublic().getPosition()),
-                           /*IsStringLocation*/ false,
-                           getSpecifierRange(startSpecifier, specifierLen));
-    }
-    if (FS.isPrivate().isSet()) {
-      EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_annotation)
-                               << "private",
-                           getLocationOfByte(FS.isPrivate().getPosition()),
-                           /*IsStringLocation*/ false,
-                           getSpecifierRange(startSpecifier, specifierLen));
-    }
-  }
-
-  const llvm::Triple &Triple = Target.getTriple();
-  if (CS.getKind() == ConversionSpecifier::nArg &&
-      (Triple.isAndroid() || Triple.isOSFuchsia())) {
-    EmitFormatDiagnostic(S.PDiag(diag::warn_printf_narg_not_supported),
-                         getLocationOfByte(CS.getStart()),
-                         /*IsStringLocation*/ false,
-                         getSpecifierRange(startSpecifier, specifierLen));
-  }
-
-  // Check for invalid use of field width
-  if (!FS.hasValidFieldWidth()) {
-    HandleInvalidAmount(FS, FS.getFieldWidth(), /* field width */ 0,
-        startSpecifier, specifierLen);
-  }
-
-  // Check for invalid use of precision
-  if (!FS.hasValidPrecision()) {
-    HandleInvalidAmount(FS, FS.getPrecision(), /* precision */ 1,
-        startSpecifier, specifierLen);
-  }
-
-  // Precision is mandatory for %P specifier.
-  if (CS.getKind() == ConversionSpecifier::PArg &&
-      FS.getPrecision().getHowSpecified() == OptionalAmount::NotSpecified) {
-    EmitFormatDiagnostic(S.PDiag(diag::warn_format_P_no_precision),
-                         getLocationOfByte(startSpecifier),
-                         /*IsStringLocation*/ false,
-                         getSpecifierRange(startSpecifier, specifierLen));
-  }
-
-  // Check each flag does not conflict with any other component.
-  if (!FS.hasValidThousandsGroupingPrefix())
-    HandleFlag(FS, FS.hasThousandsGrouping(), startSpecifier, specifierLen);
-  if (!FS.hasValidLeadingZeros())
-    HandleFlag(FS, FS.hasLeadingZeros(), startSpecifier, specifierLen);
-  if (!FS.hasValidPlusPrefix())
-    HandleFlag(FS, FS.hasPlusPrefix(), startSpecifier, specifierLen);
-  if (!FS.hasValidSpacePrefix())
-    HandleFlag(FS, FS.hasSpacePrefix(), startSpecifier, specifierLen);
-  if (!FS.hasValidAlternativeForm())
-    HandleFlag(FS, FS.hasAlternativeForm(), startSpecifier, specifierLen);
-  if (!FS.hasValidLeftJustified())
-    HandleFlag(FS, FS.isLeftJustified(), startSpecifier, specifierLen);
-
-  // Check that flags are not ignored by another flag
-  if (FS.hasSpacePrefix() && FS.hasPlusPrefix()) // ' ' ignored by '+'
-    HandleIgnoredFlag(FS, FS.hasSpacePrefix(), FS.hasPlusPrefix(),
-        startSpecifier, specifierLen);
-  if (FS.hasLeadingZeros() && FS.isLeftJustified()) // '0' ignored by '-'
-    HandleIgnoredFlag(FS, FS.hasLeadingZeros(), FS.isLeftJustified(),
-            startSpecifier, specifierLen);
-
-  // Check the length modifier is valid with the given conversion specifier.
-  if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo(),
-                                 S.getLangOpts()))
-    HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
-                                diag::warn_format_nonsensical_length);
-  else if (!FS.hasStandardLengthModifier())
-    HandleNonStandardLengthModifier(FS, startSpecifier, specifierLen);
-  else if (!FS.hasStandardLengthConversionCombination())
-    HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
-                                diag::warn_format_non_standard_conversion_spec);
-
-  if (!FS.hasStandardConversionSpecifier(S.getLangOpts()))
-    HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen);
-
-  // The remaining checks depend on the data arguments.
-  if (!HasFormatArguments())
-    return true;
-
-  if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex))
-    return false;
-
-  const Expr *Arg = getDataArg(argIndex);
-  if (!Arg)
-    return true;
-
-  return checkFormatExpr(FS, startSpecifier, specifierLen, Arg);
-}
-
-static bool requiresParensToAddCast(const Expr *E) {
-  // FIXME: We should have a general way to reason about operator
-  // precedence and whether parens are actually needed here.
-  // Take care of a few common cases where they aren't.
-  const Expr *Inside = E->IgnoreImpCasts();
-  if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(Inside))
-    Inside = POE->getSyntacticForm()->IgnoreImpCasts();
-
-  switch (Inside->getStmtClass()) {
-  case Stmt::ArraySubscriptExprClass:
-  case Stmt::CallExprClass:
-  case Stmt::CharacterLiteralClass:
-  case Stmt::CXXBoolLiteralExprClass:
-  case Stmt::DeclRefExprClass:
-  case Stmt::FloatingLiteralClass:
-  case Stmt::IntegerLiteralClass:
-  case Stmt::MemberExprClass:
-  case Stmt::ObjCArrayLiteralClass:
-  case Stmt::ObjCBoolLiteralExprClass:
-  case Stmt::ObjCBoxedExprClass:
-  case Stmt::ObjCDictionaryLiteralClass:
-  case Stmt::ObjCEncodeExprClass:
-  case Stmt::ObjCIvarRefExprClass:
-  case Stmt::ObjCMessageExprClass:
-  case Stmt::ObjCPropertyRefExprClass:
-  case Stmt::ObjCStringLiteralClass:
-  case Stmt::ObjCSubscriptRefExprClass:
-  case Stmt::ParenExprClass:
-  case Stmt::StringLiteralClass:
-  case Stmt::UnaryOperatorClass:
-    return false;
-  default:
-    return true;
-  }
-}
-
-static std::pair<QualType, StringRef>
-shouldNotPrintDirectly(const ASTContext &Context,
-                       QualType IntendedTy,
-                       const Expr *E) {
-  // Use a 'while' to peel off layers of typedefs.
-  QualType TyTy = IntendedTy;
-  while (const TypedefType *UserTy = TyTy->getAs<TypedefType>()) {
-    StringRef Name = UserTy->getDecl()->getName();
-    QualType CastTy = llvm::StringSwitch<QualType>(Name)
-      .Case("CFIndex", Context.getNSIntegerType())
-      .Case("NSInteger", Context.getNSIntegerType())
-      .Case("NSUInteger", Context.getNSUIntegerType())
-      .Case("SInt32", Context.IntTy)
-      .Case("UInt32", Context.UnsignedIntTy)
-      .Default(QualType());
-
-    if (!CastTy.isNull())
-      return std::make_pair(CastTy, Name);
-
-    TyTy = UserTy->desugar();
-  }
-
-  // Strip parens if necessary.
-  if (const ParenExpr *PE = dyn_cast<ParenExpr>(E))
-    return shouldNotPrintDirectly(Context,
-                                  PE->getSubExpr()->getType(),
-                                  PE->getSubExpr());
-
-  // If this is a conditional expression, then its result type is constructed
-  // via usual arithmetic conversions and thus there might be no necessary
-  // typedef sugar there.  Recurse to operands to check for NSInteger &
-  // Co. usage condition.
-  if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
-    QualType TrueTy, FalseTy;
-    StringRef TrueName, FalseName;
-
-    std::tie(TrueTy, TrueName) =
-      shouldNotPrintDirectly(Context,
-                             CO->getTrueExpr()->getType(),
-                             CO->getTrueExpr());
-    std::tie(FalseTy, FalseName) =
-      shouldNotPrintDirectly(Context,
-                             CO->getFalseExpr()->getType(),
-                             CO->getFalseExpr());
-
-    if (TrueTy == FalseTy)
-      return std::make_pair(TrueTy, TrueName);
-    else if (TrueTy.isNull())
-      return std::make_pair(FalseTy, FalseName);
-    else if (FalseTy.isNull())
-      return std::make_pair(TrueTy, TrueName);
-  }
-
-  return std::make_pair(QualType(), StringRef());
-}
-
-/// Return true if \p ICE is an implicit argument promotion of an arithmetic
-/// type. Bit-field 'promotions' from a higher ranked type to a lower ranked
-/// type do not count.
-static bool
-isArithmeticArgumentPromotion(Sema &S, const ImplicitCastExpr *ICE) {
-  QualType From = ICE->getSubExpr()->getType();
-  QualType To = ICE->getType();
-  // It's an integer promotion if the destination type is the promoted
-  // source type.
-  if (ICE->getCastKind() == CK_IntegralCast &&
-      S.Context.isPromotableIntegerType(From) &&
-      S.Context.getPromotedIntegerType(From) == To)
-    return true;
-  // Look through vector types, since we do default argument promotion for
-  // those in OpenCL.
-  if (const auto *VecTy = From->getAs<ExtVectorType>())
-    From = VecTy->getElementType();
-  if (const auto *VecTy = To->getAs<ExtVectorType>())
-    To = VecTy->getElementType();
-  // It's a floating promotion if the source type is a lower rank.
-  return ICE->getCastKind() == CK_FloatingCast &&
-         S.Context.getFloatingTypeOrder(From, To) < 0;
-}
-
-static analyze_format_string::ArgType::MatchKind
-handleFormatSignedness(analyze_format_string::ArgType::MatchKind Match,
-                       DiagnosticsEngine &Diags, SourceLocation Loc) {
-  if (Match == analyze_format_string::ArgType::NoMatchSignedness) {
-    if (Diags.isIgnored(
-            diag::warn_format_conversion_argument_type_mismatch_signedness,
-            Loc) ||
-        Diags.isIgnored(
-            // Arbitrary -Wformat diagnostic to detect -Wno-format:
-            diag::warn_format_conversion_argument_type_mismatch, Loc)) {
-      return analyze_format_string::ArgType::Match;
-    }
-  }
-  return Match;
-}
-
-bool
-CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
-                                    const char *StartSpecifier,
-                                    unsigned SpecifierLen,
-                                    const Expr *E) {
-  using namespace analyze_format_string;
-  using namespace analyze_printf;
-
-  // Now type check the data expression that matches the
-  // format specifier.
-  const analyze_printf::ArgType &AT = FS.getArgType(S.Context, isObjCContext());
-  if (!AT.isValid())
-    return true;
-
-  QualType ExprTy = E->getType();
-  while (const TypeOfExprType *TET = dyn_cast<TypeOfExprType>(ExprTy)) {
-    ExprTy = TET->getUnderlyingExpr()->getType();
-  }
-
-  // When using the format attribute in C++, you can receive a function or an
-  // array that will necessarily decay to a pointer when passed to the final
-  // format consumer. Apply decay before type comparison.
-  if (ExprTy->canDecayToPointerType())
-    ExprTy = S.Context.getDecayedType(ExprTy);
-
-  // Diagnose attempts to print a boolean value as a character. Unlike other
-  // -Wformat diagnostics, this is fine from a type perspective, but it still
-  // doesn't make sense.
-  if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::cArg &&
-      E->isKnownToHaveBooleanValue()) {
-    const CharSourceRange &CSR =
-        getSpecifierRange(StartSpecifier, SpecifierLen);
-    SmallString<4> FSString;
-    llvm::raw_svector_ostream os(FSString);
-    FS.toString(os);
-    EmitFormatDiagnostic(S.PDiag(diag::warn_format_bool_as_character)
-                             << FSString,
-                         E->getExprLoc(), false, CSR);
-    return true;
-  }
-
-  // Diagnose attempts to use '%P' with ObjC object types, which will result in
-  // dumping raw class data (like is-a pointer), not actual data.
-  if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::PArg &&
-      ExprTy->isObjCObjectPointerType()) {
-    const CharSourceRange &CSR =
-        getSpecifierRange(StartSpecifier, SpecifierLen);
-    EmitFormatDiagnostic(S.PDiag(diag::warn_format_P_with_objc_pointer),
-                         E->getExprLoc(), false, CSR);
-    return true;
-  }
-
-  ArgType::MatchKind ImplicitMatch = ArgType::NoMatch;
-  ArgType::MatchKind Match = AT.matchesType(S.Context, ExprTy);
-  ArgType::MatchKind OrigMatch = Match;
-
-  Match = handleFormatSignedness(Match, S.getDiagnostics(), E->getExprLoc());
-  if (Match == ArgType::Match)
-    return true;
-
-  // NoMatchPromotionTypeConfusion should be only returned in ImplictCastExpr
-  assert(Match != ArgType::NoMatchPromotionTypeConfusion);
-
-  // Look through argument promotions for our error message's reported type.
-  // This includes the integral and floating promotions, but excludes array
-  // and function pointer decay (seeing that an argument intended to be a
-  // string has type 'char [6]' is probably more confusing than 'char *') and
-  // certain bitfield promotions (bitfields can be 'demoted' to a lesser type).
-  if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
-    if (isArithmeticArgumentPromotion(S, ICE)) {
-      E = ICE->getSubExpr();
-      ExprTy = E->getType();
-
-      // Check if we didn't match because of an implicit cast from a 'char'
-      // or 'short' to an 'int'.  This is done because printf is a varargs
-      // function.
-      if (ICE->getType() == S.Context.IntTy ||
-          ICE->getType() == S.Context.UnsignedIntTy) {
-        // All further checking is done on the subexpression
-        ImplicitMatch = AT.matchesType(S.Context, ExprTy);
-        if (OrigMatch == ArgType::NoMatchSignedness &&
-            ImplicitMatch != ArgType::NoMatchSignedness)
-          // If the original match was a signedness match this match on the
-          // implicit cast type also need to be signedness match otherwise we
-          // might introduce new unexpected warnings from -Wformat-signedness.
-          return true;
-        ImplicitMatch = handleFormatSignedness(
-            ImplicitMatch, S.getDiagnostics(), E->getExprLoc());
-        if (ImplicitMatch == ArgType::Match)
-          return true;
-      }
-    }
-  } else if (const CharacterLiteral *CL = dyn_cast<CharacterLiteral>(E)) {
-    // Special case for 'a', which has type 'int' in C.
-    // Note, however, that we do /not/ want to treat multibyte constants like
-    // 'MooV' as characters! This form is deprecated but still exists. In
-    // addition, don't treat expressions as of type 'char' if one byte length
-    // modifier is provided.
-    if (ExprTy == S.Context.IntTy &&
-        FS.getLengthModifier().getKind() != LengthModifier::AsChar)
-      if (llvm::isUIntN(S.Context.getCharWidth(), CL->getValue())) {
-        ExprTy = S.Context.CharTy;
-        // To improve check results, we consider a character literal in C
-        // to be a 'char' rather than an 'int'. 'printf("%hd", 'a');' is
-        // more likely a type confusion situation, so we will suggest to
-        // use '%hhd' instead by discarding the MatchPromotion.
-        if (Match == ArgType::MatchPromotion)
-          Match = ArgType::NoMatch;
-      }
-  }
-  if (Match == ArgType::MatchPromotion) {
-    // WG14 N2562 only clarified promotions in *printf
-    // For NSLog in ObjC, just preserve -Wformat behavior
-    if (!S.getLangOpts().ObjC &&
-        ImplicitMatch != ArgType::NoMatchPromotionTypeConfusion &&
-        ImplicitMatch != ArgType::NoMatchTypeConfusion)
-      return true;
-    Match = ArgType::NoMatch;
-  }
-  if (ImplicitMatch == ArgType::NoMatchPedantic ||
-      ImplicitMatch == ArgType::NoMatchTypeConfusion)
-    Match = ImplicitMatch;
-  assert(Match != ArgType::MatchPromotion);
-
-  // Look through unscoped enums to their underlying type.
-  bool IsEnum = false;
-  bool IsScopedEnum = false;
-  QualType IntendedTy = ExprTy;
-  if (const auto *ED = ExprTy->getAsEnumDecl()) {
-    IntendedTy = ED->getIntegerType();
-    if (!ED->isScoped()) {
-      ExprTy = IntendedTy;
-      // This controls whether we're talking about the underlying type or not,
-      // which we only want to do when it's an unscoped enum.
-      IsEnum = true;
-    } else {
-      IsScopedEnum = true;
-    }
-  }
-
-  // %C in an Objective-C context prints a unichar, not a wchar_t.
-  // If the argument is an integer of some kind, believe the %C and suggest
-  // a cast instead of changing the conversion specifier.
-  if (isObjCContext() &&
-      FS.getConversionSpecifier().getKind() == ConversionSpecifier::CArg) {
-    if (ExprTy->isIntegralOrUnscopedEnumerationType() &&
-        !ExprTy->isCharType()) {
-      // 'unichar' is defined as a typedef of unsigned short, but we should
-      // prefer using the typedef if it is visible.
-      IntendedTy = S.Context.UnsignedShortTy;
-
-      // While we are here, check if the value is an IntegerLiteral that happens
-      // to be within the valid range.
-      if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(E)) {
-        const llvm::APInt &V = IL->getValue();
-        if (V.getActiveBits() <= S.Context.getTypeSize(IntendedTy))
-          return true;
-      }
-
-      LookupResult Result(S, &S.Context.Idents.get("unichar"), E->getBeginLoc(),
-                          Sema::LookupOrdinaryName);
-      if (S.LookupName(Result, S.getCurScope())) {
-        NamedDecl *ND = Result.getFoundDecl();
-        if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(ND))
-          if (TD->getUnderlyingType() == IntendedTy)
-            IntendedTy =
-                S.Context.getTypedefType(ElaboratedTypeKeyword::None,
-                                         /*Qualifier=*/std::nullopt, TD);
-      }
-    }
-  }
-
-  // Special-case some of Darwin's platform-independence types by suggesting
-  // casts to primitive types that are known to be large enough.
-  bool ShouldNotPrintDirectly = false; StringRef CastTyName;
-  if (S.Context.getTargetInfo().getTriple().isOSDarwin()) {
-    QualType CastTy;
-    std::tie(CastTy, CastTyName) = shouldNotPrintDirectly(S.Context, IntendedTy, E);
-    if (!CastTy.isNull()) {
-      // %zi/%zu and %td/%tu are OK to use for NSInteger/NSUInteger of type int
-      // (long in ASTContext). Only complain to pedants or when they're the
-      // underlying type of a scoped enum (which always needs a cast).
-      if (!IsScopedEnum &&
-          (CastTyName == "NSInteger" || CastTyName == "NSUInteger") &&
-          (AT.isSizeT() || AT.isPtrdiffT()) &&
-          AT.matchesType(S.Context, CastTy))
-        Match = ArgType::NoMatchPedantic;
-      IntendedTy = CastTy;
-      ShouldNotPrintDirectly = true;
-    }
-  }
-
-  // We may be able to offer a FixItHint if it is a supported type.
-  PrintfSpecifier fixedFS = FS;
-  bool Success =
-      fixedFS.fixType(IntendedTy, S.getLangOpts(), S.Context, isObjCContext());
-
-  if (Success) {
-    // Get the fix string from the fixed format specifier
-    SmallString<16> buf;
-    llvm::raw_svector_ostream os(buf);
-    fixedFS.toString(os);
-
-    CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen);
-
-    if (IntendedTy == ExprTy && !ShouldNotPrintDirectly && !IsScopedEnum) {
-      unsigned Diag;
-      switch (Match) {
-      case ArgType::Match:
-      case ArgType::MatchPromotion:
-      case ArgType::NoMatchPromotionTypeConfusion:
-        llvm_unreachable("expected non-matching");
-      case ArgType::NoMatchSignedness:
-        Diag = diag::warn_format_conversion_argument_type_mismatch_signedness;
-        break;
-      case ArgType::NoMatchPedantic:
-        Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
-        break;
-      case ArgType::NoMatchTypeConfusion:
-        Diag = diag::warn_format_conversion_argument_type_mismatch_confusion;
-        break;
-      case ArgType::NoMatch:
-        Diag = diag::warn_format_conversion_argument_type_mismatch;
-        break;
-      }
-
-      // In this case, the specifier is wrong and should be changed to match
-      // the argument.
-      EmitFormatDiagnostic(S.PDiag(Diag)
-                               << AT.getRepresentativeTypeName(S.Context)
-                               << IntendedTy << IsEnum << E->getSourceRange(),
-                           E->getBeginLoc(),
-                           /*IsStringLocation*/ false, SpecRange,
-                           FixItHint::CreateReplacement(SpecRange, os.str()));
-    } else {
-      // The canonical type for formatting this value is different from the
-      // actual type of the expression. (This occurs, for example, with Darwin's
-      // NSInteger on 32-bit platforms, where it is typedef'd as 'int', but
-      // should be printed as 'long' for 64-bit compatibility.)
-      // Rather than emitting a normal format/argument mismatch, we want to
-      // add a cast to the recommended type (and correct the format string
-      // if necessary). We should also do so for scoped enumerations.
-      SmallString<16> CastBuf;
-      llvm::raw_svector_ostream CastFix(CastBuf);
-      CastFix << (S.LangOpts.CPlusPlus ? "static_cast<" : "(");
-      IntendedTy.print(CastFix, S.Context.getPrintingPolicy());
-      CastFix << (S.LangOpts.CPlusPlus ? ">" : ")");
-
-      SmallVector<FixItHint,4> Hints;
-      ArgType::MatchKind IntendedMatch = AT.matchesType(S.Context, IntendedTy);
-      IntendedMatch = handleFormatSignedness(IntendedMatch, S.getDiagnostics(),
-                                             E->getExprLoc());
-      if ((IntendedMatch != ArgType::Match) || ShouldNotPrintDirectly)
-        Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str()));
-
-      if (const CStyleCastExpr *CCast = dyn_cast<CStyleCastExpr>(E)) {
-        // If there's already a cast present, just replace it.
-        SourceRange CastRange(CCast->getLParenLoc(), CCast->getRParenLoc());
-        Hints.push_back(FixItHint::CreateReplacement(CastRange, CastFix.str()));
-
-      } else if (!requiresParensToAddCast(E) && !S.LangOpts.CPlusPlus) {
-        // If the expression has high enough precedence,
-        // just write the C-style cast.
-        Hints.push_back(
-            FixItHint::CreateInsertion(E->getBeginLoc(), CastFix.str()));
-      } else {
-        // Otherwise, add parens around the expression as well as the cast.
-        CastFix << "(";
-        Hints.push_back(
-            FixItHint::CreateInsertion(E->getBeginLoc(), CastFix.str()));
-
-        // We don't use getLocForEndOfToken because it returns invalid source
-        // locations for macro expansions (by design).
-        SourceLocation EndLoc = S.SourceMgr.getSpellingLoc(E->getEndLoc());
-        SourceLocation After = EndLoc.getLocWithOffset(
-            Lexer::MeasureTokenLength(EndLoc, S.SourceMgr, S.LangOpts));
-        Hints.push_back(FixItHint::CreateInsertion(After, ")"));
-      }
-
-      if (ShouldNotPrintDirectly && !IsScopedEnum) {
-        // The expression has a type that should not be printed directly.
-        // We extract the name from the typedef because we don't want to show
-        // the underlying type in the diagnostic.
-        StringRef Name;
-        if (const auto *TypedefTy = ExprTy->getAs<TypedefType>())
-          Name = TypedefTy->getDecl()->getName();
-        else
-          Name = CastTyName;
-        unsigned Diag = Match == ArgType::NoMatchPedantic
-                            ? diag::warn_format_argument_needs_cast_pedantic
-                            : diag::warn_format_argument_needs_cast;
-        EmitFormatDiagnostic(S.PDiag(Diag) << Name << IntendedTy << IsEnum
-                                           << E->getSourceRange(),
-                             E->getBeginLoc(), /*IsStringLocation=*/false,
-                             SpecRange, Hints);
-      } else {
-        // In this case, the expression could be printed using a different
-        // specifier, but we've decided that the specifier is probably correct
-        // and we should cast instead. Just use the normal warning message.
-
-        unsigned Diag =
-            IsScopedEnum
-                ? diag::warn_format_conversion_argument_type_mismatch_pedantic
-                : diag::warn_format_conversion_argument_type_mismatch;
-
-        EmitFormatDiagnostic(
-            S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy
-                          << IsEnum << E->getSourceRange(),
-            E->getBeginLoc(), /*IsStringLocation*/ false, SpecRange, Hints);
-      }
-    }
-  } else {
-    const CharSourceRange &CSR = getSpecifierRange(StartSpecifier,
-                                                   SpecifierLen);
-    // Since the warning for passing non-POD types to variadic functions
-    // was deferred until now, we emit a warning for non-POD
-    // arguments here.
-    bool EmitTypeMismatch = false;
-    switch (S.isValidVarArgType(ExprTy)) {
-    case VarArgKind::Valid:
-    case VarArgKind::ValidInCXX11: {
-      unsigned Diag;
-      switch (Match) {
-      case ArgType::Match:
-      case ArgType::MatchPromotion:
-      case ArgType::NoMatchPromotionTypeConfusion:
-        llvm_unreachable("expected non-matching");
-      case ArgType::NoMatchSignedness:
-        Diag = diag::warn_format_conversion_argument_type_mismatch_signedness;
-        break;
-      case ArgType::NoMatchPedantic:
-        Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
-        break;
-      case ArgType::NoMatchTypeConfusion:
-        Diag = diag::warn_format_conversion_argument_type_mismatch_confusion;
-        break;
-      case ArgType::NoMatch:
-        Diag = isInvalidOSLogArgTypeForCodeGen(FSType, ExprTy)
-                   ? diag::err_format_conversion_argument_type_mismatch
-                   : diag::warn_format_conversion_argument_type_mismatch;
-        break;
-      }
-
-      EmitFormatDiagnostic(
-          S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy
-                        << IsEnum << CSR << E->getSourceRange(),
-          E->getBeginLoc(), /*IsStringLocation*/ false, CSR);
-      break;
-    }
-    case VarArgKind::Undefined:
-    case VarArgKind::MSVCUndefined:
-      if (CallType == VariadicCallType::DoesNotApply) {
-        EmitTypeMismatch = true;
-      } else {
-        EmitFormatDiagnostic(
-            S.PDiag(diag::warn_non_pod_vararg_with_format_string)
-                << S.getLangOpts().CPlusPlus11 << ExprTy << CallType
-                << AT.getRepresentativeTypeName(S.Context) << CSR
-                << E->getSourceRange(),
-            E->getBeginLoc(), /*IsStringLocation*/ false, CSR);
-        checkForCStrMembers(AT, E);
-      }
-      break;
-
-    case VarArgKind::Invalid:
-      if (CallType == VariadicCallType::DoesNotApply)
-        EmitTypeMismatch = true;
-      else if (ExprTy->isObjCObjectType())
-        EmitFormatDiagnostic(
-            S.PDiag(diag::err_cannot_pass_objc_interface_to_vararg_format)
-                << S.getLangOpts().CPlusPlus11 << ExprTy << CallType
-                << AT.getRepresentativeTypeName(S.Context) << CSR
-                << E->getSourceRange(),
-            E->getBeginLoc(), /*IsStringLocation*/ false, CSR);
-      else
-        // FIXME: If this is an initializer list, suggest removing the braces
-        // or inserting a cast to the target type.
-        S.Diag(E->getBeginLoc(), diag::err_cannot_pass_to_vararg_format)
-            << isa<InitListExpr>(E) << ExprTy << CallType
-            << AT.getRepresentativeTypeName(S.Context) << E->getSourceRange();
-      break;
-    }
-
-    if (EmitTypeMismatch) {
-      // The function is not variadic, so we do not generate warnings about
-      // being allowed to pass that object as a variadic argument. Instead,
-      // since there are inherently no printf specifiers for types which cannot
-      // be passed as variadic arguments, emit a plain old specifier mismatch
-      // argument.
-      EmitFormatDiagnostic(
-          S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
-              << AT.getRepresentativeTypeName(S.Context) << ExprTy << false
-              << E->getSourceRange(),
-          E->getBeginLoc(), false, CSR);
-    }
-
-    assert(FirstDataArg + FS.getArgIndex() < CheckedVarArgs.size() &&
-           "format string specifier index out of range");
-    CheckedVarArgs[FirstDataArg + FS.getArgIndex()] = true;
-  }
-
-  return true;
-}
-
-//===--- CHECK: Scanf format string checking ------------------------------===//
-
-namespace {
-
-class CheckScanfHandler : public CheckFormatHandler {
-public:
-  CheckScanfHandler(Sema &s, const FormatStringLiteral *fexpr,
-                    const Expr *origFormatExpr, FormatStringType type,
-                    unsigned firstDataArg, unsigned numDataArgs,
-                    const char *beg, Sema::FormatArgumentPassingKind APK,
-                    ArrayRef<const Expr *> Args, unsigned formatIdx,
-                    bool inFunctionCall, VariadicCallType CallType,
-                    llvm::SmallBitVector &CheckedVarArgs,
-                    UncoveredArgHandler &UncoveredArg)
-      : CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg,
-                           numDataArgs, beg, APK, Args, formatIdx,
-                           inFunctionCall, CallType, CheckedVarArgs,
-                           UncoveredArg) {}
-
-  bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
-                            const char *startSpecifier,
-                            unsigned specifierLen) override;
-
-  bool HandleInvalidScanfConversionSpecifier(
-          const analyze_scanf::ScanfSpecifier &FS,
-          const char *startSpecifier,
-          unsigned specifierLen) override;
-
-  void HandleIncompleteScanList(const char *start, const char *end) override;
-};
-
-} // namespace
-
-void CheckScanfHandler::HandleIncompleteScanList(const char *start,
-                                                 const char *end) {
-  EmitFormatDiagnostic(S.PDiag(diag::warn_scanf_scanlist_incomplete),
-                       getLocationOfByte(end), /*IsStringLocation*/true,
-                       getSpecifierRange(start, end - start));
-}
-
-bool CheckScanfHandler::HandleInvalidScanfConversionSpecifier(
-                                        const analyze_scanf::ScanfSpecifier &FS,
-                                        const char *startSpecifier,
-                                        unsigned specifierLen) {
-  const analyze_scanf::ScanfConversionSpecifier &CS =
-    FS.getConversionSpecifier();
-
-  return HandleInvalidConversionSpecifier(FS.getArgIndex(),
-                                          getLocationOfByte(CS.getStart()),
-                                          startSpecifier, specifierLen,
-                                          CS.getStart(), CS.getLength());
-}
-
-bool CheckScanfHandler::HandleScanfSpecifier(
-                                       const analyze_scanf::ScanfSpecifier &FS,
-                                       const char *startSpecifier,
-                                       unsigned specifierLen) {
-  using namespace analyze_scanf;
-  using namespace analyze_format_string;
-
-  const ScanfConversionSpecifier &CS = FS.getConversionSpecifier();
-
-  // Handle case where '%' and '*' don't consume an argument.  These shouldn't
-  // be used to decide if we are using positional arguments consistently.
-  if (FS.consumesDataArgument()) {
-    if (atFirstArg) {
-      atFirstArg = false;
-      usesPositionalArgs = FS.usesPositionalArg();
-    }
-    else if (usesPositionalArgs != FS.usesPositionalArg()) {
-      HandlePositionalNonpositionalArgs(getLocationOfByte(CS.getStart()),
-                                        startSpecifier, specifierLen);
-      return false;
-    }
-  }
-
-  // Check if the field with is non-zero.
-  const OptionalAmount &Amt = FS.getFieldWidth();
-  if (Amt.getHowSpecified() == OptionalAmount::Constant) {
-    if (Amt.getConstantAmount() == 0) {
-      const CharSourceRange &R = getSpecifierRange(Amt.getStart(),
-                                                   Amt.getConstantLength());
-      EmitFormatDiagnostic(S.PDiag(diag::warn_scanf_nonzero_width),
-                           getLocationOfByte(Amt.getStart()),
-                           /*IsStringLocation*/true, R,
-                           FixItHint::CreateRemoval(R));
-    }
-  }
-
-  if (!FS.consumesDataArgument()) {
-    // FIXME: Technically specifying a precision or field width here
-    // makes no sense.  Worth issuing a warning at some point.
-    return true;
-  }
-
-  // Consume the argument.
-  unsigned argIndex = FS.getArgIndex();
-  if (argIndex < NumDataArgs) {
-      // The check to see if the argIndex is valid will come later.
-      // We set the bit here because we may exit early from this
-      // function if we encounter some other error.
-    CoveredArgs.set(argIndex);
-  }
-
-  // Check the length modifier is valid with the given conversion specifier.
-  if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo(),
-                                 S.getLangOpts()))
-    HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
-                                diag::warn_format_nonsensical_length);
-  else if (!FS.hasStandardLengthModifier())
-    HandleNonStandardLengthModifier(FS, startSpecifier, specifierLen);
-  else if (!FS.hasStandardLengthConversionCombination())
-    HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
-                                diag::warn_format_non_standard_conversion_spec);
-
-  if (!FS.hasStandardConversionSpecifier(S.getLangOpts()))
-    HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen);
-
-  // The remaining checks depend on the data arguments.
-  if (!HasFormatArguments())
-    return true;
-
-  if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex))
-    return false;
-
-  // Check that the argument type matches the format specifier.
-  const Expr *Ex = getDataArg(argIndex);
-  if (!Ex)
-    return true;
-
-  const analyze_format_string::ArgType &AT = FS.getArgType(S.Context);
-
-  if (!AT.isValid()) {
-    return true;
-  }
-
-  analyze_format_string::ArgType::MatchKind Match =
-      AT.matchesType(S.Context, Ex->getType());
-  Match = handleFormatSignedness(Match, S.getDiagnostics(), Ex->getExprLoc());
-  if (Match == analyze_format_string::ArgType::Match)
-    return true;
-  bool Pedantic = Match == analyze_format_string::ArgType::NoMatchPedantic;
-  bool Signedness = Match == analyze_format_string::ArgType::NoMatchSignedness;
-
-  ScanfSpecifier fixedFS = FS;
-  bool Success = fixedFS.fixType(Ex->getType(), Ex->IgnoreImpCasts()->getType(),
-                                 S.getLangOpts(), S.Context);
-
-  unsigned Diag =
-      Pedantic ? diag::warn_format_conversion_argument_type_mismatch_pedantic
-      : Signedness
-          ? diag::warn_format_conversion_argument_type_mismatch_signedness
-          : diag::warn_format_conversion_argument_type_mismatch;
-
-  if (Success) {
-    // Get the fix string from the fixed format specifier.
-    SmallString<128> buf;
-    llvm::raw_svector_ostream os(buf);
-    fixedFS.toString(os);
-
-    EmitFormatDiagnostic(
-        S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context)
-                      << Ex->getType() << false << Ex->getSourceRange(),
-        Ex->getBeginLoc(),
-        /*IsStringLocation*/ false,
-        getSpecifierRange(startSpecifier, specifierLen),
-        FixItHint::CreateReplacement(
-            getSpecifierRange(startSpecifier, specifierLen), os.str()));
-  } else {
-    EmitFormatDiagnostic(S.PDiag(Diag)
-                             << AT.getRepresentativeTypeName(S.Context)
-                             << Ex->getType() << false << Ex->getSourceRange(),
-                         Ex->getBeginLoc(),
-                         /*IsStringLocation*/ false,
-                         getSpecifierRange(startSpecifier, specifierLen));
-  }
-
-  return true;
-}
-
-static bool CompareFormatSpecifiers(Sema &S, const StringLiteral *Ref,
-                                    ArrayRef<EquatableFormatArgument> RefArgs,
-                                    const StringLiteral *Fmt,
-                                    ArrayRef<EquatableFormatArgument> FmtArgs,
-                                    const Expr *FmtExpr, bool InFunctionCall) {
-  bool HadError = false;
-  auto FmtIter = FmtArgs.begin(), FmtEnd = FmtArgs.end();
-  auto RefIter = RefArgs.begin(), RefEnd = RefArgs.end();
-  while (FmtIter < FmtEnd && RefIter < RefEnd) {
-    // In positional-style format strings, the same specifier can appear
-    // multiple times (like %2$i %2$d). Specifiers in both RefArgs and FmtArgs
-    // are sorted by getPosition(), and we process each range of equal
-    // getPosition() values as one group.
-    // RefArgs are taken from a string literal that was given to
-    // attribute(format_matches), and if we got this far, we have already
-    // verified that if it has positional specifiers that appear in multiple
-    // locations, then they are all mutually compatible. What's left for us to
-    // do is verify that all specifiers with the same position in FmtArgs are
-    // compatible with the RefArgs specifiers. We check each specifier from
-    // FmtArgs against the first member of the RefArgs group.
-    for (; FmtIter < FmtEnd; ++FmtIter) {
-      // Clang does not diagnose missing format specifiers in positional-style
-      // strings (TODO: which it probably should do, as it is UB to skip over a
-      // format argument). Skip specifiers if needed.
-      if (FmtIter->getPosition() < RefIter->getPosition())
-        continue;
-
-      // Delimits a new getPosition() value.
-      if (FmtIter->getPosition() > RefIter->getPosition())
-        break;
-
-      HadError |=
-          !FmtIter->VerifyCompatible(S, *RefIter, FmtExpr, InFunctionCall);
-    }
-
-    // Jump RefIter to the start of the next group.
-    RefIter = std::find_if(RefIter + 1, RefEnd, [=](const auto &Arg) {
-      return Arg.getPosition() != RefIter->getPosition();
-    });
-  }
-
-  if (FmtIter < FmtEnd) {
-    CheckFormatHandler::EmitFormatDiagnostic(
-        S, InFunctionCall, FmtExpr,
-        S.PDiag(diag::warn_format_cmp_specifier_arity) << 1,
-        FmtExpr->getBeginLoc(), false, FmtIter->getSourceRange());
-    HadError = S.Diag(Ref->getBeginLoc(), diag::note_format_cmp_with) << 1;
-  } else if (RefIter < RefEnd) {
-    CheckFormatHandler::EmitFormatDiagnostic(
-        S, InFunctionCall, FmtExpr,
-        S.PDiag(diag::warn_format_cmp_specifier_arity) << 0,
-        FmtExpr->getBeginLoc(), false, Fmt->getSourceRange());
-    HadError = S.Diag(Ref->getBeginLoc(), diag::note_format_cmp_with)
-               << 1 << RefIter->getSourceRange();
-  }
-  return !HadError;
-}
-
-static void CheckFormatString(
-    Sema &S, const FormatStringLiteral *FExpr,
-    const StringLiteral *ReferenceFormatString, const Expr *OrigFormatExpr,
-    ArrayRef<const Expr *> Args, Sema::FormatArgumentPassingKind APK,
-    unsigned format_idx, unsigned firstDataArg, FormatStringType Type,
-    bool inFunctionCall, VariadicCallType CallType,
-    llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg,
-    bool IgnoreStringsWithoutSpecifiers) {
-  // CHECK: is the format string a wide literal?
-  if (!FExpr->isAscii() && !FExpr->isUTF8()) {
-    CheckFormatHandler::EmitFormatDiagnostic(
-        S, inFunctionCall, Args[format_idx],
-        S.PDiag(diag::warn_format_string_is_wide_literal), FExpr->getBeginLoc(),
-        /*IsStringLocation*/ true, OrigFormatExpr->getSourceRange());
-    return;
-  }
-
-  // Str - The format string.  NOTE: this is NOT null-terminated!
-  StringRef StrRef = FExpr->getString();
-  const char *Str = StrRef.data();
-  // Account for cases where the string literal is truncated in a declaration.
-  const ConstantArrayType *T =
-    S.Context.getAsConstantArrayType(FExpr->getType());
-  assert(T && "String literal not of constant array type!");
-  size_t TypeSize = T->getZExtSize();
-  size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size());
-  const unsigned numDataArgs = Args.size() - firstDataArg;
-
-  if (IgnoreStringsWithoutSpecifiers &&
-      !analyze_format_string::parseFormatStringHasFormattingSpecifiers(
-          Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo()))
-    return;
-
-  // Emit a warning if the string literal is truncated and does not contain an
-  // embedded null character.
-  if (TypeSize <= StrRef.size() && !StrRef.substr(0, TypeSize).contains('\0')) {
-    CheckFormatHandler::EmitFormatDiagnostic(
-        S, inFunctionCall, Args[format_idx],
-        S.PDiag(diag::warn_printf_format_string_not_null_terminated),
-        FExpr->getBeginLoc(),
-        /*IsStringLocation=*/true, OrigFormatExpr->getSourceRange());
-    return;
-  }
-
-  // CHECK: empty format string?
-  if (StrLen == 0 && numDataArgs > 0) {
-    CheckFormatHandler::EmitFormatDiagnostic(
-        S, inFunctionCall, Args[format_idx],
-        S.PDiag(diag::warn_empty_format_string), FExpr->getBeginLoc(),
-        /*IsStringLocation*/ true, OrigFormatExpr->getSourceRange());
-    return;
-  }
-
-  if (Type == FormatStringType::Printf || Type == FormatStringType::NSString ||
-      Type == FormatStringType::Kprintf ||
-      Type == FormatStringType::FreeBSDKPrintf ||
-      Type == FormatStringType::OSLog || Type == FormatStringType::OSTrace) {
-    bool IsObjC =
-        Type == FormatStringType::NSString || Type == FormatStringType::OSTrace;
-    if (ReferenceFormatString == nullptr) {
-      CheckPrintfHandler H(S, FExpr, OrigFormatExpr, Type, firstDataArg,
-                           numDataArgs, IsObjC, Str, APK, Args, format_idx,
-                           inFunctionCall, CallType, CheckedVarArgs,
-                           UncoveredArg);
-
-      if (!analyze_format_string::ParsePrintfString(
-              H, Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo(),
-              Type == FormatStringType::Kprintf ||
-                  Type == FormatStringType::FreeBSDKPrintf))
-        H.DoneProcessing();
-    } else {
-      S.CheckFormatStringsCompatible(
-          Type, ReferenceFormatString, FExpr->getFormatString(),
-          inFunctionCall ? nullptr : Args[format_idx]);
-    }
-  } else if (Type == FormatStringType::Scanf) {
-    CheckScanfHandler H(S, FExpr, OrigFormatExpr, Type, firstDataArg,
-                        numDataArgs, Str, APK, Args, format_idx, inFunctionCall,
-                        CallType, CheckedVarArgs, UncoveredArg);
-
-    if (!analyze_format_string::ParseScanfString(
-            H, Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo()))
-      H.DoneProcessing();
-  } // TODO: handle other formats
-}
-
-bool Sema::CheckFormatStringsCompatible(
-    FormatStringType Type, const StringLiteral *AuthoritativeFormatString,
-    const StringLiteral *TestedFormatString, const Expr *FunctionCallArg) {
-  if (Type != FormatStringType::Printf && Type != FormatStringType::NSString &&
-      Type != FormatStringType::Kprintf &&
-      Type != FormatStringType::FreeBSDKPrintf &&
-      Type != FormatStringType::OSLog && Type != FormatStringType::OSTrace)
-    return true;
-
-  bool IsObjC =
-      Type == FormatStringType::NSString || Type == FormatStringType::OSTrace;
-  llvm::SmallVector<EquatableFormatArgument, 9> RefArgs, FmtArgs;
-  FormatStringLiteral RefLit = AuthoritativeFormatString;
-  FormatStringLiteral TestLit = TestedFormatString;
-  const Expr *Arg;
-  bool DiagAtStringLiteral;
-  if (FunctionCallArg) {
-    Arg = FunctionCallArg;
-    DiagAtStringLiteral = false;
-  } else {
-    Arg = TestedFormatString;
-    DiagAtStringLiteral = true;
-  }
-  if (DecomposePrintfHandler::GetSpecifiers(*this, &RefLit,
-                                            AuthoritativeFormatString, Type,
-                                            IsObjC, true, RefArgs) &&
-      DecomposePrintfHandler::GetSpecifiers(*this, &TestLit, Arg, Type, IsObjC,
-                                            DiagAtStringLiteral, FmtArgs)) {
-    return CompareFormatSpecifiers(*this, AuthoritativeFormatString, RefArgs,
-                                   TestedFormatString, FmtArgs, Arg,
-                                   DiagAtStringLiteral);
-  }
-  return false;
-}
-
-bool Sema::ValidateFormatString(FormatStringType Type,
-                                const StringLiteral *Str) {
-  if (Type != FormatStringType::Printf && Type != FormatStringType::NSString &&
-      Type != FormatStringType::Kprintf &&
-      Type != FormatStringType::FreeBSDKPrintf &&
-      Type != FormatStringType::OSLog && Type != FormatStringType::OSTrace)
-    return true;
-
-  FormatStringLiteral RefLit = Str;
-  llvm::SmallVector<EquatableFormatArgument, 9> Args;
-  bool IsObjC =
-      Type == FormatStringType::NSString || Type == FormatStringType::OSTrace;
-  if (!DecomposePrintfHandler::GetSpecifiers(*this, &RefLit, Str, Type, IsObjC,
-                                             true, Args))
-    return false;
-
-  // Group arguments by getPosition() value, and check that each member of the
-  // group is compatible with the first member. This verifies that when
-  // positional arguments are used multiple times (such as %2$i %2$d), all uses
-  // are mutually compatible. As an optimization, don't test the first member
-  // against itself.
-  bool HadError = false;
-  auto Iter = Args.begin();
-  auto End = Args.end();
-  while (Iter != End) {
-    const auto &FirstInGroup = *Iter;
-    for (++Iter;
-         Iter != End && Iter->getPosition() == FirstInGroup.getPosition();
-         ++Iter) {
-      HadError |= !Iter->VerifyCompatible(*this, FirstInGroup, Str, true);
-    }
-  }
-  return !HadError;
-}
-
-bool Sema::FormatStringHasSArg(const StringLiteral *FExpr) {
-  // Str - The format string.  NOTE: this is NOT null-terminated!
-  StringRef StrRef = FExpr->getString();
-  const char *Str = StrRef.data();
-  // Account for cases where the string literal is truncated in a declaration.
-  const ConstantArrayType *T = Context.getAsConstantArrayType(FExpr->getType());
-  assert(T && "String literal not of constant array type!");
-  size_t TypeSize = T->getZExtSize();
-  size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size());
-  return analyze_format_string::ParseFormatStringHasSArg(Str, Str + StrLen,
-                                                         getLangOpts(),
-                                                         Context.getTargetInfo());
-}
-
-//===--- CHECK: Warn on use of wrong absolute value function. -------------===//
-
-// Returns the related absolute value function that is larger, of 0 if one
-// does not exist.
-static unsigned getLargerAbsoluteValueFunction(unsigned AbsFunction) {
-  switch (AbsFunction) {
-  default:
-    return 0;
-
-  case Builtin::BI__builtin_abs:
-    return Builtin::BI__builtin_labs;
-  case Builtin::BI__builtin_labs:
-    return Builtin::BI__builtin_llabs;
-  case Builtin::BI__builtin_llabs:
-    return 0;
-
-  case Builtin::BI__builtin_fabsf:
-    return Builtin::BI__builtin_fabs;
-  case Builtin::BI__builtin_fabs:
-    return Builtin::BI__builtin_fabsl;
-  case Builtin::BI__builtin_fabsl:
-    return 0;
-
-  case Builtin::BI__builtin_cabsf:
-    return Builtin::BI__builtin_cabs;
-  case Builtin::BI__builtin_cabs:
-    return Builtin::BI__builtin_cabsl;
-  case Builtin::BI__builtin_cabsl:
-    return 0;
-
-  case Builtin::BIabs:
-    return Builtin::BIlabs;
-  case Builtin::BIlabs:
-    return Builtin::BIllabs;
-  case Builtin::BIllabs:
-    return 0;
-
-  case Builtin::BIfabsf:
-    return Builtin::BIfabs;
-  case Builtin::BIfabs:
-    return Builtin::BIfabsl;
-  case Builtin::BIfabsl:
-    return 0;
-
-  case Builtin::BIcabsf:
-   return Builtin::BIcabs;
-  case Builtin::BIcabs:
-    return Builtin::BIcabsl;
-  case Builtin::BIcabsl:
-    return 0;
-  }
-}
-
-// Returns the argument type of the absolute value function.
-static QualType getAbsoluteValueArgumentType(ASTContext &Context,
-                                             unsigned AbsType) {
-  if (AbsType == 0)
-    return QualType();
-
-  ASTContext::GetBuiltinTypeError Error = ASTContext::GE_None;
-  QualType BuiltinType = Context.GetBuiltinType(AbsType, Error);
-  if (Error != ASTContext::GE_None)
-    return QualType();
-
-  const FunctionProtoType *FT = BuiltinType->getAs<FunctionProtoType>();
-  if (!FT)
-    return QualType();
-
-  if (FT->getNumParams() != 1)
-    return QualType();
-
-  return FT->getParamType(0);
-}
-
-// Returns the best absolute value function, or zero, based on type and
-// current absolute value function.
-static unsigned getBestAbsFunction(ASTContext &Context, QualType ArgType,
-                                   unsigned AbsFunctionKind) {
-  unsigned BestKind = 0;
-  uint64_t ArgSize = Context.getTypeSize(ArgType);
-  for (unsigned Kind = AbsFunctionKind; Kind != 0;
-       Kind = getLargerAbsoluteValueFunction(Kind)) {
-    QualType ParamType = getAbsoluteValueArgumentType(Context, Kind);
-    if (Context.getTypeSize(ParamType) >= ArgSize) {
-      if (BestKind == 0)
-        BestKind = Kind;
-      else if (Context.hasSameType(ParamType, ArgType)) {
-        BestKind = Kind;
-        break;
-      }
-    }
-  }
-  return BestKind;
-}
-
-enum AbsoluteValueKind {
-  AVK_Integer,
-  AVK_Floating,
-  AVK_Complex
-};
-
-static AbsoluteValueKind getAbsoluteValueKind(QualType T) {
-  if (T->isIntegralOrEnumerationType())
-    return AVK_Integer;
-  if (T->isRealFloatingType())
-    return AVK_Floating;
-  if (T->isAnyComplexType())
-    return AVK_Complex;
-
-  llvm_unreachable("Type not integer, floating, or complex");
-}
-
-// Changes the absolute value function to a different type.  Preserves whether
-// the function is a builtin.
-static unsigned changeAbsFunction(unsigned AbsKind,
-                                  AbsoluteValueKind ValueKind) {
-  switch (ValueKind) {
-  case AVK_Integer:
-    switch (AbsKind) {
-    default:
-      return 0;
-    case Builtin::BI__builtin_fabsf:
-    case Builtin::BI__builtin_fabs:
-    case Builtin::BI__builtin_fabsl:
-    case Builtin::BI__builtin_cabsf:
-    case Builtin::BI__builtin_cabs:
-    case Builtin::BI__builtin_cabsl:
-      return Builtin::BI__builtin_abs;
-    case Builtin::BIfabsf:
-    case Builtin::BIfabs:
-    case Builtin::BIfabsl:
-    case Builtin::BIcabsf:
-    case Builtin::BIcabs:
-    case Builtin::BIcabsl:
-      return Builtin::BIabs;
-    }
-  case AVK_Floating:
-    switch (AbsKind) {
-    default:
-      return 0;
-    case Builtin::BI__builtin_abs:
-    case Builtin::BI__builtin_labs:
-    case Builtin::BI__builtin_llabs:
-    case Builtin::BI__builtin_cabsf:
-    case Builtin::BI__builtin_cabs:
-    case Builtin::BI__builtin_cabsl:
-      return Builtin::BI__builtin_fabsf;
-    case Builtin::BIabs:
-    case Builtin::BIlabs:
-    case Builtin::BIllabs:
-    case Builtin::BIcabsf:
-    case Builtin::BIcabs:
-    case Builtin::BIcabsl:
-      return Builtin::BIfabsf;
-    }
-  case AVK_Complex:
-    switch (AbsKind) {
-    default:
-      return 0;
-    case Builtin::BI__builtin_abs:
-    case Builtin::BI__builtin_labs:
-    case Builtin::BI__builtin_llabs:
-    case Builtin::BI__builtin_fabsf:
-    case Builtin::BI__builtin_fabs:
-    case Builtin::BI__builtin_fabsl:
-      return Builtin::BI__builtin_cabsf;
-    case Builtin::BIabs:
-    case Builtin::BIlabs:
-    case Builtin::BIllabs:
-    case Builtin::BIfabsf:
-    case Builtin::BIfabs:
-    case Builtin::BIfabsl:
-      return Builtin::BIcabsf;
-    }
-  }
-  llvm_unreachable("Unable to convert function");
-}
-
-static unsigned getAbsoluteValueFunctionKind(const FunctionDecl *FDecl) {
-  const IdentifierInfo *FnInfo = FDecl->getIdentifier();
-  if (!FnInfo)
-    return 0;
-
-  switch (FDecl->getBuiltinID()) {
-  default:
-    return 0;
-  case Builtin::BI__builtin_abs:
-  case Builtin::BI__builtin_fabs:
-  case Builtin::BI__builtin_fabsf:
-  case Builtin::BI__builtin_fabsl:
-  case Builtin::BI__builtin_labs:
-  case Builtin::BI__builtin_llabs:
-  case Builtin::BI__builtin_cabs:
-  case Builtin::BI__builtin_cabsf:
-  case Builtin::BI__builtin_cabsl:
-  case Builtin::BIabs:
-  case Builtin::BIlabs:
-  case Builtin::BIllabs:
-  case Builtin::BIfabs:
-  case Builtin::BIfabsf:
-  case Builtin::BIfabsl:
-  case Builtin::BIcabs:
-  case Builtin::BIcabsf:
-  case Builtin::BIcabsl:
-    return FDecl->getBuiltinID();
-  }
-  llvm_unreachable("Unknown Builtin type");
-}
-
-// If the replacement is valid, emit a note with replacement function.
-// Additionally, suggest including the proper header if not already included.
-static void emitReplacement(Sema &S, SourceLocation Loc, SourceRange Range,
-                            unsigned AbsKind, QualType ArgType) {
-  bool EmitHeaderHint = true;
-  const char *HeaderName = nullptr;
-  std::string FunctionName;
-  if (S.getLangOpts().CPlusPlus && !ArgType->isAnyComplexType()) {
-    FunctionName = "std::abs";
-    if (ArgType->isIntegralOrEnumerationType()) {
-      HeaderName = "cstdlib";
-    } else if (ArgType->isRealFloatingType()) {
-      HeaderName = "cmath";
-    } else {
-      llvm_unreachable("Invalid Type");
-    }
-
-    // Lookup all std::abs
-    if (NamespaceDecl *Std = S.getStdNamespace()) {
-      LookupResult R(S, &S.Context.Idents.get("abs"), Loc, Sema::LookupAnyName);
-      R.suppressDiagnostics();
-      S.LookupQualifiedName(R, Std);
-
-      for (const auto *I : R) {
-        const FunctionDecl *FDecl = nullptr;
-        if (const UsingShadowDecl *UsingD = dyn_cast<UsingShadowDecl>(I)) {
-          FDecl = dyn_cast<FunctionDecl>(UsingD->getTargetDecl());
-        } else {
-          FDecl = dyn_cast<FunctionDecl>(I);
-        }
-        if (!FDecl)
-          continue;
-
-        // Found std::abs(), check that they are the right ones.
-        if (FDecl->getNumParams() != 1)
-          continue;
-
-        // Check that the parameter type can handle the argument.
-        QualType ParamType = FDecl->getParamDecl(0)->getType();
-        if (getAbsoluteValueKind(ArgType) == getAbsoluteValueKind(ParamType) &&
-            S.Context.getTypeSize(ArgType) <=
-                S.Context.getTypeSize(ParamType)) {
-          // Found a function, don't need the header hint.
-          EmitHeaderHint = false;
-          break;
-        }
-      }
-    }
-  } else {
-    FunctionName = S.Context.BuiltinInfo.getName(AbsKind);
-    HeaderName = S.Context.BuiltinInfo.getHeaderName(AbsKind);
-
-    if (HeaderName) {
-      DeclarationName DN(&S.Context.Idents.get(FunctionName));
-      LookupResult R(S, DN, Loc, Sema::LookupAnyName);
-      R.suppressDiagnostics();
-      S.LookupName(R, S.getCurScope());
-
-      if (R.isSingleResult()) {
-        FunctionDecl *FD = dyn_cast<FunctionDecl>(R.getFoundDecl());
-        if (FD && FD->getBuiltinID() == AbsKind) {
-          EmitHeaderHint = false;
-        } else {
-          return;
-        }
-      } else if (!R.empty()) {
-        return;
-      }
-    }
-  }
-
-  S.Diag(Loc, diag::note_replace_abs_function)
-      << FunctionName << FixItHint::CreateReplacement(Range, FunctionName);
-
-  if (!HeaderName)
-    return;
-
-  if (!EmitHeaderHint)
-    return;
-
-  S.Diag(Loc, diag::note_include_header_or_declare) << HeaderName
-                                                    << FunctionName;
-}
-
-template <std::size_t StrLen>
-static bool IsStdFunction(const FunctionDecl *FDecl,
-                          const char (&Str)[StrLen]) {
-  if (!FDecl)
-    return false;
-  if (!FDecl->getIdentifier() || !FDecl->getIdentifier()->isStr(Str))
-    return false;
-  if (!FDecl->isInStdNamespace())
-    return false;
-
-  return true;
-}
-
-enum class MathCheck { NaN, Inf };
-static bool IsInfOrNanFunction(StringRef calleeName, MathCheck Check) {
-  auto MatchesAny = [&](std::initializer_list<llvm::StringRef> names) {
-    return llvm::is_contained(names, calleeName);
-  };
-
-  switch (Check) {
-  case MathCheck::NaN:
-    return MatchesAny({"__builtin_nan", "__builtin_nanf", "__builtin_nanl",
-                       "__builtin_nanf16", "__builtin_nanf128"});
-  case MathCheck::Inf:
-    return MatchesAny({"__builtin_inf", "__builtin_inff", "__builtin_infl",
-                       "__builtin_inff16", "__builtin_inff128"});
-  }
-  llvm_unreachable("unknown MathCheck");
-}
-
-static bool IsInfinityFunction(const FunctionDecl *FDecl) {
-  if (FDecl->getName() != "infinity")
-    return false;
-
-  if (const CXXMethodDecl *MDecl = dyn_cast<CXXMethodDecl>(FDecl)) {
-    const CXXRecordDecl *RDecl = MDecl->getParent();
-    if (RDecl->getName() != "numeric_limits")
-      return false;
-
-    if (const NamespaceDecl *NSDecl =
-            dyn_cast<NamespaceDecl>(RDecl->getDeclContext()))
-      return NSDecl->isStdNamespace();
-  }
-
-  return false;
-}
-
-void Sema::CheckInfNaNFunction(const CallExpr *Call,
-                               const FunctionDecl *FDecl) {
-  if (!FDecl->getIdentifier())
-    return;
-
-  FPOptions FPO = Call->getFPFeaturesInEffect(getLangOpts());
-  if (FPO.getNoHonorNaNs() &&
-      (IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered") ||
-       IsInfOrNanFunction(FDecl->getName(), MathCheck::NaN))) {
-    Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled)
-        << 1 << 0 << Call->getSourceRange();
-    return;
-  }
-
-  if (FPO.getNoHonorInfs() &&
-      (IsStdFunction(FDecl, "isinf") || IsStdFunction(FDecl, "isfinite") ||
-       IsInfinityFunction(FDecl) ||
-       IsInfOrNanFunction(FDecl->getName(), MathCheck::Inf))) {
-    Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled)
-        << 0 << 0 << Call->getSourceRange();
-  }
-}
-
-void Sema::CheckAbsoluteValueFunction(const CallExpr *Call,
-                                      const FunctionDecl *FDecl) {
-  if (Call->getNumArgs() != 1)
-    return;
-
-  unsigned AbsKind = getAbsoluteValueFunctionKind(FDecl);
-  bool IsStdAbs = IsStdFunction(FDecl, "abs");
-  if (AbsKind == 0 && !IsStdAbs)
-    return;
-
-  QualType ArgType = Call->getArg(0)->IgnoreParenImpCasts()->getType();
-  QualType ParamType = Call->getArg(0)->getType();
-
-  // Unsigned types cannot be negative.  Suggest removing the absolute value
-  // function call.
-  if (ArgType->isUnsignedIntegerType()) {
-    std::string FunctionName =
-        IsStdAbs ? "std::abs" : Context.BuiltinInfo.getName(AbsKind);
-    Diag(Call->getExprLoc(), diag::warn_unsigned_abs) << ArgType << ParamType;
-    Diag(Call->getExprLoc(), diag::note_remove_abs)
-        << FunctionName
-        << FixItHint::CreateRemoval(Call->getCallee()->getSourceRange());
-    return;
-  }
-
-  // Taking the absolute value of a pointer is very suspicious, they probably
-  // wanted to index into an array, dereference a pointer, call a function, etc.
-  if (ArgType->isPointerType() || ArgType->canDecayToPointerType()) {
-    unsigned DiagType = 0;
-    if (ArgType->isFunctionType())
-      DiagType = 1;
-    else if (ArgType->isArrayType())
-      DiagType = 2;
-
-    Diag(Call->getExprLoc(), diag::warn_pointer_abs) << DiagType << ArgType;
-    return;
-  }
-
-  // std::abs has overloads which prevent most of the absolute value problems
-  // from occurring.
-  if (IsStdAbs)
-    return;
-
-  AbsoluteValueKind ArgValueKind = getAbsoluteValueKind(ArgType);
-  AbsoluteValueKind ParamValueKind = getAbsoluteValueKind(ParamType);
-
-  // The argument and parameter are the same kind.  Check if they are the right
-  // size.
-  if (ArgValueKind == ParamValueKind) {
-    if (Context.getTypeSize(ArgType) <= Context.getTypeSize(ParamType))
-      return;
-
-    unsigned NewAbsKind = getBestAbsFunction(Context, ArgType, AbsKind);
-    Diag(Call->getExprLoc(), diag::warn_abs_too_small)
-        << FDecl << ArgType << ParamType;
-
-    if (NewAbsKind == 0)
-      return;
-
-    emitReplacement(*this, Call->getExprLoc(),
-                    Call->getCallee()->getSourceRange(), NewAbsKind, ArgType);
-    return;
-  }
-
-  // ArgValueKind != ParamValueKind
-  // The wrong type of absolute value function was used.  Attempt to find the
-  // proper one.
-  unsigned NewAbsKind = changeAbsFunction(AbsKind, ArgValueKind);
-  NewAbsKind = getBestAbsFunction(Context, ArgType, NewAbsKind);
-  if (NewAbsKind == 0)
-    return;
-
-  Diag(Call->getExprLoc(), diag::warn_wrong_absolute_value_type)
-      << FDecl << ParamValueKind << ArgValueKind;
-
-  emitReplacement(*this, Call->getExprLoc(),
-                  Call->getCallee()->getSourceRange(), NewAbsKind, ArgType);
-}
-
-//===--- CHECK: Warn on use of std::max and unsigned zero. r---------------===//
-void Sema::CheckMaxUnsignedZero(const CallExpr *Call,
-                                const FunctionDecl *FDecl) {
-  if (!Call || !FDecl) return;
-
-  // Ignore template specializations and macros.
-  if (inTemplateInstantiation()) return;
-  if (Call->getExprLoc().isMacroID()) return;
-
-  // Only care about the one template argument, two function parameter std::max
-  if (Call->getNumArgs() != 2) return;
-  if (!IsStdFunction(FDecl, "max")) return;
-  const auto * ArgList = FDecl->getTemplateSpecializationArgs();
-  if (!ArgList) return;
-  if (ArgList->size() != 1) return;
-
-  // Check that template type argument is unsigned integer.
-  const auto& TA = ArgList->get(0);
-  if (TA.getKind() != TemplateArgument::Type) return;
-  QualType ArgType = TA.getAsType();
-  if (!ArgType->isUnsignedIntegerType()) return;
-
-  // See if either argument is a literal zero.
-  auto IsLiteralZeroArg = [](const Expr* E) -> bool {
-    const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E);
-    if (!MTE) return false;
-    const auto *Num = dyn_cast<IntegerLiteral>(MTE->getSubExpr());
-    if (!Num) return false;
-    if (Num->getValue() != 0) return false;
-    return true;
-  };
-
-  const Expr *FirstArg = Call->getArg(0);
-  const Expr *SecondArg = Call->getArg(1);
-  const bool IsFirstArgZero = IsLiteralZeroArg(FirstArg);
-  const bool IsSecondArgZero = IsLiteralZeroArg(SecondArg);
-
-  // Only warn when exactly one argument is zero.
-  if (IsFirstArgZero == IsSecondArgZero) return;
-
-  SourceRange FirstRange = FirstArg->getSourceRange();
-  SourceRange SecondRange = SecondArg->getSourceRange();
-
-  SourceRange ZeroRange = IsFirstArgZero ? FirstRange : SecondRange;
-
-  Diag(Call->getExprLoc(), diag::warn_max_unsigned_zero)
-      << IsFirstArgZero << Call->getCallee()->getSourceRange() << ZeroRange;
-
-  // Deduce what parts to remove so that "std::max(0u, foo)" becomes "(foo)".
-  SourceRange RemovalRange;
-  if (IsFirstArgZero) {
-    RemovalRange = SourceRange(FirstRange.getBegin(),
-                               SecondRange.getBegin().getLocWithOffset(-1));
-  } else {
-    RemovalRange = SourceRange(getLocForEndOfToken(FirstRange.getEnd()),
-                               SecondRange.getEnd());
-  }
-
-  Diag(Call->getExprLoc(), diag::note_remove_max_call)
-        << FixItHint::CreateRemoval(Call->getCallee()->getSourceRange())
-        << FixItHint::CreateRemoval(RemovalRange);
-}
-
-//===--- CHECK: Standard memory functions ---------------------------------===//
-
-/// Takes the expression passed to the size_t parameter of functions
-/// such as memcmp, strncat, etc and warns if it's a comparison.
-///
-/// This is to catch typos like `if (memcmp(&a, &b, sizeof(a) > 0))`.
-static bool CheckMemorySizeofForComparison(Sema &S, const Expr *E,
-                                           const IdentifierInfo *FnName,
-                                           SourceLocation FnLoc,
-                                           SourceLocation RParenLoc) {
-  const auto *Size = dyn_cast<BinaryOperator>(E);
-  if (!Size)
-    return false;
-
-  // if E is binop and op is <=>, >, <, >=, <=, ==, &&, ||:
-  if (!Size->isComparisonOp() && !Size->isLogicalOp())
-    return false;
-
-  SourceRange SizeRange = Size->getSourceRange();
-  S.Diag(Size->getOperatorLoc(), diag::warn_memsize_comparison)
-      << SizeRange << FnName;
-  S.Diag(FnLoc, diag::note_memsize_comparison_paren)
-      << FnName
-      << FixItHint::CreateInsertion(
-             S.getLocForEndOfToken(Size->getLHS()->getEndLoc()), ")")
-      << FixItHint::CreateRemoval(RParenLoc);
-  S.Diag(SizeRange.getBegin(), diag::note_memsize_comparison_cast_silence)
-      << FixItHint::CreateInsertion(SizeRange.getBegin(), "(size_t)(")
-      << FixItHint::CreateInsertion(S.getLocForEndOfToken(SizeRange.getEnd()),
-                                    ")");
-
-  return true;
-}
-
-/// Determine whether the given type is or contains a dynamic class type
-/// (e.g., whether it has a vtable).
-static const CXXRecordDecl *getContainedDynamicClass(QualType T,
-                                                     bool &IsContained) {
-  // Look through array types while ignoring qualifiers.
-  const Type *Ty = T->getBaseElementTypeUnsafe();
-  IsContained = false;
-
-  const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
-  RD = RD ? RD->getDefinition() : nullptr;
-  if (!RD || RD->isInvalidDecl())
-    return nullptr;
-
-  if (RD->isDynamicClass())
-    return RD;
-
-  // Check all the fields.  If any bases were dynamic, the class is dynamic.
-  // It's impossible for a class to transitively contain itself by value, so
-  // infinite recursion is impossible.
-  for (auto *FD : RD->fields()) {
-    bool SubContained;
-    if (const CXXRecordDecl *ContainedRD =
-            getContainedDynamicClass(FD->getType(), SubContained)) {
-      IsContained = true;
-      return ContainedRD;
-    }
-  }
-
-  return nullptr;
-}
-
-static const UnaryExprOrTypeTraitExpr *getAsSizeOfExpr(const Expr *E) {
-  if (const auto *Unary = dyn_cast<UnaryExprOrTypeTraitExpr>(E))
-    if (Unary->getKind() == UETT_SizeOf)
-      return Unary;
-  return nullptr;
-}
-
-/// If E is a sizeof expression, returns its argument expression,
-/// otherwise returns NULL.
-static const Expr *getSizeOfExprArg(const Expr *E) {
-  if (const UnaryExprOrTypeTraitExpr *SizeOf = getAsSizeOfExpr(E))
-    if (!SizeOf->isArgumentType())
-      return SizeOf->getArgumentExpr()->IgnoreParenImpCasts();
-  return nullptr;
-}
-
-/// If E is a sizeof expression, returns its argument type.
-static QualType getSizeOfArgType(const Expr *E) {
-  if (const UnaryExprOrTypeTraitExpr *SizeOf = getAsSizeOfExpr(E))
-    return SizeOf->getTypeOfArgument();
-  return QualType();
-}
-
-namespace {
-
-struct SearchNonTrivialToInitializeField
-    : DefaultInitializedTypeVisitor<SearchNonTrivialToInitializeField> {
-  using Super =
-      DefaultInitializedTypeVisitor<SearchNonTrivialToInitializeField>;
-
-  SearchNonTrivialToInitializeField(const Expr *E, Sema &S) : E(E), S(S) {}
-
-  void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType FT,
-                     SourceLocation SL) {
-    if (const auto *AT = asDerived().getContext().getAsArrayType(FT)) {
-      asDerived().visitArray(PDIK, AT, SL);
-      return;
-    }
-
-    Super::visitWithKind(PDIK, FT, SL);
-  }
-
-  void visitARCStrong(QualType FT, SourceLocation SL) {
-    S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 1);
-  }
-  void visitARCWeak(QualType FT, SourceLocation SL) {
-    S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 1);
-  }
-  void visitStruct(QualType FT, SourceLocation SL) {
-    for (const FieldDecl *FD : FT->castAsRecordDecl()->fields())
-      visit(FD->getType(), FD->getLocation());
-  }
-  void visitArray(QualType::PrimitiveDefaultInitializeKind PDIK,
-                  const ArrayType *AT, SourceLocation SL) {
-    visit(getContext().getBaseElementType(AT), SL);
-  }
-  void visitTrivial(QualType FT, SourceLocation SL) {}
-
-  static void diag(QualType RT, const Expr *E, Sema &S) {
-    SearchNonTrivialToInitializeField(E, S).visitStruct(RT, SourceLocation());
-  }
-
-  ASTContext &getContext() { return S.getASTContext(); }
-
-  const Expr *E;
-  Sema &S;
-};
-
-struct SearchNonTrivialToCopyField
-    : CopiedTypeVisitor<SearchNonTrivialToCopyField, false> {
-  using Super = CopiedTypeVisitor<SearchNonTrivialToCopyField, false>;
-
-  SearchNonTrivialToCopyField(const Expr *E, Sema &S) : E(E), S(S) {}
-
-  void visitWithKind(QualType::PrimitiveCopyKind PCK, QualType FT,
-                     SourceLocation SL) {
-    if (const auto *AT = asDerived().getContext().getAsArrayType(FT)) {
-      asDerived().visitArray(PCK, AT, SL);
-      return;
-    }
-
-    Super::visitWithKind(PCK, FT, SL);
-  }
-
-  void visitARCStrong(QualType FT, SourceLocation SL) {
-    S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0);
-  }
-  void visitARCWeak(QualType FT, SourceLocation SL) {
-    S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0);
-  }
-  void visitPtrAuth(QualType FT, SourceLocation SL) {
-    S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0);
-  }
-  void visitStruct(QualType FT, SourceLocation SL) {
-    for (const FieldDecl *FD : FT->castAsRecordDecl()->fields())
-      visit(FD->getType(), FD->getLocation());
-  }
-  void visitArray(QualType::PrimitiveCopyKind PCK, const ArrayType *AT,
-                  SourceLocation SL) {
-    visit(getContext().getBaseElementType(AT), SL);
-  }
-  void preVisit(QualType::PrimitiveCopyKind PCK, QualType FT,
-                SourceLocation SL) {}
-  void visitTrivial(QualType FT, SourceLocation SL) {}
-  void visitVolatileTrivial(QualType FT, SourceLocation SL) {}
-
-  static void diag(QualType RT, const Expr *E, Sema &S) {
-    SearchNonTrivialToCopyField(E, S).visitStruct(RT, SourceLocation());
-  }
-
-  ASTContext &getContext() { return S.getASTContext(); }
-
-  const Expr *E;
-  Sema &S;
-};
-
-}
-
-/// Detect if \c SizeofExpr is likely to calculate the sizeof an object.
-static bool doesExprLikelyComputeSize(const Expr *SizeofExpr) {
-  SizeofExpr = SizeofExpr->IgnoreParenImpCasts();
-
-  if (const auto *BO = dyn_cast<BinaryOperator>(SizeofExpr)) {
-    if (BO->getOpcode() != BO_Mul && BO->getOpcode() != BO_Add)
-      return false;
-
-    return doesExprLikelyComputeSize(BO->getLHS()) ||
-           doesExprLikelyComputeSize(BO->getRHS());
-  }
-
-  return getAsSizeOfExpr(SizeofExpr) != nullptr;
-}
-
-/// Check if the ArgLoc originated from a macro passed to the call at CallLoc.
-///
-/// \code
-///   #define MACRO 0
-///   foo(MACRO);
-///   foo(0);
-/// \endcode
-///
-/// This should return true for the first call to foo, but not for the second
-/// (regardless of whether foo is a macro or function).
-static bool isArgumentExpandedFromMacro(SourceManager &SM,
-                                        SourceLocation CallLoc,
-                                        SourceLocation ArgLoc) {
-  if (!CallLoc.isMacroID())
-    return SM.getFileID(CallLoc) != SM.getFileID(ArgLoc);
-
-  return SM.getFileID(SM.getImmediateMacroCallerLoc(CallLoc)) !=
-         SM.getFileID(SM.getImmediateMacroCallerLoc(ArgLoc));
-}
-
-/// Diagnose cases like 'memset(buf, sizeof(buf), 0)', which should have the
-/// last two arguments transposed.
-static void CheckMemaccessSize(Sema &S, unsigned BId, const CallExpr *Call) {
-  if (BId != Builtin::BImemset && BId != Builtin::BIbzero)
-    return;
-
-  const Expr *SizeArg =
-    Call->getArg(BId == Builtin::BImemset ? 2 : 1)->IgnoreImpCasts();
-
-  auto isLiteralZero = [](const Expr *E) {
-    return (isa<IntegerLiteral>(E) &&
-            cast<IntegerLiteral>(E)->getValue() == 0) ||
-           (isa<CharacterLiteral>(E) &&
-            cast<CharacterLiteral>(E)->getValue() == 0);
-  };
-
-  // If we're memsetting or bzeroing 0 bytes, then this is likely an error.
-  SourceLocation CallLoc = Call->getRParenLoc();
-  SourceManager &SM = S.getSourceManager();
-  if (isLiteralZero(SizeArg) &&
-      !isArgumentExpandedFromMacro(SM, CallLoc, SizeArg->getExprLoc())) {
-
-    SourceLocation DiagLoc = SizeArg->getExprLoc();
-
-    // Some platforms #define bzero to __builtin_memset. See if this is the
-    // case, and if so, emit a better diagnostic.
-    if (BId == Builtin::BIbzero ||
-        (CallLoc.isMacroID() && Lexer::getImmediateMacroName(
-                                    CallLoc, SM, S.getLangOpts()) == "bzero")) {
-      S.Diag(DiagLoc, diag::warn_suspicious_bzero_size);
-      S.Diag(DiagLoc, diag::note_suspicious_bzero_size_silence);
-    } else if (!isLiteralZero(Call->getArg(1)->IgnoreImpCasts())) {
-      S.Diag(DiagLoc, diag::warn_suspicious_sizeof_memset) << 0;
-      S.Diag(DiagLoc, diag::note_suspicious_sizeof_memset_silence) << 0;
-    }
-    return;
-  }
-
-  // If the second argument to a memset is a sizeof expression and the third
-  // isn't, this is also likely an error. This should catch
-  // 'memset(buf, sizeof(buf), 0xff)'.
-  if (BId == Builtin::BImemset &&
-      doesExprLikelyComputeSize(Call->getArg(1)) &&
-      !doesExprLikelyComputeSize(Call->getArg(2))) {
-    SourceLocation DiagLoc = Call->getArg(1)->getExprLoc();
-    S.Diag(DiagLoc, diag::warn_suspicious_sizeof_memset) << 1;
-    S.Diag(DiagLoc, diag::note_suspicious_sizeof_memset_silence) << 1;
-    return;
-  }
-}
-
-void Sema::CheckMemaccessArguments(const CallExpr *Call,
-                                   unsigned BId,
-                                   IdentifierInfo *FnName) {
-  assert(BId != 0);
-
-  // It is possible to have a non-standard definition of memset.  Validate
-  // we have enough arguments, and if not, abort further checking.
-  unsigned ExpectedNumArgs =
-      (BId == Builtin::BIstrndup || BId == Builtin::BIbzero ? 2 : 3);
-  if (Call->getNumArgs() < ExpectedNumArgs)
-    return;
-
-  unsigned LastArg = (BId == Builtin::BImemset || BId == Builtin::BIbzero ||
-                      BId == Builtin::BIstrndup ? 1 : 2);
-  unsigned LenArg =
-      (BId == Builtin::BIbzero || BId == Builtin::BIstrndup ? 1 : 2);
-  const Expr *LenExpr = Call->getArg(LenArg)->IgnoreParenImpCasts();
-
-  if (CheckMemorySizeofForComparison(*this, LenExpr, FnName,
-                                     Call->getBeginLoc(), Call->getRParenLoc()))
-    return;
-
-  // Catch cases like 'memset(buf, sizeof(buf), 0)'.
-  CheckMemaccessSize(*this, BId, Call);
-
-  // We have special checking when the length is a sizeof expression.
-  QualType SizeOfArgTy = getSizeOfArgType(LenExpr);
-  const Expr *SizeOfArg = getSizeOfExprArg(LenExpr);
-  llvm::FoldingSetNodeID SizeOfArgID;
-
-  // Although widely used, 'bzero' is not a standard function. Be more strict
-  // with the argument types before allowing diagnostics and only allow the
-  // form bzero(ptr, sizeof(...)).
-  QualType FirstArgTy = Call->getArg(0)->IgnoreParenImpCasts()->getType();
-  if (BId == Builtin::BIbzero && !FirstArgTy->getAs<PointerType>())
-    return;
-
-  for (unsigned ArgIdx = 0; ArgIdx != LastArg; ++ArgIdx) {
-    const Expr *Dest = Call->getArg(ArgIdx)->IgnoreParenImpCasts();
-    SourceRange ArgRange = Call->getArg(ArgIdx)->getSourceRange();
-
-    QualType DestTy = Dest->getType();
-    QualType PointeeTy;
-    if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) {
-      PointeeTy = DestPtrTy->getPointeeType();
-
-      // Never warn about void type pointers. This can be used to suppress
-      // false positives.
-      if (PointeeTy->isVoidType())
-        continue;
-
-      // Catch "memset(p, 0, sizeof(p))" -- needs to be sizeof(*p). Do this by
-      // actually comparing the expressions for equality. Because computing the
-      // expression IDs can be expensive, we only do this if the diagnostic is
-      // enabled.
-      if (SizeOfArg &&
-          !Diags.isIgnored(diag::warn_sizeof_pointer_expr_memaccess,
-                           SizeOfArg->getExprLoc())) {
-        // We only compute IDs for expressions if the warning is enabled, and
-        // cache the sizeof arg's ID.
-        if (SizeOfArgID == llvm::FoldingSetNodeID())
-          SizeOfArg->Profile(SizeOfArgID, Context, true);
-        llvm::FoldingSetNodeID DestID;
-        Dest->Profile(DestID, Context, true);
-        if (DestID == SizeOfArgID) {
-          // TODO: For strncpy() and friends, this could suggest sizeof(dst)
-          //       over sizeof(src) as well.
-          unsigned ActionIdx = 0; // Default is to suggest dereferencing.
-          StringRef ReadableName = FnName->getName();
-
-          if (const UnaryOperator *UnaryOp = dyn_cast<UnaryOperator>(Dest))
-            if (UnaryOp->getOpcode() == UO_AddrOf)
-              ActionIdx = 1; // If its an address-of operator, just remove it.
-          if (!PointeeTy->isIncompleteType() &&
-              (Context.getTypeSize(PointeeTy) == Context.getCharWidth()))
-            ActionIdx = 2; // If the pointee's size is sizeof(char),
-                           // suggest an explicit length.
-
-          // If the function is defined as a builtin macro, do not show macro
-          // expansion.
-          SourceLocation SL = SizeOfArg->getExprLoc();
-          SourceRange DSR = Dest->getSourceRange();
-          SourceRange SSR = SizeOfArg->getSourceRange();
-          SourceManager &SM = getSourceManager();
-
-          if (SM.isMacroArgExpansion(SL)) {
-            ReadableName = Lexer::getImmediateMacroName(SL, SM, LangOpts);
-            SL = SM.getSpellingLoc(SL);
-            DSR = SourceRange(SM.getSpellingLoc(DSR.getBegin()),
-                             SM.getSpellingLoc(DSR.getEnd()));
-            SSR = SourceRange(SM.getSpellingLoc(SSR.getBegin()),
-                             SM.getSpellingLoc(SSR.getEnd()));
-          }
-
-          DiagRuntimeBehavior(SL, SizeOfArg,
-                              PDiag(diag::warn_sizeof_pointer_expr_memaccess)
-                                << ReadableName
-                                << PointeeTy
-                                << DestTy
-                                << DSR
-                                << SSR);
-          DiagRuntimeBehavior(SL, SizeOfArg,
-                         PDiag(diag::warn_sizeof_pointer_expr_memaccess_note)
-                                << ActionIdx
-                                << SSR);
-
-          break;
-        }
-      }
-
-      // Also check for cases where the sizeof argument is the exact same
-      // type as the memory argument, and where it points to a user-defined
-      // record type.
-      if (SizeOfArgTy != QualType()) {
-        if (PointeeTy->isRecordType() &&
-            Context.typesAreCompatible(SizeOfArgTy, DestTy)) {
-          DiagRuntimeBehavior(LenExpr->getExprLoc(), Dest,
-                              PDiag(diag::warn_sizeof_pointer_type_memaccess)
-                                << FnName << SizeOfArgTy << ArgIdx
-                                << PointeeTy << Dest->getSourceRange()
-                                << LenExpr->getSourceRange());
-          break;
-        }
-      }
-    } else if (DestTy->isArrayType()) {
-      PointeeTy = DestTy;
-    }
-
-    if (PointeeTy == QualType())
-      continue;
-
-    // Always complain about dynamic classes.
-    bool IsContained;
-    if (const CXXRecordDecl *ContainedRD =
-            getContainedDynamicClass(PointeeTy, IsContained)) {
-
-      unsigned OperationType = 0;
-      const bool IsCmp = BId == Builtin::BImemcmp || BId == Builtin::BIbcmp;
-      // "overwritten" if we're warning about the destination for any call
-      // but memcmp; otherwise a verb appropriate to the call.
-      if (ArgIdx != 0 || IsCmp) {
-        if (BId == Builtin::BImemcpy)
-          OperationType = 1;
-        else if(BId == Builtin::BImemmove)
-          OperationType = 2;
-        else if (IsCmp)
-          OperationType = 3;
-      }
-
-      DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
-                          PDiag(diag::warn_dyn_class_memaccess)
-                              << (IsCmp ? ArgIdx + 2 : ArgIdx) << FnName
-                              << IsContained << ContainedRD << OperationType
-                              << Call->getCallee()->getSourceRange());
-    } else if (PointeeTy.hasNonTrivialObjCLifetime() &&
-             BId != Builtin::BImemset)
-      DiagRuntimeBehavior(
-        Dest->getExprLoc(), Dest,
-        PDiag(diag::warn_arc_object_memaccess)
-          << ArgIdx << FnName << PointeeTy
-          << Call->getCallee()->getSourceRange());
-    else if (const auto *RD = PointeeTy->getAsRecordDecl()) {
-
-      // FIXME: Do not consider incomplete types even though they may be
-      // completed later. GCC does not diagnose such code, but we may want to
-      // consider diagnosing it in the future, perhaps under a different, but
-      // related, diagnostic group.
-      bool NonTriviallyCopyableCXXRecord =
-          getLangOpts().CPlusPlus && RD->isCompleteDefinition() &&
-          !PointeeTy.isTriviallyCopyableType(Context);
-
-      if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) &&
-          RD->isNonTrivialToPrimitiveDefaultInitialize()) {
-        DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
-                            PDiag(diag::warn_cstruct_memaccess)
-                                << ArgIdx << FnName << PointeeTy << 0);
-        SearchNonTrivialToInitializeField::diag(PointeeTy, Dest, *this);
-      } else if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) &&
-                 NonTriviallyCopyableCXXRecord && ArgIdx == 0) {
-        // FIXME: Limiting this warning to dest argument until we decide
-        // whether it's valid for source argument too.
-        DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
-                            PDiag(diag::warn_cxxstruct_memaccess)
-                                << FnName << PointeeTy);
-      } else if ((BId == Builtin::BImemcpy || BId == Builtin::BImemmove) &&
-                 RD->isNonTrivialToPrimitiveCopy()) {
-        DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
-                            PDiag(diag::warn_cstruct_memaccess)
-                                << ArgIdx << FnName << PointeeTy << 1);
-        SearchNonTrivialToCopyField::diag(PointeeTy, Dest, *this);
-      } else if ((BId == Builtin::BImemcpy || BId == Builtin::BImemmove) &&
-                 NonTriviallyCopyableCXXRecord && ArgIdx == 0) {
-        // FIXME: Limiting this warning to dest argument until we decide
-        // whether it's valid for source argument too.
-        DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
-                            PDiag(diag::warn_cxxstruct_memaccess)
-                                << FnName << PointeeTy);
-      } else {
-        continue;
-      }
-    } else
-      continue;
-
-    DiagRuntimeBehavior(
-      Dest->getExprLoc(), Dest,
-      PDiag(diag::note_bad_memaccess_silence)
-        << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)"));
-    break;
-  }
-}
-
-// A little helper routine: ignore addition and subtraction of integer literals.
-// This intentionally does not ignore all integer constant expressions because
-// we don't want to remove sizeof().
-static const Expr *ignoreLiteralAdditions(const Expr *Ex, ASTContext &Ctx) {
-  Ex = Ex->IgnoreParenCasts();
-
-  while (true) {
-    const BinaryOperator * BO = dyn_cast<BinaryOperator>(Ex);
-    if (!BO || !BO->isAdditiveOp())
-      break;
-
-    const Expr *RHS = BO->getRHS()->IgnoreParenCasts();
-    const Expr *LHS = BO->getLHS()->IgnoreParenCasts();
-
-    if (isa<IntegerLiteral>(RHS))
-      Ex = LHS;
-    else if (isa<IntegerLiteral>(LHS))
-      Ex = RHS;
-    else
-      break;
-  }
-
-  return Ex;
-}
-
-static bool isConstantSizeArrayWithMoreThanOneElement(QualType Ty,
-                                                      ASTContext &Context) {
-  // Only handle constant-sized or VLAs, but not flexible members.
-  if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(Ty)) {
-    // Only issue the FIXIT for arrays of size > 1.
-    if (CAT->getZExtSize() <= 1)
-      return false;
-  } else if (!Ty->isVariableArrayType()) {
-    return false;
-  }
-  return true;
-}
-
-void Sema::CheckStrlcpycatArguments(const CallExpr *Call,
-                                    IdentifierInfo *FnName) {
-
-  // Don't crash if the user has the wrong number of arguments
-  unsigned NumArgs = Call->getNumArgs();
-  if ((NumArgs != 3) && (NumArgs != 4))
-    return;
-
-  const Expr *SrcArg = ignoreLiteralAdditions(Call->getArg(1), Context);
-  const Expr *SizeArg = ignoreLiteralAdditions(Call->getArg(2), Context);
-  const Expr *CompareWithSrc = nullptr;
-
-  if (CheckMemorySizeofForComparison(*this, SizeArg, FnName,
-                                     Call->getBeginLoc(), Call->getRParenLoc()))
-    return;
-
-  // Look for 'strlcpy(dst, x, sizeof(x))'
-  if (const Expr *Ex = getSizeOfExprArg(SizeArg))
-    CompareWithSrc = Ex;
-  else {
-    // Look for 'strlcpy(dst, x, strlen(x))'
-    if (const CallExpr *SizeCall = dyn_cast<CallExpr>(SizeArg)) {
-      if (SizeCall->getBuiltinCallee() == Builtin::BIstrlen &&
-          SizeCall->getNumArgs() == 1)
-        CompareWithSrc = ignoreLiteralAdditions(SizeCall->getArg(0), Context);
-    }
-  }
-
-  if (!CompareWithSrc)
-    return;
-
-  // Determine if the argument to sizeof/strlen is equal to the source
-  // argument.  In principle there's all kinds of things you could do
-  // here, for instance creating an == expression and evaluating it with
-  // EvaluateAsBooleanCondition, but this uses a more direct technique:
-  const DeclRefExpr *SrcArgDRE = dyn_cast<DeclRefExpr>(SrcArg);
-  if (!SrcArgDRE)
-    return;
-
-  const DeclRefExpr *CompareWithSrcDRE = dyn_cast<DeclRefExpr>(CompareWithSrc);
-  if (!CompareWithSrcDRE ||
-      SrcArgDRE->getDecl() != CompareWithSrcDRE->getDecl())
-    return;
-
-  const Expr *OriginalSizeArg = Call->getArg(2);
-  Diag(CompareWithSrcDRE->getBeginLoc(), diag::warn_strlcpycat_wrong_size)
-      << OriginalSizeArg->getSourceRange() << FnName;
-
-  // Output a FIXIT hint if the destination is an array (rather than a
-  // pointer to an array).  This could be enhanced to handle some
-  // pointers if we know the actual size, like if DstArg is 'array+2'
-  // we could say 'sizeof(array)-2'.
-  const Expr *DstArg = Call->getArg(0)->IgnoreParenImpCasts();
-  if (!isConstantSizeArrayWithMoreThanOneElement(DstArg->getType(), Context))
-    return;
-
-  SmallString<128> sizeString;
-  llvm::raw_svector_ostream OS(sizeString);
-  OS << "sizeof(";
-  DstArg->printPretty(OS, nullptr, getPrintingPolicy());
-  OS << ")";
-
-  Diag(OriginalSizeArg->getBeginLoc(), diag::note_strlcpycat_wrong_size)
-      << FixItHint::CreateReplacement(OriginalSizeArg->getSourceRange(),
-                                      OS.str());
-}
-
-/// Check if two expressions refer to the same declaration.
-static bool referToTheSameDecl(const Expr *E1, const Expr *E2) {
-  if (const DeclRefExpr *D1 = dyn_cast_or_null<DeclRefExpr>(E1))
-    if (const DeclRefExpr *D2 = dyn_cast_or_null<DeclRefExpr>(E2))
-      return D1->getDecl() == D2->getDecl();
-  return false;
-}
-
-static const Expr *getStrlenExprArg(const Expr *E) {
-  if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
-    const FunctionDecl *FD = CE->getDirectCallee();
-    if (!FD || FD->getMemoryFunctionKind() != Builtin::BIstrlen)
-      return nullptr;
-    return CE->getArg(0)->IgnoreParenCasts();
-  }
-  return nullptr;
-}
-
-void Sema::CheckStrncatArguments(const CallExpr *CE,
-                                 const IdentifierInfo *FnName) {
-  // Don't crash if the user has the wrong number of arguments.
-  if (CE->getNumArgs() < 3)
-    return;
-  const Expr *DstArg = CE->getArg(0)->IgnoreParenCasts();
-  const Expr *SrcArg = CE->getArg(1)->IgnoreParenCasts();
-  const Expr *LenArg = CE->getArg(2)->IgnoreParenCasts();
-
-  if (CheckMemorySizeofForComparison(*this, LenArg, FnName, CE->getBeginLoc(),
-                                     CE->getRParenLoc()))
-    return;
-
-  // Identify common expressions, which are wrongly used as the size argument
-  // to strncat and may lead to buffer overflows.
-  unsigned PatternType = 0;
-  if (const Expr *SizeOfArg = getSizeOfExprArg(LenArg)) {
-    // - sizeof(dst)
-    if (referToTheSameDecl(SizeOfArg, DstArg))
-      PatternType = 1;
-    // - sizeof(src)
-    else if (referToTheSameDecl(SizeOfArg, SrcArg))
-      PatternType = 2;
-  } else if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(LenArg)) {
-    if (BE->getOpcode() == BO_Sub) {
-      const Expr *L = BE->getLHS()->IgnoreParenCasts();
-      const Expr *R = BE->getRHS()->IgnoreParenCasts();
-      // - sizeof(dst) - strlen(dst)
-      if (referToTheSameDecl(DstArg, getSizeOfExprArg(L)) &&
-          referToTheSameDecl(DstArg, getStrlenExprArg(R)))
-        PatternType = 1;
-      // - sizeof(src) - (anything)
-      else if (referToTheSameDecl(SrcArg, getSizeOfExprArg(L)))
-        PatternType = 2;
-    }
-  }
-
-  if (PatternType == 0)
-    return;
-
-  // Generate the diagnostic.
-  SourceLocation SL = LenArg->getBeginLoc();
-  SourceRange SR = LenArg->getSourceRange();
-  SourceManager &SM = getSourceManager();
-
-  // If the function is defined as a builtin macro, do not show macro expansion.
-  if (SM.isMacroArgExpansion(SL)) {
-    SL = SM.getSpellingLoc(SL);
-    SR = SourceRange(SM.getSpellingLoc(SR.getBegin()),
-                     SM.getSpellingLoc(SR.getEnd()));
-  }
-
-  // Check if the destination is an array (rather than a pointer to an array).
-  QualType DstTy = DstArg->getType();
-  bool isKnownSizeArray = isConstantSizeArrayWithMoreThanOneElement(DstTy,
-                                                                    Context);
-  if (!isKnownSizeArray) {
-    if (PatternType == 1)
-      Diag(SL, diag::warn_strncat_wrong_size) << SR;
-    else
-      Diag(SL, diag::warn_strncat_src_size) << SR;
-    return;
-  }
-
-  if (PatternType == 1)
-    Diag(SL, diag::warn_strncat_large_size) << SR;
-  else
-    Diag(SL, diag::warn_strncat_src_size) << SR;
-
-  SmallString<128> sizeString;
-  llvm::raw_svector_ostream OS(sizeString);
-  OS << "sizeof(";
-  DstArg->printPretty(OS, nullptr, getPrintingPolicy());
-  OS << ") - ";
-  OS << "strlen(";
-  DstArg->printPretty(OS, nullptr, getPrintingPolicy());
-  OS << ") - 1";
-
-  Diag(SL, diag::note_strncat_wrong_size)
-    << FixItHint::CreateReplacement(SR, OS.str());
-}
-
-namespace {
-void CheckFreeArgumentsOnLvalue(Sema &S, const std::string &CalleeName,
-                                const UnaryOperator *UnaryExpr, const Decl *D) {
-  if (isa<FieldDecl, FunctionDecl, VarDecl>(D)) {
-    S.Diag(UnaryExpr->getBeginLoc(), diag::warn_free_nonheap_object)
-        << CalleeName << 0 /*object: */ << cast<NamedDecl>(D);
-    return;
-  }
-}
-
-void CheckFreeArgumentsAddressof(Sema &S, const std::string &CalleeName,
-                                 const UnaryOperator *UnaryExpr) {
-  if (const auto *Lvalue = dyn_cast<DeclRefExpr>(UnaryExpr->getSubExpr())) {
-    const Decl *D = Lvalue->getDecl();
-    if (const auto *DD = dyn_cast<DeclaratorDecl>(D)) {
-      if (!DD->getType()->isReferenceType())
-        return CheckFreeArgumentsOnLvalue(S, CalleeName, UnaryExpr, D);
-    }
-  }
-
-  if (const auto *Lvalue = dyn_cast<MemberExpr>(UnaryExpr->getSubExpr()))
-    return CheckFreeArgumentsOnLvalue(S, CalleeName, UnaryExpr,
-                                      Lvalue->getMemberDecl());
-}
-
-void CheckFreeArgumentsPlus(Sema &S, const std::string &CalleeName,
-                            const UnaryOperator *UnaryExpr) {
-  const auto *Lambda = dyn_cast<LambdaExpr>(
-      UnaryExpr->getSubExpr()->IgnoreImplicitAsWritten()->IgnoreParens());
-  if (!Lambda)
-    return;
-
-  S.Diag(Lambda->getBeginLoc(), diag::warn_free_nonheap_object)
-      << CalleeName << 2 /*object: lambda expression*/;
-}
-
-void CheckFreeArgumentsStackArray(Sema &S, const std::string &CalleeName,
-                                  const DeclRefExpr *Lvalue) {
-  const auto *Var = dyn_cast<VarDecl>(Lvalue->getDecl());
-  if (Var == nullptr)
-    return;
-
-  S.Diag(Lvalue->getBeginLoc(), diag::warn_free_nonheap_object)
-      << CalleeName << 0 /*object: */ << Var;
-}
-
-void CheckFreeArgumentsCast(Sema &S, const std::string &CalleeName,
-                            const CastExpr *Cast) {
-  SmallString<128> SizeString;
-  llvm::raw_svector_ostream OS(SizeString);
-
-  clang::CastKind Kind = Cast->getCastKind();
-  if (Kind == clang::CK_BitCast &&
-      !Cast->getSubExpr()->getType()->isFunctionPointerType())
-    return;
-  if (Kind == clang::CK_IntegralToPointer &&
-      !isa<IntegerLiteral>(
-          Cast->getSubExpr()->IgnoreParenImpCasts()->IgnoreParens()))
-    return;
-
-  switch (Cast->getCastKind()) {
-  case clang::CK_BitCast:
-  case clang::CK_IntegralToPointer:
-  case clang::CK_FunctionToPointerDecay:
-    OS << '\'';
-    Cast->printPretty(OS, nullptr, S.getPrintingPolicy());
-    OS << '\'';
-    break;
-  default:
-    return;
-  }
-
-  S.Diag(Cast->getBeginLoc(), diag::warn_free_nonheap_object)
-      << CalleeName << 0 /*object: */ << OS.str();
-}
-} // namespace
-
-void Sema::CheckFreeArguments(const CallExpr *E) {
-  const std::string CalleeName =
-      cast<FunctionDecl>(E->getCalleeDecl())->getQualifiedNameAsString();
-
-  { // Prefer something that doesn't involve a cast to make things simpler.
-    const Expr *Arg = E->getArg(0)->IgnoreParenCasts();
-    if (const auto *UnaryExpr = dyn_cast<UnaryOperator>(Arg))
-      switch (UnaryExpr->getOpcode()) {
-      case UnaryOperator::Opcode::UO_AddrOf:
-        return CheckFreeArgumentsAddressof(*this, CalleeName, UnaryExpr);
-      case UnaryOperator::Opcode::UO_Plus:
-        return CheckFreeArgumentsPlus(*this, CalleeName, UnaryExpr);
-      default:
-        break;
-      }
-
-    if (const auto *Lvalue = dyn_cast<DeclRefExpr>(Arg))
-      if (Lvalue->getType()->isArrayType())
-        return CheckFreeArgumentsStackArray(*this, CalleeName, Lvalue);
-
-    if (const auto *Label = dyn_cast<AddrLabelExpr>(Arg)) {
-      Diag(Label->getBeginLoc(), diag::warn_free_nonheap_object)
-          << CalleeName << 0 /*object: */ << Label->getLabel()->getIdentifier();
-      return;
-    }
-
-    if (isa<BlockExpr>(Arg)) {
-      Diag(Arg->getBeginLoc(), diag::warn_free_nonheap_object)
-          << CalleeName << 1 /*object: block*/;
-      return;
-    }
-  }
-  // Maybe the cast was important, check after the other cases.
-  if (const auto *Cast = dyn_cast<CastExpr>(E->getArg(0)))
-    return CheckFreeArgumentsCast(*this, CalleeName, Cast);
-}
-
-void
-Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType,
-                         SourceLocation ReturnLoc,
-                         bool isObjCMethod,
-                         const AttrVec *Attrs,
-                         const FunctionDecl *FD) {
-  // Check if the return value is null but should not be.
-  if (((Attrs && hasSpecificAttr<ReturnsNonNullAttr>(*Attrs)) ||
-       (!isObjCMethod && isNonNullType(lhsType))) &&
-      CheckNonNullExpr(*this, RetValExp))
-    Diag(ReturnLoc, diag::warn_null_ret)
-      << (isObjCMethod ? 1 : 0) << RetValExp->getSourceRange();
-
-  // C++11 [basic.stc.dynamic.allocation]p4:
-  //   If an allocation function declared with a non-throwing
-  //   exception-specification fails to allocate storage, it shall return
-  //   a null pointer. Any other allocation function that fails to allocate
-  //   storage shall indicate failure only by throwing an exception [...]
-  if (FD) {
-    OverloadedOperatorKind Op = FD->getOverloadedOperator();
-    if (Op == OO_New || Op == OO_Array_New) {
-      const FunctionProtoType *Proto
-        = FD->getType()->castAs<FunctionProtoType>();
-      if (!Proto->isNothrow(/*ResultIfDependent*/true) &&
-          CheckNonNullExpr(*this, RetValExp))
-        Diag(ReturnLoc, diag::warn_operator_new_returns_null)
-          << FD << getLangOpts().CPlusPlus11;
-    }
-  }
-
-  if (RetValExp && RetValExp->getType()->isWebAssemblyTableType()) {
-    Diag(ReturnLoc, diag::err_wasm_table_art) << 1;
-  }
-
-  // PPC MMA non-pointer types are not allowed as return type. Checking the type
-  // here prevent the user from using a PPC MMA type as trailing return type.
-  if (Context.getTargetInfo().getTriple().isPPC64())
-    PPC().CheckPPCMMAType(RetValExp->getType(), ReturnLoc);
-}
-
-void Sema::CheckFloatComparison(SourceLocation Loc, const Expr *LHS,
-                                const Expr *RHS, BinaryOperatorKind Opcode) {
-  if (!BinaryOperator::isEqualityOp(Opcode))
-    return;
-
-  // Match and capture subexpressions such as "(float) X == 0.1".
-  const FloatingLiteral *FPLiteral;
-  const CastExpr *FPCast;
-  auto getCastAndLiteral = [&FPLiteral, &FPCast](const Expr *L, const Expr *R) {
-    FPLiteral = dyn_cast<FloatingLiteral>(L->IgnoreParens());
-    FPCast = dyn_cast<CastExpr>(R->IgnoreParens());
-    return FPLiteral && FPCast;
-  };
-
-  if (getCastAndLiteral(LHS, RHS) || getCastAndLiteral(RHS, LHS)) {
-    auto *SourceTy = FPCast->getSubExpr()->getType()->getAs<BuiltinType>();
-    auto *TargetTy = FPLiteral->getType()->getAs<BuiltinType>();
-    if (SourceTy && TargetTy && SourceTy->isFloatingPoint() &&
-        TargetTy->isFloatingPoint()) {
-      bool Lossy;
-      llvm::APFloat TargetC = FPLiteral->getValue();
-      TargetC.convert(Context.getFloatTypeSemantics(QualType(SourceTy, 0)),
-                      llvm::APFloat::rmNearestTiesToEven, &Lossy);
-      if (Lossy) {
-        // If the literal cannot be represented in the source type, then a
-        // check for == is always false and check for != is always true.
-        Diag(Loc, diag::warn_float_compare_literal)
-            << (Opcode == BO_EQ) << QualType(SourceTy, 0)
-            << LHS->getSourceRange() << RHS->getSourceRange();
-        return;
-      }
-    }
-  }
-
-  // Match a more general floating-point equality comparison (-Wfloat-equal).
-  const Expr *LeftExprSansParen = LHS->IgnoreParenImpCasts();
-  const Expr *RightExprSansParen = RHS->IgnoreParenImpCasts();
-
-  // Special case: check for x == x (which is OK).
-  // Do not emit warnings for such cases.
-  if (const auto *DRL = dyn_cast<DeclRefExpr>(LeftExprSansParen))
-    if (const auto *DRR = dyn_cast<DeclRefExpr>(RightExprSansParen))
-      if (DRL->getDecl() == DRR->getDecl())
-        return;
-
-  // Special case: check for comparisons against literals that can be exactly
-  //  represented by APFloat.  In such cases, do not emit a warning.  This
-  //  is a heuristic: often comparison against such literals are used to
-  //  detect if a value in a variable has not changed.  This clearly can
-  //  lead to false negatives.
-  if (const auto *FLL = dyn_cast<FloatingLiteral>(LeftExprSansParen)) {
-    if (FLL->isExact())
-      return;
-  } else if (const auto *FLR = dyn_cast<FloatingLiteral>(RightExprSansParen))
-    if (FLR->isExact())
-      return;
-
-  // Check for comparisons with builtin types.
-  if (const auto *CL = dyn_cast<CallExpr>(LeftExprSansParen);
-      CL && CL->getBuiltinCallee())
-    return;
-
-  if (const auto *CR = dyn_cast<CallExpr>(RightExprSansParen);
-      CR && CR->getBuiltinCallee())
-    return;
-
-  // Emit the diagnostic.
-  Diag(Loc, diag::warn_floatingpoint_eq)
-    << LHS->getSourceRange() << RHS->getSourceRange();
-}
-
-//===--- CHECK: Integer mixed-sign comparisons (-Wsign-compare) --------===//
-//===--- CHECK: Lossy implicit conversions (-Wconversion) --------------===//
-
-namespace {
-
-/// Structure recording the 'active' range of an integer-valued
-/// expression.
-struct IntRange {
-  /// The number of bits active in the int. Note that this includes exactly one
-  /// sign bit if !NonNegative.
-  unsigned Width;
-
-  /// True if the int is known not to have negative values. If so, all leading
-  /// bits before Width are known zero, otherwise they are known to be the
-  /// same as the MSB within Width.
-  bool NonNegative;
-
-  IntRange(unsigned Width, bool NonNegative)
-      : Width(Width), NonNegative(NonNegative) {}
-
-  /// Number of bits excluding the sign bit.
-  unsigned valueBits() const {
-    return NonNegative ? Width : Width - 1;
-  }
-
-  /// Returns the range of the bool type.
-  static IntRange forBoolType() {
-    return IntRange(1, true);
-  }
-
-  /// Returns the range of an opaque value of the given integral type.
-  static IntRange forValueOfType(ASTContext &C, QualType T) {
-    return forValueOfCanonicalType(C,
-                          T->getCanonicalTypeInternal().getTypePtr());
-  }
-
-  /// Returns the range of an opaque value of a canonical integral type.
-  static IntRange forValueOfCanonicalType(ASTContext &C, const Type *T) {
-    assert(T->isCanonicalUnqualified());
-
-    if (const auto *VT = dyn_cast<VectorType>(T))
-      T = VT->getElementType().getTypePtr();
-    if (const auto *CT = dyn_cast<ComplexType>(T))
-      T = CT->getElementType().getTypePtr();
-    if (const auto *AT = dyn_cast<AtomicType>(T))
-      T = AT->getValueType().getTypePtr();
-
-    if (!C.getLangOpts().CPlusPlus) {
-      // For enum types in C code, use the underlying datatype.
-      if (const auto *ED = T->getAsEnumDecl())
-        T = ED->getIntegerType().getDesugaredType(C).getTypePtr();
-    } else if (auto *Enum = T->getAsEnumDecl()) {
-      // For enum types in C++, use the known bit width of the enumerators.
-      // In C++11, enums can have a fixed underlying type. Use this type to
-      // compute the range.
-      if (Enum->isFixed()) {
-        return IntRange(C.getIntWidth(QualType(T, 0)),
-                        !Enum->getIntegerType()->isSignedIntegerType());
-      }
-
-      unsigned NumPositive = Enum->getNumPositiveBits();
-      unsigned NumNegative = Enum->getNumNegativeBits();
-
-      if (NumNegative == 0)
-        return IntRange(NumPositive, true/*NonNegative*/);
-      else
-        return IntRange(std::max(NumPositive + 1, NumNegative),
-                        false/*NonNegative*/);
-    }
-
-    if (const auto *EIT = dyn_cast<BitIntType>(T))
-      return IntRange(EIT->getNumBits(), EIT->isUnsigned());
-
-    const BuiltinType *BT = cast<BuiltinType>(T);
-    assert(BT->isInteger());
-
-    return IntRange(C.getIntWidth(QualType(T, 0)), BT->isUnsignedInteger());
-  }
-
-  /// Returns the "target" range of a canonical integral type, i.e.
-  /// the range of values expressible in the type.
-  ///
-  /// This matches forValueOfCanonicalType except that enums have the
-  /// full range of their type, not the range of their enumerators.
-  static IntRange forTargetOfCanonicalType(ASTContext &C, const Type *T) {
-    assert(T->isCanonicalUnqualified());
-
-    if (const VectorType *VT = dyn_cast<VectorType>(T))
-      T = VT->getElementType().getTypePtr();
-    if (const ComplexType *CT = dyn_cast<ComplexType>(T))
-      T = CT->getElementType().getTypePtr();
-    if (const AtomicType *AT = dyn_cast<AtomicType>(T))
-      T = AT->getValueType().getTypePtr();
-    if (const auto *ED = T->getAsEnumDecl())
-      T = C.getCanonicalType(ED->getIntegerType()).getTypePtr();
-
-    if (const auto *EIT = dyn_cast<BitIntType>(T))
-      return IntRange(EIT->getNumBits(), EIT->isUnsigned());
-
-    const BuiltinType *BT = cast<BuiltinType>(T);
-    assert(BT->isInteger());
-
-    return IntRange(C.getIntWidth(QualType(T, 0)), BT->isUnsignedInteger());
-  }
-
-  /// Returns the supremum of two ranges: i.e. their conservative merge.
-  static IntRange join(IntRange L, IntRange R) {
-    bool Unsigned = L.NonNegative && R.NonNegative;
-    return IntRange(std::max(L.valueBits(), R.valueBits()) + !Unsigned,
-                    L.NonNegative && R.NonNegative);
-  }
-
-  /// Return the range of a bitwise-AND of the two ranges.
-  static IntRange bit_and(IntRange L, IntRange R) {
-    unsigned Bits = std::max(L.Width, R.Width);
-    bool NonNegative = false;
-    if (L.NonNegative) {
-      Bits = std::min(Bits, L.Width);
-      NonNegative = true;
-    }
-    if (R.NonNegative) {
-      Bits = std::min(Bits, R.Width);
-      NonNegative = true;
-    }
-    return IntRange(Bits, NonNegative);
-  }
-
-  /// Return the range of a sum of the two ranges.
-  static IntRange sum(IntRange L, IntRange R) {
-    bool Unsigned = L.NonNegative && R.NonNegative;
-    return IntRange(std::max(L.valueBits(), R.valueBits()) + 1 + !Unsigned,
-                    Unsigned);
-  }
-
-  /// Return the range of a difference of the two ranges.
-  static IntRange difference(IntRange L, IntRange R) {
-    // We need a 1-bit-wider range if:
-    //   1) LHS can be negative: least value can be reduced.
-    //   2) RHS can be negative: greatest value can be increased.
-    bool CanWiden = !L.NonNegative || !R.NonNegative;
-    bool Unsigned = L.NonNegative && R.Width == 0;
-    return IntRange(std::max(L.valueBits(), R.valueBits()) + CanWiden +
-                        !Unsigned,
-                    Unsigned);
-  }
-
-  /// Return the range of a product of the two ranges.
-  static IntRange product(IntRange L, IntRange R) {
-    // If both LHS and RHS can be negative, we can form
-    //   -2^L * -2^R = 2^(L + R)
-    // which requires L + R + 1 value bits to represent.
-    bool CanWiden = !L.NonNegative && !R.NonNegative;
-    bool Unsigned = L.NonNegative && R.NonNegative;
-    return IntRange(L.valueBits() + R.valueBits() + CanWiden + !Unsigned,
-                    Unsigned);
-  }
-
-  /// Return the range of a remainder operation between the two ranges.
-  static IntRange rem(IntRange L, IntRange R) {
-    // The result of a remainder can't be larger than the result of
-    // either side. The sign of the result is the sign of the LHS.
-    bool Unsigned = L.NonNegative;
-    return IntRange(std::min(L.valueBits(), R.valueBits()) + !Unsigned,
-                    Unsigned);
-  }
-};
-
-} // namespace
-
-static IntRange GetValueRange(llvm::APSInt &value, unsigned MaxWidth) {
-  if (value.isSigned() && value.isNegative())
-    return IntRange(value.getSignificantBits(), false);
-
-  if (value.getBitWidth() > MaxWidth)
-    value = value.trunc(MaxWidth);
-
-  // isNonNegative() just checks the sign bit without considering
-  // signedness.
-  return IntRange(value.getActiveBits(), true);
-}
-
-static IntRange GetValueRange(APValue &result, QualType Ty, unsigned MaxWidth) {
-  if (result.isInt())
-    return GetValueRange(result.getInt(), MaxWidth);
-
-  if (result.isVector()) {
-    IntRange R = GetValueRange(result.getVectorElt(0), Ty, MaxWidth);
-    for (unsigned i = 1, e = result.getVectorLength(); i != e; ++i) {
-      IntRange El = GetValueRange(result.getVectorElt(i), Ty, MaxWidth);
-      R = IntRange::join(R, El);
-    }
-    return R;
-  }
-
-  if (result.isComplexInt()) {
-    IntRange R = GetValueRange(result.getComplexIntReal(), MaxWidth);
-    IntRange I = GetValueRange(result.getComplexIntImag(), MaxWidth);
-    return IntRange::join(R, I);
-  }
-
-  // This can happen with lossless casts to intptr_t of "based" lvalues.
-  // Assume it might use arbitrary bits.
-  // FIXME: The only reason we need to pass the type in here is to get
-  // the sign right on this one case.  It would be nice if APValue
-  // preserved this.
-  assert(result.isLValue() || result.isAddrLabelDiff());
-  return IntRange(MaxWidth, Ty->isUnsignedIntegerOrEnumerationType());
-}
-
-static QualType GetExprType(const Expr *E) {
-  QualType Ty = E->getType();
-  if (const auto *AtomicRHS = Ty->getAs<AtomicType>())
-    Ty = AtomicRHS->getValueType();
-  return Ty;
-}
-
-/// Attempts to estimate an approximate range for the given integer expression.
-/// Returns a range if successful, otherwise it returns \c std::nullopt if a
-/// reliable estimation cannot be determined.
-///
-/// \param MaxWidth The width to which the value will be truncated.
-/// \param InConstantContext If \c true, interpret the expression within a
-///        constant context.
-/// \param Approximate If \c true, provide a likely range of values by assuming
-///        that arithmetic on narrower types remains within those types.
-///        If \c false, return a range that includes all possible values
-///        resulting from the expression.
-/// \returns A range of values that the expression might take, or
-///          std::nullopt if a reliable estimation cannot be determined.
-static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E,
-                                               unsigned MaxWidth,
-                                               bool InConstantContext,
-                                               bool Approximate) {
-  E = E->IgnoreParens();
-
-  // Try a full evaluation first.
-  Expr::EvalResult result;
-  if (E->EvaluateAsRValue(result, C, InConstantContext))
-    return GetValueRange(result.Val, GetExprType(E), MaxWidth);
-
-  // I think we only want to look through implicit casts here; if the
-  // user has an explicit widening cast, we should treat the value as
-  // being of the new, wider type.
-  if (const auto *CE = dyn_cast<ImplicitCastExpr>(E)) {
-    if (CE->getCastKind() == CK_NoOp || CE->getCastKind() == CK_LValueToRValue)
-      return TryGetExprRange(C, CE->getSubExpr(), MaxWidth, InConstantContext,
-                             Approximate);
-
-    IntRange OutputTypeRange = IntRange::forValueOfType(C, GetExprType(CE));
-
-    bool isIntegerCast = CE->getCastKind() == CK_IntegralCast ||
-                         CE->getCastKind() == CK_BooleanToSignedIntegral;
-
-    // Assume that non-integer casts can span the full range of the type.
-    if (!isIntegerCast)
-      return OutputTypeRange;
-
-    std::optional<IntRange> SubRange = TryGetExprRange(
-        C, CE->getSubExpr(), std::min(MaxWidth, OutputTypeRange.Width),
-        InConstantContext, Approximate);
-    if (!SubRange)
-      return std::nullopt;
-
-    // Bail out if the subexpr's range is as wide as the cast type.
-    if (SubRange->Width >= OutputTypeRange.Width)
-      return OutputTypeRange;
-
-    // Otherwise, we take the smaller width, and we're non-negative if
-    // either the output type or the subexpr is.
-    return IntRange(SubRange->Width,
-                    SubRange->NonNegative || OutputTypeRange.NonNegative);
-  }
-
-  if (const auto *CO = dyn_cast<ConditionalOperator>(E)) {
-    // If we can fold the condition, just take that operand.
-    bool CondResult;
-    if (CO->getCond()->EvaluateAsBooleanCondition(CondResult, C))
-      return TryGetExprRange(
-          C, CondResult ? CO->getTrueExpr() : CO->getFalseExpr(), MaxWidth,
-          InConstantContext, Approximate);
-
-    // Otherwise, conservatively merge.
-    // TryGetExprRange requires an integer expression, but a throw expression
-    // results in a void type.
-    Expr *TrueExpr = CO->getTrueExpr();
-    if (TrueExpr->getType()->isVoidType())
-      return std::nullopt;
-
-    std::optional<IntRange> L =
-        TryGetExprRange(C, TrueExpr, MaxWidth, InConstantContext, Approximate);
-    if (!L)
-      return std::nullopt;
-
-    Expr *FalseExpr = CO->getFalseExpr();
-    if (FalseExpr->getType()->isVoidType())
-      return std::nullopt;
-
-    std::optional<IntRange> R =
-        TryGetExprRange(C, FalseExpr, MaxWidth, InConstantContext, Approximate);
-    if (!R)
-      return std::nullopt;
-
-    return IntRange::join(*L, *R);
-  }
-
-  if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
-    IntRange (*Combine)(IntRange, IntRange) = IntRange::join;
-
-    switch (BO->getOpcode()) {
-    case BO_Cmp:
-      llvm_unreachable("builtin <=> should have class type");
-
-    // Boolean-valued operations are single-bit and positive.
-    case BO_LAnd:
-    case BO_LOr:
-    case BO_LT:
-    case BO_GT:
-    case BO_LE:
-    case BO_GE:
-    case BO_EQ:
-    case BO_NE:
-      return IntRange::forBoolType();
-
-    // The type of the assignments is the type of the LHS, so the RHS
-    // is not necessarily the same type.
-    case BO_MulAssign:
-    case BO_DivAssign:
-    case BO_RemAssign:
-    case BO_AddAssign:
-    case BO_SubAssign:
-    case BO_XorAssign:
-    case BO_OrAssign:
-      // TODO: bitfields?
-      return IntRange::forValueOfType(C, GetExprType(E));
-
-    // Simple assignments just pass through the RHS, which will have
-    // been coerced to the LHS type.
-    case BO_Assign:
-      // TODO: bitfields?
-      return TryGetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext,
-                             Approximate);
-
-    // Operations with opaque sources are black-listed.
-    case BO_PtrMemD:
-    case BO_PtrMemI:
-      return IntRange::forValueOfType(C, GetExprType(E));
-
-    // Bitwise-and uses the *infinum* of the two source ranges.
-    case BO_And:
-    case BO_AndAssign:
-      Combine = IntRange::bit_and;
-      break;
-
-    // Left shift gets black-listed based on a judgement call.
-    case BO_Shl:
-      // ...except that we want to treat '1 << (blah)' as logically
-      // positive.  It's an important idiom.
-      if (IntegerLiteral *I
-            = dyn_cast<IntegerLiteral>(BO->getLHS()->IgnoreParenCasts())) {
-        if (I->getValue() == 1) {
-          IntRange R = IntRange::forValueOfType(C, GetExprType(E));
-          return IntRange(R.Width, /*NonNegative*/ true);
-        }
-      }
-      [[fallthrough]];
-
-    case BO_ShlAssign:
-      return IntRange::forValueOfType(C, GetExprType(E));
-
-    // Right shift by a constant can narrow its left argument.
-    case BO_Shr:
-    case BO_ShrAssign: {
-      std::optional<IntRange> L = TryGetExprRange(
-          C, BO->getLHS(), MaxWidth, InConstantContext, Approximate);
-      if (!L)
-        return std::nullopt;
-
-      // If the shift amount is a positive constant, drop the width by
-      // that much.
-      if (std::optional<llvm::APSInt> shift =
-              BO->getRHS()->getIntegerConstantExpr(C)) {
-        if (shift->isNonNegative()) {
-          if (shift->uge(L->Width))
-            L->Width = (L->NonNegative ? 0 : 1);
-          else
-            L->Width -= shift->getZExtValue();
-        }
-      }
-
-      return L;
-    }
-
-    // Comma acts as its right operand.
-    case BO_Comma:
-      return TryGetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext,
-                             Approximate);
-
-    case BO_Add:
-      if (!Approximate)
-        Combine = IntRange::sum;
-      break;
-
-    case BO_Sub:
-      if (BO->getLHS()->getType()->isPointerType())
-        return IntRange::forValueOfType(C, GetExprType(E));
-      if (!Approximate)
-        Combine = IntRange::difference;
-      break;
-
-    case BO_Mul:
-      if (!Approximate)
-        Combine = IntRange::product;
-      break;
-
-    // The width of a division result is mostly determined by the size
-    // of the LHS.
-    case BO_Div: {
-      // Don't 'pre-truncate' the operands.
-      unsigned opWidth = C.getIntWidth(GetExprType(E));
-      std::optional<IntRange> L = TryGetExprRange(
-          C, BO->getLHS(), opWidth, InConstantContext, Approximate);
-      if (!L)
-        return std::nullopt;
-
-      // If the divisor is constant, use that.
-      if (std::optional<llvm::APSInt> divisor =
-              BO->getRHS()->getIntegerConstantExpr(C)) {
-        unsigned log2 = divisor->logBase2(); // floor(log_2(divisor))
-        if (log2 >= L->Width)
-          L->Width = (L->NonNegative ? 0 : 1);
-        else
-          L->Width = std::min(L->Width - log2, MaxWidth);
-        return L;
-      }
-
-      // Otherwise, just use the LHS's width.
-      // FIXME: This is wrong if the LHS could be its minimal value and the RHS
-      // could be -1.
-      std::optional<IntRange> R = TryGetExprRange(
-          C, BO->getRHS(), opWidth, InConstantContext, Approximate);
-      if (!R)
-        return std::nullopt;
-
-      return IntRange(L->Width, L->NonNegative && R->NonNegative);
-    }
-
-    case BO_Rem:
-      Combine = IntRange::rem;
-      break;
-
-    // The default behavior is okay for these.
-    case BO_Xor:
-    case BO_Or:
-      break;
-    }
-
-    // Combine the two ranges, but limit the result to the type in which we
-    // performed the computation.
-    QualType T = GetExprType(E);
-    unsigned opWidth = C.getIntWidth(T);
-    std::optional<IntRange> L = TryGetExprRange(C, BO->getLHS(), opWidth,
-                                                InConstantContext, Approximate);
-    if (!L)
-      return std::nullopt;
-
-    std::optional<IntRange> R = TryGetExprRange(C, BO->getRHS(), opWidth,
-                                                InConstantContext, Approximate);
-    if (!R)
-      return std::nullopt;
-
-    IntRange C = Combine(*L, *R);
-    C.NonNegative |= T->isUnsignedIntegerOrEnumerationType();
-    C.Width = std::min(C.Width, MaxWidth);
-    return C;
-  }
-
-  if (const auto *UO = dyn_cast<UnaryOperator>(E)) {
-    switch (UO->getOpcode()) {
-    // Boolean-valued operations are white-listed.
-    case UO_LNot:
-      return IntRange::forBoolType();
-
-    // Operations with opaque sources are black-listed.
-    case UO_Deref:
-    case UO_AddrOf: // should be impossible
-      return IntRange::forValueOfType(C, GetExprType(E));
-
-    case UO_Minus: {
-      if (E->getType()->isUnsignedIntegerType()) {
-        return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext,
-                               Approximate);
-      }
-
-      std::optional<IntRange> SubRange = TryGetExprRange(
-          C, UO->getSubExpr(), MaxWidth, InConstantContext, Approximate);
-
-      if (!SubRange)
-        return std::nullopt;
-
-      // If the range was previously non-negative, we need an extra bit for the
-      // sign bit. Otherwise, we need an extra bit because the negation of the
-      // most-negative value is one bit wider than that value.
-      return IntRange(std::min(SubRange->Width + 1, MaxWidth), false);
-    }
-
-    case UO_Not: {
-      if (E->getType()->isUnsignedIntegerType()) {
-        return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext,
-                               Approximate);
-      }
-
-      std::optional<IntRange> SubRange = TryGetExprRange(
-          C, UO->getSubExpr(), MaxWidth, InConstantContext, Approximate);
-
-      if (!SubRange)
-        return std::nullopt;
-
-      // The width increments by 1 if the sub-expression cannot be negative
-      // since it now can be.
-      return IntRange(
-          std::min(SubRange->Width + (int)SubRange->NonNegative, MaxWidth),
-          false);
-    }
-
-    default:
-      return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext,
-                             Approximate);
-    }
-  }
-
-  if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E))
-    return TryGetExprRange(C, OVE->getSourceExpr(), MaxWidth, InConstantContext,
-                           Approximate);
-
-  if (const auto *BitField = E->getSourceBitField())
-    return IntRange(BitField->getBitWidthValue(),
-                    BitField->getType()->isUnsignedIntegerOrEnumerationType());
-
-  if (GetExprType(E)->isVoidType())
-    return std::nullopt;
-
-  return IntRange::forValueOfType(C, GetExprType(E));
-}
-
-static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E,
-                                               bool InConstantContext,
-                                               bool Approximate) {
-  return TryGetExprRange(C, E, C.getIntWidth(GetExprType(E)), InConstantContext,
-                         Approximate);
-}
-
-/// Checks whether the given value, which currently has the given
-/// source semantics, has the same value when coerced through the
-/// target semantics.
-static bool IsSameFloatAfterCast(const llvm::APFloat &value,
-                                 const llvm::fltSemantics &Src,
-                                 const llvm::fltSemantics &Tgt) {
-  llvm::APFloat truncated = value;
-
-  bool ignored;
-  truncated.convert(Src, llvm::APFloat::rmNearestTiesToEven, &ignored);
-  truncated.convert(Tgt, llvm::APFloat::rmNearestTiesToEven, &ignored);
-
-  return truncated.bitwiseIsEqual(value);
-}
-
-/// Checks whether the given value, which currently has the given
-/// source semantics, has the same value when coerced through the
-/// target semantics.
-///
-/// The value might be a vector of floats (or a complex number).
-static bool IsSameFloatAfterCast(const APValue &value,
-                                 const llvm::fltSemantics &Src,
-                                 const llvm::fltSemantics &Tgt) {
-  if (value.isFloat())
-    return IsSameFloatAfterCast(value.getFloat(), Src, Tgt);
-
-  if (value.isVector()) {
-    for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i)
-      if (!IsSameFloatAfterCast(value.getVectorElt(i), Src, Tgt))
-        return false;
-    return true;
-  }
-
-  assert(value.isComplexFloat());
-  return (IsSameFloatAfterCast(value.getComplexFloatReal(), Src, Tgt) &&
-          IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt));
-}
-
-static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC,
-                                       bool IsListInit = false);
-
-static bool IsEnumConstOrFromMacro(Sema &S, const Expr *E) {
-  // Suppress cases where we are comparing against an enum constant.
-  if (const auto *DR = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
-    if (isa<EnumConstantDecl>(DR->getDecl()))
-      return true;
-
-  // Suppress cases where the value is expanded from a macro, unless that macro
-  // is how a language represents a boolean literal. This is the case in both C
-  // and Objective-C.
-  SourceLocation BeginLoc = E->getBeginLoc();
-  if (BeginLoc.isMacroID()) {
-    StringRef MacroName = Lexer::getImmediateMacroName(
-        BeginLoc, S.getSourceManager(), S.getLangOpts());
-    return MacroName != "YES" && MacroName != "NO" &&
-           MacroName != "true" && MacroName != "false";
-  }
-
-  return false;
-}
-
-static bool isKnownToHaveUnsignedValue(const Expr *E) {
-  return E->getType()->isIntegerType() &&
-         (!E->getType()->isSignedIntegerType() ||
-          !E->IgnoreParenImpCasts()->getType()->isSignedIntegerType());
-}
-
-namespace {
-/// The promoted range of values of a type. In general this has the
-/// following structure:
-///
-///     |-----------| . . . |-----------|
-///     ^           ^       ^           ^
-///    Min       HoleMin  HoleMax      Max
-///
-/// ... where there is only a hole if a signed type is promoted to unsigned
-/// (in which case Min and Max are the smallest and largest representable
-/// values).
-struct PromotedRange {
-  // Min, or HoleMax if there is a hole.
-  llvm::APSInt PromotedMin;
-  // Max, or HoleMin if there is a hole.
-  llvm::APSInt PromotedMax;
-
-  PromotedRange(IntRange R, unsigned BitWidth, bool Unsigned) {
-    if (R.Width == 0)
-      PromotedMin = PromotedMax = llvm::APSInt(BitWidth, Unsigned);
-    else if (R.Width >= BitWidth && !Unsigned) {
-      // Promotion made the type *narrower*. This happens when promoting
-      // a < 32-bit unsigned / <= 32-bit signed bit-field to 'signed int'.
-      // Treat all values of 'signed int' as being in range for now.
-      PromotedMin = llvm::APSInt::getMinValue(BitWidth, Unsigned);
-      PromotedMax = llvm::APSInt::getMaxValue(BitWidth, Unsigned);
-    } else {
-      PromotedMin = llvm::APSInt::getMinValue(R.Width, R.NonNegative)
-                        .extOrTrunc(BitWidth);
-      PromotedMin.setIsUnsigned(Unsigned);
-
-      PromotedMax = llvm::APSInt::getMaxValue(R.Width, R.NonNegative)
-                        .extOrTrunc(BitWidth);
-      PromotedMax.setIsUnsigned(Unsigned);
-    }
-  }
-
-  // Determine whether this range is contiguous (has no hole).
-  bool isContiguous() const { return PromotedMin <= PromotedMax; }
-
-  // Where a constant value is within the range.
-  enum ComparisonResult {
-    LT = 0x1,
-    LE = 0x2,
-    GT = 0x4,
-    GE = 0x8,
-    EQ = 0x10,
-    NE = 0x20,
-    InRangeFlag = 0x40,
-
-    Less = LE | LT | NE,
-    Min = LE | InRangeFlag,
-    InRange = InRangeFlag,
-    Max = GE | InRangeFlag,
-    Greater = GE | GT | NE,
-
-    OnlyValue = LE | GE | EQ | InRangeFlag,
-    InHole = NE
-  };
-
-  ComparisonResult compare(const llvm::APSInt &Value) const {
-    assert(Value.getBitWidth() == PromotedMin.getBitWidth() &&
-           Value.isUnsigned() == PromotedMin.isUnsigned());
-    if (!isContiguous()) {
-      assert(Value.isUnsigned() && "discontiguous range for signed compare");
-      if (Value.isMinValue()) return Min;
-      if (Value.isMaxValue()) return Max;
-      if (Value >= PromotedMin) return InRange;
-      if (Value <= PromotedMax) return InRange;
-      return InHole;
-    }
-
-    switch (llvm::APSInt::compareValues(Value, PromotedMin)) {
-    case -1: return Less;
-    case 0: return PromotedMin == PromotedMax ? OnlyValue : Min;
-    case 1:
-      switch (llvm::APSInt::compareValues(Value, PromotedMax)) {
-      case -1: return InRange;
-      case 0: return Max;
-      case 1: return Greater;
-      }
-    }
-
-    llvm_unreachable("impossible compare result");
-  }
-
-  static std::optional<StringRef>
-  constantValue(BinaryOperatorKind Op, ComparisonResult R, bool ConstantOnRHS) {
-    if (Op == BO_Cmp) {
-      ComparisonResult LTFlag = LT, GTFlag = GT;
-      if (ConstantOnRHS) std::swap(LTFlag, GTFlag);
-
-      if (R & EQ) return StringRef("'std::strong_ordering::equal'");
-      if (R & LTFlag) return StringRef("'std::strong_ordering::less'");
-      if (R & GTFlag) return StringRef("'std::strong_ordering::greater'");
-      return std::nullopt;
-    }
-
-    ComparisonResult TrueFlag, FalseFlag;
-    if (Op == BO_EQ) {
-      TrueFlag = EQ;
-      FalseFlag = NE;
-    } else if (Op == BO_NE) {
-      TrueFlag = NE;
-      FalseFlag = EQ;
-    } else {
-      if ((Op == BO_LT || Op == BO_GE) ^ ConstantOnRHS) {
-        TrueFlag = LT;
-        FalseFlag = GE;
-      } else {
-        TrueFlag = GT;
-        FalseFlag = LE;
-      }
-      if (Op == BO_GE || Op == BO_LE)
-        std::swap(TrueFlag, FalseFlag);
-    }
-    if (R & TrueFlag)
-      return StringRef("true");
-    if (R & FalseFlag)
-      return StringRef("false");
-    return std::nullopt;
-  }
-};
-}
-
-static bool HasEnumType(const Expr *E) {
-  // Strip off implicit integral promotions.
-  while (const auto *ICE = dyn_cast<ImplicitCastExpr>(E)) {
-    if (ICE->getCastKind() != CK_IntegralCast &&
-        ICE->getCastKind() != CK_NoOp)
-      break;
-    E = ICE->getSubExpr();
-  }
-
-  return E->getType()->isEnumeralType();
-}
-
-static int classifyConstantValue(Expr *Constant) {
-  // The values of this enumeration are used in the diagnostics
-  // diag::warn_out_of_range_compare and diag::warn_tautological_bool_compare.
-  enum ConstantValueKind {
-    Miscellaneous = 0,
-    LiteralTrue,
-    LiteralFalse
-  };
-  if (auto *BL = dyn_cast<CXXBoolLiteralExpr>(Constant))
-    return BL->getValue() ? ConstantValueKind::LiteralTrue
-                          : ConstantValueKind::LiteralFalse;
-  return ConstantValueKind::Miscellaneous;
-}
-
-static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E,
-                                        Expr *Constant, Expr *Other,
-                                        const llvm::APSInt &Value,
-                                        bool RhsConstant) {
-  if (S.inTemplateInstantiation())
-    return false;
-
-  Expr *OriginalOther = Other;
-
-  Constant = Constant->IgnoreParenImpCasts();
-  Other = Other->IgnoreParenImpCasts();
-
-  // Suppress warnings on tautological comparisons between values of the same
-  // enumeration type. There are only two ways we could warn on this:
-  //  - If the constant is outside the range of representable values of
-  //    the enumeration. In such a case, we should warn about the cast
-  //    to enumeration type, not about the comparison.
-  //  - If the constant is the maximum / minimum in-range value. For an
-  //    enumeratin type, such comparisons can be meaningful and useful.
-  if (Constant->getType()->isEnumeralType() &&
-      S.Context.hasSameUnqualifiedType(Constant->getType(), Other->getType()))
-    return false;
-
-  std::optional<IntRange> OtherValueRange = TryGetExprRange(
-      S.Context, Other, S.isConstantEvaluatedContext(), /*Approximate=*/false);
-  if (!OtherValueRange)
-    return false;
-
-  QualType OtherT = Other->getType();
-  if (const auto *AT = OtherT->getAs<AtomicType>())
-    OtherT = AT->getValueType();
-  IntRange OtherTypeRange = IntRange::forValueOfType(S.Context, OtherT);
-
-  // Special case for ObjC BOOL on targets where its a typedef for a signed char
-  // (Namely, macOS). FIXME: IntRange::forValueOfType should do this.
-  bool IsObjCSignedCharBool = S.getLangOpts().ObjC &&
-                              S.ObjC().NSAPIObj->isObjCBOOLType(OtherT) &&
-                              OtherT->isSpecificBuiltinType(BuiltinType::SChar);
-
-  // Whether we're treating Other as being a bool because of the form of
-  // expression despite it having another type (typically 'int' in C).
-  bool OtherIsBooleanDespiteType =
-      !OtherT->isBooleanType() && Other->isKnownToHaveBooleanValue();
-  if (OtherIsBooleanDespiteType || IsObjCSignedCharBool)
-    OtherTypeRange = *OtherValueRange = IntRange::forBoolType();
-
-  // Check if all values in the range of possible values of this expression
-  // lead to the same comparison outcome.
-  PromotedRange OtherPromotedValueRange(*OtherValueRange, Value.getBitWidth(),
-                                        Value.isUnsigned());
-  auto Cmp = OtherPromotedValueRange.compare(Value);
-  auto Result = PromotedRange::constantValue(E->getOpcode(), Cmp, RhsConstant);
-  if (!Result)
-    return false;
-
-  // Also consider the range determined by the type alone. This allows us to
-  // classify the warning under the proper diagnostic group.
-  bool TautologicalTypeCompare = false;
-  {
-    PromotedRange OtherPromotedTypeRange(OtherTypeRange, Value.getBitWidth(),
-                                         Value.isUnsigned());
-    auto TypeCmp = OtherPromotedTypeRange.compare(Value);
-    if (auto TypeResult = PromotedRange::constantValue(E->getOpcode(), TypeCmp,
-                                                       RhsConstant)) {
-      TautologicalTypeCompare = true;
-      Cmp = TypeCmp;
-      Result = TypeResult;
-    }
-  }
-
-  // Don't warn if the non-constant operand actually always evaluates to the
-  // same value.
-  if (!TautologicalTypeCompare && OtherValueRange->Width == 0)
-    return false;
-
-  // Suppress the diagnostic for an in-range comparison if the constant comes
-  // from a macro or enumerator. We don't want to diagnose
-  //
-  //   some_long_value <= INT_MAX
-  //
-  // when sizeof(int) == sizeof(long).
-  bool InRange = Cmp & PromotedRange::InRangeFlag;
-  if (InRange && IsEnumConstOrFromMacro(S, Constant))
-    return false;
-
-  // A comparison of an unsigned bit-field against 0 is really a type problem,
-  // even though at the type level the bit-field might promote to 'signed int'.
-  if (Other->refersToBitField() && InRange && Value == 0 &&
-      Other->getType()->isUnsignedIntegerOrEnumerationType())
-    TautologicalTypeCompare = true;
-
-  // If this is a comparison to an enum constant, include that
-  // constant in the diagnostic.
-  const EnumConstantDecl *ED = nullptr;
-  if (const auto *DR = dyn_cast<DeclRefExpr>(Constant))
-    ED = dyn_cast<EnumConstantDecl>(DR->getDecl());
-
-  // Should be enough for uint128 (39 decimal digits)
-  SmallString<64> PrettySourceValue;
-  llvm::raw_svector_ostream OS(PrettySourceValue);
-  if (ED) {
-    OS << '\'' << *ED << "' (" << Value << ")";
-  } else if (auto *BL = dyn_cast<ObjCBoolLiteralExpr>(
-               Constant->IgnoreParenImpCasts())) {
-    OS << (BL->getValue() ? "YES" : "NO");
-  } else {
-    OS << Value;
-  }
-
-  if (!TautologicalTypeCompare) {
-    S.Diag(E->getOperatorLoc(), diag::warn_tautological_compare_value_range)
-        << RhsConstant << OtherValueRange->Width << OtherValueRange->NonNegative
-        << E->getOpcodeStr() << OS.str() << *Result
-        << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
-    return true;
-  }
-
-  if (IsObjCSignedCharBool) {
-    S.DiagRuntimeBehavior(E->getOperatorLoc(), E,
-                          S.PDiag(diag::warn_tautological_compare_objc_bool)
-                              << OS.str() << *Result);
-    return true;
-  }
-
-  // FIXME: We use a somewhat different formatting for the in-range cases and
-  // cases involving boolean values for historical reasons. We should pick a
-  // consistent way of presenting these diagnostics.
-  if (!InRange || Other->isKnownToHaveBooleanValue()) {
-
-    S.DiagRuntimeBehavior(
-        E->getOperatorLoc(), E,
-        S.PDiag(!InRange ? diag::warn_out_of_range_compare
-                         : diag::warn_tautological_bool_compare)
-            << OS.str() << classifyConstantValue(Constant) << OtherT
-            << OtherIsBooleanDespiteType << *Result
-            << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange());
-  } else {
-    bool IsCharTy = OtherT.withoutLocalFastQualifiers() == S.Context.CharTy;
-    unsigned Diag =
-        (isKnownToHaveUnsignedValue(OriginalOther) && Value == 0)
-            ? (HasEnumType(OriginalOther)
-                   ? diag::warn_unsigned_enum_always_true_comparison
-                   : IsCharTy ? diag::warn_unsigned_char_always_true_comparison
-                              : diag::warn_unsigned_always_true_comparison)
-            : diag::warn_tautological_constant_compare;
-
-    S.Diag(E->getOperatorLoc(), Diag)
-        << RhsConstant << OtherT << E->getOpcodeStr() << OS.str() << *Result
-        << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
-  }
-
-  return true;
-}
-
-/// Analyze the operands of the given comparison.  Implements the
-/// fallback case from AnalyzeComparison.
-static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
-  AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc());
-  AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc());
-}
-
-/// Implements -Wsign-compare.
-///
-/// \param E the binary operator to check for warnings
-static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
-  // The type the comparison is being performed in.
-  QualType T = E->getLHS()->getType();
-
-  // Only analyze comparison operators where both sides have been converted to
-  // the same type.
-  if (!S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType()))
-    return AnalyzeImpConvsInComparison(S, E);
-
-  // Don't analyze value-dependent comparisons directly.
-  if (E->isValueDependent())
-    return AnalyzeImpConvsInComparison(S, E);
-
-  Expr *LHS = E->getLHS();
-  Expr *RHS = E->getRHS();
-
-  if (T->isIntegralType(S.Context)) {
-    std::optional<llvm::APSInt> RHSValue =
-        RHS->getIntegerConstantExpr(S.Context);
-    std::optional<llvm::APSInt> LHSValue =
-        LHS->getIntegerConstantExpr(S.Context);
-
-    // We don't care about expressions whose result is a constant.
-    if (RHSValue && LHSValue)
-      return AnalyzeImpConvsInComparison(S, E);
-
-    // We only care about expressions where just one side is literal
-    if ((bool)RHSValue ^ (bool)LHSValue) {
-      // Is the constant on the RHS or LHS?
-      const bool RhsConstant = (bool)RHSValue;
-      Expr *Const = RhsConstant ? RHS : LHS;
-      Expr *Other = RhsConstant ? LHS : RHS;
-      const llvm::APSInt &Value = RhsConstant ? *RHSValue : *LHSValue;
-
-      // Check whether an integer constant comparison results in a value
-      // of 'true' or 'false'.
-      if (CheckTautologicalComparison(S, E, Const, Other, Value, RhsConstant))
-        return AnalyzeImpConvsInComparison(S, E);
-    }
-  }
-
-  if (!T->hasUnsignedIntegerRepresentation()) {
-    // We don't do anything special if this isn't an unsigned integral
-    // comparison:  we're only interested in integral comparisons, and
-    // signed comparisons only happen in cases we don't care to warn about.
-    return AnalyzeImpConvsInComparison(S, E);
-  }
-
-  LHS = LHS->IgnoreParenImpCasts();
-  RHS = RHS->IgnoreParenImpCasts();
-
-  if (!S.getLangOpts().CPlusPlus) {
-    // Avoid warning about comparison of integers with different signs when
-    // RHS/LHS has a `typeof(E)` type whose sign is different from the sign of
-    // the type of `E`.
-    if (const auto *TET = dyn_cast<TypeOfExprType>(LHS->getType()))
-      LHS = TET->getUnderlyingExpr()->IgnoreParenImpCasts();
-    if (const auto *TET = dyn_cast<TypeOfExprType>(RHS->getType()))
-      RHS = TET->getUnderlyingExpr()->IgnoreParenImpCasts();
-  }
-
-  // Check to see if one of the (unmodified) operands is of different
-  // signedness.
-  Expr *signedOperand, *unsignedOperand;
-  if (LHS->getType()->hasSignedIntegerRepresentation()) {
-    assert(!RHS->getType()->hasSignedIntegerRepresentation() &&
-           "unsigned comparison between two signed integer expressions?");
-    signedOperand = LHS;
-    unsignedOperand = RHS;
-  } else if (RHS->getType()->hasSignedIntegerRepresentation()) {
-    signedOperand = RHS;
-    unsignedOperand = LHS;
-  } else {
-    return AnalyzeImpConvsInComparison(S, E);
-  }
-
-  // Otherwise, calculate the effective range of the signed operand.
-  std::optional<IntRange> signedRange =
-      TryGetExprRange(S.Context, signedOperand, S.isConstantEvaluatedContext(),
-                      /*Approximate=*/true);
-  if (!signedRange)
-    return;
-
-  // Go ahead and analyze implicit conversions in the operands.  Note
-  // that we skip the implicit conversions on both sides.
-  AnalyzeImplicitConversions(S, LHS, E->getOperatorLoc());
-  AnalyzeImplicitConversions(S, RHS, E->getOperatorLoc());
-
-  // If the signed range is non-negative, -Wsign-compare won't fire.
-  if (signedRange->NonNegative)
-    return;
-
-  // For (in)equality comparisons, if the unsigned operand is a
-  // constant which cannot collide with a overflowed signed operand,
-  // then reinterpreting the signed operand as unsigned will not
-  // change the result of the comparison.
-  if (E->isEqualityOp()) {
-    unsigned comparisonWidth = S.Context.getIntWidth(T);
-    std::optional<IntRange> unsignedRange = TryGetExprRange(
-        S.Context, unsignedOperand, S.isConstantEvaluatedContext(),
-        /*Approximate=*/true);
-    if (!unsignedRange)
-      return;
-
-    // We should never be unable to prove that the unsigned operand is
-    // non-negative.
-    assert(unsignedRange->NonNegative && "unsigned range includes negative?");
-
-    if (unsignedRange->Width < comparisonWidth)
-      return;
-  }
-
-  S.DiagRuntimeBehavior(E->getOperatorLoc(), E,
-                        S.PDiag(diag::warn_mixed_sign_comparison)
-                            << LHS->getType() << RHS->getType()
-                            << LHS->getSourceRange() << RHS->getSourceRange());
-}
-
-/// Analyzes an attempt to assign the given value to a bitfield.
-///
-/// Returns true if there was something fishy about the attempt.
-static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
-                                      SourceLocation InitLoc) {
-  assert(Bitfield->isBitField());
-  if (Bitfield->isInvalidDecl())
-    return false;
-
-  // White-list bool bitfields.
-  QualType BitfieldType = Bitfield->getType();
-  if (BitfieldType->isBooleanType())
-     return false;
-
-  if (auto *BitfieldEnumDecl = BitfieldType->getAsEnumDecl()) {
-    // If the underlying enum type was not explicitly specified as an unsigned
-    // type and the enum contain only positive values, MSVC++ will cause an
-    // inconsistency by storing this as a signed type.
-    if (S.getLangOpts().CPlusPlus11 &&
-        !BitfieldEnumDecl->getIntegerTypeSourceInfo() &&
-        BitfieldEnumDecl->getNumPositiveBits() > 0 &&
-        BitfieldEnumDecl->getNumNegativeBits() == 0) {
-      S.Diag(InitLoc, diag::warn_no_underlying_type_specified_for_enum_bitfield)
-          << BitfieldEnumDecl;
-    }
-  }
-
-  // Ignore value- or type-dependent expressions.
-  if (Bitfield->getBitWidth()->isValueDependent() ||
-      Bitfield->getBitWidth()->isTypeDependent() ||
-      Init->isValueDependent() ||
-      Init->isTypeDependent())
-    return false;
-
-  Expr *OriginalInit = Init->IgnoreParenImpCasts();
-  unsigned FieldWidth = Bitfield->getBitWidthValue();
-
-  Expr::EvalResult Result;
-  if (!OriginalInit->EvaluateAsInt(Result, S.Context,
-                                   Expr::SE_AllowSideEffects)) {
-    // The RHS is not constant.  If the RHS has an enum type, make sure the
-    // bitfield is wide enough to hold all the values of the enum without
-    // truncation.
-    const auto *ED = OriginalInit->getType()->getAsEnumDecl();
-    const PreferredTypeAttr *PTAttr = nullptr;
-    if (!ED) {
-      PTAttr = Bitfield->getAttr<PreferredTypeAttr>();
-      if (PTAttr)
-        ED = PTAttr->getType()->getAsEnumDecl();
-    }
-    if (ED) {
-      bool SignedBitfield = BitfieldType->isSignedIntegerOrEnumerationType();
-
-      // Enum types are implicitly signed on Windows, so check if there are any
-      // negative enumerators to see if the enum was intended to be signed or
-      // not.
-      bool SignedEnum = ED->getNumNegativeBits() > 0;
-
-      // Check for surprising sign changes when assigning enum values to a
-      // bitfield of different signedness.  If the bitfield is signed and we
-      // have exactly the right number of bits to store this unsigned enum,
-      // suggest changing the enum to an unsigned type. This typically happens
-      // on Windows where unfixed enums always use an underlying type of 'int'.
-      unsigned DiagID = 0;
-      if (SignedEnum && !SignedBitfield) {
-        DiagID =
-            PTAttr == nullptr
-                ? diag::warn_unsigned_bitfield_assigned_signed_enum
-                : diag::
-                      warn_preferred_type_unsigned_bitfield_assigned_signed_enum;
-      } else if (SignedBitfield && !SignedEnum &&
-                 ED->getNumPositiveBits() == FieldWidth) {
-        DiagID =
-            PTAttr == nullptr
-                ? diag::warn_signed_bitfield_enum_conversion
-                : diag::warn_preferred_type_signed_bitfield_enum_conversion;
-      }
-      if (DiagID) {
-        S.Diag(InitLoc, DiagID) << Bitfield << ED;
-        TypeSourceInfo *TSI = Bitfield->getTypeSourceInfo();
-        SourceRange TypeRange =
-            TSI ? TSI->getTypeLoc().getSourceRange() : SourceRange();
-        S.Diag(Bitfield->getTypeSpecStartLoc(), diag::note_change_bitfield_sign)
-            << SignedEnum << TypeRange;
-        if (PTAttr)
-          S.Diag(PTAttr->getLocation(), diag::note_bitfield_preferred_type)
-              << ED;
-      }
-
-      // Compute the required bitwidth. If the enum has negative values, we need
-      // one more bit than the normal number of positive bits to represent the
-      // sign bit.
-      unsigned BitsNeeded = SignedEnum ? std::max(ED->getNumPositiveBits() + 1,
-                                                  ED->getNumNegativeBits())
-                                       : ED->getNumPositiveBits();
-
-      // Check the bitwidth.
-      if (BitsNeeded > FieldWidth) {
-        Expr *WidthExpr = Bitfield->getBitWidth();
-        auto DiagID =
-            PTAttr == nullptr
-                ? diag::warn_bitfield_too_small_for_enum
-                : diag::warn_preferred_type_bitfield_too_small_for_enum;
-        S.Diag(InitLoc, DiagID) << Bitfield << ED;
-        S.Diag(WidthExpr->getExprLoc(), diag::note_widen_bitfield)
-            << BitsNeeded << ED << WidthExpr->getSourceRange();
-        if (PTAttr)
-          S.Diag(PTAttr->getLocation(), diag::note_bitfield_preferred_type)
-              << ED;
-      }
-    }
-
-    return false;
-  }
-
-  llvm::APSInt Value = Result.Val.getInt();
-
-  unsigned OriginalWidth = Value.getBitWidth();
-
-  // In C, the macro 'true' from stdbool.h will evaluate to '1'; To reduce
-  // false positives where the user is demonstrating they intend to use the
-  // bit-field as a Boolean, check to see if the value is 1 and we're assigning
-  // to a one-bit bit-field to see if the value came from a macro named 'true'.
-  bool OneAssignedToOneBitBitfield = FieldWidth == 1 && Value == 1;
-  if (OneAssignedToOneBitBitfield && !S.LangOpts.CPlusPlus) {
-    SourceLocation MaybeMacroLoc = OriginalInit->getBeginLoc();
-    if (S.SourceMgr.isInSystemMacro(MaybeMacroLoc) &&
-        S.findMacroSpelling(MaybeMacroLoc, "true"))
-      return false;
-  }
-
-  if (!Value.isSigned() || Value.isNegative())
-    if (UnaryOperator *UO = dyn_cast<UnaryOperator>(OriginalInit))
-      if (UO->getOpcode() == UO_Minus || UO->getOpcode() == UO_Not)
-        OriginalWidth = Value.getSignificantBits();
-
-  if (OriginalWidth <= FieldWidth)
-    return false;
-
-  // Compute the value which the bitfield will contain.
-  llvm::APSInt TruncatedValue = Value.trunc(FieldWidth);
-  TruncatedValue.setIsSigned(BitfieldType->isSignedIntegerType());
-
-  // Check whether the stored value is equal to the original value.
-  TruncatedValue = TruncatedValue.extend(OriginalWidth);
-  if (llvm::APSInt::isSameValue(Value, TruncatedValue))
-    return false;
-
-  std::string PrettyValue = toString(Value, 10);
-  std::string PrettyTrunc = toString(TruncatedValue, 10);
-
-  S.Diag(InitLoc, OneAssignedToOneBitBitfield
-                      ? diag::warn_impcast_single_bit_bitield_precision_constant
-                      : diag::warn_impcast_bitfield_precision_constant)
-      << PrettyValue << PrettyTrunc << OriginalInit->getType()
-      << Init->getSourceRange();
-
-  return true;
-}
-
-/// Analyze the given simple or compound assignment for warning-worthy
-/// operations.
-static void AnalyzeAssignment(Sema &S, BinaryOperator *E) {
-  // Just recurse on the LHS.
-  AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc());
-
-  // We want to recurse on the RHS as normal unless we're assigning to
-  // a bitfield.
-  if (FieldDecl *Bitfield = E->getLHS()->getSourceBitField()) {
-    if (AnalyzeBitFieldAssignment(S, Bitfield, E->getRHS(),
-                                  E->getOperatorLoc())) {
-      // Recurse, ignoring any implicit conversions on the RHS.
-      return AnalyzeImplicitConversions(S, E->getRHS()->IgnoreParenImpCasts(),
-                                        E->getOperatorLoc());
-    }
-  }
-
-  AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc());
-
-  // Diagnose implicitly sequentially-consistent atomic assignment.
-  if (E->getLHS()->getType()->isAtomicType())
-    S.Diag(E->getRHS()->getBeginLoc(), diag::warn_atomic_implicit_seq_cst);
-}
-
-/// Diagnose an implicit cast;  purely a helper for CheckImplicitConversion.
-static void DiagnoseImpCast(Sema &S, const Expr *E, QualType SourceType,
-                            QualType T, SourceLocation CContext, unsigned diag,
-                            bool PruneControlFlow = false) {
-  // For languages like HLSL and OpenCL, implicit conversion diagnostics listing
-  // address space annotations isn't really useful. The warnings aren't because
-  // you're converting a `private int` to `unsigned int`, it is because you're
-  // conerting `int` to `unsigned int`.
-  if (SourceType.hasAddressSpace())
-    SourceType = S.getASTContext().removeAddrSpaceQualType(SourceType);
-  if (T.hasAddressSpace())
-    T = S.getASTContext().removeAddrSpaceQualType(T);
-  if (PruneControlFlow) {
-    S.DiagRuntimeBehavior(E->getExprLoc(), E,
-                          S.PDiag(diag)
-                              << SourceType << T << E->getSourceRange()
-                              << SourceRange(CContext));
-    return;
-  }
-  S.Diag(E->getExprLoc(), diag)
-    << SourceType << T << E->getSourceRange() << SourceRange(CContext);
-}
-
-/// Diagnose an implicit cast;  purely a helper for CheckImplicitConversion.
-static void DiagnoseImpCast(Sema &S, const Expr *E, QualType T,
-                            SourceLocation CContext, unsigned diag,
-                            bool PruneControlFlow = false) {
-  DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, PruneControlFlow);
-}
-
-/// Diagnose an implicit cast from a floating point value to an integer value.
-static void DiagnoseFloatingImpCast(Sema &S, const Expr *E, QualType T,
-                                    SourceLocation CContext) {
-  bool IsBool = T->isSpecificBuiltinType(BuiltinType::Bool);
-  bool PruneWarnings = S.inTemplateInstantiation();
-
-  const Expr *InnerE = E->IgnoreParenImpCasts();
-  // We also want to warn on, e.g., "int i = -1.234"
-  if (const auto *UOp = dyn_cast<UnaryOperator>(InnerE))
-    if (UOp->getOpcode() == UO_Minus || UOp->getOpcode() == UO_Plus)
-      InnerE = UOp->getSubExpr()->IgnoreParenImpCasts();
-
-  bool IsLiteral = isa<FloatingLiteral>(E) || isa<FloatingLiteral>(InnerE);
-
-  llvm::APFloat Value(0.0);
-  bool IsConstant =
-    E->EvaluateAsFloat(Value, S.Context, Expr::SE_AllowSideEffects);
-  if (!IsConstant) {
-    if (S.ObjC().isSignedCharBool(T)) {
-      return S.ObjC().adornBoolConversionDiagWithTernaryFixit(
-          E, S.Diag(CContext, diag::warn_impcast_float_to_objc_signed_char_bool)
-                 << E->getType());
-    }
-
-    return DiagnoseImpCast(S, E, T, CContext,
-                           diag::warn_impcast_float_integer, PruneWarnings);
-  }
-
-  bool isExact = false;
-
-  llvm::APSInt IntegerValue(S.Context.getIntWidth(T),
-                            T->hasUnsignedIntegerRepresentation());
-  llvm::APFloat::opStatus Result = Value.convertToInteger(
-      IntegerValue, llvm::APFloat::rmTowardZero, &isExact);
-
-  // FIXME: Force the precision of the source value down so we don't print
-  // digits which are usually useless (we don't really care here if we
-  // truncate a digit by accident in edge cases).  Ideally, APFloat::toString
-  // would automatically print the shortest representation, but it's a bit
-  // tricky to implement.
-  SmallString<16> PrettySourceValue;
-  unsigned precision = llvm::APFloat::semanticsPrecision(Value.getSemantics());
-  precision = (precision * 59 + 195) / 196;
-  Value.toString(PrettySourceValue, precision);
-
-  if (S.ObjC().isSignedCharBool(T) && IntegerValue != 0 && IntegerValue != 1) {
-    return S.ObjC().adornBoolConversionDiagWithTernaryFixit(
-        E, S.Diag(CContext, diag::warn_impcast_constant_value_to_objc_bool)
-               << PrettySourceValue);
-  }
-
-  if (Result == llvm::APFloat::opOK && isExact) {
-    if (IsLiteral) return;
-    return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer,
-                           PruneWarnings);
-  }
-
-  // Conversion of a floating-point value to a non-bool integer where the
-  // integral part cannot be represented by the integer type is undefined.
-  if (!IsBool && Result == llvm::APFloat::opInvalidOp)
-    return DiagnoseImpCast(
-        S, E, T, CContext,
-        IsLiteral ? diag::warn_impcast_literal_float_to_integer_out_of_range
-                  : diag::warn_impcast_float_to_integer_out_of_range,
-        PruneWarnings);
-
-  unsigned DiagID = 0;
-  if (IsLiteral) {
-    // Warn on floating point literal to integer.
-    DiagID = diag::warn_impcast_literal_float_to_integer;
-  } else if (IntegerValue == 0) {
-    if (Value.isZero()) {  // Skip -0.0 to 0 conversion.
-      return DiagnoseImpCast(S, E, T, CContext,
-                             diag::warn_impcast_float_integer, PruneWarnings);
-    }
-    // Warn on non-zero to zero conversion.
-    DiagID = diag::warn_impcast_float_to_integer_zero;
-  } else {
-    if (IntegerValue.isUnsigned()) {
-      if (!IntegerValue.isMaxValue()) {
-        return DiagnoseImpCast(S, E, T, CContext,
-                               diag::warn_impcast_float_integer, PruneWarnings);
-      }
-    } else {  // IntegerValue.isSigned()
-      if (!IntegerValue.isMaxSignedValue() &&
-          !IntegerValue.isMinSignedValue()) {
-        return DiagnoseImpCast(S, E, T, CContext,
-                               diag::warn_impcast_float_integer, PruneWarnings);
-      }
-    }
-    // Warn on evaluatable floating point expression to integer conversion.
-    DiagID = diag::warn_impcast_float_to_integer;
-  }
-
-  SmallString<16> PrettyTargetValue;
-  if (IsBool)
-    PrettyTargetValue = Value.isZero() ? "false" : "true";
-  else
-    IntegerValue.toString(PrettyTargetValue);
-
-  if (PruneWarnings) {
-    S.DiagRuntimeBehavior(E->getExprLoc(), E,
-                          S.PDiag(DiagID)
-                              << E->getType() << T.getUnqualifiedType()
-                              << PrettySourceValue << PrettyTargetValue
-                              << E->getSourceRange() << SourceRange(CContext));
-  } else {
-    S.Diag(E->getExprLoc(), DiagID)
-        << E->getType() << T.getUnqualifiedType() << PrettySourceValue
-        << PrettyTargetValue << E->getSourceRange() << SourceRange(CContext);
-  }
-}
-
-/// Analyze the given compound assignment for the possible losing of
-/// floating-point precision.
-static void AnalyzeCompoundAssignment(Sema &S, BinaryOperator *E) {
-  assert(isa<CompoundAssignOperator>(E) &&
-         "Must be compound assignment operation");
-  // Recurse on the LHS and RHS in here
-  AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc());
-  AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc());
-
-  if (E->getLHS()->getType()->isAtomicType())
-    S.Diag(E->getOperatorLoc(), diag::warn_atomic_implicit_seq_cst);
-
-  // Now check the outermost expression
-  const auto *ResultBT = E->getLHS()->getType()->getAs<BuiltinType>();
-  const auto *RBT = cast<CompoundAssignOperator>(E)
-                        ->getComputationResultType()
-                        ->getAs<BuiltinType>();
-
-  // The below checks assume source is floating point.
-  if (!ResultBT || !RBT || !RBT->isFloatingPoint()) return;
-
-  // If source is floating point but target is an integer.
-  if (ResultBT->isInteger())
-    return DiagnoseImpCast(S, E, E->getRHS()->getType(), E->getLHS()->getType(),
-                           E->getExprLoc(), diag::warn_impcast_float_integer);
-
-  if (!ResultBT->isFloatingPoint())
-    return;
-
-  // If both source and target are floating points, warn about losing precision.
-  int Order = S.getASTContext().getFloatingTypeSemanticOrder(
-      QualType(ResultBT, 0), QualType(RBT, 0));
-  if (Order < 0 && !S.SourceMgr.isInSystemMacro(E->getOperatorLoc()))
-    // warn about dropping FP rank.
-    DiagnoseImpCast(S, E->getRHS(), E->getLHS()->getType(), E->getOperatorLoc(),
-                    diag::warn_impcast_float_result_precision);
-}
-
-static std::string PrettyPrintInRange(const llvm::APSInt &Value,
-                                      IntRange Range) {
-  if (!Range.Width) return "0";
-
-  llvm::APSInt ValueInRange = Value;
-  ValueInRange.setIsSigned(!Range.NonNegative);
-  ValueInRange = ValueInRange.trunc(Range.Width);
-  return toString(ValueInRange, 10);
-}
-
-static bool IsImplicitBoolFloatConversion(Sema &S, const Expr *Ex,
-                                          bool ToBool) {
-  if (!isa<ImplicitCastExpr>(Ex))
-    return false;
-
-  const Expr *InnerE = Ex->IgnoreParenImpCasts();
-  const Type *Target = S.Context.getCanonicalType(Ex->getType()).getTypePtr();
-  const Type *Source =
-    S.Context.getCanonicalType(InnerE->getType()).getTypePtr();
-  if (Target->isDependentType())
-    return false;
-
-  const auto *FloatCandidateBT =
-      dyn_cast<BuiltinType>(ToBool ? Source : Target);
-  const Type *BoolCandidateType = ToBool ? Target : Source;
-
-  return (BoolCandidateType->isSpecificBuiltinType(BuiltinType::Bool) &&
-          FloatCandidateBT && (FloatCandidateBT->isFloatingPoint()));
-}
-
-static void CheckImplicitArgumentConversions(Sema &S, const CallExpr *TheCall,
-                                             SourceLocation CC) {
-  for (unsigned I = 0, N = TheCall->getNumArgs(); I < N; ++I) {
-    const Expr *CurrA = TheCall->getArg(I);
-    if (!IsImplicitBoolFloatConversion(S, CurrA, true))
-      continue;
-
-    bool IsSwapped = ((I > 0) && IsImplicitBoolFloatConversion(
-                                     S, TheCall->getArg(I - 1), false));
-    IsSwapped |= ((I < (N - 1)) && IsImplicitBoolFloatConversion(
-                                       S, TheCall->getArg(I + 1), false));
-    if (IsSwapped) {
-      // Warn on this floating-point to bool conversion.
-      DiagnoseImpCast(S, CurrA->IgnoreParenImpCasts(),
-                      CurrA->getType(), CC,
-                      diag::warn_impcast_floating_point_to_bool);
-    }
-  }
-}
-
-static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T,
-                                   SourceLocation CC) {
-  // Don't warn on functions which have return type nullptr_t.
-  if (isa<CallExpr>(E))
-    return;
-
-  // Check for NULL (GNUNull) or nullptr (CXX11_nullptr).
-  const Expr *NewE = E->IgnoreParenImpCasts();
-  bool IsGNUNullExpr = isa<GNUNullExpr>(NewE);
-  bool HasNullPtrType = NewE->getType()->isNullPtrType();
-  if (!IsGNUNullExpr && !HasNullPtrType)
-    return;
-
-  // Return if target type is a safe conversion.
-  if (T->isAnyPointerType() || T->isBlockPointerType() ||
-      T->isMemberPointerType() || !T->isScalarType() || T->isNullPtrType())
-    return;
-
-  if (S.Diags.isIgnored(diag::warn_impcast_null_pointer_to_integer,
-                        E->getExprLoc()))
-    return;
-
-  SourceLocation Loc = E->getSourceRange().getBegin();
-
-  // Venture through the macro stacks to get to the source of macro arguments.
-  // The new location is a better location than the complete location that was
-  // passed in.
-  Loc = S.SourceMgr.getTopMacroCallerLoc(Loc);
-  CC = S.SourceMgr.getTopMacroCallerLoc(CC);
-
-  // __null is usually wrapped in a macro.  Go up a macro if that is the case.
-  if (IsGNUNullExpr && Loc.isMacroID()) {
-    StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics(
-        Loc, S.SourceMgr, S.getLangOpts());
-    if (MacroName == "NULL")
-      Loc = S.SourceMgr.getImmediateExpansionRange(Loc).getBegin();
-  }
-
-  // Only warn if the null and context location are in the same macro expansion.
-  if (S.SourceMgr.getFileID(Loc) != S.SourceMgr.getFileID(CC))
-    return;
-
-  S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer)
-      << HasNullPtrType << T << SourceRange(CC)
-      << FixItHint::CreateReplacement(Loc,
-                                      S.getFixItZeroLiteralForType(T, Loc));
-}
-
-// Helper function to filter out cases for constant width constant conversion.
-// Don't warn on char array initialization or for non-decimal values.
-static bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T,
-                                          SourceLocation CC) {
-  // If initializing from a constant, and the constant starts with '0',
-  // then it is a binary, octal, or hexadecimal.  Allow these constants
-  // to fill all the bits, even if there is a sign change.
-  if (auto *IntLit = dyn_cast<IntegerLiteral>(E->IgnoreParenImpCasts())) {
-    const char FirstLiteralCharacter =
-        S.getSourceManager().getCharacterData(IntLit->getBeginLoc())[0];
-    if (FirstLiteralCharacter == '0')
-      return false;
-  }
-
-  // If the CC location points to a '{', and the type is char, then assume
-  // assume it is an array initialization.
-  if (CC.isValid() && T->isCharType()) {
-    const char FirstContextCharacter =
-        S.getSourceManager().getCharacterData(CC)[0];
-    if (FirstContextCharacter == '{')
-      return false;
-  }
-
-  return true;
-}
-
-static const IntegerLiteral *getIntegerLiteral(Expr *E) {
-  const auto *IL = dyn_cast<IntegerLiteral>(E);
-  if (!IL) {
-    if (auto *UO = dyn_cast<UnaryOperator>(E)) {
-      if (UO->getOpcode() == UO_Minus)
-        return dyn_cast<IntegerLiteral>(UO->getSubExpr());
-    }
-  }
-
-  return IL;
-}
-
-static void DiagnoseIntInBoolContext(Sema &S, Expr *E) {
-  E = E->IgnoreParenImpCasts();
-  SourceLocation ExprLoc = E->getExprLoc();
-
-  if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
-    BinaryOperator::Opcode Opc = BO->getOpcode();
-    Expr::EvalResult Result;
-    // Do not diagnose unsigned shifts.
-    if (Opc == BO_Shl) {
-      const auto *LHS = getIntegerLiteral(BO->getLHS());
-      const auto *RHS = getIntegerLiteral(BO->getRHS());
-      if (LHS && LHS->getValue() == 0)
-        S.Diag(ExprLoc, diag::warn_left_shift_always) << 0;
-      else if (!E->isValueDependent() && LHS && RHS &&
-               RHS->getValue().isNonNegative() &&
-               E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects))
-        S.Diag(ExprLoc, diag::warn_left_shift_always)
-            << (Result.Val.getInt() != 0);
-      else if (E->getType()->isSignedIntegerType())
-        S.Diag(ExprLoc, diag::warn_left_shift_in_bool_context)
-            << FixItHint::CreateInsertion(E->getBeginLoc(), "(")
-            << FixItHint::CreateInsertion(S.getLocForEndOfToken(E->getEndLoc()),
-                                          ") != 0");
-    }
-  }
-
-  if (const auto *CO = dyn_cast<ConditionalOperator>(E)) {
-    const auto *LHS = getIntegerLiteral(CO->getTrueExpr());
-    const auto *RHS = getIntegerLiteral(CO->getFalseExpr());
-    if (!LHS || !RHS)
-      return;
-    if ((LHS->getValue() == 0 || LHS->getValue() == 1) &&
-        (RHS->getValue() == 0 || RHS->getValue() == 1))
-      // Do not diagnose common idioms.
-      return;
-    if (LHS->getValue() != 0 && RHS->getValue() != 0)
-      S.Diag(ExprLoc, diag::warn_integer_constants_in_conditional_always_true);
-  }
-}
-
-static void DiagnoseMixedUnicodeImplicitConversion(Sema &S, const Type *Source,
-                                                   const Type *Target, Expr *E,
-                                                   QualType T,
-                                                   SourceLocation CC) {
-  assert(Source->isUnicodeCharacterType() && Target->isUnicodeCharacterType() &&
-         Source != Target);
-
-  // Lone surrogates have a distinct representation in UTF-32.
-  // Converting between UTF-16 and UTF-32 codepoints seems very widespread,
-  // so don't warn on such conversion.
-  if (Source->isChar16Type() && Target->isChar32Type())
-    return;
-
-  Expr::EvalResult Result;
-  if (E->EvaluateAsInt(Result, S.getASTContext(), Expr::SE_AllowSideEffects,
-                       S.isConstantEvaluatedContext())) {
-    llvm::APSInt Value(32);
-    Value = Result.Val.getInt();
-    bool IsASCII = Value <= 0x7F;
-    bool IsBMP = Value <= 0xDFFF || (Value >= 0xE000 && Value <= 0xFFFF);
-    bool ConversionPreservesSemantics =
-        IsASCII || (!Source->isChar8Type() && !Target->isChar8Type() && IsBMP);
-
-    if (!ConversionPreservesSemantics) {
-      auto IsSingleCodeUnitCP = [](const QualType &T,
-                                   const llvm::APSInt &Value) {
-        if (T->isChar8Type())
-          return llvm::IsSingleCodeUnitUTF8Codepoint(Value.getExtValue());
-        if (T->isChar16Type())
-          return llvm::IsSingleCodeUnitUTF16Codepoint(Value.getExtValue());
-        assert(T->isChar32Type());
-        return llvm::IsSingleCodeUnitUTF32Codepoint(Value.getExtValue());
-      };
-
-      S.Diag(CC, diag::warn_impcast_unicode_char_type_constant)
-          << E->getType() << T
-          << IsSingleCodeUnitCP(E->getType().getUnqualifiedType(), Value)
-          << FormatUTFCodeUnitAsCodepoint(Value.getExtValue(), E->getType());
-    }
-  } else {
-    bool LosesPrecision = S.getASTContext().getIntWidth(E->getType()) >
-                          S.getASTContext().getIntWidth(T);
-    DiagnoseImpCast(S, E, T, CC,
-                    LosesPrecision ? diag::warn_impcast_unicode_precision
-                                   : diag::warn_impcast_unicode_char_type);
-  }
-}
-
-bool Sema::DiscardingCFIUncheckedCallee(QualType From, QualType To) const {
-  From = Context.getCanonicalType(From);
-  To = Context.getCanonicalType(To);
-  QualType MaybePointee = From->getPointeeType();
-  if (!MaybePointee.isNull() && MaybePointee->getAs<FunctionType>())
-    From = MaybePointee;
-  MaybePointee = To->getPointeeType();
-  if (!MaybePointee.isNull() && MaybePointee->getAs<FunctionType>())
-    To = MaybePointee;
-
-  if (const auto *FromFn = From->getAs<FunctionType>()) {
-    if (const auto *ToFn = To->getAs<FunctionType>()) {
-      if (FromFn->getCFIUncheckedCalleeAttr() &&
-          !ToFn->getCFIUncheckedCalleeAttr())
-        return true;
-    }
-  }
-  return false;
-}
-
-void Sema::CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC,
-                                   bool *ICContext, bool IsListInit) {
-  if (E->isTypeDependent() || E->isValueDependent()) return;
-
-  const Type *Source = Context.getCanonicalType(E->getType()).getTypePtr();
-  const Type *Target = Context.getCanonicalType(T).getTypePtr();
-  if (Source == Target) return;
-  if (Target->isDependentType()) return;
-
-  // If the conversion context location is invalid don't complain. We also
-  // don't want to emit a warning if the issue occurs from the expansion of
-  // a system macro. The problem is that 'getSpellingLoc()' is slow, so we
-  // delay this check as long as possible. Once we detect we are in that
-  // scenario, we just return.
-  if (CC.isInvalid())
-    return;
-
-  if (Source->isAtomicType())
-    Diag(E->getExprLoc(), diag::warn_atomic_implicit_seq_cst);
-
-  // Diagnose implicit casts to bool.
-  if (Target->isSpecificBuiltinType(BuiltinType::Bool)) {
-    if (isa<StringLiteral>(E))
-      // Warn on string literal to bool.  Checks for string literals in logical
-      // and expressions, for instance, assert(0 && "error here"), are
-      // prevented by a check in AnalyzeImplicitConversions().
-      return DiagnoseImpCast(*this, E, T, CC,
-                             diag::warn_impcast_string_literal_to_bool);
-    if (isa<ObjCStringLiteral>(E) || isa<ObjCArrayLiteral>(E) ||
-        isa<ObjCDictionaryLiteral>(E) || isa<ObjCBoxedExpr>(E)) {
-      // This covers the literal expressions that evaluate to Objective-C
-      // objects.
-      return DiagnoseImpCast(*this, E, T, CC,
-                             diag::warn_impcast_objective_c_literal_to_bool);
-    }
-    if (Source->isPointerType() || Source->canDecayToPointerType()) {
-      // Warn on pointer to bool conversion that is always true.
-      DiagnoseAlwaysNonNullPointer(E, Expr::NPCK_NotNull, /*IsEqual*/ false,
-                                   SourceRange(CC));
-    }
-  }
-
-  // If the we're converting a constant to an ObjC BOOL on a platform where BOOL
-  // is a typedef for signed char (macOS), then that constant value has to be 1
-  // or 0.
-  if (ObjC().isSignedCharBool(T) && Source->isIntegralType(Context)) {
-    Expr::EvalResult Result;
-    if (E->EvaluateAsInt(Result, getASTContext(), Expr::SE_AllowSideEffects)) {
-      if (Result.Val.getInt() != 1 && Result.Val.getInt() != 0) {
-        ObjC().adornBoolConversionDiagWithTernaryFixit(
-            E, Diag(CC, diag::warn_impcast_constant_value_to_objc_bool)
-                   << toString(Result.Val.getInt(), 10));
-      }
-      return;
-    }
-  }
-
-  // Check implicit casts from Objective-C collection literals to specialized
-  // collection types, e.g., NSArray<NSString *> *.
-  if (auto *ArrayLiteral = dyn_cast<ObjCArrayLiteral>(E))
-    ObjC().checkArrayLiteral(QualType(Target, 0), ArrayLiteral);
-  else if (auto *DictionaryLiteral = dyn_cast<ObjCDictionaryLiteral>(E))
-    ObjC().checkDictionaryLiteral(QualType(Target, 0), DictionaryLiteral);
-
-  // Strip vector types.
-  if (isa<VectorType>(Source)) {
-    if (Target->isSveVLSBuiltinType() &&
-        (ARM().areCompatibleSveTypes(QualType(Target, 0),
-                                     QualType(Source, 0)) ||
-         ARM().areLaxCompatibleSveTypes(QualType(Target, 0),
-                                        QualType(Source, 0))))
-      return;
-
-    if (Target->isRVVVLSBuiltinType() &&
-        (Context.areCompatibleRVVTypes(QualType(Target, 0),
-                                       QualType(Source, 0)) ||
-         Context.areLaxCompatibleRVVTypes(QualType(Target, 0),
-                                          QualType(Source, 0))))
-      return;
-
-    if (!isa<VectorType>(Target)) {
-      if (SourceMgr.isInSystemMacro(CC))
-        return;
-      return DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_vector_scalar);
-    }
-    if (getLangOpts().HLSL &&
-        Target->castAs<VectorType>()->getNumElements() <
-            Source->castAs<VectorType>()->getNumElements()) {
-      // Diagnose vector truncation but don't return. We may also want to
-      // diagnose an element conversion.
-      DiagnoseImpCast(*this, E, T, CC,
-                      diag::warn_hlsl_impcast_vector_truncation);
-    }
-
-    // If the vector cast is cast between two vectors of the same size, it is
-    // a bitcast, not a conversion, except under HLSL where it is a conversion.
-    if (!getLangOpts().HLSL &&
-        Context.getTypeSize(Source) == Context.getTypeSize(Target))
-      return;
-
-    Source = cast<VectorType>(Source)->getElementType().getTypePtr();
-    Target = cast<VectorType>(Target)->getElementType().getTypePtr();
-  }
-  if (const auto *VecTy = dyn_cast<VectorType>(Target))
-    Target = VecTy->getElementType().getTypePtr();
-
-  if (isa<ConstantMatrixType>(Source)) {
-    if (Target->isScalarType())
-      return DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_matrix_scalar);
-
-    if (getLangOpts().HLSL &&
-        Target->castAs<ConstantMatrixType>()->getNumElementsFlattened() <
-            Source->castAs<ConstantMatrixType>()->getNumElementsFlattened()) {
-      // Diagnose Matrix truncation but don't return. We may also want to
-      // diagnose an element conversion.
-      DiagnoseImpCast(*this, E, T, CC,
-                      diag::warn_hlsl_impcast_matrix_truncation);
-    }
-  }
-  // Strip complex types.
-  if (isa<ComplexType>(Source)) {
-    if (!isa<ComplexType>(Target)) {
-      if (SourceMgr.isInSystemMacro(CC) || Target->isBooleanType())
-        return;
-
-      return DiagnoseImpCast(*this, E, T, CC,
-                             getLangOpts().CPlusPlus
-                                 ? diag::err_impcast_complex_scalar
-                                 : diag::warn_impcast_complex_scalar);
-    }
-
-    Source = cast<ComplexType>(Source)->getElementType().getTypePtr();
-    Target = cast<ComplexType>(Target)->getElementType().getTypePtr();
-  }
-
-  const BuiltinType *SourceBT = dyn_cast<BuiltinType>(Source);
-  const BuiltinType *TargetBT = dyn_cast<BuiltinType>(Target);
-
-  // Strip SVE vector types
-  if (SourceBT && SourceBT->isSveVLSBuiltinType()) {
-    // Need the original target type for vector type checks
-    const Type *OriginalTarget = Context.getCanonicalType(T).getTypePtr();
-    // Handle conversion from scalable to fixed when msve-vector-bits is
-    // specified
-    if (ARM().areCompatibleSveTypes(QualType(OriginalTarget, 0),
-                                    QualType(Source, 0)) ||
-        ARM().areLaxCompatibleSveTypes(QualType(OriginalTarget, 0),
-                                       QualType(Source, 0)))
-      return;
-
-    // If the vector cast is cast between two vectors of the same size, it is
-    // a bitcast, not a conversion.
-    if (Context.getTypeSize(Source) == Context.getTypeSize(Target))
-      return;
-
-    Source = SourceBT->getSveEltType(Context).getTypePtr();
-  }
-
-  if (TargetBT && TargetBT->isSveVLSBuiltinType())
-    Target = TargetBT->getSveEltType(Context).getTypePtr();
-
-  // If the source is floating point...
-  if (SourceBT && SourceBT->isFloatingPoint()) {
-    // ...and the target is floating point...
-    if (TargetBT && TargetBT->isFloatingPoint()) {
-      // ...then warn if we're dropping FP rank.
-
-      int Order = getASTContext().getFloatingTypeSemanticOrder(
-          QualType(SourceBT, 0), QualType(TargetBT, 0));
-      if (Order > 0) {
-        // Don't warn about float constants that are precisely
-        // representable in the target type.
-        Expr::EvalResult result;
-        if (E->EvaluateAsRValue(result, Context)) {
-          // Value might be a float, a float vector, or a float complex.
-          if (IsSameFloatAfterCast(
-                  result.Val,
-                  Context.getFloatTypeSemantics(QualType(TargetBT, 0)),
-                  Context.getFloatTypeSemantics(QualType(SourceBT, 0))))
-            return;
-        }
-
-        if (SourceMgr.isInSystemMacro(CC))
-          return;
-
-        DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_float_precision);
-      }
-      // ... or possibly if we're increasing rank, too
-      else if (Order < 0) {
-        if (SourceMgr.isInSystemMacro(CC))
-          return;
-
-        DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_double_promotion);
-      }
-      return;
-    }
-
-    // If the target is integral, always warn.
-    if (TargetBT && TargetBT->isInteger()) {
-      if (SourceMgr.isInSystemMacro(CC))
-        return;
-
-      DiagnoseFloatingImpCast(*this, E, T, CC);
-    }
-
-    // Detect the case where a call result is converted from floating-point to
-    // to bool, and the final argument to the call is converted from bool, to
-    // discover this typo:
-    //
-    //    bool b = fabs(x < 1.0);  // should be "bool b = fabs(x) < 1.0;"
-    //
-    // FIXME: This is an incredibly special case; is there some more general
-    // way to detect this class of misplaced-parentheses bug?
-    if (Target->isBooleanType() && isa<CallExpr>(E)) {
-      // Check last argument of function call to see if it is an
-      // implicit cast from a type matching the type the result
-      // is being cast to.
-      CallExpr *CEx = cast<CallExpr>(E);
-      if (unsigned NumArgs = CEx->getNumArgs()) {
-        Expr *LastA = CEx->getArg(NumArgs - 1);
-        Expr *InnerE = LastA->IgnoreParenImpCasts();
-        if (isa<ImplicitCastExpr>(LastA) &&
-            InnerE->getType()->isBooleanType()) {
-          // Warn on this floating-point to bool conversion
-          DiagnoseImpCast(*this, E, T, CC,
-                          diag::warn_impcast_floating_point_to_bool);
-        }
-      }
-    }
-    return;
-  }
-
-  // Valid casts involving fixed point types should be accounted for here.
-  if (Source->isFixedPointType()) {
-    if (Target->isUnsaturatedFixedPointType()) {
-      Expr::EvalResult Result;
-      if (E->EvaluateAsFixedPoint(Result, Context, Expr::SE_AllowSideEffects,
-                                  isConstantEvaluatedContext())) {
-        llvm::APFixedPoint Value = Result.Val.getFixedPoint();
-        llvm::APFixedPoint MaxVal = Context.getFixedPointMax(T);
-        llvm::APFixedPoint MinVal = Context.getFixedPointMin(T);
-        if (Value > MaxVal || Value < MinVal) {
-          DiagRuntimeBehavior(E->getExprLoc(), E,
-                              PDiag(diag::warn_impcast_fixed_point_range)
-                                  << Value.toString() << T
-                                  << E->getSourceRange()
-                                  << clang::SourceRange(CC));
-          return;
-        }
-      }
-    } else if (Target->isIntegerType()) {
-      Expr::EvalResult Result;
-      if (!isConstantEvaluatedContext() &&
-          E->EvaluateAsFixedPoint(Result, Context, Expr::SE_AllowSideEffects)) {
-        llvm::APFixedPoint FXResult = Result.Val.getFixedPoint();
-
-        bool Overflowed;
-        llvm::APSInt IntResult = FXResult.convertToInt(
-            Context.getIntWidth(T), Target->isSignedIntegerOrEnumerationType(),
-            &Overflowed);
-
-        if (Overflowed) {
-          DiagRuntimeBehavior(E->getExprLoc(), E,
-                              PDiag(diag::warn_impcast_fixed_point_range)
-                                  << FXResult.toString() << T
-                                  << E->getSourceRange()
-                                  << clang::SourceRange(CC));
-          return;
-        }
-      }
-    }
-  } else if (Target->isUnsaturatedFixedPointType()) {
-    if (Source->isIntegerType()) {
-      Expr::EvalResult Result;
-      if (!isConstantEvaluatedContext() &&
-          E->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects)) {
-        llvm::APSInt Value = Result.Val.getInt();
-
-        bool Overflowed;
-        llvm::APFixedPoint IntResult = llvm::APFixedPoint::getFromIntValue(
-            Value, Context.getFixedPointSemantics(T), &Overflowed);
-
-        if (Overflowed) {
-          DiagRuntimeBehavior(E->getExprLoc(), E,
-                              PDiag(diag::warn_impcast_fixed_point_range)
-                                  << toString(Value, /*Radix=*/10) << T
-                                  << E->getSourceRange()
-                                  << clang::SourceRange(CC));
-          return;
-        }
-      }
-    }
-  }
-
-  // If we are casting an integer type to a floating point type without
-  // initialization-list syntax, we might lose accuracy if the floating
-  // point type has a narrower significand than the integer type.
-  if (SourceBT && TargetBT && SourceBT->isIntegerType() &&
-      TargetBT->isFloatingType() && !IsListInit) {
-    // Determine the number of precision bits in the source integer type.
-    std::optional<IntRange> SourceRange =
-        TryGetExprRange(Context, E, isConstantEvaluatedContext(),
-                        /*Approximate=*/true);
-    if (!SourceRange)
-      return;
-    unsigned int SourcePrecision = SourceRange->Width;
-
-    // Determine the number of precision bits in the
-    // target floating point type.
-    unsigned int TargetPrecision = llvm::APFloatBase::semanticsPrecision(
-        Context.getFloatTypeSemantics(QualType(TargetBT, 0)));
-
-    if (SourcePrecision > 0 && TargetPrecision > 0 &&
-        SourcePrecision > TargetPrecision) {
-
-      if (std::optional<llvm::APSInt> SourceInt =
-              E->getIntegerConstantExpr(Context)) {
-        // If the source integer is a constant, convert it to the target
-        // floating point type. Issue a warning if the value changes
-        // during the whole conversion.
-        llvm::APFloat TargetFloatValue(
-            Context.getFloatTypeSemantics(QualType(TargetBT, 0)));
-        llvm::APFloat::opStatus ConversionStatus =
-            TargetFloatValue.convertFromAPInt(
-                *SourceInt, SourceBT->isSignedInteger(),
-                llvm::APFloat::rmNearestTiesToEven);
-
-        if (ConversionStatus != llvm::APFloat::opOK) {
-          SmallString<32> PrettySourceValue;
-          SourceInt->toString(PrettySourceValue, 10);
-          SmallString<32> PrettyTargetValue;
-          TargetFloatValue.toString(PrettyTargetValue, TargetPrecision);
-
-          DiagRuntimeBehavior(
-              E->getExprLoc(), E,
-              PDiag(diag::warn_impcast_integer_float_precision_constant)
-                  << PrettySourceValue << PrettyTargetValue << E->getType() << T
-                  << E->getSourceRange() << clang::SourceRange(CC));
-        }
-      } else {
-        // Otherwise, the implicit conversion may lose precision.
-        DiagnoseImpCast(*this, E, T, CC,
-                        diag::warn_impcast_integer_float_precision);
-      }
-    }
-  }
-
-  DiagnoseNullConversion(*this, E, T, CC);
-
-  DiscardMisalignedMemberAddress(Target, E);
-
-  if (Source->isUnicodeCharacterType() && Target->isUnicodeCharacterType()) {
-    DiagnoseMixedUnicodeImplicitConversion(*this, Source, Target, E, T, CC);
-    return;
-  }
-
-  if (Target->isBooleanType())
-    DiagnoseIntInBoolContext(*this, E);
-
-  if (DiscardingCFIUncheckedCallee(QualType(Source, 0), QualType(Target, 0))) {
-    Diag(CC, diag::warn_cast_discards_cfi_unchecked_callee)
-        << QualType(Source, 0) << QualType(Target, 0);
-  }
-
-  if (!Source->isIntegerType() || !Target->isIntegerType())
-    return;
-
-  // TODO: remove this early return once the false positives for constant->bool
-  // in templates, macros, etc, are reduced or removed.
-  if (Target->isSpecificBuiltinType(BuiltinType::Bool))
-    return;
-
-  if (ObjC().isSignedCharBool(T) && !Source->isCharType() &&
-      !E->isKnownToHaveBooleanValue(/*Semantic=*/false)) {
-    return ObjC().adornBoolConversionDiagWithTernaryFixit(
-        E, Diag(CC, diag::warn_impcast_int_to_objc_signed_char_bool)
-               << E->getType());
-  }
-  std::optional<IntRange> LikelySourceRange = TryGetExprRange(
-      Context, E, isConstantEvaluatedContext(), /*Approximate=*/true);
-  if (!LikelySourceRange)
-    return;
-
-  IntRange SourceTypeRange =
-      IntRange::forTargetOfCanonicalType(Context, Source);
-  IntRange TargetRange = IntRange::forTargetOfCanonicalType(Context, Target);
-
-  if (LikelySourceRange->Width > TargetRange.Width) {
-    // If the source is a constant, use a default-on diagnostic.
-    // TODO: this should happen for bitfield stores, too.
-    Expr::EvalResult Result;
-    if (E->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects,
-                         isConstantEvaluatedContext())) {
-      llvm::APSInt Value(32);
-      Value = Result.Val.getInt();
-
-      if (SourceMgr.isInSystemMacro(CC))
-        return;
-
-      std::string PrettySourceValue = toString(Value, 10);
-      std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange);
-
-      DiagRuntimeBehavior(E->getExprLoc(), E,
-                          PDiag(diag::warn_impcast_integer_precision_constant)
-                              << PrettySourceValue << PrettyTargetValue
-                              << E->getType() << T << E->getSourceRange()
-                              << SourceRange(CC));
-      return;
-    }
-
-    // People want to build with -Wshorten-64-to-32 and not -Wconversion.
-    if (SourceMgr.isInSystemMacro(CC))
-      return;
-
-    if (const auto *UO = dyn_cast<UnaryOperator>(E)) {
-      if (UO->getOpcode() == UO_Minus)
-        return DiagnoseImpCast(
-            *this, E, T, CC, diag::warn_impcast_integer_precision_on_negation);
-    }
-
-    if (TargetRange.Width == 32 && Context.getIntWidth(E->getType()) == 64)
-      return DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_integer_64_32,
-                             /* pruneControlFlow */ true);
-    return DiagnoseImpCast(*this, E, T, CC,
-                           diag::warn_impcast_integer_precision);
-  }
-
-  if (TargetRange.Width > SourceTypeRange.Width) {
-    if (auto *UO = dyn_cast<UnaryOperator>(E))
-      if (UO->getOpcode() == UO_Minus)
-        if (Source->isUnsignedIntegerType()) {
-          if (Target->isUnsignedIntegerType())
-            return DiagnoseImpCast(*this, E, T, CC,
-                                   diag::warn_impcast_high_order_zero_bits);
-          if (Target->isSignedIntegerType())
-            return DiagnoseImpCast(*this, E, T, CC,
-                                   diag::warn_impcast_nonnegative_result);
-        }
-  }
-
-  if (TargetRange.Width == LikelySourceRange->Width &&
-      !TargetRange.NonNegative && LikelySourceRange->NonNegative &&
-      Source->isSignedIntegerType()) {
-    // Warn when doing a signed to signed conversion, warn if the positive
-    // source value is exactly the width of the target type, which will
-    // cause a negative value to be stored.
-
-    Expr::EvalResult Result;
-    if (E->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects) &&
-        !SourceMgr.isInSystemMacro(CC)) {
-      llvm::APSInt Value = Result.Val.getInt();
-      if (isSameWidthConstantConversion(*this, E, T, CC)) {
-        std::string PrettySourceValue = toString(Value, 10);
-        std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange);
-
-        Diag(E->getExprLoc(),
-             PDiag(diag::warn_impcast_integer_precision_constant)
-                 << PrettySourceValue << PrettyTargetValue << E->getType() << T
-                 << E->getSourceRange() << SourceRange(CC));
-        return;
-      }
-    }
-
-    // Fall through for non-constants to give a sign conversion warning.
-  }
-
-  if ((!isa<EnumType>(Target) || !isa<EnumType>(Source)) &&
-      ((TargetRange.NonNegative && !LikelySourceRange->NonNegative) ||
-       (!TargetRange.NonNegative && LikelySourceRange->NonNegative &&
-        LikelySourceRange->Width == TargetRange.Width))) {
-    if (SourceMgr.isInSystemMacro(CC))
-      return;
-
-    if (SourceBT && SourceBT->isInteger() && TargetBT &&
-        TargetBT->isInteger() &&
-        Source->isSignedIntegerType() == Target->isSignedIntegerType()) {
-      return;
-    }
-
-    unsigned DiagID = diag::warn_impcast_integer_sign;
-
-    // Traditionally, gcc has warned about this under -Wsign-compare.
-    // We also want to warn about it in -Wconversion.
-    // So if -Wconversion is off, use a completely identical diagnostic
-    // in the sign-compare group.
-    // The conditional-checking code will
-    if (ICContext) {
-      DiagID = diag::warn_impcast_integer_sign_conditional;
-      *ICContext = true;
-    }
-
-    DiagnoseImpCast(*this, E, T, CC, DiagID);
-  }
-
-  // If we're implicitly converting from an integer into an enumeration, that
-  // is valid in C but invalid in C++.
-  QualType SourceType = E->getEnumCoercedType(Context);
-  const BuiltinType *CoercedSourceBT = SourceType->getAs<BuiltinType>();
-  if (CoercedSourceBT && CoercedSourceBT->isInteger() && isa<EnumType>(Target))
-    return DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_int_to_enum);
-
-  // Diagnose conversions between different enumeration types.
-  // In C, we pretend that the type of an EnumConstantDecl is its enumeration
-  // type, to give us better diagnostics.
-  Source = Context.getCanonicalType(SourceType).getTypePtr();
-
-  if (const EnumType *SourceEnum = Source->getAsCanonical<EnumType>())
-    if (const EnumType *TargetEnum = Target->getAsCanonical<EnumType>())
-      if (SourceEnum->getDecl()->hasNameForLinkage() &&
-          TargetEnum->getDecl()->hasNameForLinkage() &&
-          SourceEnum != TargetEnum) {
-        if (SourceMgr.isInSystemMacro(CC))
-          return;
-
-        return DiagnoseImpCast(*this, E, SourceType, T, CC,
-                               diag::warn_impcast_different_enum_types);
-      }
-}
-
-static void CheckConditionalOperator(Sema &S, AbstractConditionalOperator *E,
-                                     SourceLocation CC, QualType T);
-
-static void CheckConditionalOperand(Sema &S, Expr *E, QualType T,
-                                    SourceLocation CC, bool &ICContext) {
-  E = E->IgnoreParenImpCasts();
-  // Diagnose incomplete type for second or third operand in C.
-  if (!S.getLangOpts().CPlusPlus && E->getType()->isRecordType())
-    S.RequireCompleteExprType(E, diag::err_incomplete_type);
-
-  if (auto *CO = dyn_cast<AbstractConditionalOperator>(E))
-    return CheckConditionalOperator(S, CO, CC, T);
-
-  AnalyzeImplicitConversions(S, E, CC);
-  if (E->getType() != T)
-    return S.CheckImplicitConversion(E, T, CC, &ICContext);
-}
-
-static void CheckConditionalOperator(Sema &S, AbstractConditionalOperator *E,
-                                     SourceLocation CC, QualType T) {
-  AnalyzeImplicitConversions(S, E->getCond(), E->getQuestionLoc());
-
-  Expr *TrueExpr = E->getTrueExpr();
-  if (auto *BCO = dyn_cast<BinaryConditionalOperator>(E))
-    TrueExpr = BCO->getCommon();
-
-  bool Suspicious = false;
-  CheckConditionalOperand(S, TrueExpr, T, CC, Suspicious);
-  CheckConditionalOperand(S, E->getFalseExpr(), T, CC, Suspicious);
-
-  if (T->isBooleanType())
-    DiagnoseIntInBoolContext(S, E);
-
-  // If -Wconversion would have warned about either of the candidates
-  // for a signedness conversion to the context type...
-  if (!Suspicious) return;
-
-  // ...but it's currently ignored...
-  if (!S.Diags.isIgnored(diag::warn_impcast_integer_sign_conditional, CC))
-    return;
-
-  // ...then check whether it would have warned about either of the
-  // candidates for a signedness conversion to the condition type.
-  if (E->getType() == T) return;
-
-  Suspicious = false;
-  S.CheckImplicitConversion(TrueExpr->IgnoreParenImpCasts(), E->getType(), CC,
-                            &Suspicious);
-  if (!Suspicious)
-    S.CheckImplicitConversion(E->getFalseExpr()->IgnoreParenImpCasts(),
-                              E->getType(), CC, &Suspicious);
-}
-
-/// Check conversion of given expression to boolean.
-/// Input argument E is a logical expression.
-static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) {
-  // Run the bool-like conversion checks only for C since there bools are
-  // still not used as the return type from "boolean" operators or as the input
-  // type for conditional operators.
-  if (S.getLangOpts().CPlusPlus)
-    return;
-  if (E->IgnoreParenImpCasts()->getType()->isAtomicType())
-    return;
-  S.CheckImplicitConversion(E->IgnoreParenImpCasts(), S.Context.BoolTy, CC);
-}
-
-namespace {
-struct AnalyzeImplicitConversionsWorkItem {
-  Expr *E;
-  SourceLocation CC;
-  bool IsListInit;
-};
-}
-
-static void CheckCommaOperand(
-    Sema &S, Expr *E, QualType T, SourceLocation CC,
-    bool ExtraCheckForImplicitConversion,
-    llvm::SmallVectorImpl<AnalyzeImplicitConversionsWorkItem> &WorkList) {
-  E = E->IgnoreParenImpCasts();
-  WorkList.push_back({E, CC, false});
-
-  if (ExtraCheckForImplicitConversion && E->getType() != T)
-    S.CheckImplicitConversion(E, T, CC);
-}
-
-/// Data recursive variant of AnalyzeImplicitConversions. Subexpressions
-/// that should be visited are added to WorkList.
-static void AnalyzeImplicitConversions(
-    Sema &S, AnalyzeImplicitConversionsWorkItem Item,
-    llvm::SmallVectorImpl<AnalyzeImplicitConversionsWorkItem> &WorkList) {
-  Expr *OrigE = Item.E;
-  SourceLocation CC = Item.CC;
-
-  QualType T = OrigE->getType();
-  Expr *E = OrigE->IgnoreParenImpCasts();
-
-  // Propagate whether we are in a C++ list initialization expression.
-  // If so, we do not issue warnings for implicit int-float conversion
-  // precision loss, because C++11 narrowing already handles it.
-  //
-  // HLSL's initialization lists are special, so they shouldn't observe the C++
-  // behavior here.
-  bool IsListInit =
-      Item.IsListInit || (isa<InitListExpr>(OrigE) &&
-                          S.getLangOpts().CPlusPlus && !S.getLangOpts().HLSL);
-
-  if (E->isTypeDependent() || E->isValueDependent())
-    return;
-
-  Expr *SourceExpr = E;
-  // Examine, but don't traverse into the source expression of an
-  // OpaqueValueExpr, since it may have multiple parents and we don't want to
-  // emit duplicate diagnostics. Its fine to examine the form or attempt to
-  // evaluate it in the context of checking the specific conversion to T though.
-  if (auto *OVE = dyn_cast<OpaqueValueExpr>(E))
-    if (auto *Src = OVE->getSourceExpr())
-      SourceExpr = Src;
-
-  if (const auto *UO = dyn_cast<UnaryOperator>(SourceExpr))
-    if (UO->getOpcode() == UO_Not &&
-        UO->getSubExpr()->isKnownToHaveBooleanValue())
-      S.Diag(UO->getBeginLoc(), diag::warn_bitwise_negation_bool)
-          << OrigE->getSourceRange() << T->isBooleanType()
-          << FixItHint::CreateReplacement(UO->getBeginLoc(), "!");
-
-  if (auto *BO = dyn_cast<BinaryOperator>(SourceExpr)) {
-    if ((BO->getOpcode() == BO_And || BO->getOpcode() == BO_Or) &&
-        BO->getLHS()->isKnownToHaveBooleanValue() &&
-        BO->getRHS()->isKnownToHaveBooleanValue() &&
-        BO->getLHS()->HasSideEffects(S.Context) &&
-        BO->getRHS()->HasSideEffects(S.Context)) {
-      SourceManager &SM = S.getSourceManager();
-      const LangOptions &LO = S.getLangOpts();
-      SourceLocation BLoc = BO->getOperatorLoc();
-      SourceLocation ELoc = Lexer::getLocForEndOfToken(BLoc, 0, SM, LO);
-      StringRef SR = clang::Lexer::getSourceText(
-          clang::CharSourceRange::getTokenRange(BLoc, ELoc), SM, LO);
-      // To reduce false positives, only issue the diagnostic if the operator
-      // is explicitly spelled as a punctuator. This suppresses the diagnostic
-      // when using 'bitand' or 'bitor' either as keywords in C++ or as macros
-      // in C, along with other macro spellings the user might invent.
-      if (SR.str() == "&" || SR.str() == "|") {
-
-        S.Diag(BO->getBeginLoc(), diag::warn_bitwise_instead_of_logical)
-            << (BO->getOpcode() == BO_And ? "&" : "|")
-            << OrigE->getSourceRange()
-            << FixItHint::CreateReplacement(
-                   BO->getOperatorLoc(),
-                   (BO->getOpcode() == BO_And ? "&&" : "||"));
-        S.Diag(BO->getBeginLoc(), diag::note_cast_operand_to_int);
-      }
-    } else if (BO->isCommaOp() && !S.getLangOpts().CPlusPlus) {
-      /// Analyze the given comma operator. The basic idea behind the analysis
-      /// is to analyze the left and right operands slightly differently. The
-      /// left operand needs to check whether the operand itself has an implicit
-      /// conversion, but not whether the left operand induces an implicit
-      /// conversion for the entire comma expression itself. This is similar to
-      /// how CheckConditionalOperand behaves; it's as-if the correct operand
-      /// were directly used for the implicit conversion check.
-      CheckCommaOperand(S, BO->getLHS(), T, BO->getOperatorLoc(),
-                        /*ExtraCheckForImplicitConversion=*/false, WorkList);
-      CheckCommaOperand(S, BO->getRHS(), T, BO->getOperatorLoc(),
-                        /*ExtraCheckForImplicitConversion=*/true, WorkList);
-      return;
-    }
-  }
-
-  // For conditional operators, we analyze the arguments as if they
-  // were being fed directly into the output.
-  if (auto *CO = dyn_cast<AbstractConditionalOperator>(SourceExpr)) {
-    CheckConditionalOperator(S, CO, CC, T);
-    return;
-  }
-
-  // Check implicit argument conversions for function calls.
-  if (const auto *Call = dyn_cast<CallExpr>(SourceExpr))
-    CheckImplicitArgumentConversions(S, Call, CC);
-
-  // Go ahead and check any implicit conversions we might have skipped.
-  // The non-canonical typecheck is just an optimization;
-  // CheckImplicitConversion will filter out dead implicit conversions.
-  if (SourceExpr->getType() != T)
-    S.CheckImplicitConversion(SourceExpr, T, CC, nullptr, IsListInit);
-
-  // Now continue drilling into this expression.
-
-  if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) {
-    // The bound subexpressions in a PseudoObjectExpr are not reachable
-    // as transitive children.
-    // FIXME: Use a more uniform representation for this.
-    for (auto *SE : POE->semantics())
-      if (auto *OVE = dyn_cast<OpaqueValueExpr>(SE))
-        WorkList.push_back({OVE->getSourceExpr(), CC, IsListInit});
-  }
-
-  // Skip past explicit casts.
-  if (auto *CE = dyn_cast<ExplicitCastExpr>(E)) {
-    E = CE->getSubExpr();
-    // In the special case of a C++ function-style cast with braces,
-    // CXXFunctionalCastExpr has an InitListExpr as direct child with a single
-    // initializer. This InitListExpr basically belongs to the cast itself, so
-    // we skip it too. Specifically this is needed to silence -Wdouble-promotion
-    if (isa<CXXFunctionalCastExpr>(CE)) {
-      if (auto *InitListE = dyn_cast<InitListExpr>(E)) {
-        if (InitListE->getNumInits() == 1) {
-          E = InitListE->getInit(0);
-        }
-      }
-    }
-    E = E->IgnoreParenImpCasts();
-    if (!CE->getType()->isVoidType() && E->getType()->isAtomicType())
-      S.Diag(E->getBeginLoc(), diag::warn_atomic_implicit_seq_cst);
-    WorkList.push_back({E, CC, IsListInit});
-    return;
-  }
-
-  if (auto *OutArgE = dyn_cast<HLSLOutArgExpr>(E)) {
-    WorkList.push_back({OutArgE->getArgLValue(), CC, IsListInit});
-    // The base expression is only used to initialize the parameter for
-    // arguments to `inout` parameters, so we only traverse down the base
-    // expression for `inout` cases.
-    if (OutArgE->isInOut())
-      WorkList.push_back(
-          {OutArgE->getCastedTemporary()->getSourceExpr(), CC, IsListInit});
-    WorkList.push_back({OutArgE->getWritebackCast(), CC, IsListInit});
-    return;
-  }
-
-  if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
-    // Do a somewhat different check with comparison operators.
-    if (BO->isComparisonOp())
-      return AnalyzeComparison(S, BO);
-
-    // And with simple assignments.
-    if (BO->getOpcode() == BO_Assign)
-      return AnalyzeAssignment(S, BO);
-    // And with compound assignments.
-    if (BO->isAssignmentOp())
-      return AnalyzeCompoundAssignment(S, BO);
-  }
-
-  // These break the otherwise-useful invariant below.  Fortunately,
-  // we don't really need to recurse into them, because any internal
-  // expressions should have been analyzed already when they were
-  // built into statements.
-  if (isa<StmtExpr>(E)) return;
-
-  // Don't descend into unevaluated contexts.
-  if (isa<UnaryExprOrTypeTraitExpr>(E)) return;
-
-  // Now just recurse over the expression's children.
-  CC = E->getExprLoc();
-  BinaryOperator *BO = dyn_cast<BinaryOperator>(E);
-  bool IsLogicalAndOperator = BO && BO->getOpcode() == BO_LAnd;
-  for (Stmt *SubStmt : E->children()) {
-    Expr *ChildExpr = dyn_cast_or_null<Expr>(SubStmt);
-    if (!ChildExpr)
-      continue;
-
-    if (auto *CSE = dyn_cast<CoroutineSuspendExpr>(E))
-      if (ChildExpr == CSE->getOperand())
-        // Do not recurse over a CoroutineSuspendExpr's operand.
-        // The operand is also a subexpression of getCommonExpr(), and
-        // recursing into it directly would produce duplicate diagnostics.
-        continue;
-
-    if (IsLogicalAndOperator &&
-        isa<StringLiteral>(ChildExpr->IgnoreParenImpCasts()))
-      // Ignore checking string literals that are in logical and operators.
-      // This is a common pattern for asserts.
-      continue;
-    WorkList.push_back({ChildExpr, CC, IsListInit});
-  }
-
-  if (BO && BO->isLogicalOp()) {
-    Expr *SubExpr = BO->getLHS()->IgnoreParenImpCasts();
-    if (!IsLogicalAndOperator || !isa<StringLiteral>(SubExpr))
-      ::CheckBoolLikeConversion(S, SubExpr, BO->getExprLoc());
-
-    SubExpr = BO->getRHS()->IgnoreParenImpCasts();
-    if (!IsLogicalAndOperator || !isa<StringLiteral>(SubExpr))
-      ::CheckBoolLikeConversion(S, SubExpr, BO->getExprLoc());
-  }
-
-  if (const UnaryOperator *U = dyn_cast<UnaryOperator>(E)) {
-    if (U->getOpcode() == UO_LNot) {
-      ::CheckBoolLikeConversion(S, U->getSubExpr(), CC);
-    } else if (U->getOpcode() != UO_AddrOf) {
-      if (U->getSubExpr()->getType()->isAtomicType())
-        S.Diag(U->getSubExpr()->getBeginLoc(),
-               diag::warn_atomic_implicit_seq_cst);
-    }
-  }
-}
-
-/// AnalyzeImplicitConversions - Find and report any interesting
-/// implicit conversions in the given expression.  There are a couple
-/// of competing diagnostics here, -Wconversion and -Wsign-compare.
-static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC,
-                                       bool IsListInit/*= false*/) {
-  llvm::SmallVector<AnalyzeImplicitConversionsWorkItem, 16> WorkList;
-  WorkList.push_back({OrigE, CC, IsListInit});
-  while (!WorkList.empty())
-    AnalyzeImplicitConversions(S, WorkList.pop_back_val(), WorkList);
-}
-
-// Helper function for Sema::DiagnoseAlwaysNonNullPointer.
-// Returns true when emitting a warning about taking the address of a reference.
-static bool CheckForReference(Sema &SemaRef, const Expr *E,
-                              const PartialDiagnostic &PD) {
-  E = E->IgnoreParenImpCasts();
-
-  const FunctionDecl *FD = nullptr;
-
-  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
-    if (!DRE->getDecl()->getType()->isReferenceType())
-      return false;
-  } else if (const MemberExpr *M = dyn_cast<MemberExpr>(E)) {
-    if (!M->getMemberDecl()->getType()->isReferenceType())
-      return false;
-  } else if (const CallExpr *Call = dyn_cast<CallExpr>(E)) {
-    if (!Call->getCallReturnType(SemaRef.Context)->isReferenceType())
-      return false;
-    FD = Call->getDirectCallee();
-  } else {
-    return false;
-  }
-
-  SemaRef.Diag(E->getExprLoc(), PD);
-
-  // If possible, point to location of function.
-  if (FD) {
-    SemaRef.Diag(FD->getLocation(), diag::note_reference_is_return_value) << FD;
-  }
-
-  return true;
-}
-
-// Returns true if the SourceLocation is expanded from any macro body.
-// Returns false if the SourceLocation is invalid, is from not in a macro
-// expansion, or is from expanded from a top-level macro argument.
-static bool IsInAnyMacroBody(const SourceManager &SM, SourceLocation Loc) {
-  if (Loc.isInvalid())
-    return false;
-
-  while (Loc.isMacroID()) {
-    if (SM.isMacroBodyExpansion(Loc))
-      return true;
-    Loc = SM.getImmediateMacroCallerLoc(Loc);
-  }
-
-  return false;
-}
-
-void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
-                                        Expr::NullPointerConstantKind NullKind,
-                                        bool IsEqual, SourceRange Range) {
-  if (!E)
-    return;
-
-  // Don't warn inside macros.
-  if (E->getExprLoc().isMacroID()) {
-    const SourceManager &SM = getSourceManager();
-    if (IsInAnyMacroBody(SM, E->getExprLoc()) ||
-        IsInAnyMacroBody(SM, Range.getBegin()))
-      return;
-  }
-  E = E->IgnoreImpCasts();
-
-  const bool IsCompare = NullKind != Expr::NPCK_NotNull;
-
-  if (isa<CXXThisExpr>(E)) {
-    unsigned DiagID = IsCompare ? diag::warn_this_null_compare
-                                : diag::warn_this_bool_conversion;
-    Diag(E->getExprLoc(), DiagID) << E->getSourceRange() << Range << IsEqual;
-    return;
-  }
-
-  bool IsAddressOf = false;
-
-  if (auto *UO = dyn_cast<UnaryOperator>(E->IgnoreParens())) {
-    if (UO->getOpcode() != UO_AddrOf)
-      return;
-    IsAddressOf = true;
-    E = UO->getSubExpr();
-  }
-
-  if (IsAddressOf) {
-    unsigned DiagID = IsCompare
-                          ? diag::warn_address_of_reference_null_compare
-                          : diag::warn_address_of_reference_bool_conversion;
-    PartialDiagnostic PD = PDiag(DiagID) << E->getSourceRange() << Range
-                                         << IsEqual;
-    if (CheckForReference(*this, E, PD)) {
-      return;
-    }
-  }
-
-  auto ComplainAboutNonnullParamOrCall = [&](const Attr *NonnullAttr) {
-    bool IsParam = isa<NonNullAttr>(NonnullAttr);
-    std::string Str;
-    llvm::raw_string_ostream S(Str);
-    E->printPretty(S, nullptr, getPrintingPolicy());
-    unsigned DiagID = IsCompare ? diag::warn_nonnull_expr_compare
-                                : diag::warn_cast_nonnull_to_bool;
-    Diag(E->getExprLoc(), DiagID) << IsParam << S.str()
-      << E->getSourceRange() << Range << IsEqual;
-    Diag(NonnullAttr->getLocation(), diag::note_declared_nonnull) << IsParam;
-  };
-
-  // If we have a CallExpr that is tagged with returns_nonnull, we can complain.
-  if (auto *Call = dyn_cast<CallExpr>(E->IgnoreParenImpCasts())) {
-    if (auto *Callee = Call->getDirectCallee()) {
-      if (const Attr *A = Callee->getAttr<ReturnsNonNullAttr>()) {
-        ComplainAboutNonnullParamOrCall(A);
-        return;
-      }
-    }
-  }
-
-  // Complain if we are converting a lambda expression to a boolean value
-  // outside of instantiation.
-  if (!inTemplateInstantiation()) {
-    if (const auto *MCallExpr = dyn_cast<CXXMemberCallExpr>(E)) {
-      if (const auto *MRecordDecl = MCallExpr->getRecordDecl();
-          MRecordDecl && MRecordDecl->isLambda()) {
-        Diag(E->getExprLoc(), diag::warn_impcast_pointer_to_bool)
-            << /*LambdaPointerConversionOperatorType=*/3
-            << MRecordDecl->getSourceRange() << Range << IsEqual;
-        return;
-      }
-    }
-  }
-
-  // Expect to find a single Decl.  Skip anything more complicated.
-  ValueDecl *D = nullptr;
-  if (DeclRefExpr *R = dyn_cast<DeclRefExpr>(E)) {
-    D = R->getDecl();
-  } else if (MemberExpr *M = dyn_cast<MemberExpr>(E)) {
-    D = M->getMemberDecl();
-  }
-
-  // Weak Decls can be null.
-  if (!D || D->isWeak())
-    return;
-
-  // Check for parameter decl with nonnull attribute
-  if (const auto* PV = dyn_cast<ParmVarDecl>(D)) {
-    if (getCurFunction() &&
-        !getCurFunction()->ModifiedNonNullParams.count(PV)) {
-      if (const Attr *A = PV->getAttr<NonNullAttr>()) {
-        ComplainAboutNonnullParamOrCall(A);
-        return;
-      }
-
-      if (const auto *FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) {
-        // Skip function template not specialized yet.
-        if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
-          return;
-        auto ParamIter = llvm::find(FD->parameters(), PV);
-        assert(ParamIter != FD->param_end());
-        unsigned ParamNo = std::distance(FD->param_begin(), ParamIter);
-
-        for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
-          if (!NonNull->args_size()) {
-              ComplainAboutNonnullParamOrCall(NonNull);
-              return;
-          }
-
-          for (const ParamIdx &ArgNo : NonNull->args()) {
-            if (ArgNo.getASTIndex() == ParamNo) {
-              ComplainAboutNonnullParamOrCall(NonNull);
-              return;
-            }
-          }
-        }
-      }
-    }
-  }
-
-  QualType T = D->getType();
-  const bool IsArray = T->isArrayType();
-  const bool IsFunction = T->isFunctionType();
-
-  // Address of function is used to silence the function warning.
-  if (IsAddressOf && IsFunction) {
-    return;
-  }
-
-  // Found nothing.
-  if (!IsAddressOf && !IsFunction && !IsArray)
-    return;
-
-  // Pretty print the expression for the diagnostic.
-  std::string Str;
-  llvm::raw_string_ostream S(Str);
-  E->printPretty(S, nullptr, getPrintingPolicy());
-
-  unsigned DiagID = IsCompare ? diag::warn_null_pointer_compare
-                              : diag::warn_impcast_pointer_to_bool;
-  enum {
-    AddressOf,
-    FunctionPointer,
-    ArrayPointer
-  } DiagType;
-  if (IsAddressOf)
-    DiagType = AddressOf;
-  else if (IsFunction)
-    DiagType = FunctionPointer;
-  else if (IsArray)
-    DiagType = ArrayPointer;
-  else
-    llvm_unreachable("Could not determine diagnostic.");
-  Diag(E->getExprLoc(), DiagID) << DiagType << S.str() << E->getSourceRange()
-                                << Range << IsEqual;
-
-  if (!IsFunction)
-    return;
-
-  // Suggest '&' to silence the function warning.
-  Diag(E->getExprLoc(), diag::note_function_warning_silence)
-      << FixItHint::CreateInsertion(E->getBeginLoc(), "&");
-
-  // Check to see if '()' fixit should be emitted.
-  QualType ReturnType;
-  UnresolvedSet<4> NonTemplateOverloads;
-  tryExprAsCall(*E, ReturnType, NonTemplateOverloads);
-  if (ReturnType.isNull())
-    return;
-
-  if (IsCompare) {
-    // There are two cases here.  If there is null constant, the only suggest
-    // for a pointer return type.  If the null is 0, then suggest if the return
-    // type is a pointer or an integer type.
-    if (!ReturnType->isPointerType()) {
-      if (NullKind == Expr::NPCK_ZeroExpression ||
-          NullKind == Expr::NPCK_ZeroLiteral) {
-        if (!ReturnType->isIntegerType())
-          return;
-      } else {
-        return;
-      }
-    }
-  } else { // !IsCompare
-    // For function to bool, only suggest if the function pointer has bool
-    // return type.
-    if (!ReturnType->isSpecificBuiltinType(BuiltinType::Bool))
-      return;
-  }
-  Diag(E->getExprLoc(), diag::note_function_to_function_call)
-      << FixItHint::CreateInsertion(getLocForEndOfToken(E->getEndLoc()), "()");
-}
-
-void Sema::CheckImplicitConversions(Expr *E, SourceLocation CC) {
-  // Don't diagnose in unevaluated contexts.
-  if (isUnevaluatedContext())
-    return;
-
-  // Don't diagnose for value- or type-dependent expressions.
-  if (E->isTypeDependent() || E->isValueDependent())
-    return;
-
-  // Check for array bounds violations in cases where the check isn't triggered
-  // elsewhere for other Expr types (like BinaryOperators), e.g. when an
-  // ArraySubscriptExpr is on the RHS of a variable initialization.
-  CheckArrayAccess(E);
-
-  // This is not the right CC for (e.g.) a variable initialization.
-  AnalyzeImplicitConversions(*this, E, CC);
-}
-
-void Sema::CheckBoolLikeConversion(Expr *E, SourceLocation CC) {
-  ::CheckBoolLikeConversion(*this, E, CC);
-}
-
-void Sema::CheckForIntOverflow (const Expr *E) {
-  // Use a work list to deal with nested struct initializers.
-  SmallVector<const Expr *, 2> Exprs(1, E);
-
-  do {
-    const Expr *OriginalE = Exprs.pop_back_val();
-    const Expr *E = OriginalE->IgnoreParenCasts();
-
-    if (isa<BinaryOperator, UnaryOperator>(E)) {
-      E->EvaluateForOverflow(Context);
-      continue;
-    }
-
-    if (const auto *InitList = dyn_cast<InitListExpr>(OriginalE))
-      Exprs.append(InitList->inits().begin(), InitList->inits().end());
-    else if (isa<ObjCBoxedExpr>(OriginalE))
-      E->EvaluateForOverflow(Context);
-    else if (const auto *Call = dyn_cast<CallExpr>(E))
-      Exprs.append(Call->arg_begin(), Call->arg_end());
-    else if (const auto *Message = dyn_cast<ObjCMessageExpr>(E))
-      Exprs.append(Message->arg_begin(), Message->arg_end());
-    else if (const auto *Construct = dyn_cast<CXXConstructExpr>(E))
-      Exprs.append(Construct->arg_begin(), Construct->arg_end());
-    else if (const auto *Temporary = dyn_cast<CXXBindTemporaryExpr>(E))
-      Exprs.push_back(Temporary->getSubExpr());
-    else if (const auto *Array = dyn_cast<ArraySubscriptExpr>(E))
-      Exprs.push_back(Array->getIdx());
-    else if (const auto *Compound = dyn_cast<CompoundLiteralExpr>(E))
-      Exprs.push_back(Compound->getInitializer());
-    else if (const auto *New = dyn_cast<CXXNewExpr>(E);
-             New && New->isArray()) {
-      if (auto ArraySize = New->getArraySize())
-        Exprs.push_back(*ArraySize);
-    } else if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(OriginalE))
-      Exprs.push_back(MTE->getSubExpr());
-  } while (!Exprs.empty());
-}
-
-namespace {
-
-/// Visitor for expressions which looks for unsequenced operations on the
-/// same object.
-class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
-  using Base = ConstEvaluatedExprVisitor<SequenceChecker>;
-
-  /// A tree of sequenced regions within an expression. Two regions are
-  /// unsequenced if one is an ancestor or a descendent of the other. When we
-  /// finish processing an expression with sequencing, such as a comma
-  /// expression, we fold its tree nodes into its parent, since they are
-  /// unsequenced with respect to nodes we will visit later.
-  class SequenceTree {
-    struct Value {
-      explicit Value(unsigned Parent) : Parent(Parent), Merged(false) {}
-      unsigned Parent : 31;
-      LLVM_PREFERRED_TYPE(bool)
-      unsigned Merged : 1;
-    };
-    SmallVector<Value, 8> Values;
-
-  public:
-    /// A region within an expression which may be sequenced with respect
-    /// to some other region.
-    class Seq {
-      friend class SequenceTree;
-
-      unsigned Index;
-
-      explicit Seq(unsigned N) : Index(N) {}
-
-    public:
-      Seq() : Index(0) {}
-    };
-
-    SequenceTree() { Values.push_back(Value(0)); }
-    Seq root() const { return Seq(0); }
-
-    /// Create a new sequence of operations, which is an unsequenced
-    /// subset of \p Parent. This sequence of operations is sequenced with
-    /// respect to other children of \p Parent.
-    Seq allocate(Seq Parent) {
-      Values.push_back(Value(Parent.Index));
-      return Seq(Values.size() - 1);
-    }
-
-    /// Merge a sequence of operations into its parent.
-    void merge(Seq S) {
-      Values[S.Index].Merged = true;
-    }
-
-    /// Determine whether two operations are unsequenced. This operation
-    /// is asymmetric: \p Cur should be the more recent sequence, and \p Old
-    /// should have been merged into its parent as appropriate.
-    bool isUnsequenced(Seq Cur, Seq Old) {
-      unsigned C = representative(Cur.Index);
-      unsigned Target = representative(Old.Index);
-      while (C >= Target) {
-        if (C == Target)
-          return true;
-        C = Values[C].Parent;
-      }
-      return false;
-    }
-
-  private:
-    /// Pick a representative for a sequence.
-    unsigned representative(unsigned K) {
-      if (Values[K].Merged)
-        // Perform path compression as we go.
-        return Values[K].Parent = representative(Values[K].Parent);
-      return K;
-    }
-  };
-
-  /// An object for which we can track unsequenced uses.
-  using Object = const ValueDecl *;
-
-  /// Different flavors of object usage which we track. We only track the
-  /// least-sequenced usage of each kind.
-  enum UsageKind {
-    /// A read of an object. Multiple unsequenced reads are OK.
-    UK_Use,
-
-    /// A modification of an object which is sequenced before the value
-    /// computation of the expression, such as ++n in C++.
-    UK_ModAsValue,
-
-    /// A modification of an object which is not sequenced before the value
-    /// computation of the expression, such as n++.
-    UK_ModAsSideEffect,
-
-    UK_Count = UK_ModAsSideEffect + 1
-  };
-
-  enum WarningKind { WK_UseAndMod, WK_ModAndMod, WK_Volatile_UseAndUse };
-
-  /// Bundle together a sequencing region and the expression corresponding
-  /// to a specific usage. One Usage is stored for each usage kind in UsageInfo.
-  struct Usage {
-    const Expr *UsageExpr = nullptr;
-    SequenceTree::Seq Seq;
-
-    Usage() = default;
-  };
-
-  struct UsageInfo {
-    Usage Uses[UK_Count];
-
-    /// Have we issued a diagnostic for this object already?
-    bool Diagnosed = false;
-
-    UsageInfo();
-  };
-  using UsageInfoMap = llvm::SmallDenseMap<Object, UsageInfo, 16>;
-
-  Sema &SemaRef;
-
-  /// Sequenced regions within the expression.
-  SequenceTree Tree;
-
-  /// Declaration modifications and references which we have seen.
-  UsageInfoMap UsageMap;
-
-  /// The region we are currently within.
-  SequenceTree::Seq Region;
-
-  /// Filled in with declarations which were modified as a side-effect
-  /// (that is, post-increment operations).
-  SmallVectorImpl<std::pair<Object, Usage>> *ModAsSideEffect = nullptr;
-
-  /// Expressions to check later. We defer checking these to reduce
-  /// stack usage.
-  SmallVectorImpl<const Expr *> &WorkList;
-
-  /// RAII object wrapping the visitation of a sequenced subexpression of an
-  /// expression. At the end of this process, the side-effects of the evaluation
-  /// become sequenced with respect to the value computation of the result, so
-  /// we downgrade any UK_ModAsSideEffect within the evaluation to
-  /// UK_ModAsValue.
-  struct SequencedSubexpression {
-    SequencedSubexpression(SequenceChecker &Self)
-      : Self(Self), OldModAsSideEffect(Self.ModAsSideEffect) {
-      Self.ModAsSideEffect = &ModAsSideEffect;
-    }
-
-    ~SequencedSubexpression() {
-      for (const std::pair<Object, Usage> &M : llvm::reverse(ModAsSideEffect)) {
-        // Add a new usage with usage kind UK_ModAsValue, and then restore
-        // the previous usage with UK_ModAsSideEffect (thus clearing it if
-        // the previous one was empty).
-        UsageInfo &UI = Self.UsageMap[M.first];
-        auto &SideEffectUsage = UI.Uses[UK_ModAsSideEffect];
-        Self.addUsage(M.first, UI, SideEffectUsage.UsageExpr, UK_ModAsValue);
-        SideEffectUsage = M.second;
-      }
-      Self.ModAsSideEffect = OldModAsSideEffect;
-    }
-
-    SequenceChecker &Self;
-    SmallVector<std::pair<Object, Usage>, 4> ModAsSideEffect;
-    SmallVectorImpl<std::pair<Object, Usage>> *OldModAsSideEffect;
-  };
-
-  /// RAII object wrapping the visitation of a subexpression which we might
-  /// choose to evaluate as a constant. If any subexpression is evaluated and
-  /// found to be non-constant, this allows us to suppress the evaluation of
-  /// the outer expression.
-  class EvaluationTracker {
-  public:
-    EvaluationTracker(SequenceChecker &Self)
-        : Self(Self), Prev(Self.EvalTracker) {
-      Self.EvalTracker = this;
-    }
-
-    ~EvaluationTracker() {
-      Self.EvalTracker = Prev;
-      if (Prev)
-        Prev->EvalOK &= EvalOK;
-    }
-
-    bool evaluate(const Expr *E, bool &Result) {
-      if (!EvalOK || E->isValueDependent())
-        return false;
-      EvalOK = E->EvaluateAsBooleanCondition(
-          Result, Self.SemaRef.Context,
-          Self.SemaRef.isConstantEvaluatedContext());
-      return EvalOK;
-    }
-
-  private:
-    SequenceChecker &Self;
-    EvaluationTracker *Prev;
-    bool EvalOK = true;
-  } *EvalTracker = nullptr;
-
-  /// Find the object which is produced by the specified expression,
-  /// if any.
-  Object getObject(const Expr *E, bool Mod) const {
-    E = E->IgnoreParenCasts();
-    if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
-      if (Mod && (UO->getOpcode() == UO_PreInc || UO->getOpcode() == UO_PreDec))
-        return getObject(UO->getSubExpr(), Mod);
-    } else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
-      if (BO->getOpcode() == BO_Comma)
-        return getObject(BO->getRHS(), Mod);
-      if (Mod && BO->isAssignmentOp())
-        return getObject(BO->getLHS(), Mod);
-    } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
-      // FIXME: Check for more interesting cases, like "x.n = ++x.n".
-      if (isa<CXXThisExpr>(ME->getBase()->IgnoreParenCasts()))
-        return ME->getMemberDecl();
-    } else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
-      // FIXME: If this is a reference, map through to its value.
-      return DRE->getDecl();
-    return nullptr;
-  }
-
-  /// Note that an object \p O was modified or used by an expression
-  /// \p UsageExpr with usage kind \p UK. \p UI is the \p UsageInfo for
-  /// the object \p O as obtained via the \p UsageMap.
-  void addUsage(Object O, UsageInfo &UI, const Expr *UsageExpr, UsageKind UK) {
-    // Get the old usage for the given object and usage kind.
-    Usage &U = UI.Uses[UK];
-    if (!U.UsageExpr || !Tree.isUnsequenced(Region, U.Seq)) {
-      // If we have a modification as side effect and are in a sequenced
-      // subexpression, save the old Usage so that we can restore it later
-      // in SequencedSubexpression::~SequencedSubexpression.
-      if (UK == UK_ModAsSideEffect && ModAsSideEffect)
-        ModAsSideEffect->push_back(std::make_pair(O, U));
-      // Then record the new usage with the current sequencing region.
-      U.UsageExpr = UsageExpr;
-      U.Seq = Region;
-    }
-  }
-
-  /// Check whether a modification or use of an object \p O in an expression
-  /// \p UsageExpr conflicts with a prior usage of kind \p OtherKind. \p UI is
-  /// the \p UsageInfo for the object \p O as obtained via the \p UsageMap.
-  /// \p IsModMod is true when we are checking for a mod-mod unsequenced
-  /// usage and false we are checking for a mod-use unsequenced usage.
-  void checkUsage(Object O, UsageInfo &UI, const Expr *UsageExpr,
-                  UsageKind OtherKind, WarningKind WarnKind) {
-    if (UI.Diagnosed)
-      return;
-
-    const Usage &U = UI.Uses[OtherKind];
-    if (!U.UsageExpr || !Tree.isUnsequenced(Region, U.Seq))
-      return;
-
-    const Expr *Mod = U.UsageExpr;
-    const Expr *ModOrUse = UsageExpr;
-    if (OtherKind == UK_Use)
-      std::swap(Mod, ModOrUse);
-
-    unsigned DiagID = 0;
-    switch (WarnKind) {
-    case WK_UseAndMod:
-      DiagID = diag::warn_unsequenced_mod_use;
-      break;
-    case WK_ModAndMod:
-      DiagID = diag::warn_unsequenced_mod_mod;
-      break;
-    case WK_Volatile_UseAndUse:
-      DiagID = diag::warn_unsequenced_use_use_volatile;
-      break;
-    }
-
-    SemaRef.DiagRuntimeBehavior(
-        Mod->getExprLoc(), {Mod, ModOrUse},
-        SemaRef.PDiag(DiagID) << O << SourceRange(ModOrUse->getExprLoc()));
-    UI.Diagnosed = true;
-  }
-
-  // A note on note{Pre, Post}{Use, Mod}:
-  //
-  // (It helps to follow the algorithm with an expression such as
-  //  "((++k)++, k) = k" or "k = (k++, k++)". Both contain unsequenced
-  //  operations before C++17 and both are well-defined in C++17).
-  //
-  // When visiting a node which uses/modify an object we first call notePreUse
-  // or notePreMod before visiting its sub-expression(s). At this point the
-  // children of the current node have not yet been visited and so the eventual
-  // uses/modifications resulting from the children of the current node have not
-  // been recorded yet.
-  //
-  // We then visit the children of the current node. After that notePostUse or
-  // notePostMod is called. These will 1) detect an unsequenced modification
-  // as side effect (as in "k++ + k") and 2) add a new usage with the
-  // appropriate usage kind.
-  //
-  // We also have to be careful that some operation sequences modification as
-  // side effect as well (for example: || or ,). To account for this we wrap
-  // the visitation of such a sub-expression (for example: the LHS of || or ,)
-  // with SequencedSubexpression. SequencedSubexpression is an RAII object
-  // which record usages which are modifications as side effect, and then
-  // downgrade them (or more accurately restore the previous usage which was a
-  // modification as side effect) when exiting the scope of the sequenced
-  // subexpression.
-
-  void notePreUse(Object O, const Expr *UseExpr) {
-    UsageInfo &UI = UsageMap[O];
-    // Uses conflict with other modifications.
-    checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsValue, WK_UseAndMod);
-    // Volatile uses conflict with other uses.
-    if (O->getType().isVolatileQualified())
-      checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_Use, WK_Volatile_UseAndUse);
-  }
-
-  void notePostUse(Object O, const Expr *UseExpr) {
-    UsageInfo &UI = UsageMap[O];
-    checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsSideEffect, WK_UseAndMod);
-    addUsage(O, UI, UseExpr, /*UsageKind=*/UK_Use);
-  }
-
-  void notePreMod(Object O, const Expr *ModExpr) {
-    UsageInfo &UI = UsageMap[O];
-    // Modifications conflict with other modifications and with uses.
-    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsValue, WK_ModAndMod);
-    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_Use, WK_UseAndMod);
-  }
-
-  void notePostMod(Object O, const Expr *ModExpr, UsageKind UK) {
-    UsageInfo &UI = UsageMap[O];
-    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsSideEffect, WK_ModAndMod);
-    addUsage(O, UI, ModExpr, /*UsageKind=*/UK);
-  }
-
-public:
-  SequenceChecker(Sema &S, const Expr *E,
-                  SmallVectorImpl<const Expr *> &WorkList)
-      : Base(S.Context), SemaRef(S), Region(Tree.root()), WorkList(WorkList) {
-    Visit(E);
-    // Silence a -Wunused-private-field since WorkList is now unused.
-    // TODO: Evaluate if it can be used, and if not remove it.
-    (void)this->WorkList;
-  }
-
-  void VisitStmt(const Stmt *S) {
-    // Skip all statements which aren't expressions for now.
-  }
-
-  void VisitExpr(const Expr *E) {
-    // By default, just recurse to evaluated subexpressions.
-    Base::VisitStmt(E);
-  }
-
-  void VisitCoroutineSuspendExpr(const CoroutineSuspendExpr *CSE) {
-    for (auto *Sub : CSE->children()) {
-      const Expr *ChildExpr = dyn_cast_or_null<Expr>(Sub);
-      if (!ChildExpr)
-        continue;
-
-      if (ChildExpr == CSE->getOperand())
-        // Do not recurse over a CoroutineSuspendExpr's operand.
-        // The operand is also a subexpression of getCommonExpr(), and
-        // recursing into it directly could confuse object management
-        // for the sake of sequence tracking.
-        continue;
-
-      Visit(Sub);
-    }
-  }
-
-  void VisitCastExpr(const CastExpr *E) {
-    Object O = Object();
-    if (E->getCastKind() == CK_LValueToRValue)
-      O = getObject(E->getSubExpr(), false);
-
-    if (O)
-      notePreUse(O, E);
-    VisitExpr(E);
-    if (O)
-      notePostUse(O, E);
-  }
-
-  void VisitSequencedExpressions(const Expr *SequencedBefore,
-                                 const Expr *SequencedAfter) {
-    SequenceTree::Seq BeforeRegion = Tree.allocate(Region);
-    SequenceTree::Seq AfterRegion = Tree.allocate(Region);
-    SequenceTree::Seq OldRegion = Region;
-
-    {
-      SequencedSubexpression SeqBefore(*this);
-      Region = BeforeRegion;
-      Visit(SequencedBefore);
-    }
-
-    Region = AfterRegion;
-    Visit(SequencedAfter);
-
-    Region = OldRegion;
-
-    Tree.merge(BeforeRegion);
-    Tree.merge(AfterRegion);
-  }
-
-  void VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE) {
-    // C++17 [expr.sub]p1:
-    //   The expression E1[E2] is identical (by definition) to *((E1)+(E2)). The
-    //   expression E1 is sequenced before the expression E2.
-    if (SemaRef.getLangOpts().CPlusPlus17)
-      VisitSequencedExpressions(ASE->getLHS(), ASE->getRHS());
-    else {
-      Visit(ASE->getLHS());
-      Visit(ASE->getRHS());
-    }
-  }
-
-  void VisitBinPtrMemD(const BinaryOperator *BO) { VisitBinPtrMem(BO); }
-  void VisitBinPtrMemI(const BinaryOperator *BO) { VisitBinPtrMem(BO); }
-  void VisitBinPtrMem(const BinaryOperator *BO) {
-    // C++17 [expr.mptr.oper]p4:
-    //  Abbreviating pm-expression.*cast-expression as E1.*E2, [...]
-    //  the expression E1 is sequenced before the expression E2.
-    if (SemaRef.getLangOpts().CPlusPlus17)
-      VisitSequencedExpressions(BO->getLHS(), BO->getRHS());
-    else {
-      Visit(BO->getLHS());
-      Visit(BO->getRHS());
-    }
-  }
-
-  void VisitBinShl(const BinaryOperator *BO) { VisitBinShlShr(BO); }
-  void VisitBinShr(const BinaryOperator *BO) { VisitBinShlShr(BO); }
-  void VisitBinShlShr(const BinaryOperator *BO) {
-    // C++17 [expr.shift]p4:
-    //  The expression E1 is sequenced before the expression E2.
-    if (SemaRef.getLangOpts().CPlusPlus17)
-      VisitSequencedExpressions(BO->getLHS(), BO->getRHS());
-    else {
-      Visit(BO->getLHS());
-      Visit(BO->getRHS());
-    }
-  }
-
-  void VisitBinComma(const BinaryOperator *BO) {
-    // C++11 [expr.comma]p1:
-    //   Every value computation and side effect associated with the left
-    //   expression is sequenced before every value computation and side
-    //   effect associated with the right expression.
-    VisitSequencedExpressions(BO->getLHS(), BO->getRHS());
-  }
-
-  void VisitBinAssign(const BinaryOperator *BO) {
-    SequenceTree::Seq RHSRegion;
-    SequenceTree::Seq LHSRegion;
-    if (SemaRef.getLangOpts().CPlusPlus17) {
-      RHSRegion = Tree.allocate(Region);
-      LHSRegion = Tree.allocate(Region);
-    } else {
-      RHSRegion = Region;
-      LHSRegion = Region;
-    }
-    SequenceTree::Seq OldRegion = Region;
-
-    // C++11 [expr.ass]p1:
-    //  [...] the assignment is sequenced after the value computation
-    //  of the right and left operands, [...]
-    //
-    // so check it before inspecting the operands and update the
-    // map afterwards.
-    Object O = getObject(BO->getLHS(), /*Mod=*/true);
-    if (O)
-      notePreMod(O, BO);
-
-    if (SemaRef.getLangOpts().CPlusPlus17) {
-      // C++17 [expr.ass]p1:
-      //  [...] The right operand is sequenced before the left operand. [...]
-      {
-        SequencedSubexpression SeqBefore(*this);
-        Region = RHSRegion;
-        Visit(BO->getRHS());
-      }
-
-      Region = LHSRegion;
-      Visit(BO->getLHS());
-
-      if (O && isa<CompoundAssignOperator>(BO))
-        notePostUse(O, BO);
-
-    } else {
-      // C++11 does not specify any sequencing between the LHS and RHS.
-      Region = LHSRegion;
-      Visit(BO->getLHS());
-
-      if (O && isa<CompoundAssignOperator>(BO))
-        notePostUse(O, BO);
-
-      Region = RHSRegion;
-      Visit(BO->getRHS());
-    }
-
-    // C++11 [expr.ass]p1:
-    //  the assignment is sequenced [...] before the value computation of the
-    //  assignment expression.
-    // C11 6.5.16/3 has no such rule.
-    Region = OldRegion;
-    if (O)
-      notePostMod(O, BO,
-                  SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
-                                                  : UK_ModAsSideEffect);
-    if (SemaRef.getLangOpts().CPlusPlus17) {
-      Tree.merge(RHSRegion);
-      Tree.merge(LHSRegion);
-    }
-  }
-
-  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) {
-    Object O = getObject(UO->getSubExpr(), true);
-    if (!O)
-      return VisitExpr(UO);
-
-    notePreMod(O, UO);
-    Visit(UO->getSubExpr());
-    // C++11 [expr.pre.incr]p1:
-    //   the expression ++x is equivalent to x+=1
-    notePostMod(O, UO,
-                SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
-                                                : UK_ModAsSideEffect);
-  }
-
-  void VisitUnaryPostInc(const UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
-  void VisitUnaryPostDec(const UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
-  void VisitUnaryPostIncDec(const UnaryOperator *UO) {
-    Object O = getObject(UO->getSubExpr(), true);
-    if (!O)
-      return VisitExpr(UO);
-
-    notePreMod(O, UO);
-    Visit(UO->getSubExpr());
-    notePostMod(O, UO, UK_ModAsSideEffect);
-  }
-
-  void VisitBinLOr(const BinaryOperator *BO) {
-    // C++11 [expr.log.or]p2:
-    //  If the second expression is evaluated, every value computation and
-    //  side effect associated with the first expression is sequenced before
-    //  every value computation and side effect associated with the
-    //  second expression.
-    SequenceTree::Seq LHSRegion = Tree.allocate(Region);
-    SequenceTree::Seq RHSRegion = Tree.allocate(Region);
-    SequenceTree::Seq OldRegion = Region;
-
-    EvaluationTracker Eval(*this);
-    {
-      SequencedSubexpression Sequenced(*this);
-      Region = LHSRegion;
-      Visit(BO->getLHS());
-    }
-
-    // C++11 [expr.log.or]p1:
-    //  [...] the second operand is not evaluated if the first operand
-    //  evaluates to true.
-    bool EvalResult = false;
-    bool EvalOK = Eval.evaluate(BO->getLHS(), EvalResult);
-    bool ShouldVisitRHS = !EvalOK || !EvalResult;
-    if (ShouldVisitRHS) {
-      Region = RHSRegion;
-      Visit(BO->getRHS());
-    }
-
-    Region = OldRegion;
-    Tree.merge(LHSRegion);
-    Tree.merge(RHSRegion);
-  }
-
-  void VisitBinLAnd(const BinaryOperator *BO) {
-    // C++11 [expr.log.and]p2:
-    //  If the second expression is evaluated, every value computation and
-    //  side effect associated with the first expression is sequenced before
-    //  every value computation and side effect associated with the
-    //  second expression.
-    SequenceTree::Seq LHSRegion = Tree.allocate(Region);
-    SequenceTree::Seq RHSRegion = Tree.allocate(Region);
-    SequenceTree::Seq OldRegion = Region;
-
-    EvaluationTracker Eval(*this);
-    {
-      SequencedSubexpression Sequenced(*this);
-      Region = LHSRegion;
-      Visit(BO->getLHS());
-    }
-
-    // C++11 [expr.log.and]p1:
-    //  [...] the second operand is not evaluated if the first operand is false.
-    bool EvalResult = false;
-    bool EvalOK = Eval.evaluate(BO->getLHS(), EvalResult);
-    bool ShouldVisitRHS = !EvalOK || EvalResult;
-    if (ShouldVisitRHS) {
-      Region = RHSRegion;
-      Visit(BO->getRHS());
-    }
-
-    Region = OldRegion;
-    Tree.merge(LHSRegion);
-    Tree.merge(RHSRegion);
-  }
-
-  void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO) {
-    // C++11 [expr.cond]p1:
-    //  [...] Every value computation and side effect associated with the first
-    //  expression is sequenced before every value computation and side effect
-    //  associated with the second or third expression.
-    SequenceTree::Seq ConditionRegion = Tree.allocate(Region);
-
-    // No sequencing is specified between the true and false expression.
-    // However since exactly one of both is going to be evaluated we can
-    // consider them to be sequenced. This is needed to avoid warning on
-    // something like "x ? y+= 1 : y += 2;" in the case where we will visit
-    // both the true and false expressions because we can't evaluate x.
-    // This will still allow us to detect an expression like (pre C++17)
-    // "(x ? y += 1 : y += 2) = y".
-    //
-    // We don't wrap the visitation of the true and false expression with
-    // SequencedSubexpression because we don't want to downgrade modifications
-    // as side effect in the true and false expressions after the visition
-    // is done. (for example in the expression "(x ? y++ : y++) + y" we should
-    // not warn between the two "y++", but we should warn between the "y++"
-    // and the "y".
-    SequenceTree::Seq TrueRegion = Tree.allocate(Region);
-    SequenceTree::Seq FalseRegion = Tree.allocate(Region);
-    SequenceTree::Seq OldRegion = Region;
-
-    EvaluationTracker Eval(*this);
-    {
-      SequencedSubexpression Sequenced(*this);
-      Region = ConditionRegion;
-      Visit(CO->getCond());
-    }
-
-    // C++11 [expr.cond]p1:
-    // [...] The first expression is contextually converted to bool (Clause 4).
-    // It is evaluated and if it is true, the result of the conditional
-    // expression is the value of the second expression, otherwise that of the
-    // third expression. Only one of the second and third expressions is
-    // evaluated. [...]
-    bool EvalResult = false;
-    bool EvalOK = Eval.evaluate(CO->getCond(), EvalResult);
-    bool ShouldVisitTrueExpr = !EvalOK || EvalResult;
-    bool ShouldVisitFalseExpr = !EvalOK || !EvalResult;
-    if (ShouldVisitTrueExpr) {
-      Region = TrueRegion;
-      Visit(CO->getTrueExpr());
-    }
-    if (ShouldVisitFalseExpr) {
-      Region = FalseRegion;
-      Visit(CO->getFalseExpr());
-    }
-
-    Region = OldRegion;
-    Tree.merge(ConditionRegion);
-    Tree.merge(TrueRegion);
-    Tree.merge(FalseRegion);
-  }
-
-  void VisitCallExpr(const CallExpr *CE) {
-    // FIXME: CXXNewExpr and CXXDeleteExpr implicitly call functions.
-
-    if (CE->isUnevaluatedBuiltinCall(Context))
-      return;
-
-    // C++11 [intro.execution]p15:
-    //   When calling a function [...], every value computation and side effect
-    //   associated with any argument expression, or with the postfix expression
-    //   designating the called function, is sequenced before execution of every
-    //   expression or statement in the body of the function [and thus before
-    //   the value computation of its result].
-    SequencedSubexpression Sequenced(*this);
-    SemaRef.runWithSufficientStackSpace(CE->getExprLoc(), [&] {
-      // C++17 [expr.call]p5
-      //   The postfix-expression is sequenced before each expression in the
-      //   expression-list and any default argument. [...]
-      SequenceTree::Seq CalleeRegion;
-      SequenceTree::Seq OtherRegion;
-      if (SemaRef.getLangOpts().CPlusPlus17) {
-        CalleeRegion = Tree.allocate(Region);
-        OtherRegion = Tree.allocate(Region);
-      } else {
-        CalleeRegion = Region;
-        OtherRegion = Region;
-      }
-      SequenceTree::Seq OldRegion = Region;
-
-      // Visit the callee expression first.
-      Region = CalleeRegion;
-      if (SemaRef.getLangOpts().CPlusPlus17) {
-        SequencedSubexpression Sequenced(*this);
-        Visit(CE->getCallee());
-      } else {
-        Visit(CE->getCallee());
-      }
-
-      // Then visit the argument expressions.
-      Region = OtherRegion;
-      for (const Expr *Argument : CE->arguments())
-        Visit(Argument);
-
-      Region = OldRegion;
-      if (SemaRef.getLangOpts().CPlusPlus17) {
-        Tree.merge(CalleeRegion);
-        Tree.merge(OtherRegion);
-      }
-    });
-  }
-
-  void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *CXXOCE) {
-    // C++17 [over.match.oper]p2:
-    //   [...] the operator notation is first transformed to the equivalent
-    //   function-call notation as summarized in Table 12 (where @ denotes one
-    //   of the operators covered in the specified subclause). However, the
-    //   operands are sequenced in the order prescribed for the built-in
-    //   operator (Clause 8).
-    //
-    // From the above only overloaded binary operators and overloaded call
-    // operators have sequencing rules in C++17 that we need to handle
-    // separately.
-    if (!SemaRef.getLangOpts().CPlusPlus17 ||
-        (CXXOCE->getNumArgs() != 2 && CXXOCE->getOperator() != OO_Call))
-      return VisitCallExpr(CXXOCE);
-
-    enum {
-      NoSequencing,
-      LHSBeforeRHS,
-      RHSBeforeLHS,
-      LHSBeforeRest
-    } SequencingKind;
-    switch (CXXOCE->getOperator()) {
-    case OO_Equal:
-    case OO_PlusEqual:
-    case OO_MinusEqual:
-    case OO_StarEqual:
-    case OO_SlashEqual:
-    case OO_PercentEqual:
-    case OO_CaretEqual:
-    case OO_AmpEqual:
-    case OO_PipeEqual:
-    case OO_LessLessEqual:
-    case OO_GreaterGreaterEqual:
-      SequencingKind = RHSBeforeLHS;
-      break;
-
-    case OO_LessLess:
-    case OO_GreaterGreater:
-    case OO_AmpAmp:
-    case OO_PipePipe:
-    case OO_Comma:
-    case OO_ArrowStar:
-    case OO_Subscript:
-      SequencingKind = LHSBeforeRHS;
-      break;
-
-    case OO_Call:
-      SequencingKind = LHSBeforeRest;
-      break;
-
-    default:
-      SequencingKind = NoSequencing;
-      break;
-    }
-
-    if (SequencingKind == NoSequencing)
-      return VisitCallExpr(CXXOCE);
-
-    // This is a call, so all subexpressions are sequenced before the result.
-    SequencedSubexpression Sequenced(*this);
-
-    SemaRef.runWithSufficientStackSpace(CXXOCE->getExprLoc(), [&] {
-      assert(SemaRef.getLangOpts().CPlusPlus17 &&
-             "Should only get there with C++17 and above!");
-      assert((CXXOCE->getNumArgs() == 2 || CXXOCE->getOperator() == OO_Call) &&
-             "Should only get there with an overloaded binary operator"
-             " or an overloaded call operator!");
-
-      if (SequencingKind == LHSBeforeRest) {
-        assert(CXXOCE->getOperator() == OO_Call &&
-               "We should only have an overloaded call operator here!");
-
-        // This is very similar to VisitCallExpr, except that we only have the
-        // C++17 case. The postfix-expression is the first argument of the
-        // CXXOperatorCallExpr. The expressions in the expression-list, if any,
-        // are in the following arguments.
-        //
-        // Note that we intentionally do not visit the callee expression since
-        // it is just a decayed reference to a function.
-        SequenceTree::Seq PostfixExprRegion = Tree.allocate(Region);
-        SequenceTree::Seq ArgsRegion = Tree.allocate(Region);
-        SequenceTree::Seq OldRegion = Region;
-
-        assert(CXXOCE->getNumArgs() >= 1 &&
-               "An overloaded call operator must have at least one argument"
-               " for the postfix-expression!");
-        const Expr *PostfixExpr = CXXOCE->getArgs()[0];
-        llvm::ArrayRef<const Expr *> Args(CXXOCE->getArgs() + 1,
-                                          CXXOCE->getNumArgs() - 1);
-
-        // Visit the postfix-expression first.
-        {
-          Region = PostfixExprRegion;
-          SequencedSubexpression Sequenced(*this);
-          Visit(PostfixExpr);
-        }
-
-        // Then visit the argument expressions.
-        Region = ArgsRegion;
-        for (const Expr *Arg : Args)
-          Visit(Arg);
-
-        Region = OldRegion;
-        Tree.merge(PostfixExprRegion);
-        Tree.merge(ArgsRegion);
-      } else {
-        assert(CXXOCE->getNumArgs() == 2 &&
-               "Should only have two arguments here!");
-        assert((SequencingKind == LHSBeforeRHS ||
-                SequencingKind == RHSBeforeLHS) &&
-               "Unexpected sequencing kind!");
-
-        // We do not visit the callee expression since it is just a decayed
-        // reference to a function.
-        const Expr *E1 = CXXOCE->getArg(0);
-        const Expr *E2 = CXXOCE->getArg(1);
-        if (SequencingKind == RHSBeforeLHS)
-          std::swap(E1, E2);
-
-        return VisitSequencedExpressions(E1, E2);
-      }
-    });
-  }
-
-  void VisitCXXConstructExpr(const CXXConstructExpr *CCE) {
-    // This is a call, so all subexpressions are sequenced before the result.
-    SequencedSubexpression Sequenced(*this);
-
-    if (!CCE->isListInitialization())
-      return VisitExpr(CCE);
-
-    // In C++11, list initializations are sequenced.
-    SequenceExpressionsInOrder(
-        llvm::ArrayRef(CCE->getArgs(), CCE->getNumArgs()));
-  }
-
-  void VisitInitListExpr(const InitListExpr *ILE) {
-    if (!SemaRef.getLangOpts().CPlusPlus11)
-      return VisitExpr(ILE);
-
-    // In C++11, list initializations are sequenced.
-    SequenceExpressionsInOrder(ILE->inits());
-  }
-
-  void VisitCXXParenListInitExpr(const CXXParenListInitExpr *PLIE) {
-    // C++20 parenthesized list initializations are sequenced. See C++20
-    // [decl.init.general]p16.5 and [decl.init.general]p16.6.2.2.
-    SequenceExpressionsInOrder(PLIE->getInitExprs());
-  }
-
-private:
-  void SequenceExpressionsInOrder(ArrayRef<const Expr *> ExpressionList) {
-    SmallVector<SequenceTree::Seq, 32> Elts;
-    SequenceTree::Seq Parent = Region;
-    for (const Expr *E : ExpressionList) {
-      if (!E)
-        continue;
-      Region = Tree.allocate(Parent);
-      Elts.push_back(Region);
-      Visit(E);
-    }
-
-    // Forget that the initializers are sequenced.
-    Region = Parent;
-    for (unsigned I = 0; I < Elts.size(); ++I)
-      Tree.merge(Elts[I]);
-  }
-};
-
-SequenceChecker::UsageInfo::UsageInfo() = default;
-
-} // namespace
-
-void Sema::CheckUnsequencedOperations(const Expr *E) {
-  SmallVector<const Expr *, 8> WorkList;
-  WorkList.push_back(E);
-  while (!WorkList.empty()) {
-    const Expr *Item = WorkList.pop_back_val();
-    SequenceChecker(*this, Item, WorkList);
-  }
-}
-
-void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc,
-                              bool IsConstexpr) {
-  llvm::SaveAndRestore ConstantContext(isConstantEvaluatedOverride,
-                                       IsConstexpr || isa<ConstantExpr>(E));
-  CheckImplicitConversions(E, CheckLoc);
-  if (!E->isInstantiationDependent())
-    CheckUnsequencedOperations(E);
-  if (!IsConstexpr && !E->isValueDependent())
-    CheckForIntOverflow(E);
-}
-
-void Sema::CheckBitFieldInitialization(SourceLocation InitLoc,
-                                       FieldDecl *BitField,
-                                       Expr *Init) {
-  (void) AnalyzeBitFieldAssignment(*this, BitField, Init, InitLoc);
-}
-
-static void diagnoseArrayStarInParamType(Sema &S, QualType PType,
-                                         SourceLocation Loc) {
-  if (!PType->isVariablyModifiedType())
-    return;
-  if (const auto *PointerTy = dyn_cast<PointerType>(PType)) {
-    diagnoseArrayStarInParamType(S, PointerTy->getPointeeType(), Loc);
-    return;
-  }
-  if (const auto *ReferenceTy = dyn_cast<ReferenceType>(PType)) {
-    diagnoseArrayStarInParamType(S, ReferenceTy->getPointeeType(), Loc);
-    return;
-  }
-  if (const auto *ParenTy = dyn_cast<ParenType>(PType)) {
-    diagnoseArrayStarInParamType(S, ParenTy->getInnerType(), Loc);
-    return;
-  }
-
-  const ArrayType *AT = S.Context.getAsArrayType(PType);
-  if (!AT)
-    return;
-
-  if (AT->getSizeModifier() != ArraySizeModifier::Star) {
-    diagnoseArrayStarInParamType(S, AT->getElementType(), Loc);
-    return;
-  }
-
-  S.Diag(Loc, diag::err_array_star_in_function_definition);
-}
-
-bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters,
-                                    bool CheckParameterNames) {
-  bool HasInvalidParm = false;
-  for (ParmVarDecl *Param : Parameters) {
-    assert(Param && "null in a parameter list");
-    // C99 6.7.5.3p4: the parameters in a parameter type list in a
-    // function declarator that is part of a function definition of
-    // that function shall not have incomplete type.
-    //
-    // C++23 [dcl.fct.def.general]/p2
-    // The type of a parameter [...] for a function definition
-    // shall not be a (possibly cv-qualified) class type that is incomplete
-    // or abstract within the function body unless the function is deleted.
-    if (!Param->isInvalidDecl() &&
-        (RequireCompleteType(Param->getLocation(), Param->getType(),
-                             diag::err_typecheck_decl_incomplete_type) ||
-         RequireNonAbstractType(Param->getBeginLoc(), Param->getOriginalType(),
-                                diag::err_abstract_type_in_decl,
-                                AbstractParamType))) {
-      Param->setInvalidDecl();
-      HasInvalidParm = true;
-    }
-
-    // C99 6.9.1p5: If the declarator includes a parameter type list, the
-    // declaration of each parameter shall include an identifier.
-    if (CheckParameterNames && Param->getIdentifier() == nullptr &&
-        !Param->isImplicit() && !getLangOpts().CPlusPlus) {
-      // Diagnose this as an extension in C17 and earlier.
-      if (!getLangOpts().C23)
-        Diag(Param->getLocation(), diag::ext_parameter_name_omitted_c23);
-    }
-
-    // C99 6.7.5.3p12:
-    //   If the function declarator is not part of a definition of that
-    //   function, parameters may have incomplete type and may use the [*]
-    //   notation in their sequences of declarator specifiers to specify
-    //   variable length array types.
-    QualType PType = Param->getOriginalType();
-    // FIXME: This diagnostic should point the '[*]' if source-location
-    // information is added for it.
-    diagnoseArrayStarInParamType(*this, PType, Param->getLocation());
-
-    // If the parameter is a c++ class type and it has to be destructed in the
-    // callee function, declare the destructor so that it can be called by the
-    // callee function. Do not perform any direct access check on the dtor here.
-    if (!Param->isInvalidDecl()) {
-      if (CXXRecordDecl *ClassDecl = Param->getType()->getAsCXXRecordDecl()) {
-        if (!ClassDecl->isInvalidDecl() &&
-            !ClassDecl->hasIrrelevantDestructor() &&
-            !ClassDecl->isDependentContext() &&
-            ClassDecl->isParamDestroyedInCallee()) {
-          CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl);
-          MarkFunctionReferenced(Param->getLocation(), Destructor);
-          DiagnoseUseOfDecl(Destructor, Param->getLocation());
-        }
-      }
-    }
-
-    // Parameters with the pass_object_size attribute only need to be marked
-    // constant at function definitions. Because we lack information about
-    // whether we're on a declaration or definition when we're instantiating the
-    // attribute, we need to check for constness here.
-    if (const auto *Attr = Param->getAttr<PassObjectSizeAttr>())
-      if (!Param->getType().isConstQualified())
-        Diag(Param->getLocation(), diag::err_attribute_pointers_only)
-            << Attr->getSpelling() << 1;
-
-    // Check for parameter names shadowing fields from the class.
-    if (LangOpts.CPlusPlus && !Param->isInvalidDecl()) {
-      // The owning context for the parameter should be the function, but we
-      // want to see if this function's declaration context is a record.
-      DeclContext *DC = Param->getDeclContext();
-      if (DC && DC->isFunctionOrMethod()) {
-        if (auto *RD = dyn_cast<CXXRecordDecl>(DC->getParent()))
-          CheckShadowInheritedFields(Param->getLocation(), Param->getDeclName(),
-                                     RD, /*DeclIsField*/ false);
-      }
-    }
-
-    if (!Param->isInvalidDecl() &&
-        Param->getOriginalType()->isWebAssemblyTableType()) {
-      Param->setInvalidDecl();
-      HasInvalidParm = true;
-      Diag(Param->getLocation(), diag::err_wasm_table_as_function_parameter);
-    }
-  }
-
-  return HasInvalidParm;
-}
-
-std::optional<std::pair<
-    CharUnits, CharUnits>> static getBaseAlignmentAndOffsetFromPtr(const Expr
-                                                                       *E,
-                                                                   ASTContext
-                                                                       &Ctx);
-
-/// Compute the alignment and offset of the base class object given the
-/// derived-to-base cast expression and the alignment and offset of the derived
-/// class object.
-static std::pair<CharUnits, CharUnits>
-getDerivedToBaseAlignmentAndOffset(const CastExpr *CE, QualType DerivedType,
-                                   CharUnits BaseAlignment, CharUnits Offset,
-                                   ASTContext &Ctx) {
-  for (auto PathI = CE->path_begin(), PathE = CE->path_end(); PathI != PathE;
-       ++PathI) {
-    const CXXBaseSpecifier *Base = *PathI;
-    const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl();
-    if (Base->isVirtual()) {
-      // The complete object may have a lower alignment than the non-virtual
-      // alignment of the base, in which case the base may be misaligned. Choose
-      // the smaller of the non-virtual alignment and BaseAlignment, which is a
-      // conservative lower bound of the complete object alignment.
-      CharUnits NonVirtualAlignment =
-          Ctx.getASTRecordLayout(BaseDecl).getNonVirtualAlignment();
-      BaseAlignment = std::min(BaseAlignment, NonVirtualAlignment);
-      Offset = CharUnits::Zero();
-    } else {
-      const ASTRecordLayout &RL =
-          Ctx.getASTRecordLayout(DerivedType->getAsCXXRecordDecl());
-      Offset += RL.getBaseClassOffset(BaseDecl);
-    }
-    DerivedType = Base->getType();
-  }
-
-  return std::make_pair(BaseAlignment, Offset);
-}
-
-/// Compute the alignment and offset of a binary additive operator.
-static std::optional<std::pair<CharUnits, CharUnits>>
-getAlignmentAndOffsetFromBinAddOrSub(const Expr *PtrE, const Expr *IntE,
-                                     bool IsSub, ASTContext &Ctx) {
-  QualType PointeeType = PtrE->getType()->getPointeeType();
-
-  if (!PointeeType->isConstantSizeType())
-    return std::nullopt;
-
-  auto P = getBaseAlignmentAndOffsetFromPtr(PtrE, Ctx);
-
-  if (!P)
-    return std::nullopt;
-
-  CharUnits EltSize = Ctx.getTypeSizeInChars(PointeeType);
-  if (std::optional<llvm::APSInt> IdxRes = IntE->getIntegerConstantExpr(Ctx)) {
-    CharUnits Offset = EltSize * IdxRes->getExtValue();
-    if (IsSub)
-      Offset = -Offset;
-    return std::make_pair(P->first, P->second + Offset);
-  }
-
-  // If the integer expression isn't a constant expression, compute the lower
-  // bound of the alignment using the alignment and offset of the pointer
-  // expression and the element size.
-  return std::make_pair(
-      P->first.alignmentAtOffset(P->second).alignmentAtOffset(EltSize),
-      CharUnits::Zero());
-}
-
-/// This helper function takes an lvalue expression and returns the alignment of
-/// a VarDecl and a constant offset from the VarDecl.
-std::optional<std::pair<
-    CharUnits,
-    CharUnits>> static getBaseAlignmentAndOffsetFromLValue(const Expr *E,
-                                                           ASTContext &Ctx) {
-  E = E->IgnoreParens();
-  switch (E->getStmtClass()) {
-  default:
-    break;
-  case Stmt::CStyleCastExprClass:
-  case Stmt::CXXStaticCastExprClass:
-  case Stmt::ImplicitCastExprClass: {
-    auto *CE = cast<CastExpr>(E);
-    const Expr *From = CE->getSubExpr();
-    switch (CE->getCastKind()) {
-    default:
-      break;
-    case CK_NoOp:
-      return getBaseAlignmentAndOffsetFromLValue(From, Ctx);
-    case CK_UncheckedDerivedToBase:
-    case CK_DerivedToBase: {
-      auto P = getBaseAlignmentAndOffsetFromLValue(From, Ctx);
-      if (!P)
-        break;
-      return getDerivedToBaseAlignmentAndOffset(CE, From->getType(), P->first,
-                                                P->second, Ctx);
-    }
-    }
-    break;
-  }
-  case Stmt::ArraySubscriptExprClass: {
-    auto *ASE = cast<ArraySubscriptExpr>(E);
-    return getAlignmentAndOffsetFromBinAddOrSub(ASE->getBase(), ASE->getIdx(),
-                                                false, Ctx);
-  }
-  case Stmt::DeclRefExprClass: {
-    if (auto *VD = dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl())) {
-      // FIXME: If VD is captured by copy or is an escaping __block variable,
-      // use the alignment of VD's type.
-      if (!VD->getType()->isReferenceType()) {
-        // Dependent alignment cannot be resolved -> bail out.
-        if (VD->hasDependentAlignment())
-          break;
-        return std::make_pair(Ctx.getDeclAlign(VD), CharUnits::Zero());
-      }
-      if (VD->hasInit())
-        return getBaseAlignmentAndOffsetFromLValue(VD->getInit(), Ctx);
-    }
-    break;
-  }
-  case Stmt::MemberExprClass: {
-    auto *ME = cast<MemberExpr>(E);
-    auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
-    if (!FD || FD->getType()->isReferenceType() ||
-        FD->getParent()->isInvalidDecl())
-      break;
-    std::optional<std::pair<CharUnits, CharUnits>> P;
-    if (ME->isArrow())
-      P = getBaseAlignmentAndOffsetFromPtr(ME->getBase(), Ctx);
-    else
-      P = getBaseAlignmentAndOffsetFromLValue(ME->getBase(), Ctx);
-    if (!P)
-      break;
-    const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(FD->getParent());
-    uint64_t Offset = Layout.getFieldOffset(FD->getFieldIndex());
-    return std::make_pair(P->first,
-                          P->second + CharUnits::fromQuantity(Offset));
-  }
-  case Stmt::UnaryOperatorClass: {
-    auto *UO = cast<UnaryOperator>(E);
-    switch (UO->getOpcode()) {
-    default:
-      break;
-    case UO_Deref:
-      return getBaseAlignmentAndOffsetFromPtr(UO->getSubExpr(), Ctx);
-    }
-    break;
-  }
-  case Stmt::BinaryOperatorClass: {
-    auto *BO = cast<BinaryOperator>(E);
-    auto Opcode = BO->getOpcode();
-    switch (Opcode) {
-    default:
-      break;
-    case BO_Comma:
-      return getBaseAlignmentAndOffsetFromLValue(BO->getRHS(), Ctx);
-    }
-    break;
-  }
-  }
-  return std::nullopt;
-}
-
-/// This helper function takes a pointer expression and returns the alignment of
-/// a VarDecl and a constant offset from the VarDecl.
-std::optional<std::pair<
-    CharUnits, CharUnits>> static getBaseAlignmentAndOffsetFromPtr(const Expr
-                                                                       *E,
-                                                                   ASTContext
-                                                                       &Ctx) {
-  E = E->IgnoreParens();
-  switch (E->getStmtClass()) {
-  default:
-    break;
-  case Stmt::CStyleCastExprClass:
-  case Stmt::CXXStaticCastExprClass:
-  case Stmt::ImplicitCastExprClass: {
-    auto *CE = cast<CastExpr>(E);
-    const Expr *From = CE->getSubExpr();
-    switch (CE->getCastKind()) {
-    default:
-      break;
-    case CK_NoOp:
-      return getBaseAlignmentAndOffsetFromPtr(From, Ctx);
-    case CK_ArrayToPointerDecay:
-      return getBaseAlignmentAndOffsetFromLValue(From, Ctx);
-    case CK_UncheckedDerivedToBase:
-    case CK_DerivedToBase: {
-      auto P = getBaseAlignmentAndOffsetFromPtr(From, Ctx);
-      if (!P)
-        break;
-      return getDerivedToBaseAlignmentAndOffset(
-          CE, From->getType()->getPointeeType(), P->first, P->second, Ctx);
-    }
-    }
-    break;
-  }
-  case Stmt::CXXThisExprClass: {
-    auto *RD = E->getType()->getPointeeType()->getAsCXXRecordDecl();
-    CharUnits Alignment = Ctx.getASTRecordLayout(RD).getNonVirtualAlignment();
-    return std::make_pair(Alignment, CharUnits::Zero());
-  }
-  case Stmt::UnaryOperatorClass: {
-    auto *UO = cast<UnaryOperator>(E);
-    if (UO->getOpcode() == UO_AddrOf)
-      return getBaseAlignmentAndOffsetFromLValue(UO->getSubExpr(), Ctx);
-    break;
-  }
-  case Stmt::BinaryOperatorClass: {
-    auto *BO = cast<BinaryOperator>(E);
-    auto Opcode = BO->getOpcode();
-    switch (Opcode) {
-    default:
-      break;
-    case BO_Add:
-    case BO_Sub: {
-      const Expr *LHS = BO->getLHS(), *RHS = BO->getRHS();
-      if (Opcode == BO_Add && !RHS->getType()->isIntegralOrEnumerationType())
-        std::swap(LHS, RHS);
-      return getAlignmentAndOffsetFromBinAddOrSub(LHS, RHS, Opcode == BO_Sub,
-                                                  Ctx);
-    }
-    case BO_Comma:
-      return getBaseAlignmentAndOffsetFromPtr(BO->getRHS(), Ctx);
-    }
-    break;
-  }
-  }
-  return std::nullopt;
-}
-
-static CharUnits getPresumedAlignmentOfPointer(const Expr *E, Sema &S) {
-  // See if we can compute the alignment of a VarDecl and an offset from it.
-  std::optional<std::pair<CharUnits, CharUnits>> P =
-      getBaseAlignmentAndOffsetFromPtr(E, S.Context);
-
-  if (P)
-    return P->first.alignmentAtOffset(P->second);
-
-  // If that failed, return the type's alignment.
-  return S.Context.getTypeAlignInChars(E->getType()->getPointeeType());
-}
-
-void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) {
-  // This is actually a lot of work to potentially be doing on every
-  // cast; don't do it if we're ignoring -Wcast_align (as is the default).
-  if (getDiagnostics().isIgnored(diag::warn_cast_align, TRange.getBegin()))
-    return;
-
-  // Ignore dependent types.
-  if (T->isDependentType() || Op->getType()->isDependentType())
-    return;
-
-  // Require that the destination be a pointer type.
-  const PointerType *DestPtr = T->getAs<PointerType>();
-  if (!DestPtr) return;
-
-  // If the destination has alignment 1, we're done.
-  QualType DestPointee = DestPtr->getPointeeType();
-  if (DestPointee->isIncompleteType()) return;
-  CharUnits DestAlign = Context.getTypeAlignInChars(DestPointee);
-  if (DestAlign.isOne()) return;
-
-  // Require that the source be a pointer type.
-  const PointerType *SrcPtr = Op->getType()->getAs<PointerType>();
-  if (!SrcPtr) return;
-  QualType SrcPointee = SrcPtr->getPointeeType();
-
-  // Explicitly allow casts from cv void*.  We already implicitly
-  // allowed casts to cv void*, since they have alignment 1.
-  // Also allow casts involving incomplete types, which implicitly
-  // includes 'void'.
-  if (SrcPointee->isIncompleteType()) return;
-
-  CharUnits SrcAlign = getPresumedAlignmentOfPointer(Op, *this);
-
-  if (SrcAlign >= DestAlign) return;
-
-  Diag(TRange.getBegin(), diag::warn_cast_align)
-    << Op->getType() << T
-    << static_cast<unsigned>(SrcAlign.getQuantity())
-    << static_cast<unsigned>(DestAlign.getQuantity())
-    << TRange << Op->getSourceRange();
-}
-
-void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
-                            const ArraySubscriptExpr *ASE,
-                            bool AllowOnePastEnd, bool IndexNegated) {
-  // Already diagnosed by the constant evaluator.
-  if (isConstantEvaluatedContext())
-    return;
-
-  IndexExpr = IndexExpr->IgnoreParenImpCasts();
-  if (IndexExpr->isValueDependent())
-    return;
-
-  const Type *EffectiveType =
-      BaseExpr->getType()->getPointeeOrArrayElementType();
-  BaseExpr = BaseExpr->IgnoreParenCasts();
-  const ConstantArrayType *ArrayTy =
-      Context.getAsConstantArrayType(BaseExpr->getType());
-
-  LangOptions::StrictFlexArraysLevelKind
-    StrictFlexArraysLevel = getLangOpts().getStrictFlexArraysLevel();
-
-  const Type *BaseType =
-      ArrayTy == nullptr ? nullptr : ArrayTy->getElementType().getTypePtr();
-  bool IsUnboundedArray =
-      BaseType == nullptr || BaseExpr->isFlexibleArrayMemberLike(
-                                 Context, StrictFlexArraysLevel,
-                                 /*IgnoreTemplateOrMacroSubstitution=*/true);
-  if (EffectiveType->isDependentType() ||
-      (!IsUnboundedArray && BaseType->isDependentType()))
-    return;
-
-  Expr::EvalResult Result;
-  if (!IndexExpr->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects))
-    return;
-
-  llvm::APSInt index = Result.Val.getInt();
-  if (IndexNegated) {
-    index.setIsUnsigned(false);
-    index = -index;
-  }
-
-  if (IsUnboundedArray) {
-    if (EffectiveType->isFunctionType())
-      return;
-    if (index.isUnsigned() || !index.isNegative()) {
-      const auto &ASTC = getASTContext();
-      unsigned AddrBits = ASTC.getTargetInfo().getPointerWidth(
-          EffectiveType->getCanonicalTypeInternal().getAddressSpace());
-      if (index.getBitWidth() < AddrBits)
-        index = index.zext(AddrBits);
-      std::optional<CharUnits> ElemCharUnits =
-          ASTC.getTypeSizeInCharsIfKnown(EffectiveType);
-      // PR50741 - If EffectiveType has unknown size (e.g., if it's a void
-      // pointer) bounds-checking isn't meaningful.
-      if (!ElemCharUnits || ElemCharUnits->isZero())
-        return;
-      llvm::APInt ElemBytes(index.getBitWidth(), ElemCharUnits->getQuantity());
-      // If index has more active bits than address space, we already know
-      // we have a bounds violation to warn about.  Otherwise, compute
-      // address of (index + 1)th element, and warn about bounds violation
-      // only if that address exceeds address space.
-      if (index.getActiveBits() <= AddrBits) {
-        bool Overflow;
-        llvm::APInt Product(index);
-        Product += 1;
-        Product = Product.umul_ov(ElemBytes, Overflow);
-        if (!Overflow && Product.getActiveBits() <= AddrBits)
-          return;
-      }
-
-      // Need to compute max possible elements in address space, since that
-      // is included in diag message.
-      llvm::APInt MaxElems = llvm::APInt::getMaxValue(AddrBits);
-      MaxElems = MaxElems.zext(std::max(AddrBits + 1, ElemBytes.getBitWidth()));
-      MaxElems += 1;
-      ElemBytes = ElemBytes.zextOrTrunc(MaxElems.getBitWidth());
-      MaxElems = MaxElems.udiv(ElemBytes);
-
-      unsigned DiagID =
-          ASE ? diag::warn_array_index_exceeds_max_addressable_bounds
-              : diag::warn_ptr_arith_exceeds_max_addressable_bounds;
-
-      // Diag message shows element size in bits and in "bytes" (platform-
-      // dependent CharUnits)
-      DiagRuntimeBehavior(BaseExpr->getBeginLoc(), BaseExpr,
-                          PDiag(DiagID) << index << AddrBits
-                                        << (unsigned)ASTC.toBits(*ElemCharUnits)
-                                        << ElemBytes << MaxElems
-                                        << MaxElems.getZExtValue()
-                                        << IndexExpr->getSourceRange());
-
-      const NamedDecl *ND = nullptr;
-      // Try harder to find a NamedDecl to point at in the note.
-      while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr))
-        BaseExpr = ASE->getBase()->IgnoreParenCasts();
-      if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
-        ND = DRE->getDecl();
-      if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr))
-        ND = ME->getMemberDecl();
-
-      if (ND)
-        DiagRuntimeBehavior(ND->getBeginLoc(), BaseExpr,
-                            PDiag(diag::note_array_declared_here) << ND);
-    }
-    return;
-  }
-
-  if (index.isUnsigned() || !index.isNegative()) {
-    // It is possible that the type of the base expression after
-    // IgnoreParenCasts is incomplete, even though the type of the base
-    // expression before IgnoreParenCasts is complete (see PR39746 for an
-    // example). In this case we have no information about whether the array
-    // access exceeds the array bounds. However we can still diagnose an array
-    // access which precedes the array bounds.
-    if (BaseType->isIncompleteType())
-      return;
-
-    llvm::APInt size = ArrayTy->getSize();
-
-    if (BaseType != EffectiveType) {
-      // Make sure we're comparing apples to apples when comparing index to
-      // size.
-      uint64_t ptrarith_typesize = Context.getTypeSize(EffectiveType);
-      uint64_t array_typesize = Context.getTypeSize(BaseType);
-
-      // Handle ptrarith_typesize being zero, such as when casting to void*.
-      // Use the size in bits (what "getTypeSize()" returns) rather than bytes.
-      if (!ptrarith_typesize)
-        ptrarith_typesize = Context.getCharWidth();
-
-      if (ptrarith_typesize != array_typesize) {
-        // There's a cast to a different size type involved.
-        uint64_t ratio = array_typesize / ptrarith_typesize;
-
-        // TODO: Be smarter about handling cases where array_typesize is not a
-        // multiple of ptrarith_typesize.
-        if (ptrarith_typesize * ratio == array_typesize)
-          size *= llvm::APInt(size.getBitWidth(), ratio);
-      }
-    }
-
-    if (size.getBitWidth() > index.getBitWidth())
-      index = index.zext(size.getBitWidth());
-    else if (size.getBitWidth() < index.getBitWidth())
-      size = size.zext(index.getBitWidth());
-
-    // For array subscripting the index must be less than size, but for pointer
-    // arithmetic also allow the index (offset) to be equal to size since
-    // computing the next address after the end of the array is legal and
-    // commonly done e.g. in C++ iterators and range-based for loops.
-    if (AllowOnePastEnd ? index.ule(size) : index.ult(size))
-      return;
-
-    // Suppress the warning if the subscript expression (as identified by the
-    // ']' location) and the index expression are both from macro expansions
-    // within a system header.
-    if (ASE) {
-      SourceLocation RBracketLoc = SourceMgr.getSpellingLoc(
-          ASE->getRBracketLoc());
-      if (SourceMgr.isInSystemHeader(RBracketLoc)) {
-        SourceLocation IndexLoc =
-            SourceMgr.getSpellingLoc(IndexExpr->getBeginLoc());
-        if (SourceMgr.isWrittenInSameFile(RBracketLoc, IndexLoc))
-          return;
-      }
-    }
-
-    unsigned DiagID = ASE ? diag::warn_array_index_exceeds_bounds
-                          : diag::warn_ptr_arith_exceeds_bounds;
-    unsigned CastMsg = (!ASE || BaseType == EffectiveType) ? 0 : 1;
-    QualType CastMsgTy = ASE ? ASE->getLHS()->getType() : QualType();
-
-    DiagRuntimeBehavior(BaseExpr->getBeginLoc(), BaseExpr,
-                        PDiag(DiagID)
-                            << index << ArrayTy->desugar() << CastMsg
-                            << CastMsgTy << IndexExpr->getSourceRange());
-  } else {
-    unsigned DiagID = diag::warn_array_index_precedes_bounds;
-    if (!ASE) {
-      DiagID = diag::warn_ptr_arith_precedes_bounds;
-      if (index.isNegative()) index = -index;
-    }
-
-    DiagRuntimeBehavior(BaseExpr->getBeginLoc(), BaseExpr,
-                        PDiag(DiagID) << index << IndexExpr->getSourceRange());
-  }
-
-  const NamedDecl *ND = nullptr;
-  // Try harder to find a NamedDecl to point at in the note.
-  while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr))
-    BaseExpr = ASE->getBase()->IgnoreParenCasts();
-  if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
-    ND = DRE->getDecl();
-  if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr))
-    ND = ME->getMemberDecl();
-
-  if (ND)
-    DiagRuntimeBehavior(ND->getBeginLoc(), BaseExpr,
-                        PDiag(diag::note_array_declared_here) << ND);
-}
-
-void Sema::CheckArrayAccess(const Expr *expr) {
-  int AllowOnePastEnd = 0;
-  while (expr) {
-    expr = expr->IgnoreParenImpCasts();
-    switch (expr->getStmtClass()) {
-      case Stmt::ArraySubscriptExprClass: {
-        const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(expr);
-        CheckArrayAccess(ASE->getBase(), ASE->getIdx(), ASE,
-                         AllowOnePastEnd > 0);
-        expr = ASE->getBase();
-        break;
-      }
-      case Stmt::MemberExprClass: {
-        expr = cast<MemberExpr>(expr)->getBase();
-        break;
-      }
-      case Stmt::CXXMemberCallExprClass: {
-        expr = cast<CXXMemberCallExpr>(expr)->getImplicitObjectArgument();
-        break;
-      }
-      case Stmt::ArraySectionExprClass: {
-        const ArraySectionExpr *ASE = cast<ArraySectionExpr>(expr);
-        // FIXME: We should probably be checking all of the elements to the
-        // 'length' here as well.
-        if (ASE->getLowerBound())
-          CheckArrayAccess(ASE->getBase(), ASE->getLowerBound(),
-                           /*ASE=*/nullptr, AllowOnePastEnd > 0);
-        return;
-      }
-      case Stmt::UnaryOperatorClass: {
-        // Only unwrap the * and & unary operators
-        const UnaryOperator *UO = cast<UnaryOperator>(expr);
-        expr = UO->getSubExpr();
-        switch (UO->getOpcode()) {
-          case UO_AddrOf:
-            AllowOnePastEnd++;
-            break;
-          case UO_Deref:
-            AllowOnePastEnd--;
-            break;
-          default:
-            return;
-        }
-        break;
-      }
-      case Stmt::ConditionalOperatorClass: {
-        const ConditionalOperator *cond = cast<ConditionalOperator>(expr);
-        if (const Expr *lhs = cond->getLHS())
-          CheckArrayAccess(lhs);
-        if (const Expr *rhs = cond->getRHS())
-          CheckArrayAccess(rhs);
-        return;
-      }
-      case Stmt::CXXOperatorCallExprClass: {
-        const auto *OCE = cast<CXXOperatorCallExpr>(expr);
-        for (const auto *Arg : OCE->arguments())
-          CheckArrayAccess(Arg);
-        return;
-      }
-      default:
-        return;
-    }
-  }
-}
-
-static bool checkUnsafeAssignLiteral(Sema &S, SourceLocation Loc,
-                                     Expr *RHS, bool isProperty) {
-  // Check if RHS is an Objective-C object literal, which also can get
-  // immediately zapped in a weak reference.  Note that we explicitly
-  // allow ObjCStringLiterals, since those are designed to never really die.
-  RHS = RHS->IgnoreParenImpCasts();
-
-  // This enum needs to match with the 'select' in
-  // warn_objc_arc_literal_assign (off-by-1).
-  SemaObjC::ObjCLiteralKind Kind = S.ObjC().CheckLiteralKind(RHS);
-  if (Kind == SemaObjC::LK_String || Kind == SemaObjC::LK_None)
-    return false;
-
-  S.Diag(Loc, diag::warn_arc_literal_assign)
-    << (unsigned) Kind
-    << (isProperty ? 0 : 1)
-    << RHS->getSourceRange();
-
-  return true;
-}
-
-static bool checkUnsafeAssignObject(Sema &S, SourceLocation Loc,
-                                    Qualifiers::ObjCLifetime LT,
-                                    Expr *RHS, bool isProperty) {
-  // Strip off any implicit cast added to get to the one ARC-specific.
-  while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
-    if (cast->getCastKind() == CK_ARCConsumeObject) {
-      S.Diag(Loc, diag::warn_arc_retained_assign)
-        << (LT == Qualifiers::OCL_ExplicitNone)
-        << (isProperty ? 0 : 1)
-        << RHS->getSourceRange();
-      return true;
-    }
-    RHS = cast->getSubExpr();
-  }
-
-  if (LT == Qualifiers::OCL_Weak &&
-      checkUnsafeAssignLiteral(S, Loc, RHS, isProperty))
-    return true;
-
-  return false;
-}
-
-bool Sema::checkUnsafeAssigns(SourceLocation Loc,
-                              QualType LHS, Expr *RHS) {
-  Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime();
-
-  if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone)
-    return false;
-
-  if (checkUnsafeAssignObject(*this, Loc, LT, RHS, false))
-    return true;
-
-  return false;
-}
-
-void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
-                              Expr *LHS, Expr *RHS) {
-  QualType LHSType;
-  // PropertyRef on LHS type need be directly obtained from
-  // its declaration as it has a PseudoType.
-  ObjCPropertyRefExpr *PRE
-    = dyn_cast<ObjCPropertyRefExpr>(LHS->IgnoreParens());
-  if (PRE && !PRE->isImplicitProperty()) {
-    const ObjCPropertyDecl *PD = PRE->getExplicitProperty();
-    if (PD)
-      LHSType = PD->getType();
-  }
-
-  if (LHSType.isNull())
-    LHSType = LHS->getType();
-
-  Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime();
-
-  if (LT == Qualifiers::OCL_Weak) {
-    if (!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc))
-      getCurFunction()->markSafeWeakUse(LHS);
-  }
-
-  if (checkUnsafeAssigns(Loc, LHSType, RHS))
-    return;
-
-  // FIXME. Check for other life times.
-  if (LT != Qualifiers::OCL_None)
-    return;
-
-  if (PRE) {
-    if (PRE->isImplicitProperty())
-      return;
-    const ObjCPropertyDecl *PD = PRE->getExplicitProperty();
-    if (!PD)
-      return;
-
-    unsigned Attributes = PD->getPropertyAttributes();
-    if (Attributes & ObjCPropertyAttribute::kind_assign) {
-      // when 'assign' attribute was not explicitly specified
-      // by user, ignore it and rely on property type itself
-      // for lifetime info.
-      unsigned AsWrittenAttr = PD->getPropertyAttributesAsWritten();
-      if (!(AsWrittenAttr & ObjCPropertyAttribute::kind_assign) &&
-          LHSType->isObjCRetainableType())
-        return;
-
-      while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
-        if (cast->getCastKind() == CK_ARCConsumeObject) {
-          Diag(Loc, diag::warn_arc_retained_property_assign)
-          << RHS->getSourceRange();
-          return;
-        }
-        RHS = cast->getSubExpr();
-      }
-    } else if (Attributes & ObjCPropertyAttribute::kind_weak) {
-      if (checkUnsafeAssignObject(*this, Loc, Qualifiers::OCL_Weak, RHS, true))
-        return;
-    }
-  }
-}
-
-//===--- CHECK: Empty statement body (-Wempty-body) ---------------------===//
-
-static bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr,
-                                        SourceLocation StmtLoc,
-                                        const NullStmt *Body) {
-  // Do not warn if the body is a macro that expands to nothing, e.g:
-  //
-  // #define CALL(x)
-  // if (condition)
-  //   CALL(0);
-  if (Body->hasLeadingEmptyMacro())
-    return false;
-
-  // Get line numbers of statement and body.
-  bool StmtLineInvalid;
-  unsigned StmtLine = SourceMgr.getPresumedLineNumber(StmtLoc,
-                                                      &StmtLineInvalid);
-  if (StmtLineInvalid)
-    return false;
-
-  bool BodyLineInvalid;
-  unsigned BodyLine = SourceMgr.getSpellingLineNumber(Body->getSemiLoc(),
-                                                      &BodyLineInvalid);
-  if (BodyLineInvalid)
-    return false;
-
-  // Warn if null statement and body are on the same line.
-  if (StmtLine != BodyLine)
-    return false;
-
-  return true;
-}
-
-void Sema::DiagnoseEmptyStmtBody(SourceLocation StmtLoc,
-                                 const Stmt *Body,
-                                 unsigned DiagID) {
-  // Since this is a syntactic check, don't emit diagnostic for template
-  // instantiations, this just adds noise.
-  if (CurrentInstantiationScope)
-    return;
-
-  // The body should be a null statement.
-  const NullStmt *NBody = dyn_cast<NullStmt>(Body);
-  if (!NBody)
-    return;
-
-  // Do the usual checks.
-  if (!ShouldDiagnoseEmptyStmtBody(SourceMgr, StmtLoc, NBody))
-    return;
-
-  Diag(NBody->getSemiLoc(), DiagID);
-  Diag(NBody->getSemiLoc(), diag::note_empty_body_on_separate_line);
-}
-
-void Sema::DiagnoseEmptyLoopBody(const Stmt *S,
-                                 const Stmt *PossibleBody) {
-  assert(!CurrentInstantiationScope); // Ensured by caller
-
-  SourceLocation StmtLoc;
-  const Stmt *Body;
-  unsigned DiagID;
-  if (const ForStmt *FS = dyn_cast<ForStmt>(S)) {
-    StmtLoc = FS->getRParenLoc();
-    Body = FS->getBody();
-    DiagID = diag::warn_empty_for_body;
-  } else if (const WhileStmt *WS = dyn_cast<WhileStmt>(S)) {
-    StmtLoc = WS->getRParenLoc();
-    Body = WS->getBody();
-    DiagID = diag::warn_empty_while_body;
-  } else
-    return; // Neither `for' nor `while'.
-
-  // The body should be a null statement.
-  const NullStmt *NBody = dyn_cast<NullStmt>(Body);
-  if (!NBody)
-    return;
-
-  // Skip expensive checks if diagnostic is disabled.
-  if (Diags.isIgnored(DiagID, NBody->getSemiLoc()))
-    return;
-
-  // Do the usual checks.
-  if (!ShouldDiagnoseEmptyStmtBody(SourceMgr, StmtLoc, NBody))
-    return;
-
-  // `for(...);' and `while(...);' are popular idioms, so in order to keep
-  // noise level low, emit diagnostics only if for/while is followed by a
-  // CompoundStmt, e.g.:
-  //    for (int i = 0; i < n; i++);
-  //    {
-  //      a(i);
-  //    }
-  // or if for/while is followed by a statement with more indentation
-  // than for/while itself:
-  //    for (int i = 0; i < n; i++);
-  //      a(i);
-  bool ProbableTypo = isa<CompoundStmt>(PossibleBody);
-  if (!ProbableTypo) {
-    bool BodyColInvalid;
-    unsigned BodyCol = SourceMgr.getPresumedColumnNumber(
-        PossibleBody->getBeginLoc(), &BodyColInvalid);
-    if (BodyColInvalid)
-      return;
-
-    bool StmtColInvalid;
-    unsigned StmtCol =
-        SourceMgr.getPresumedColumnNumber(S->getBeginLoc(), &StmtColInvalid);
-    if (StmtColInvalid)
-      return;
-
-    if (BodyCol > StmtCol)
-      ProbableTypo = true;
-  }
-
-  if (ProbableTypo) {
-    Diag(NBody->getSemiLoc(), DiagID);
-    Diag(NBody->getSemiLoc(), diag::note_empty_body_on_separate_line);
-  }
-}
-
-//===--- CHECK: Warn on self move with std::move. -------------------------===//
-
-void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr,
-                             SourceLocation OpLoc) {
-  if (Diags.isIgnored(diag::warn_sizeof_pointer_expr_memaccess, OpLoc))
-    return;
-
-  if (inTemplateInstantiation())
-    return;
-
-  // Strip parens and casts away.
-  LHSExpr = LHSExpr->IgnoreParenImpCasts();
-  RHSExpr = RHSExpr->IgnoreParenImpCasts();
-
-  // Check for a call to std::move or for a static_cast<T&&>(..) to an xvalue
-  // which we can treat as an inlined std::move
-  if (const auto *CE = dyn_cast<CallExpr>(RHSExpr);
-      CE && CE->getNumArgs() == 1 && CE->isCallToStdMove())
-    RHSExpr = CE->getArg(0);
-  else if (const auto *CXXSCE = dyn_cast<CXXStaticCastExpr>(RHSExpr);
-           CXXSCE && CXXSCE->isXValue())
-    RHSExpr = CXXSCE->getSubExpr();
-  else
-    return;
-
-  const DeclRefExpr *LHSDeclRef = dyn_cast<DeclRefExpr>(LHSExpr);
-  const DeclRefExpr *RHSDeclRef = dyn_cast<DeclRefExpr>(RHSExpr);
-
-  // Two DeclRefExpr's, check that the decls are the same.
-  if (LHSDeclRef && RHSDeclRef) {
-    if (!LHSDeclRef->getDecl() || !RHSDeclRef->getDecl())
-      return;
-    if (LHSDeclRef->getDecl()->getCanonicalDecl() !=
-        RHSDeclRef->getDecl()->getCanonicalDecl())
-      return;
-
-    auto D = Diag(OpLoc, diag::warn_self_move)
-             << LHSExpr->getType() << LHSExpr->getSourceRange()
-             << RHSExpr->getSourceRange();
-    if (const FieldDecl *F =
-            getSelfAssignmentClassMemberCandidate(RHSDeclRef->getDecl()))
-      D << 1 << F
-        << FixItHint::CreateInsertion(LHSDeclRef->getBeginLoc(), "this->");
-    else
-      D << 0;
-    return;
-  }
-
-  // Member variables require a different approach to check for self moves.
-  // MemberExpr's are the same if every nested MemberExpr refers to the same
-  // Decl and that the base Expr's are DeclRefExpr's with the same Decl or
-  // the base Expr's are CXXThisExpr's.
-  const Expr *LHSBase = LHSExpr;
-  const Expr *RHSBase = RHSExpr;
-  const MemberExpr *LHSME = dyn_cast<MemberExpr>(LHSExpr);
-  const MemberExpr *RHSME = dyn_cast<MemberExpr>(RHSExpr);
-  if (!LHSME || !RHSME)
-    return;
-
-  while (LHSME && RHSME) {
-    if (LHSME->getMemberDecl()->getCanonicalDecl() !=
-        RHSME->getMemberDecl()->getCanonicalDecl())
-      return;
-
-    LHSBase = LHSME->getBase();
-    RHSBase = RHSME->getBase();
-    LHSME = dyn_cast<MemberExpr>(LHSBase);
-    RHSME = dyn_cast<MemberExpr>(RHSBase);
-  }
-
-  LHSDeclRef = dyn_cast<DeclRefExpr>(LHSBase);
-  RHSDeclRef = dyn_cast<DeclRefExpr>(RHSBase);
-  if (LHSDeclRef && RHSDeclRef) {
-    if (!LHSDeclRef->getDecl() || !RHSDeclRef->getDecl())
-      return;
-    if (LHSDeclRef->getDecl()->getCanonicalDecl() !=
-        RHSDeclRef->getDecl()->getCanonicalDecl())
-      return;
-
-    Diag(OpLoc, diag::warn_self_move)
-        << LHSExpr->getType() << 0 << LHSExpr->getSourceRange()
-        << RHSExpr->getSourceRange();
-    return;
-  }
-
-  if (isa<CXXThisExpr>(LHSBase) && isa<CXXThisExpr>(RHSBase))
-    Diag(OpLoc, diag::warn_self_move)
-        << LHSExpr->getType() << 0 << LHSExpr->getSourceRange()
-        << RHSExpr->getSourceRange();
-}
-
-//===--- Layout compatibility ----------------------------------------------//
-
-static bool isLayoutCompatible(const ASTContext &C, QualType T1, QualType T2);
-
-/// Check if two enumeration types are layout-compatible.
-static bool isLayoutCompatible(const ASTContext &C, const EnumDecl *ED1,
-                               const EnumDecl *ED2) {
-  // C++11 [dcl.enum] p8:
-  // Two enumeration types are layout-compatible if they have the same
-  // underlying type.
-  return ED1->isComplete() && ED2->isComplete() &&
-         C.hasSameType(ED1->getIntegerType(), ED2->getIntegerType());
-}
-
-/// Check if two fields are layout-compatible.
-/// Can be used on union members, which are exempt from alignment requirement
-/// of common initial sequence.
-static bool isLayoutCompatible(const ASTContext &C, const FieldDecl *Field1,
-                               const FieldDecl *Field2,
-                               bool AreUnionMembers = false) {
-#ifndef NDEBUG
-  CanQualType Field1Parent = C.getCanonicalTagType(Field1->getParent());
-  CanQualType Field2Parent = C.getCanonicalTagType(Field2->getParent());
-  assert(((Field1Parent->isStructureOrClassType() &&
-           Field2Parent->isStructureOrClassType()) ||
-          (Field1Parent->isUnionType() && Field2Parent->isUnionType())) &&
-         "Can't evaluate layout compatibility between a struct field and a "
-         "union field.");
-  assert(((!AreUnionMembers && Field1Parent->isStructureOrClassType()) ||
-          (AreUnionMembers && Field1Parent->isUnionType())) &&
-         "AreUnionMembers should be 'true' for union fields (only).");
-#endif
-
-  if (!isLayoutCompatible(C, Field1->getType(), Field2->getType()))
-    return false;
-
-  if (Field1->isBitField() != Field2->isBitField())
-    return false;
-
-  if (Field1->isBitField()) {
-    // Make sure that the bit-fields are the same length.
-    unsigned Bits1 = Field1->getBitWidthValue();
-    unsigned Bits2 = Field2->getBitWidthValue();
-
-    if (Bits1 != Bits2)
-      return false;
-  }
-
-  if (Field1->hasAttr<clang::NoUniqueAddressAttr>() ||
-      Field2->hasAttr<clang::NoUniqueAddressAttr>())
-    return false;
-
-  if (!AreUnionMembers &&
-      Field1->getMaxAlignment() != Field2->getMaxAlignment())
-    return false;
-
-  return true;
-}
-
-/// Check if two standard-layout structs are layout-compatible.
-/// (C++11 [class.mem] p17)
-static bool isLayoutCompatibleStruct(const ASTContext &C, const RecordDecl *RD1,
-                                     const RecordDecl *RD2) {
-  // Get to the class where the fields are declared
-  if (const CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(RD1))
-    RD1 = D1CXX->getStandardLayoutBaseWithFields();
-
-  if (const CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(RD2))
-    RD2 = D2CXX->getStandardLayoutBaseWithFields();
-
-  // Check the fields.
-  return llvm::equal(RD1->fields(), RD2->fields(),
-                     [&C](const FieldDecl *F1, const FieldDecl *F2) -> bool {
-                       return isLayoutCompatible(C, F1, F2);
-                     });
-}
-
-/// Check if two standard-layout unions are layout-compatible.
-/// (C++11 [class.mem] p18)
-static bool isLayoutCompatibleUnion(const ASTContext &C, const RecordDecl *RD1,
-                                    const RecordDecl *RD2) {
-  llvm::SmallPtrSet<const FieldDecl *, 8> UnmatchedFields(llvm::from_range,
-                                                          RD2->fields());
-
-  for (auto *Field1 : RD1->fields()) {
-    auto I = UnmatchedFields.begin();
-    auto E = UnmatchedFields.end();
-
-    for ( ; I != E; ++I) {
-      if (isLayoutCompatible(C, Field1, *I, /*IsUnionMember=*/true)) {
-        bool Result = UnmatchedFields.erase(*I);
-        (void) Result;
-        assert(Result);
-        break;
-      }
-    }
-    if (I == E)
-      return false;
-  }
-
-  return UnmatchedFields.empty();
-}
-
-static bool isLayoutCompatible(const ASTContext &C, const RecordDecl *RD1,
-                               const RecordDecl *RD2) {
-  if (RD1->isUnion() != RD2->isUnion())
-    return false;
-
-  if (RD1->isUnion())
-    return isLayoutCompatibleUnion(C, RD1, RD2);
-  else
-    return isLayoutCompatibleStruct(C, RD1, RD2);
-}
-
-/// Check if two types are layout-compatible in C++11 sense.
-static bool isLayoutCompatible(const ASTContext &C, QualType T1, QualType T2) {
-  if (T1.isNull() || T2.isNull())
-    return false;
-
-  // C++20 [basic.types] p11:
-  // Two types cv1 T1 and cv2 T2 are layout-compatible types
-  // if T1 and T2 are the same type, layout-compatible enumerations (9.7.1),
-  // or layout-compatible standard-layout class types (11.4).
-  T1 = T1.getCanonicalType().getUnqualifiedType();
-  T2 = T2.getCanonicalType().getUnqualifiedType();
-
-  if (C.hasSameType(T1, T2))
-    return true;
-
-  const Type::TypeClass TC1 = T1->getTypeClass();
-  const Type::TypeClass TC2 = T2->getTypeClass();
-
-  if (TC1 != TC2)
-    return false;
-
-  if (TC1 == Type::Enum)
-    return isLayoutCompatible(C, T1->castAsEnumDecl(), T2->castAsEnumDecl());
-  if (TC1 == Type::Record) {
-    if (!T1->isStandardLayoutType() || !T2->isStandardLayoutType())
-      return false;
-
-    return isLayoutCompatible(C, T1->castAsRecordDecl(),
-                              T2->castAsRecordDecl());
-  }
-
-  return false;
-}
-
-bool Sema::IsLayoutCompatible(QualType T1, QualType T2) const {
-  return isLayoutCompatible(getASTContext(), T1, T2);
-}
-
-//===-------------- Pointer interconvertibility ----------------------------//
-
-bool Sema::IsPointerInterconvertibleBaseOf(const TypeSourceInfo *Base,
-                                           const TypeSourceInfo *Derived) {
-  QualType BaseT = Base->getType()->getCanonicalTypeUnqualified();
-  QualType DerivedT = Derived->getType()->getCanonicalTypeUnqualified();
-
-  if (BaseT->isStructureOrClassType() && DerivedT->isStructureOrClassType() &&
-      getASTContext().hasSameType(BaseT, DerivedT))
-    return true;
-
-  if (!IsDerivedFrom(Derived->getTypeLoc().getBeginLoc(), DerivedT, BaseT))
-    return false;
-
-  // Per [basic.compound]/4.3, containing object has to be standard-layout.
-  if (DerivedT->getAsCXXRecordDecl()->isStandardLayout())
-    return true;
-
-  return false;
-}
-
-//===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----//
-
-/// Given a type tag expression find the type tag itself.
-///
-/// \param TypeExpr Type tag expression, as it appears in user's code.
-///
-/// \param VD Declaration of an identifier that appears in a type tag.
-///
-/// \param MagicValue Type tag magic value.
-///
-/// \param isConstantEvaluated whether the evalaution should be performed in
-
-/// constant context.
-static bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx,
-                            const ValueDecl **VD, uint64_t *MagicValue,
-                            bool isConstantEvaluated) {
-  while(true) {
-    if (!TypeExpr)
-      return false;
-
-    TypeExpr = TypeExpr->IgnoreParenImpCasts()->IgnoreParenCasts();
-
-    switch (TypeExpr->getStmtClass()) {
-    case Stmt::UnaryOperatorClass: {
-      const UnaryOperator *UO = cast<UnaryOperator>(TypeExpr);
-      if (UO->getOpcode() == UO_AddrOf || UO->getOpcode() == UO_Deref) {
-        TypeExpr = UO->getSubExpr();
-        continue;
-      }
-      return false;
-    }
-
-    case Stmt::DeclRefExprClass: {
-      const DeclRefExpr *DRE = cast<DeclRefExpr>(TypeExpr);
-      *VD = DRE->getDecl();
-      return true;
-    }
-
-    case Stmt::IntegerLiteralClass: {
-      const IntegerLiteral *IL = cast<IntegerLiteral>(TypeExpr);
-      llvm::APInt MagicValueAPInt = IL->getValue();
-      if (MagicValueAPInt.getActiveBits() <= 64) {
-        *MagicValue = MagicValueAPInt.getZExtValue();
-        return true;
-      } else
-        return false;
-    }
-
-    case Stmt::BinaryConditionalOperatorClass:
-    case Stmt::ConditionalOperatorClass: {
-      const AbstractConditionalOperator *ACO =
-          cast<AbstractConditionalOperator>(TypeExpr);
-      bool Result;
-      if (ACO->getCond()->EvaluateAsBooleanCondition(Result, Ctx,
-                                                     isConstantEvaluated)) {
-        if (Result)
-          TypeExpr = ACO->getTrueExpr();
-        else
-          TypeExpr = ACO->getFalseExpr();
-        continue;
-      }
-      return false;
-    }
-
-    case Stmt::BinaryOperatorClass: {
-      const BinaryOperator *BO = cast<BinaryOperator>(TypeExpr);
-      if (BO->getOpcode() == BO_Comma) {
-        TypeExpr = BO->getRHS();
-        continue;
-      }
-      return false;
-    }
-
-    default:
-      return false;
-    }
-  }
-}
-
-/// Retrieve the C type corresponding to type tag TypeExpr.
-///
-/// \param TypeExpr Expression that specifies a type tag.
-///
-/// \param MagicValues Registered magic values.
-///
-/// \param FoundWrongKind Set to true if a type tag was found, but of a wrong
-///        kind.
-///
-/// \param TypeInfo Information about the corresponding C type.
-///
-/// \param isConstantEvaluated whether the evalaution should be performed in
-/// constant context.
-///
-/// \returns true if the corresponding C type was found.
-static bool GetMatchingCType(
-    const IdentifierInfo *ArgumentKind, const Expr *TypeExpr,
-    const ASTContext &Ctx,
-    const llvm::DenseMap<Sema::TypeTagMagicValue, Sema::TypeTagData>
-        *MagicValues,
-    bool &FoundWrongKind, Sema::TypeTagData &TypeInfo,
-    bool isConstantEvaluated) {
-  FoundWrongKind = false;
-
-  // Variable declaration that has type_tag_for_datatype attribute.
-  const ValueDecl *VD = nullptr;
-
-  uint64_t MagicValue;
-
-  if (!FindTypeTagExpr(TypeExpr, Ctx, &VD, &MagicValue, isConstantEvaluated))
-    return false;
-
-  if (VD) {
-    if (TypeTagForDatatypeAttr *I = VD->getAttr<TypeTagForDatatypeAttr>()) {
-      if (I->getArgumentKind() != ArgumentKind) {
-        FoundWrongKind = true;
-        return false;
-      }
-      TypeInfo.Type = I->getMatchingCType();
-      TypeInfo.LayoutCompatible = I->getLayoutCompatible();
-      TypeInfo.MustBeNull = I->getMustBeNull();
-      return true;
-    }
-    return false;
-  }
-
-  if (!MagicValues)
-    return false;
-
-  llvm::DenseMap<Sema::TypeTagMagicValue,
-                 Sema::TypeTagData>::const_iterator I =
-      MagicValues->find(std::make_pair(ArgumentKind, MagicValue));
-  if (I == MagicValues->end())
-    return false;
-
-  TypeInfo = I->second;
-  return true;
-}
-
-void Sema::RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind,
-                                      uint64_t MagicValue, QualType Type,
-                                      bool LayoutCompatible,
-                                      bool MustBeNull) {
-  if (!TypeTagForDatatypeMagicValues)
-    TypeTagForDatatypeMagicValues.reset(
-        new llvm::DenseMap<TypeTagMagicValue, TypeTagData>);
-
-  TypeTagMagicValue Magic(ArgumentKind, MagicValue);
-  (*TypeTagForDatatypeMagicValues)[Magic] =
-      TypeTagData(Type, LayoutCompatible, MustBeNull);
-}
-
-static bool IsSameCharType(QualType T1, QualType T2) {
-  const BuiltinType *BT1 = T1->getAs<BuiltinType>();
-  if (!BT1)
-    return false;
-
-  const BuiltinType *BT2 = T2->getAs<BuiltinType>();
-  if (!BT2)
-    return false;
-
-  BuiltinType::Kind T1Kind = BT1->getKind();
-  BuiltinType::Kind T2Kind = BT2->getKind();
-
-  return (T1Kind == BuiltinType::SChar  && T2Kind == BuiltinType::Char_S) ||
-         (T1Kind == BuiltinType::UChar  && T2Kind == BuiltinType::Char_U) ||
-         (T1Kind == BuiltinType::Char_U && T2Kind == BuiltinType::UChar) ||
-         (T1Kind == BuiltinType::Char_S && T2Kind == BuiltinType::SChar);
-}
-
-void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
-                                    const ArrayRef<const Expr *> ExprArgs,
-                                    SourceLocation CallSiteLoc) {
-  const IdentifierInfo *ArgumentKind = Attr->getArgumentKind();
-  bool IsPointerAttr = Attr->getIsPointer();
-
-  // Retrieve the argument representing the 'type_tag'.
-  unsigned TypeTagIdxAST = Attr->getTypeTagIdx().getASTIndex();
-  if (TypeTagIdxAST >= ExprArgs.size()) {
-    Diag(CallSiteLoc, diag::err_tag_index_out_of_range)
-        << 0 << Attr->getTypeTagIdx().getSourceIndex();
-    return;
-  }
-  const Expr *TypeTagExpr = ExprArgs[TypeTagIdxAST];
-  bool FoundWrongKind;
-  TypeTagData TypeInfo;
-  if (!GetMatchingCType(ArgumentKind, TypeTagExpr, Context,
-                        TypeTagForDatatypeMagicValues.get(), FoundWrongKind,
-                        TypeInfo, isConstantEvaluatedContext())) {
-    if (FoundWrongKind)
-      Diag(TypeTagExpr->getExprLoc(),
-           diag::warn_type_tag_for_datatype_wrong_kind)
-        << TypeTagExpr->getSourceRange();
-    return;
-  }
-
-  // Retrieve the argument representing the 'arg_idx'.
-  unsigned ArgumentIdxAST = Attr->getArgumentIdx().getASTIndex();
-  if (ArgumentIdxAST >= ExprArgs.size()) {
-    Diag(CallSiteLoc, diag::err_tag_index_out_of_range)
-        << 1 << Attr->getArgumentIdx().getSourceIndex();
-    return;
-  }
-  const Expr *ArgumentExpr = ExprArgs[ArgumentIdxAST];
-  if (IsPointerAttr) {
-    // Skip implicit cast of pointer to `void *' (as a function argument).
-    if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgumentExpr))
-      if (ICE->getType()->isVoidPointerType() &&
-          ICE->getCastKind() == CK_BitCast)
-        ArgumentExpr = ICE->getSubExpr();
-  }
-  QualType ArgumentType = ArgumentExpr->getType();
-
-  // Passing a `void*' pointer shouldn't trigger a warning.
-  if (IsPointerAttr && ArgumentType->isVoidPointerType())
-    return;
-
-  if (TypeInfo.MustBeNull) {
-    // Type tag with matching void type requires a null pointer.
-    if (!ArgumentExpr->isNullPointerConstant(Context,
-                                             Expr::NPC_ValueDependentIsNotNull)) {
-      Diag(ArgumentExpr->getExprLoc(),
-           diag::warn_type_safety_null_pointer_required)
-          << ArgumentKind->getName()
-          << ArgumentExpr->getSourceRange()
-          << TypeTagExpr->getSourceRange();
-    }
-    return;
-  }
-
-  QualType RequiredType = TypeInfo.Type;
-  if (IsPointerAttr)
-    RequiredType = Context.getPointerType(RequiredType);
-
-  bool mismatch = false;
-  if (!TypeInfo.LayoutCompatible) {
-    mismatch = !Context.hasSameType(ArgumentType, RequiredType);
-
-    // C++11 [basic.fundamental] p1:
-    // Plain char, signed char, and unsigned char are three distinct types.
-    //
-    // But we treat plain `char' as equivalent to `signed char' or `unsigned
-    // char' depending on the current char signedness mode.
-    if (mismatch)
-      if ((IsPointerAttr && IsSameCharType(ArgumentType->getPointeeType(),
-                                           RequiredType->getPointeeType())) ||
-          (!IsPointerAttr && IsSameCharType(ArgumentType, RequiredType)))
-        mismatch = false;
-  } else
-    if (IsPointerAttr)
-      mismatch = !isLayoutCompatible(Context,
-                                     ArgumentType->getPointeeType(),
-                                     RequiredType->getPointeeType());
-    else
-      mismatch = !isLayoutCompatible(Context, ArgumentType, RequiredType);
-
-  if (mismatch)
-    Diag(ArgumentExpr->getExprLoc(), diag::warn_type_safety_type_mismatch)
-        << ArgumentType << ArgumentKind
-        << TypeInfo.LayoutCompatible << RequiredType
-        << ArgumentExpr->getSourceRange()
-        << TypeTagExpr->getSourceRange();
-}
-
-void Sema::AddPotentialMisalignedMembers(Expr *E, RecordDecl *RD, ValueDecl *MD,
-                                         CharUnits Alignment) {
-  currentEvaluationContext().MisalignedMembers.emplace_back(E, RD, MD,
-                                                            Alignment);
-}
-
-void Sema::DiagnoseMisalignedMembers() {
-  for (MisalignedMember &m : currentEvaluationContext().MisalignedMembers) {
-    const NamedDecl *ND = m.RD;
-    if (ND->getName().empty()) {
-      if (const TypedefNameDecl *TD = m.RD->getTypedefNameForAnonDecl())
-        ND = TD;
-    }
-    Diag(m.E->getBeginLoc(), diag::warn_taking_address_of_packed_member)
-        << m.MD << ND << m.E->getSourceRange();
-  }
-  currentEvaluationContext().MisalignedMembers.clear();
-}
-
-void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) {
-  E = E->IgnoreParens();
-  if (!T->isPointerType() && !T->isIntegerType() && !T->isDependentType())
-    return;
-  if (isa<UnaryOperator>(E) &&
-      cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) {
-    auto *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();
-    if (isa<MemberExpr>(Op)) {
-      auto &MisalignedMembersForExpr =
-          currentEvaluationContext().MisalignedMembers;
-      auto *MA = llvm::find(MisalignedMembersForExpr, MisalignedMember(Op));
-      if (MA != MisalignedMembersForExpr.end() &&
-          (T->isDependentType() || T->isIntegerType() ||
-           (T->isPointerType() && (T->getPointeeType()->isIncompleteType() ||
-                                   Context.getTypeAlignInChars(
-                                       T->getPointeeType()) <= MA->Alignment))))
-        MisalignedMembersForExpr.erase(MA);
-    }
-  }
-}
-
-void Sema::RefersToMemberWithReducedAlignment(
-    Expr *E,
-    llvm::function_ref<void(Expr *, RecordDecl *, FieldDecl *, CharUnits)>
-        Action) {
-  const auto *ME = dyn_cast<MemberExpr>(E);
-  if (!ME)
-    return;
-
-  // No need to check expressions with an __unaligned-qualified type.
-  if (E->getType().getQualifiers().hasUnaligned())
-    return;
-
-  // For a chain of MemberExpr like "a.b.c.d" this list
-  // will keep FieldDecl's like [d, c, b].
-  SmallVector<FieldDecl *, 4> ReverseMemberChain;
-  const MemberExpr *TopME = nullptr;
-  bool AnyIsPacked = false;
-  do {
-    QualType BaseType = ME->getBase()->getType();
-    if (BaseType->isDependentType())
-      return;
-    if (ME->isArrow())
-      BaseType = BaseType->getPointeeType();
-    auto *RD = BaseType->castAsRecordDecl();
-    if (RD->isInvalidDecl())
-      return;
-
-    ValueDecl *MD = ME->getMemberDecl();
-    auto *FD = dyn_cast<FieldDecl>(MD);
-    // We do not care about non-data members.
-    if (!FD || FD->isInvalidDecl())
-      return;
-
-    AnyIsPacked =
-        AnyIsPacked || (RD->hasAttr<PackedAttr>() || MD->hasAttr<PackedAttr>());
-    ReverseMemberChain.push_back(FD);
-
-    TopME = ME;
-    ME = dyn_cast<MemberExpr>(ME->getBase()->IgnoreParens());
-  } while (ME);
-  assert(TopME && "We did not compute a topmost MemberExpr!");
-
-  // Not the scope of this diagnostic.
-  if (!AnyIsPacked)
-    return;
-
-  const Expr *TopBase = TopME->getBase()->IgnoreParenImpCasts();
-  const auto *DRE = dyn_cast<DeclRefExpr>(TopBase);
-  // TODO: The innermost base of the member expression may be too complicated.
-  // For now, just disregard these cases. This is left for future
-  // improvement.
-  if (!DRE && !isa<CXXThisExpr>(TopBase))
-      return;
-
-  // Alignment expected by the whole expression.
-  CharUnits ExpectedAlignment = Context.getTypeAlignInChars(E->getType());
-
-  // No need to do anything else with this case.
-  if (ExpectedAlignment.isOne())
-    return;
-
-  // Synthesize offset of the whole access.
-  CharUnits Offset;
-  for (const FieldDecl *FD : llvm::reverse(ReverseMemberChain))
-    Offset += Context.toCharUnitsFromBits(Context.getFieldOffset(FD));
-
-  // Compute the CompleteObjectAlignment as the alignment of the whole chain.
-  CharUnits CompleteObjectAlignment = Context.getTypeAlignInChars(
-      Context.getCanonicalTagType(ReverseMemberChain.back()->getParent()));
-
-  // The base expression of the innermost MemberExpr may give
-  // stronger guarantees than the class containing the member.
-  if (DRE && !TopME->isArrow()) {
-    const ValueDecl *VD = DRE->getDecl();
-    if (!VD->getType()->isReferenceType())
-      CompleteObjectAlignment =
-          std::max(CompleteObjectAlignment, Context.getDeclAlign(VD));
-  }
-
-  // Check if the synthesized offset fulfills the alignment.
-  if (!Offset.isMultipleOf(ExpectedAlignment) ||
-      // It may fulfill the offset it but the effective alignment may still be
-      // lower than the expected expression alignment.
-      CompleteObjectAlignment < ExpectedAlignment) {
-    // If this happens, we want to determine a sensible culprit of this.
-    // Intuitively, watching the chain of member expressions from right to
-    // left, we start with the required alignment (as required by the field
-    // type) but some packed attribute in that chain has reduced the alignment.
-    // It may happen that another packed structure increases it again. But if
-    // we are here such increase has not been enough. So pointing the first
-    // FieldDecl that either is packed or else its RecordDecl is,
-    // seems reasonable.
-    FieldDecl *FD = nullptr;
-    CharUnits Alignment;
-    for (FieldDecl *FDI : ReverseMemberChain) {
-      if (FDI->hasAttr<PackedAttr>() ||
-          FDI->getParent()->hasAttr<PackedAttr>()) {
-        FD = FDI;
-        Alignment = std::min(Context.getTypeAlignInChars(FD->getType()),
-                             Context.getTypeAlignInChars(
-                                 Context.getCanonicalTagType(FD->getParent())));
-        break;
-      }
-    }
-    assert(FD && "We did not find a packed FieldDecl!");
-    Action(E, FD->getParent(), FD, Alignment);
-  }
-}
-
-void Sema::CheckAddressOfPackedMember(Expr *rhs) {
-  using namespace std::placeholders;
-
-  RefersToMemberWithReducedAlignment(
-      rhs, std::bind(&Sema::AddPotentialMisalignedMembers, std::ref(*this), _1,
-                     _2, _3, _4));
-}
-
-bool Sema::PrepareBuiltinElementwiseMathOneArgCall(
-    CallExpr *TheCall, EltwiseBuiltinArgTyRestriction ArgTyRestr) {
-  if (checkArgCount(TheCall, 1))
-    return true;
-
-  ExprResult A = BuiltinVectorMathConversions(*this, TheCall->getArg(0));
-  if (A.isInvalid())
-    return true;
-
-  TheCall->setArg(0, A.get());
-  QualType TyA = A.get()->getType();
-
-  if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA,
-                                  ArgTyRestr, 1))
-    return true;
-
-  TheCall->setType(TyA);
-  return false;
-}
-
-bool Sema::BuiltinElementwiseMath(CallExpr *TheCall,
-                                  EltwiseBuiltinArgTyRestriction ArgTyRestr) {
-  if (auto Res = BuiltinVectorMath(TheCall, ArgTyRestr); Res.has_value()) {
-    TheCall->setType(*Res);
-    return false;
-  }
-  return true;
-}
-
-bool Sema::BuiltinVectorToScalarMath(CallExpr *TheCall) {
-  std::optional<QualType> Res = BuiltinVectorMath(TheCall);
-  if (!Res)
-    return true;
-
-  if (auto *VecTy0 = (*Res)->getAs<VectorType>())
-    TheCall->setType(VecTy0->getElementType());
-  else
-    TheCall->setType(*Res);
-
-  return false;
-}
-
-static bool checkBuiltinVectorMathMixedEnums(Sema &S, Expr *LHS, Expr *RHS,
-                                             SourceLocation Loc) {
-  QualType L = LHS->getEnumCoercedType(S.Context),
-           R = RHS->getEnumCoercedType(S.Context);
-  if (L->isUnscopedEnumerationType() && R->isUnscopedEnumerationType() &&
-      !S.Context.hasSameUnqualifiedType(L, R)) {
-    return S.Diag(Loc, diag::err_conv_mixed_enum_types)
-           << LHS->getSourceRange() << RHS->getSourceRange()
-           << /*Arithmetic Between*/ 0 << L << R;
-  }
-  return false;
-}
-
-/// Check if all arguments have the same type. If the types don't match, emit an
-/// error message and return true. Otherwise return false.
-///
-/// For scalars we directly compare their unqualified types. But even if we
-/// compare unqualified vector types, a difference in qualifiers in the element
-/// types can make the vector types be considered not equal. For example,
-/// vector of 4 'const float' values vs vector of 4 'float' values.
-/// So we compare unqualified types of their elements and number of elements.
-static bool checkBuiltinVectorMathArgTypes(Sema &SemaRef,
-                                           ArrayRef<Expr *> Args) {
-  assert(!Args.empty() && "Should have at least one argument.");
-
-  Expr *Arg0 = Args.front();
-  QualType Ty0 = Arg0->getType();
-
-  auto EmitError = [&](Expr *ArgI) {
-    SemaRef.Diag(Arg0->getBeginLoc(),
-                 diag::err_typecheck_call_different_arg_types)
-        << Arg0->getType() << ArgI->getType();
-  };
-
-  // Compare scalar types.
-  if (!Ty0->isVectorType()) {
-    for (Expr *ArgI : Args.drop_front())
-      if (!SemaRef.Context.hasSameUnqualifiedType(Ty0, ArgI->getType())) {
-        EmitError(ArgI);
-        return true;
-      }
-
-    return false;
-  }
-
-  // Compare vector types.
-  const auto *Vec0 = Ty0->castAs<VectorType>();
-  for (Expr *ArgI : Args.drop_front()) {
-    const auto *VecI = ArgI->getType()->getAs<VectorType>();
-    if (!VecI ||
-        !SemaRef.Context.hasSameUnqualifiedType(Vec0->getElementType(),
-                                                VecI->getElementType()) ||
-        Vec0->getNumElements() != VecI->getNumElements()) {
-      EmitError(ArgI);
-      return true;
-    }
-  }
-
-  return false;
-}
-
-std::optional<QualType>
-Sema::BuiltinVectorMath(CallExpr *TheCall,
-                        EltwiseBuiltinArgTyRestriction ArgTyRestr) {
-  if (checkArgCount(TheCall, 2))
-    return std::nullopt;
-
-  if (checkBuiltinVectorMathMixedEnums(
-          *this, TheCall->getArg(0), TheCall->getArg(1), TheCall->getExprLoc()))
-    return std::nullopt;
-
-  Expr *Args[2];
-  for (int I = 0; I < 2; ++I) {
-    ExprResult Converted =
-        BuiltinVectorMathConversions(*this, TheCall->getArg(I));
-    if (Converted.isInvalid())
-      return std::nullopt;
-    Args[I] = Converted.get();
-  }
-
-  SourceLocation LocA = Args[0]->getBeginLoc();
-  QualType TyA = Args[0]->getType();
-
-  if (checkMathBuiltinElementType(*this, LocA, TyA, ArgTyRestr, 1))
-    return std::nullopt;
-
-  if (checkBuiltinVectorMathArgTypes(*this, Args))
-    return std::nullopt;
-
-  TheCall->setArg(0, Args[0]);
-  TheCall->setArg(1, Args[1]);
-  return TyA;
-}
-
-bool Sema::BuiltinElementwiseTernaryMath(
-    CallExpr *TheCall, EltwiseBuiltinArgTyRestriction ArgTyRestr) {
-  if (checkArgCount(TheCall, 3))
-    return true;
-
-  SourceLocation Loc = TheCall->getExprLoc();
-  if (checkBuiltinVectorMathMixedEnums(*this, TheCall->getArg(0),
-                                       TheCall->getArg(1), Loc) ||
-      checkBuiltinVectorMathMixedEnums(*this, TheCall->getArg(1),
-                                       TheCall->getArg(2), Loc))
-    return true;
-
-  Expr *Args[3];
-  for (int I = 0; I < 3; ++I) {
-    ExprResult Converted =
-        BuiltinVectorMathConversions(*this, TheCall->getArg(I));
-    if (Converted.isInvalid())
-      return true;
-    Args[I] = Converted.get();
-  }
-
-  int ArgOrdinal = 1;
-  for (Expr *Arg : Args) {
-    if (checkMathBuiltinElementType(*this, Arg->getBeginLoc(), Arg->getType(),
-                                    ArgTyRestr, ArgOrdinal++))
-      return true;
-  }
-
-  if (checkBuiltinVectorMathArgTypes(*this, Args))
-    return true;
-
-  for (int I = 0; I < 3; ++I)
-    TheCall->setArg(I, Args[I]);
-
-  TheCall->setType(Args[0]->getType());
-  return false;
-}
-
-bool Sema::PrepareBuiltinReduceMathOneArgCall(CallExpr *TheCall) {
-  if (checkArgCount(TheCall, 1))
-    return true;
-
-  ExprResult A = UsualUnaryConversions(TheCall->getArg(0));
-  if (A.isInvalid())
-    return true;
-
-  TheCall->setArg(0, A.get());
-  return false;
-}
-
-bool Sema::BuiltinNonDeterministicValue(CallExpr *TheCall) {
-  if (checkArgCount(TheCall, 1))
-    return true;
-
-  ExprResult Arg = TheCall->getArg(0);
-  QualType TyArg = Arg.get()->getType();
-
-  if (!TyArg->isBuiltinType() && !TyArg->isVectorType())
-    return Diag(TheCall->getArg(0)->getBeginLoc(),
-                diag::err_builtin_invalid_arg_type)
-           << 1 << /* vector */ 2 << /* integer */ 1 << /* fp */ 1 << TyArg;
-
-  TheCall->setType(TyArg);
-  return false;
-}
-
-ExprResult Sema::BuiltinMatrixTranspose(CallExpr *TheCall,
-                                        ExprResult CallResult) {
-  if (checkArgCount(TheCall, 1))
-    return ExprError();
-
-  ExprResult MatrixArg = DefaultLvalueConversion(TheCall->getArg(0));
-  if (MatrixArg.isInvalid())
-    return MatrixArg;
-  Expr *Matrix = MatrixArg.get();
-
-  auto *MType = Matrix->getType()->getAs<ConstantMatrixType>();
-  if (!MType) {
-    Diag(Matrix->getBeginLoc(), diag::err_builtin_invalid_arg_type)
-        << 1 << /* matrix */ 3 << /* no int */ 0 << /* no fp */ 0
-        << Matrix->getType();
-    return ExprError();
-  }
-
-  // Create returned matrix type by swapping rows and columns of the argument
-  // matrix type.
-  QualType ResultType = Context.getConstantMatrixType(
-      MType->getElementType(), MType->getNumColumns(), MType->getNumRows());
-
-  // Change the return type to the type of the returned matrix.
-  TheCall->setType(ResultType);
-
-  // Update call argument to use the possibly converted matrix argument.
-  TheCall->setArg(0, Matrix);
-  return CallResult;
-}
-
-// Get and verify the matrix dimensions.
-static std::optional<unsigned>
-getAndVerifyMatrixDimension(Expr *Expr, StringRef Name, Sema &S) {
-  std::optional<llvm::APSInt> Value = Expr->getIntegerConstantExpr(S.Context);
-  if (!Value) {
-    S.Diag(Expr->getBeginLoc(), diag::err_builtin_matrix_scalar_unsigned_arg)
-        << Name;
-    return {};
-  }
-  uint64_t Dim = Value->getZExtValue();
-  if (Dim == 0 || Dim > S.Context.getLangOpts().MaxMatrixDimension) {
-    S.Diag(Expr->getBeginLoc(), diag::err_builtin_matrix_invalid_dimension)
-        << Name << S.Context.getLangOpts().MaxMatrixDimension;
-    return {};
-  }
-  return Dim;
-}
-
-ExprResult Sema::BuiltinMatrixColumnMajorLoad(CallExpr *TheCall,
-                                              ExprResult CallResult) {
-  if (!getLangOpts().MatrixTypes) {
-    Diag(TheCall->getBeginLoc(), diag::err_builtin_matrix_disabled);
-    return ExprError();
-  }
-
-  if (getLangOpts().getDefaultMatrixMemoryLayout() !=
-      LangOptions::MatrixMemoryLayout::MatrixColMajor) {
-    Diag(TheCall->getBeginLoc(), diag::err_builtin_matrix_major_order_disabled)
-        << /*column*/ 1 << /*load*/ 0;
-    return ExprError();
-  }
-
-  if (checkArgCount(TheCall, 4))
-    return ExprError();
-
-  unsigned PtrArgIdx = 0;
-  Expr *PtrExpr = TheCall->getArg(PtrArgIdx);
-  Expr *RowsExpr = TheCall->getArg(1);
-  Expr *ColumnsExpr = TheCall->getArg(2);
-  Expr *StrideExpr = TheCall->getArg(3);
-
-  bool ArgError = false;
-
-  // Check pointer argument.
-  {
-    ExprResult PtrConv = DefaultFunctionArrayLvalueConversion(PtrExpr);
-    if (PtrConv.isInvalid())
-      return PtrConv;
-    PtrExpr = PtrConv.get();
-    TheCall->setArg(0, PtrExpr);
-    if (PtrExpr->isTypeDependent()) {
-      TheCall->setType(Context.DependentTy);
-      return TheCall;
-    }
-  }
-
-  auto *PtrTy = PtrExpr->getType()->getAs<PointerType>();
-  QualType ElementTy;
-  if (!PtrTy) {
-    Diag(PtrExpr->getBeginLoc(), diag::err_builtin_invalid_arg_type)
-        << PtrArgIdx + 1 << 0 << /* pointer to element ty */ 5 << /* no fp */ 0
-        << PtrExpr->getType();
-    ArgError = true;
-  } else {
-    ElementTy = PtrTy->getPointeeType().getUnqualifiedType();
-
-    if (!ConstantMatrixType::isValidElementType(ElementTy, getLangOpts())) {
-      Diag(PtrExpr->getBeginLoc(), diag::err_builtin_invalid_arg_type)
-          << PtrArgIdx + 1 << 0 << /* pointer to element ty */ 5
-          << /* no fp */ 0 << PtrExpr->getType();
-      ArgError = true;
-    }
-  }
-
-  // Apply default Lvalue conversions and convert the expression to size_t.
-  auto ApplyArgumentConversions = [this](Expr *E) {
-    ExprResult Conv = DefaultLvalueConversion(E);
-    if (Conv.isInvalid())
-      return Conv;
-
-    return tryConvertExprToType(Conv.get(), Context.getSizeType());
-  };
-
-  // Apply conversion to row and column expressions.
-  ExprResult RowsConv = ApplyArgumentConversions(RowsExpr);
-  if (!RowsConv.isInvalid()) {
-    RowsExpr = RowsConv.get();
-    TheCall->setArg(1, RowsExpr);
-  } else
-    RowsExpr = nullptr;
-
-  ExprResult ColumnsConv = ApplyArgumentConversions(ColumnsExpr);
-  if (!ColumnsConv.isInvalid()) {
-    ColumnsExpr = ColumnsConv.get();
-    TheCall->setArg(2, ColumnsExpr);
-  } else
-    ColumnsExpr = nullptr;
-
-  // If any part of the result matrix type is still pending, just use
-  // Context.DependentTy, until all parts are resolved.
-  if ((RowsExpr && RowsExpr->isTypeDependent()) ||
-      (ColumnsExpr && ColumnsExpr->isTypeDependent())) {
-    TheCall->setType(Context.DependentTy);
-    return CallResult;
-  }
-
-  // Check row and column dimensions.
-  std::optional<unsigned> MaybeRows;
-  if (RowsExpr)
-    MaybeRows = getAndVerifyMatrixDimension(RowsExpr, "row", *this);
-
-  std::optional<unsigned> MaybeColumns;
-  if (ColumnsExpr)
-    MaybeColumns = getAndVerifyMatrixDimension(ColumnsExpr, "column", *this);
-
-  // Check stride argument.
-  ExprResult StrideConv = ApplyArgumentConversions(StrideExpr);
-  if (StrideConv.isInvalid())
-    return ExprError();
-  StrideExpr = StrideConv.get();
-  TheCall->setArg(3, StrideExpr);
-
-  if (MaybeRows) {
-    if (std::optional<llvm::APSInt> Value =
-            StrideExpr->getIntegerConstantExpr(Context)) {
-      uint64_t Stride = Value->getZExtValue();
-      if (Stride < *MaybeRows) {
-        Diag(StrideExpr->getBeginLoc(),
-             diag::err_builtin_matrix_stride_too_small);
-        ArgError = true;
-      }
-    }
-  }
-
-  if (ArgError || !MaybeRows || !MaybeColumns)
-    return ExprError();
-
-  TheCall->setType(
-      Context.getConstantMatrixType(ElementTy, *MaybeRows, *MaybeColumns));
-  return CallResult;
-}
-
-ExprResult Sema::BuiltinMatrixColumnMajorStore(CallExpr *TheCall,
-                                               ExprResult CallResult) {
-  if (!getLangOpts().MatrixTypes) {
-    Diag(TheCall->getBeginLoc(), diag::err_builtin_matrix_disabled);
-    return ExprError();
-  }
-
-  if (getLangOpts().getDefaultMatrixMemoryLayout() !=
-      LangOptions::MatrixMemoryLayout::MatrixColMajor) {
-    Diag(TheCall->getBeginLoc(), diag::err_builtin_matrix_major_order_disabled)
-        << /*column*/ 1 << /*store*/ 1;
-    return ExprError();
-  }
-
-  if (checkArgCount(TheCall, 3))
-    return ExprError();
-
-  unsigned PtrArgIdx = 1;
-  Expr *MatrixExpr = TheCall->getArg(0);
-  Expr *PtrExpr = TheCall->getArg(PtrArgIdx);
-  Expr *StrideExpr = TheCall->getArg(2);
-
-  bool ArgError = false;
-
-  {
-    ExprResult MatrixConv = DefaultLvalueConversion(MatrixExpr);
-    if (MatrixConv.isInvalid())
-      return MatrixConv;
-    MatrixExpr = MatrixConv.get();
-    TheCall->setArg(0, MatrixExpr);
-  }
-  if (MatrixExpr->isTypeDependent()) {
-    TheCall->setType(Context.DependentTy);
-    return TheCall;
-  }
-
-  auto *MatrixTy = MatrixExpr->getType()->getAs<ConstantMatrixType>();
-  if (!MatrixTy) {
-    Diag(MatrixExpr->getBeginLoc(), diag::err_builtin_invalid_arg_type)
-        << 1 << /* matrix ty */ 3 << 0 << 0 << MatrixExpr->getType();
-    ArgError = true;
-  }
-
-  {
-    ExprResult PtrConv = DefaultFunctionArrayLvalueConversion(PtrExpr);
-    if (PtrConv.isInvalid())
-      return PtrConv;
-    PtrExpr = PtrConv.get();
-    TheCall->setArg(1, PtrExpr);
-    if (PtrExpr->isTypeDependent()) {
-      TheCall->setType(Context.DependentTy);
-      return TheCall;
-    }
-  }
-
-  // Check pointer argument.
-  auto *PtrTy = PtrExpr->getType()->getAs<PointerType>();
-  if (!PtrTy) {
-    Diag(PtrExpr->getBeginLoc(), diag::err_builtin_invalid_arg_type)
-        << PtrArgIdx + 1 << 0 << /* pointer to element ty */ 5 << 0
-        << PtrExpr->getType();
-    ArgError = true;
-  } else {
-    QualType ElementTy = PtrTy->getPointeeType();
-    if (ElementTy.isConstQualified()) {
-      Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_store_to_const);
-      ArgError = true;
-    }
-    ElementTy = ElementTy.getUnqualifiedType().getCanonicalType();
-    if (MatrixTy &&
-        !Context.hasSameType(ElementTy, MatrixTy->getElementType())) {
-      Diag(PtrExpr->getBeginLoc(),
-           diag::err_builtin_matrix_pointer_arg_mismatch)
-          << ElementTy << MatrixTy->getElementType();
-      ArgError = true;
-    }
-  }
-
-  // Apply default Lvalue conversions and convert the stride expression to
-  // size_t.
-  {
-    ExprResult StrideConv = DefaultLvalueConversion(StrideExpr);
-    if (StrideConv.isInvalid())
-      return StrideConv;
-
-    StrideConv = tryConvertExprToType(StrideConv.get(), Context.getSizeType());
-    if (StrideConv.isInvalid())
-      return StrideConv;
-    StrideExpr = StrideConv.get();
-    TheCall->setArg(2, StrideExpr);
-  }
-
-  // Check stride argument.
-  if (MatrixTy) {
-    if (std::optional<llvm::APSInt> Value =
-            StrideExpr->getIntegerConstantExpr(Context)) {
-      uint64_t Stride = Value->getZExtValue();
-      if (Stride < MatrixTy->getNumRows()) {
-        Diag(StrideExpr->getBeginLoc(),
-             diag::err_builtin_matrix_stride_too_small);
-        ArgError = true;
-      }
-    }
-  }
-
-  if (ArgError)
-    return ExprError();
-
-  return CallResult;
-}
-
-void Sema::CheckTCBEnforcement(const SourceLocation CallExprLoc,
-                               const NamedDecl *Callee) {
-  // This warning does not make sense in code that has no runtime behavior.
-  if (isUnevaluatedContext())
-    return;
-
-  const NamedDecl *Caller = getCurFunctionOrMethodDecl();
-
-  if (!Caller || !Caller->hasAttr<EnforceTCBAttr>())
-    return;
-
-  // Search through the enforce_tcb and enforce_tcb_leaf attributes to find
-  // all TCBs the callee is a part of.
-  llvm::StringSet<> CalleeTCBs;
-  for (const auto *A : Callee->specific_attrs<EnforceTCBAttr>())
-    CalleeTCBs.insert(A->getTCBName());
-  for (const auto *A : Callee->specific_attrs<EnforceTCBLeafAttr>())
-    CalleeTCBs.insert(A->getTCBName());
-
-  // Go through the TCBs the caller is a part of and emit warnings if Caller
-  // is in a TCB that the Callee is not.
-  for (const auto *A : Caller->specific_attrs<EnforceTCBAttr>()) {
-    StringRef CallerTCB = A->getTCBName();
-    if (CalleeTCBs.count(CallerTCB) == 0) {
-      this->Diag(CallExprLoc, diag::warn_tcb_enforcement_violation)
-          << Callee << CallerTCB;
-    }
-  }
-}
+//===- SemaChecking.cpp - Extra Semantic Checking -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements extra semantic analysis beyond what is enforced
+//  by the C type system.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CheckExprLifetime.h"
+#include "clang/AST/APValue.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/AttrIterator.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/EvaluatedExprVisitor.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/FormatString.h"
+#include "clang/AST/IgnoreExpr.h"
+#include "clang/AST/NSAPI.h"
+#include "clang/AST/NonTrivialTypeVisitor.h"
+#include "clang/AST/OperationKinds.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/TemplateBase.h"
+#include "clang/AST/TemplateName.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/TypeBase.h"
+#include "clang/AST/TypeLoc.h"
+#include "clang/AST/UnresolvedSet.h"
+#include "clang/Basic/AddressSpaces.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticSema.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/OpenCLOptions.h"
+#include "clang/Basic/OperatorKinds.h"
+#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/Specifiers.h"
+#include "clang/Basic/SyncScope.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TypeTraits.h"
+#include "clang/Lex/Lexer.h" // TODO: Extract static functions to fix layering.
+#include "clang/Sema/Initialization.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Ownership.h"
+#include "clang/Sema/Scope.h"
+#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaAMDGPU.h"
+#include "clang/Sema/SemaARM.h"
+#include "clang/Sema/SemaBPF.h"
+#include "clang/Sema/SemaDirectX.h"
+#include "clang/Sema/SemaHLSL.h"
+#include "clang/Sema/SemaHexagon.h"
+#include "clang/Sema/SemaLoongArch.h"
+#include "clang/Sema/SemaMIPS.h"
+#include "clang/Sema/SemaNVPTX.h"
+#include "clang/Sema/SemaObjC.h"
+#include "clang/Sema/SemaOpenCL.h"
+#include "clang/Sema/SemaPPC.h"
+#include "clang/Sema/SemaRISCV.h"
+#include "clang/Sema/SemaSPIRV.h"
+#include "clang/Sema/SemaSystemZ.h"
+#include "clang/Sema/SemaWasm.h"
+#include "clang/Sema/SemaX86.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/STLForwardCompat.h"
+#include "llvm/ADT/SmallBitVector.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/AtomicOrdering.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Locale.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/RISCVTargetParser.h"
+#include "llvm/TargetParser/Triple.h"
+#include <algorithm>
+#include <cassert>
+#include <cctype>
+#include <cstddef>
+#include <cstdint>
+#include <functional>
+#include <limits>
+#include <optional>
+#include <string>
+#include <tuple>
+#include <utility>
+
+using namespace clang;
+using namespace sema;
+
+SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL,
+                                                    unsigned ByteNo) const {
+  return SL->getLocationOfByte(ByteNo, getSourceManager(), LangOpts,
+                               Context.getTargetInfo());
+}
+
+static constexpr unsigned short combineFAPK(Sema::FormatArgumentPassingKind A,
+                                            Sema::FormatArgumentPassingKind B) {
+  return (A << 8) | B;
+}
+
+bool Sema::checkArgCountAtLeast(CallExpr *Call, unsigned MinArgCount) {
+  unsigned ArgCount = Call->getNumArgs();
+  if (ArgCount >= MinArgCount)
+    return false;
+
+  return Diag(Call->getEndLoc(), diag::err_typecheck_call_too_few_args)
+         << 0 /*function call*/ << MinArgCount << ArgCount
+         << /*is non object*/ 0 << Call->getSourceRange();
+}
+
+bool Sema::checkArgCountAtMost(CallExpr *Call, unsigned MaxArgCount) {
+  unsigned ArgCount = Call->getNumArgs();
+  if (ArgCount <= MaxArgCount)
+    return false;
+  return Diag(Call->getEndLoc(), diag::err_typecheck_call_too_many_args_at_most)
+         << 0 /*function call*/ << MaxArgCount << ArgCount
+         << /*is non object*/ 0 << Call->getSourceRange();
+}
+
+bool Sema::checkArgCountRange(CallExpr *Call, unsigned MinArgCount,
+                              unsigned MaxArgCount) {
+  return checkArgCountAtLeast(Call, MinArgCount) ||
+         checkArgCountAtMost(Call, MaxArgCount);
+}
+
+bool Sema::checkArgCount(CallExpr *Call, unsigned DesiredArgCount) {
+  unsigned ArgCount = Call->getNumArgs();
+  if (ArgCount == DesiredArgCount)
+    return false;
+
+  if (checkArgCountAtLeast(Call, DesiredArgCount))
+    return true;
+  assert(ArgCount > DesiredArgCount && "should have diagnosed this");
+
+  // Highlight all the excess arguments.
+  SourceRange Range(Call->getArg(DesiredArgCount)->getBeginLoc(),
+                    Call->getArg(ArgCount - 1)->getEndLoc());
+
+  return Diag(Range.getBegin(), diag::err_typecheck_call_too_many_args)
+         << 0 /*function call*/ << DesiredArgCount << ArgCount
+         << /*is non object*/ 0 << Range;
+}
+
+static bool checkBuiltinVerboseTrap(CallExpr *Call, Sema &S) {
+  bool HasError = false;
+
+  for (const Expr *Arg : Call->arguments()) {
+    if (Arg->isValueDependent())
+      continue;
+
+    std::optional<std::string> ArgString = Arg->tryEvaluateString(S.Context);
+    int DiagMsgKind = -1;
+    // Arguments must be pointers to constant strings and cannot use '$'.
+    if (!ArgString.has_value())
+      DiagMsgKind = 0;
+    else if (ArgString->find('$') != std::string::npos)
+      DiagMsgKind = 1;
+
+    if (DiagMsgKind >= 0) {
+      S.Diag(Arg->getBeginLoc(), diag::err_builtin_verbose_trap_arg)
+          << DiagMsgKind << Arg->getSourceRange();
+      HasError = true;
+    }
+  }
+
+  return !HasError;
+}
+
+static bool convertArgumentToType(Sema &S, Expr *&Value, QualType Ty) {
+  if (Value->isTypeDependent())
+    return false;
+
+  InitializedEntity Entity =
+      InitializedEntity::InitializeParameter(S.Context, Ty, false);
+  ExprResult Result =
+      S.PerformCopyInitialization(Entity, SourceLocation(), Value);
+  if (Result.isInvalid())
+    return true;
+  Value = Result.get();
+  return false;
+}
+
+/// Check that the first argument to __builtin_annotation is an integer
+/// and the second argument is a non-wide string literal.
+static bool BuiltinAnnotation(Sema &S, CallExpr *TheCall) {
+  if (S.checkArgCount(TheCall, 2))
+    return true;
+
+  // First argument should be an integer.
+  Expr *ValArg = TheCall->getArg(0);
+  QualType Ty = ValArg->getType();
+  if (!Ty->isIntegerType()) {
+    S.Diag(ValArg->getBeginLoc(), diag::err_builtin_annotation_first_arg)
+        << ValArg->getSourceRange();
+    return true;
+  }
+
+  // Second argument should be a constant string.
+  Expr *StrArg = TheCall->getArg(1)->IgnoreParenCasts();
+  StringLiteral *Literal = dyn_cast<StringLiteral>(StrArg);
+  if (!Literal || !Literal->isOrdinary()) {
+    S.Diag(StrArg->getBeginLoc(), diag::err_builtin_annotation_second_arg)
+        << StrArg->getSourceRange();
+    return true;
+  }
+
+  TheCall->setType(Ty);
+  return false;
+}
+
+static bool BuiltinMSVCAnnotation(Sema &S, CallExpr *TheCall) {
+  // We need at least one argument.
+  if (TheCall->getNumArgs() < 1) {
+    S.Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least)
+        << 0 << 1 << TheCall->getNumArgs() << /*is non object*/ 0
+        << TheCall->getCallee()->getSourceRange();
+    return true;
+  }
+
+  // All arguments should be wide string literals.
+  for (Expr *Arg : TheCall->arguments()) {
+    auto *Literal = dyn_cast<StringLiteral>(Arg->IgnoreParenCasts());
+    if (!Literal || !Literal->isWide()) {
+      S.Diag(Arg->getBeginLoc(), diag::err_msvc_annotation_wide_str)
+          << Arg->getSourceRange();
+      return true;
+    }
+  }
+
+  return false;
+}
+
+/// Check that the argument to __builtin_addressof is a glvalue, and set the
+/// result type to the corresponding pointer type.
+static bool BuiltinAddressof(Sema &S, CallExpr *TheCall) {
+  if (S.checkArgCount(TheCall, 1))
+    return true;
+
+  ExprResult Arg(TheCall->getArg(0));
+  QualType ResultType = S.CheckAddressOfOperand(Arg, TheCall->getBeginLoc());
+  if (ResultType.isNull())
+    return true;
+
+  TheCall->setArg(0, Arg.get());
+  TheCall->setType(ResultType);
+  return false;
+}
+
+/// Check that the argument to __builtin_function_start is a function.
+static bool BuiltinFunctionStart(Sema &S, CallExpr *TheCall) {
+  if (S.checkArgCount(TheCall, 1))
+    return true;
+
+  if (TheCall->getArg(0)->containsErrors())
+    return true;
+
+  ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(0));
+  if (Arg.isInvalid())
+    return true;
+
+  TheCall->setArg(0, Arg.get());
+  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(
+      Arg.get()->getAsBuiltinConstantDeclRef(S.getASTContext()));
+
+  if (!FD) {
+    S.Diag(TheCall->getBeginLoc(), diag::err_function_start_invalid_type)
+        << TheCall->getSourceRange();
+    return true;
+  }
+
+  return !S.checkAddressOfFunctionIsAvailable(FD, /*Complain=*/true,
+                                              TheCall->getBeginLoc());
+}
+
+/// Check the number of arguments and set the result type to
+/// the argument type.
+static bool BuiltinPreserveAI(Sema &S, CallExpr *TheCall) {
+  if (S.checkArgCount(TheCall, 1))
+    return true;
+
+  TheCall->setType(TheCall->getArg(0)->getType());
+  return false;
+}
+
+/// Check that the value argument for __builtin_is_aligned(value, alignment) and
+/// __builtin_aligned_{up,down}(value, alignment) is an integer or a pointer
+/// type (but not a function pointer) and that the alignment is a power-of-two.
+static bool BuiltinAlignment(Sema &S, CallExpr *TheCall, unsigned ID) {
+  if (S.checkArgCount(TheCall, 2))
+    return true;
+
+  clang::Expr *Source = TheCall->getArg(0);
+  bool IsBooleanAlignBuiltin = ID == Builtin::BI__builtin_is_aligned;
+
+  auto IsValidIntegerType = [](QualType Ty) {
+    return Ty->isIntegerType() && !Ty->isEnumeralType() && !Ty->isBooleanType();
+  };
+  QualType SrcTy = Source->getType();
+  // We should also be able to use it with arrays (but not functions!).
+  if (SrcTy->canDecayToPointerType() && SrcTy->isArrayType()) {
+    SrcTy = S.Context.getDecayedType(SrcTy);
+  }
+  if ((!SrcTy->isPointerType() && !IsValidIntegerType(SrcTy)) ||
+      SrcTy->isFunctionPointerType()) {
+    // FIXME: this is not quite the right error message since we don't allow
+    // floating point types, or member pointers.
+    S.Diag(Source->getExprLoc(), diag::err_typecheck_expect_scalar_operand)
+        << SrcTy;
+    return true;
+  }
+
+  clang::Expr *AlignOp = TheCall->getArg(1);
+  if (!IsValidIntegerType(AlignOp->getType())) {
+    S.Diag(AlignOp->getExprLoc(), diag::err_typecheck_expect_int)
+        << AlignOp->getType();
+    return true;
+  }
+  Expr::EvalResult AlignResult;
+  unsigned MaxAlignmentBits = S.Context.getIntWidth(SrcTy) - 1;
+  // We can't check validity of alignment if it is value dependent.
+  if (!AlignOp->isValueDependent() &&
+      AlignOp->EvaluateAsInt(AlignResult, S.Context,
+                             Expr::SE_AllowSideEffects)) {
+    llvm::APSInt AlignValue = AlignResult.Val.getInt();
+    llvm::APSInt MaxValue(
+        llvm::APInt::getOneBitSet(MaxAlignmentBits + 1, MaxAlignmentBits));
+    if (AlignValue < 1) {
+      S.Diag(AlignOp->getExprLoc(), diag::err_alignment_too_small) << 1;
+      return true;
+    }
+    if (llvm::APSInt::compareValues(AlignValue, MaxValue) > 0) {
+      S.Diag(AlignOp->getExprLoc(), diag::err_alignment_too_big)
+          << toString(MaxValue, 10);
+      return true;
+    }
+    if (!AlignValue.isPowerOf2()) {
+      S.Diag(AlignOp->getExprLoc(), diag::err_alignment_not_power_of_two);
+      return true;
+    }
+    if (AlignValue == 1) {
+      S.Diag(AlignOp->getExprLoc(), diag::warn_alignment_builtin_useless)
+          << IsBooleanAlignBuiltin;
+    }
+  }
+
+  ExprResult SrcArg = S.PerformCopyInitialization(
+      InitializedEntity::InitializeParameter(S.Context, SrcTy, false),
+      SourceLocation(), Source);
+  if (SrcArg.isInvalid())
+    return true;
+  TheCall->setArg(0, SrcArg.get());
+  ExprResult AlignArg =
+      S.PerformCopyInitialization(InitializedEntity::InitializeParameter(
+                                      S.Context, AlignOp->getType(), false),
+                                  SourceLocation(), AlignOp);
+  if (AlignArg.isInvalid())
+    return true;
+  TheCall->setArg(1, AlignArg.get());
+  // For align_up/align_down, the return type is the same as the (potentially
+  // decayed) argument type including qualifiers. For is_aligned(), the result
+  // is always bool.
+  TheCall->setType(IsBooleanAlignBuiltin ? S.Context.BoolTy : SrcTy);
+  return false;
+}
+
+static bool BuiltinOverflow(Sema &S, CallExpr *TheCall, unsigned BuiltinID) {
+  if (S.checkArgCount(TheCall, 3))
+    return true;
+
+  std::pair<unsigned, const char *> Builtins[] = {
+    { Builtin::BI__builtin_add_overflow, "ckd_add" },
+    { Builtin::BI__builtin_sub_overflow, "ckd_sub" },
+    { Builtin::BI__builtin_mul_overflow, "ckd_mul" },
+  };
+
+  bool CkdOperation = llvm::any_of(Builtins, [&](const std::pair<unsigned,
+    const char *> &P) {
+    return BuiltinID == P.first && TheCall->getExprLoc().isMacroID() &&
+         Lexer::getImmediateMacroName(TheCall->getExprLoc(),
+         S.getSourceManager(), S.getLangOpts()) == P.second;
+  });
+
+  auto ValidCkdIntType = [](QualType QT) {
+    // A valid checked integer type is an integer type other than a plain char,
+    // bool, a bit-precise type, or an enumeration type.
+    if (const auto *BT = QT.getCanonicalType()->getAs<BuiltinType>())
+      return (BT->getKind() >= BuiltinType::Short &&
+           BT->getKind() <= BuiltinType::Int128) || (
+           BT->getKind() >= BuiltinType::UShort &&
+           BT->getKind() <= BuiltinType::UInt128) ||
+           BT->getKind() == BuiltinType::UChar ||
+           BT->getKind() == BuiltinType::SChar;
+    return false;
+  };
+
+  // First two arguments should be integers.
+  for (unsigned I = 0; I < 2; ++I) {
+    ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(I));
+    if (Arg.isInvalid()) return true;
+    TheCall->setArg(I, Arg.get());
+
+    QualType Ty = Arg.get()->getType();
+    bool IsValid = CkdOperation ? ValidCkdIntType(Ty) : Ty->isIntegerType();
+    if (!IsValid) {
+      S.Diag(Arg.get()->getBeginLoc(), diag::err_overflow_builtin_must_be_int)
+          << CkdOperation << Ty << Arg.get()->getSourceRange();
+      return true;
+    }
+  }
+
+  // Third argument should be a pointer to a non-const integer.
+  // IRGen correctly handles volatile, restrict, and address spaces, and
+  // the other qualifiers aren't possible.
+  {
+    ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(2));
+    if (Arg.isInvalid()) return true;
+    TheCall->setArg(2, Arg.get());
+
+    QualType Ty = Arg.get()->getType();
+    const auto *PtrTy = Ty->getAs<PointerType>();
+    if (!PtrTy ||
+        !PtrTy->getPointeeType()->isIntegerType() ||
+        (!ValidCkdIntType(PtrTy->getPointeeType()) && CkdOperation) ||
+        PtrTy->getPointeeType().isConstQualified()) {
+      S.Diag(Arg.get()->getBeginLoc(),
+             diag::err_overflow_builtin_must_be_ptr_int)
+        << CkdOperation << Ty << Arg.get()->getSourceRange();
+      return true;
+    }
+  }
+
+  // Disallow signed bit-precise integer args larger than 128 bits to mul
+  // function until we improve backend support.
+  if (BuiltinID == Builtin::BI__builtin_mul_overflow) {
+    for (unsigned I = 0; I < 3; ++I) {
+      const auto Arg = TheCall->getArg(I);
+      // Third argument will be a pointer.
+      auto Ty = I < 2 ? Arg->getType() : Arg->getType()->getPointeeType();
+      if (Ty->isBitIntType() && Ty->isSignedIntegerType() &&
+          S.getASTContext().getIntWidth(Ty) > 128)
+        return S.Diag(Arg->getBeginLoc(),
+                      diag::err_overflow_builtin_bit_int_max_size)
+               << 128;
+    }
+  }
+
+  return false;
+}
+
+namespace {
+struct BuiltinDumpStructGenerator {
+  Sema &S;
+  CallExpr *TheCall;
+  SourceLocation Loc = TheCall->getBeginLoc();
+  SmallVector<Expr *, 32> Actions;
+  DiagnosticErrorTrap ErrorTracker;
+  PrintingPolicy Policy;
+
+  BuiltinDumpStructGenerator(Sema &S, CallExpr *TheCall)
+      : S(S), TheCall(TheCall), ErrorTracker(S.getDiagnostics()),
+        Policy(S.Context.getPrintingPolicy()) {
+    Policy.AnonymousTagLocations = false;
+  }
+
+  Expr *makeOpaqueValueExpr(Expr *Inner) {
+    auto *OVE = new (S.Context)
+        OpaqueValueExpr(Loc, Inner->getType(), Inner->getValueKind(),
+                        Inner->getObjectKind(), Inner);
+    Actions.push_back(OVE);
+    return OVE;
+  }
+
+  Expr *getStringLiteral(llvm::StringRef Str) {
+    Expr *Lit = S.Context.getPredefinedStringLiteralFromCache(Str);
+    // Wrap the literal in parentheses to attach a source location.
+    return new (S.Context) ParenExpr(Loc, Loc, Lit);
+  }
+
+  bool callPrintFunction(llvm::StringRef Format,
+                         llvm::ArrayRef<Expr *> Exprs = {}) {
+    SmallVector<Expr *, 8> Args;
+    assert(TheCall->getNumArgs() >= 2);
+    Args.reserve((TheCall->getNumArgs() - 2) + /*Format*/ 1 + Exprs.size());
+    Args.assign(TheCall->arg_begin() + 2, TheCall->arg_end());
+    Args.push_back(getStringLiteral(Format));
+    llvm::append_range(Args, Exprs);
+
+    // Register a note to explain why we're performing the call.
+    Sema::CodeSynthesisContext Ctx;
+    Ctx.Kind = Sema::CodeSynthesisContext::BuildingBuiltinDumpStructCall;
+    Ctx.PointOfInstantiation = Loc;
+    Ctx.CallArgs = Args.data();
+    Ctx.NumCallArgs = Args.size();
+    S.pushCodeSynthesisContext(Ctx);
+
+    ExprResult RealCall =
+        S.BuildCallExpr(/*Scope=*/nullptr, TheCall->getArg(1),
+                        TheCall->getBeginLoc(), Args, TheCall->getRParenLoc());
+
+    S.popCodeSynthesisContext();
+    if (!RealCall.isInvalid())
+      Actions.push_back(RealCall.get());
+    // Bail out if we've hit any errors, even if we managed to build the
+    // call. We don't want to produce more than one error.
+    return RealCall.isInvalid() || ErrorTracker.hasErrorOccurred();
+  }
+
+  Expr *getIndentString(unsigned Depth) {
+    if (!Depth)
+      return nullptr;
+
+    llvm::SmallString<32> Indent;
+    Indent.resize(Depth * Policy.Indentation, ' ');
+    return getStringLiteral(Indent);
+  }
+
+  Expr *getTypeString(QualType T) {
+    return getStringLiteral(T.getAsString(Policy));
+  }
+
+  bool appendFormatSpecifier(QualType T, llvm::SmallVectorImpl<char> &Str) {
+    llvm::raw_svector_ostream OS(Str);
+
+    // Format 'bool', 'char', 'signed char', 'unsigned char' as numbers, rather
+    // than trying to print a single character.
+    if (auto *BT = T->getAs<BuiltinType>()) {
+      switch (BT->getKind()) {
+      case BuiltinType::Bool:
+        OS << "%d";
+        return true;
+      case BuiltinType::Char_U:
+      case BuiltinType::UChar:
+        OS << "%hhu";
+        return true;
+      case BuiltinType::Char_S:
+      case BuiltinType::SChar:
+        OS << "%hhd";
+        return true;
+      default:
+        break;
+      }
+    }
+
+    analyze_printf::PrintfSpecifier Specifier;
+    if (Specifier.fixType(T, S.getLangOpts(), S.Context, /*IsObjCLiteral=*/false)) {
+      // We were able to guess how to format this.
+      if (Specifier.getConversionSpecifier().getKind() ==
+          analyze_printf::PrintfConversionSpecifier::sArg) {
+        // Wrap double-quotes around a '%s' specifier and limit its maximum
+        // length. Ideally we'd also somehow escape special characters in the
+        // contents but printf doesn't support that.
+        // FIXME: '%s' formatting is not safe in general.
+        OS << '"';
+        Specifier.setPrecision(analyze_printf::OptionalAmount(32u));
+        Specifier.toString(OS);
+        OS << '"';
+        // FIXME: It would be nice to include a '...' if the string doesn't fit
+        // in the length limit.
+      } else {
+        Specifier.toString(OS);
+      }
+      return true;
+    }
+
+    if (T->isPointerType()) {
+      // Format all pointers with '%p'.
+      OS << "%p";
+      return true;
+    }
+
+    return false;
+  }
+
+  bool dumpUnnamedRecord(const RecordDecl *RD, Expr *E, unsigned Depth) {
+    Expr *IndentLit = getIndentString(Depth);
+    Expr *TypeLit = getTypeString(S.Context.getCanonicalTagType(RD));
+    if (IndentLit ? callPrintFunction("%s%s", {IndentLit, TypeLit})
+                  : callPrintFunction("%s", {TypeLit}))
+      return true;
+
+    return dumpRecordValue(RD, E, IndentLit, Depth);
+  }
+
+  // Dump a record value. E should be a pointer or lvalue referring to an RD.
+  bool dumpRecordValue(const RecordDecl *RD, Expr *E, Expr *RecordIndent,
+                       unsigned Depth) {
+    // FIXME: Decide what to do if RD is a union. At least we should probably
+    // turn off printing `const char*` members with `%s`, because that is very
+    // likely to crash if that's not the active member. Whatever we decide, we
+    // should document it.
+
+    // Build an OpaqueValueExpr so we can refer to E more than once without
+    // triggering re-evaluation.
+    Expr *RecordArg = makeOpaqueValueExpr(E);
+    bool RecordArgIsPtr = RecordArg->getType()->isPointerType();
+
+    if (callPrintFunction(" {\n"))
+      return true;
+
+    // Dump each base class, regardless of whether they're aggregates.
+    if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+      for (const auto &Base : CXXRD->bases()) {
+        QualType BaseType =
+            RecordArgIsPtr ? S.Context.getPointerType(Base.getType())
+                           : S.Context.getLValueReferenceType(Base.getType());
+        ExprResult BasePtr = S.BuildCStyleCastExpr(
+            Loc, S.Context.getTrivialTypeSourceInfo(BaseType, Loc), Loc,
+            RecordArg);
+        if (BasePtr.isInvalid() ||
+            dumpUnnamedRecord(Base.getType()->getAsRecordDecl(), BasePtr.get(),
+                              Depth + 1))
+          return true;
+      }
+    }
+
+    Expr *FieldIndentArg = getIndentString(Depth + 1);
+
+    // Dump each field.
+    for (auto *D : RD->decls()) {
+      auto *IFD = dyn_cast<IndirectFieldDecl>(D);
+      auto *FD = IFD ? IFD->getAnonField() : dyn_cast<FieldDecl>(D);
+      if (!FD || FD->isUnnamedBitField() || FD->isAnonymousStructOrUnion())
+        continue;
+
+      llvm::SmallString<20> Format = llvm::StringRef("%s%s %s ");
+      llvm::SmallVector<Expr *, 5> Args = {FieldIndentArg,
+                                           getTypeString(FD->getType()),
+                                           getStringLiteral(FD->getName())};
+
+      if (FD->isBitField()) {
+        Format += ": %zu ";
+        QualType SizeT = S.Context.getSizeType();
+        llvm::APInt BitWidth(S.Context.getIntWidth(SizeT),
+                             FD->getBitWidthValue());
+        Args.push_back(IntegerLiteral::Create(S.Context, BitWidth, SizeT, Loc));
+      }
+
+      Format += "=";
+
+      ExprResult Field =
+          IFD ? S.BuildAnonymousStructUnionMemberReference(
+                    CXXScopeSpec(), Loc, IFD,
+                    DeclAccessPair::make(IFD, AS_public), RecordArg, Loc)
+              : S.BuildFieldReferenceExpr(
+                    RecordArg, RecordArgIsPtr, Loc, CXXScopeSpec(), FD,
+                    DeclAccessPair::make(FD, AS_public),
+                    DeclarationNameInfo(FD->getDeclName(), Loc));
+      if (Field.isInvalid())
+        return true;
+
+      auto *InnerRD = FD->getType()->getAsRecordDecl();
+      auto *InnerCXXRD = dyn_cast_or_null<CXXRecordDecl>(InnerRD);
+      if (InnerRD && (!InnerCXXRD || InnerCXXRD->isAggregate())) {
+        // Recursively print the values of members of aggregate record type.
+        if (callPrintFunction(Format, Args) ||
+            dumpRecordValue(InnerRD, Field.get(), FieldIndentArg, Depth + 1))
+          return true;
+      } else {
+        Format += " ";
+        if (appendFormatSpecifier(FD->getType(), Format)) {
+          // We know how to print this field.
+          Args.push_back(Field.get());
+        } else {
+          // We don't know how to print this field. Print out its address
+          // with a format specifier that a smart tool will be able to
+          // recognize and treat specially.
+          Format += "*%p";
+          ExprResult FieldAddr =
+              S.BuildUnaryOp(nullptr, Loc, UO_AddrOf, Field.get());
+          if (FieldAddr.isInvalid())
+            return true;
+          Args.push_back(FieldAddr.get());
+        }
+        Format += "\n";
+        if (callPrintFunction(Format, Args))
+          return true;
+      }
+    }
+
+    return RecordIndent ? callPrintFunction("%s}\n", RecordIndent)
+                        : callPrintFunction("}\n");
+  }
+
+  Expr *buildWrapper() {
+    auto *Wrapper = PseudoObjectExpr::Create(S.Context, TheCall, Actions,
+                                             PseudoObjectExpr::NoResult);
+    TheCall->setType(Wrapper->getType());
+    TheCall->setValueKind(Wrapper->getValueKind());
+    return Wrapper;
+  }
+};
+} // namespace
+
+static ExprResult BuiltinDumpStruct(Sema &S, CallExpr *TheCall) {
+  if (S.checkArgCountAtLeast(TheCall, 2))
+    return ExprError();
+
+  ExprResult PtrArgResult = S.DefaultLvalueConversion(TheCall->getArg(0));
+  if (PtrArgResult.isInvalid())
+    return ExprError();
+  TheCall->setArg(0, PtrArgResult.get());
+
+  // First argument should be a pointer to a struct.
+  QualType PtrArgType = PtrArgResult.get()->getType();
+  if (!PtrArgType->isPointerType() ||
+      !PtrArgType->getPointeeType()->isRecordType()) {
+    S.Diag(PtrArgResult.get()->getBeginLoc(),
+           diag::err_expected_struct_pointer_argument)
+        << 1 << TheCall->getDirectCallee() << PtrArgType;
+    return ExprError();
+  }
+  QualType Pointee = PtrArgType->getPointeeType();
+  const RecordDecl *RD = Pointee->getAsRecordDecl();
+  // Try to instantiate the class template as appropriate; otherwise, access to
+  // its data() may lead to a crash.
+  if (S.RequireCompleteType(PtrArgResult.get()->getBeginLoc(), Pointee,
+                            diag::err_incomplete_type))
+    return ExprError();
+  // Second argument is a callable, but we can't fully validate it until we try
+  // calling it.
+  QualType FnArgType = TheCall->getArg(1)->getType();
+  if (!FnArgType->isFunctionType() && !FnArgType->isFunctionPointerType() &&
+      !FnArgType->isBlockPointerType() &&
+      !(S.getLangOpts().CPlusPlus && FnArgType->isRecordType())) {
+    auto *BT = FnArgType->getAs<BuiltinType>();
+    switch (BT ? BT->getKind() : BuiltinType::Void) {
+    case BuiltinType::Dependent:
+    case BuiltinType::Overload:
+    case BuiltinType::BoundMember:
+    case BuiltinType::PseudoObject:
+    case BuiltinType::UnknownAny:
+    case BuiltinType::BuiltinFn:
+      // This might be a callable.
+      break;
+
+    default:
+      S.Diag(TheCall->getArg(1)->getBeginLoc(),
+             diag::err_expected_callable_argument)
+          << 2 << TheCall->getDirectCallee() << FnArgType;
+      return ExprError();
+    }
+  }
+
+  BuiltinDumpStructGenerator Generator(S, TheCall);
+
+  // Wrap parentheses around the given pointer. This is not necessary for
+  // correct code generation, but it means that when we pretty-print the call
+  // arguments in our diagnostics we will produce '(&s)->n' instead of the
+  // incorrect '&s->n'.
+  Expr *PtrArg = PtrArgResult.get();
+  PtrArg = new (S.Context)
+      ParenExpr(PtrArg->getBeginLoc(),
+                S.getLocForEndOfToken(PtrArg->getEndLoc()), PtrArg);
+  if (Generator.dumpUnnamedRecord(RD, PtrArg, 0))
+    return ExprError();
+
+  return Generator.buildWrapper();
+}
+
+static bool BuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) {
+  if (S.checkArgCount(BuiltinCall, 2))
+    return true;
+
+  SourceLocation BuiltinLoc = BuiltinCall->getBeginLoc();
+  Expr *Builtin = BuiltinCall->getCallee()->IgnoreImpCasts();
+  Expr *Call = BuiltinCall->getArg(0);
+  Expr *Chain = BuiltinCall->getArg(1);
+
+  if (Call->getStmtClass() != Stmt::CallExprClass) {
+    S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_not_call)
+        << Call->getSourceRange();
+    return true;
+  }
+
+  auto CE = cast<CallExpr>(Call);
+  if (CE->getCallee()->getType()->isBlockPointerType()) {
+    S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_block_call)
+        << Call->getSourceRange();
+    return true;
+  }
+
+  const Decl *TargetDecl = CE->getCalleeDecl();
+  if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(TargetDecl))
+    if (FD->getBuiltinID()) {
+      S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_builtin_call)
+          << Call->getSourceRange();
+      return true;
+    }
+
+  if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens())) {
+    S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_pdtor_call)
+        << Call->getSourceRange();
+    return true;
+  }
+
+  ExprResult ChainResult = S.UsualUnaryConversions(Chain);
+  if (ChainResult.isInvalid())
+    return true;
+  if (!ChainResult.get()->getType()->isPointerType()) {
+    S.Diag(BuiltinLoc, diag::err_second_argument_to_cwsc_not_pointer)
+        << Chain->getSourceRange();
+    return true;
+  }
+
+  QualType ReturnTy = CE->getCallReturnType(S.Context);
+  QualType ArgTys[2] = { ReturnTy, ChainResult.get()->getType() };
+  QualType BuiltinTy = S.Context.getFunctionType(
+      ReturnTy, ArgTys, FunctionProtoType::ExtProtoInfo());
+  QualType BuiltinPtrTy = S.Context.getPointerType(BuiltinTy);
+
+  Builtin =
+      S.ImpCastExprToType(Builtin, BuiltinPtrTy, CK_BuiltinFnToFnPtr).get();
+
+  BuiltinCall->setType(CE->getType());
+  BuiltinCall->setValueKind(CE->getValueKind());
+  BuiltinCall->setObjectKind(CE->getObjectKind());
+  BuiltinCall->setCallee(Builtin);
+  BuiltinCall->setArg(1, ChainResult.get());
+
+  return false;
+}
+
+namespace {
+
+class ScanfDiagnosticFormatHandler
+    : public analyze_format_string::FormatStringHandler {
+  // Accepts the argument index (relative to the first destination index) of the
+  // argument whose size we want.
+  using ComputeSizeFunction =
+      llvm::function_ref<std::optional<llvm::APSInt>(unsigned)>;
+
+  // Accepts the argument index (relative to the first destination index), the
+  // destination size, and the source size).
+  using DiagnoseFunction =
+      llvm::function_ref<void(unsigned, unsigned, unsigned)>;
+
+  ComputeSizeFunction ComputeSizeArgument;
+  DiagnoseFunction Diagnose;
+
+public:
+  ScanfDiagnosticFormatHandler(ComputeSizeFunction ComputeSizeArgument,
+                               DiagnoseFunction Diagnose)
+      : ComputeSizeArgument(ComputeSizeArgument), Diagnose(Diagnose) {}
+
+  bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
+                            const char *StartSpecifier,
+                            unsigned specifierLen) override {
+    if (!FS.consumesDataArgument())
+      return true;
+
+    unsigned NulByte = 0;
+    switch ((FS.getConversionSpecifier().getKind())) {
+    default:
+      return true;
+    case analyze_format_string::ConversionSpecifier::sArg:
+    case analyze_format_string::ConversionSpecifier::ScanListArg:
+      NulByte = 1;
+      break;
+    case analyze_format_string::ConversionSpecifier::cArg:
+      break;
+    }
+
+    analyze_format_string::OptionalAmount FW = FS.getFieldWidth();
+    if (FW.getHowSpecified() !=
+        analyze_format_string::OptionalAmount::HowSpecified::Constant)
+      return true;
+
+    unsigned SourceSize = FW.getConstantAmount() + NulByte;
+
+    std::optional<llvm::APSInt> DestSizeAPS =
+        ComputeSizeArgument(FS.getArgIndex());
+    if (!DestSizeAPS)
+      return true;
+
+    unsigned DestSize = DestSizeAPS->getZExtValue();
+
+    if (DestSize < SourceSize)
+      Diagnose(FS.getArgIndex(), DestSize, SourceSize);
+
+    return true;
+  }
+};
+
+class EstimateSizeFormatHandler
+    : public analyze_format_string::FormatStringHandler {
+  size_t Size;
+  /// Whether the format string contains Linux kernel's format specifier
+  /// extension.
+  bool IsKernelCompatible = true;
+
+public:
+  EstimateSizeFormatHandler(StringRef Format)
+      : Size(std::min(Format.find(0), Format.size()) +
+             1 /* null byte always written by sprintf */) {}
+
+  bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
+                             const char *, unsigned SpecifierLen,
+                             const TargetInfo &) override {
+
+    const size_t FieldWidth = computeFieldWidth(FS);
+    const size_t Precision = computePrecision(FS);
+
+    // The actual format.
+    switch (FS.getConversionSpecifier().getKind()) {
+    // Just a char.
+    case analyze_format_string::ConversionSpecifier::cArg:
+    case analyze_format_string::ConversionSpecifier::CArg:
+      Size += std::max(FieldWidth, (size_t)1);
+      break;
+    // Just an integer.
+    case analyze_format_string::ConversionSpecifier::dArg:
+    case analyze_format_string::ConversionSpecifier::DArg:
+    case analyze_format_string::ConversionSpecifier::iArg:
+    case analyze_format_string::ConversionSpecifier::oArg:
+    case analyze_format_string::ConversionSpecifier::OArg:
+    case analyze_format_string::ConversionSpecifier::uArg:
+    case analyze_format_string::ConversionSpecifier::UArg:
+    case analyze_format_string::ConversionSpecifier::xArg:
+    case analyze_format_string::ConversionSpecifier::XArg:
+      Size += std::max(FieldWidth, Precision);
+      break;
+
+    // %g style conversion switches between %f or %e style dynamically.
+    // %g removes trailing zeros, and does not print decimal point if there are
+    // no digits that follow it. Thus %g can print a single digit.
+    // FIXME: If it is alternative form:
+    // For g and G conversions, trailing zeros are not removed from the result.
+    case analyze_format_string::ConversionSpecifier::gArg:
+    case analyze_format_string::ConversionSpecifier::GArg:
+      Size += 1;
+      break;
+
+    // Floating point number in the form '[+]ddd.ddd'.
+    case analyze_format_string::ConversionSpecifier::fArg:
+    case analyze_format_string::ConversionSpecifier::FArg:
+      Size += std::max(FieldWidth, 1 /* integer part */ +
+                                       (Precision ? 1 + Precision
+                                                  : 0) /* period + decimal */);
+      break;
+
+    // Floating point number in the form '[-]d.ddde[+-]dd'.
+    case analyze_format_string::ConversionSpecifier::eArg:
+    case analyze_format_string::ConversionSpecifier::EArg:
+      Size +=
+          std::max(FieldWidth,
+                   1 /* integer part */ +
+                       (Precision ? 1 + Precision : 0) /* period + decimal */ +
+                       1 /* e or E letter */ + 2 /* exponent */);
+      break;
+
+    // Floating point number in the form '[-]0xh.hhhhp±dd'.
+    case analyze_format_string::ConversionSpecifier::aArg:
+    case analyze_format_string::ConversionSpecifier::AArg:
+      Size +=
+          std::max(FieldWidth,
+                   2 /* 0x */ + 1 /* integer part */ +
+                       (Precision ? 1 + Precision : 0) /* period + decimal */ +
+                       1 /* p or P letter */ + 1 /* + or - */ + 1 /* value */);
+      break;
+
+    // Just a string.
+    case analyze_format_string::ConversionSpecifier::sArg:
+    case analyze_format_string::ConversionSpecifier::SArg:
+      Size += FieldWidth;
+      break;
+
+    // Just a pointer in the form '0xddd'.
+    case analyze_format_string::ConversionSpecifier::pArg:
+      // Linux kernel has its own extesion for `%p` specifier.
+      // Kernel Document:
+      // https://docs.kernel.org/core-api/printk-formats.html#pointer-types
+      IsKernelCompatible = false;
+      Size += std::max(FieldWidth, 2 /* leading 0x */ + Precision);
+      break;
+
+    // A plain percent.
+    case analyze_format_string::ConversionSpecifier::PercentArg:
+      Size += 1;
+      break;
+
+    default:
+      break;
+    }
+
+    // If field width is specified, the sign/space is already accounted for
+    // within the field width, so no additional size is needed.
+    if ((FS.hasPlusPrefix() || FS.hasSpacePrefix()) && FieldWidth == 0)
+      Size += 1;
+
+    if (FS.hasAlternativeForm()) {
+      switch (FS.getConversionSpecifier().getKind()) {
+      // For o conversion, it increases the precision, if and only if necessary,
+      // to force the first digit of the result to be a zero
+      // (if the value and precision are both 0, a single 0 is printed)
+      case analyze_format_string::ConversionSpecifier::oArg:
+      // For b conversion, a nonzero result has 0b prefixed to it.
+      case analyze_format_string::ConversionSpecifier::bArg:
+      // For x (or X) conversion, a nonzero result has 0x (or 0X) prefixed to
+      // it.
+      case analyze_format_string::ConversionSpecifier::xArg:
+      case analyze_format_string::ConversionSpecifier::XArg:
+        // Note: even when the prefix is added, if
+        // (prefix_width <= FieldWidth - formatted_length) holds,
+        // the prefix does not increase the format
+        // size. e.g.(("%#3x", 0xf) is "0xf")
+
+        // If the result is zero, o, b, x, X adds nothing.
+        break;
+      // For a, A, e, E, f, F, g, and G conversions,
+      // the result of converting a floating-point number always contains a
+      // decimal-point
+      case analyze_format_string::ConversionSpecifier::aArg:
+      case analyze_format_string::ConversionSpecifier::AArg:
+      case analyze_format_string::ConversionSpecifier::eArg:
+      case analyze_format_string::ConversionSpecifier::EArg:
+      case analyze_format_string::ConversionSpecifier::fArg:
+      case analyze_format_string::ConversionSpecifier::FArg:
+      case analyze_format_string::ConversionSpecifier::gArg:
+      case analyze_format_string::ConversionSpecifier::GArg:
+        Size += (Precision ? 0 : 1);
+        break;
+      // For other conversions, the behavior is undefined.
+      default:
+        break;
+      }
+    }
+    assert(SpecifierLen <= Size && "no underflow");
+    Size -= SpecifierLen;
+    return true;
+  }
+
+  size_t getSizeLowerBound() const { return Size; }
+  bool isKernelCompatible() const { return IsKernelCompatible; }
+
+private:
+  static size_t computeFieldWidth(const analyze_printf::PrintfSpecifier &FS) {
+    const analyze_format_string::OptionalAmount &FW = FS.getFieldWidth();
+    size_t FieldWidth = 0;
+    if (FW.getHowSpecified() == analyze_format_string::OptionalAmount::Constant)
+      FieldWidth = FW.getConstantAmount();
+    return FieldWidth;
+  }
+
+  static size_t computePrecision(const analyze_printf::PrintfSpecifier &FS) {
+    const analyze_format_string::OptionalAmount &FW = FS.getPrecision();
+    size_t Precision = 0;
+
+    // See man 3 printf for default precision value based on the specifier.
+    switch (FW.getHowSpecified()) {
+    case analyze_format_string::OptionalAmount::NotSpecified:
+      switch (FS.getConversionSpecifier().getKind()) {
+      default:
+        break;
+      case analyze_format_string::ConversionSpecifier::dArg: // %d
+      case analyze_format_string::ConversionSpecifier::DArg: // %D
+      case analyze_format_string::ConversionSpecifier::iArg: // %i
+        Precision = 1;
+        break;
+      case analyze_format_string::ConversionSpecifier::oArg: // %d
+      case analyze_format_string::ConversionSpecifier::OArg: // %D
+      case analyze_format_string::ConversionSpecifier::uArg: // %d
+      case analyze_format_string::ConversionSpecifier::UArg: // %D
+      case analyze_format_string::ConversionSpecifier::xArg: // %d
+      case analyze_format_string::ConversionSpecifier::XArg: // %D
+        Precision = 1;
+        break;
+      case analyze_format_string::ConversionSpecifier::fArg: // %f
+      case analyze_format_string::ConversionSpecifier::FArg: // %F
+      case analyze_format_string::ConversionSpecifier::eArg: // %e
+      case analyze_format_string::ConversionSpecifier::EArg: // %E
+      case analyze_format_string::ConversionSpecifier::gArg: // %g
+      case analyze_format_string::ConversionSpecifier::GArg: // %G
+        Precision = 6;
+        break;
+      case analyze_format_string::ConversionSpecifier::pArg: // %d
+        Precision = 1;
+        break;
+      }
+      break;
+    case analyze_format_string::OptionalAmount::Constant:
+      Precision = FW.getConstantAmount();
+      break;
+    default:
+      break;
+    }
+    return Precision;
+  }
+};
+
+} // namespace
+
+static bool ProcessFormatStringLiteral(const Expr *FormatExpr,
+                                       StringRef &FormatStrRef, size_t &StrLen,
+                                       ASTContext &Context) {
+  if (const auto *Format = dyn_cast<StringLiteral>(FormatExpr);
+      Format && (Format->isOrdinary() || Format->isUTF8())) {
+    FormatStrRef = Format->getString();
+    const ConstantArrayType *T =
+        Context.getAsConstantArrayType(Format->getType());
+    assert(T && "String literal not of constant array type!");
+    size_t TypeSize = T->getZExtSize();
+    // In case there's a null byte somewhere.
+    StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, FormatStrRef.find(0));
+    return true;
+  }
+  return false;
+}
+
+void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
+                                               CallExpr *TheCall) {
+  if (TheCall->isValueDependent() || TheCall->isTypeDependent() ||
+      isConstantEvaluatedContext())
+    return;
+
+  bool UseDABAttr = false;
+  const FunctionDecl *UseDecl = FD;
+
+  const auto *DABAttr = FD->getAttr<DiagnoseAsBuiltinAttr>();
+  if (DABAttr) {
+    UseDecl = DABAttr->getFunction();
+    assert(UseDecl && "Missing FunctionDecl in DiagnoseAsBuiltin attribute!");
+    UseDABAttr = true;
+  }
+
+  unsigned BuiltinID = UseDecl->getBuiltinID(/*ConsiderWrappers=*/true);
+
+  if (!BuiltinID)
+    return;
+
+  const TargetInfo &TI = getASTContext().getTargetInfo();
+  unsigned SizeTypeWidth = TI.getTypeWidth(TI.getSizeType());
+
+  auto TranslateIndex = [&](unsigned Index) -> std::optional<unsigned> {
+    // If we refer to a diagnose_as_builtin attribute, we need to change the
+    // argument index to refer to the arguments of the called function. Unless
+    // the index is out of bounds, which presumably means it's a variadic
+    // function.
+    if (!UseDABAttr)
+      return Index;
+    unsigned DABIndices = DABAttr->argIndices_size();
+    unsigned NewIndex = Index < DABIndices
+                            ? DABAttr->argIndices_begin()[Index]
+                            : Index - DABIndices + FD->getNumParams();
+    if (NewIndex >= TheCall->getNumArgs())
+      return std::nullopt;
+    return NewIndex;
+  };
+
+  auto ComputeExplicitObjectSizeArgument =
+      [&](unsigned Index) -> std::optional<llvm::APSInt> {
+    std::optional<unsigned> IndexOptional = TranslateIndex(Index);
+    if (!IndexOptional)
+      return std::nullopt;
+    unsigned NewIndex = *IndexOptional;
+    Expr::EvalResult Result;
+    Expr *SizeArg = TheCall->getArg(NewIndex);
+    if (!SizeArg->EvaluateAsInt(Result, getASTContext()))
+      return std::nullopt;
+    llvm::APSInt Integer = Result.Val.getInt();
+    Integer.setIsUnsigned(true);
+    return Integer;
+  };
+
+  auto ComputeSizeArgument =
+      [&](unsigned Index) -> std::optional<llvm::APSInt> {
+    // If the parameter has a pass_object_size attribute, then we should use its
+    // (potentially) more strict checking mode. Otherwise, conservatively assume
+    // type 0.
+    int BOSType = 0;
+    // This check can fail for variadic functions.
+    if (Index < FD->getNumParams()) {
+      if (const auto *POS =
+              FD->getParamDecl(Index)->getAttr<PassObjectSizeAttr>())
+        BOSType = POS->getType();
+    }
+
+    std::optional<unsigned> IndexOptional = TranslateIndex(Index);
+    if (!IndexOptional)
+      return std::nullopt;
+    unsigned NewIndex = *IndexOptional;
+
+    if (NewIndex >= TheCall->getNumArgs())
+      return std::nullopt;
+
+    const Expr *ObjArg = TheCall->getArg(NewIndex);
+    if (std::optional<uint64_t> ObjSize =
+            ObjArg->tryEvaluateObjectSize(getASTContext(), BOSType)) {
+      // Get the object size in the target's size_t width.
+      return llvm::APSInt::getUnsigned(*ObjSize).extOrTrunc(SizeTypeWidth);
+    }
+    return std::nullopt;
+  };
+
+  auto ComputeStrLenArgument =
+      [&](unsigned Index) -> std::optional<llvm::APSInt> {
+    std::optional<unsigned> IndexOptional = TranslateIndex(Index);
+    if (!IndexOptional)
+      return std::nullopt;
+    unsigned NewIndex = *IndexOptional;
+
+    const Expr *ObjArg = TheCall->getArg(NewIndex);
+
+    if (std::optional<uint64_t> Result =
+            ObjArg->tryEvaluateStrLen(getASTContext())) {
+      // Add 1 for null byte.
+      return llvm::APSInt::getUnsigned(*Result + 1).extOrTrunc(SizeTypeWidth);
+    }
+    return std::nullopt;
+  };
+
+  std::optional<llvm::APSInt> SourceSize;
+  std::optional<llvm::APSInt> DestinationSize;
+  unsigned DiagID = 0;
+  bool IsChkVariant = false;
+
+  auto GetFunctionName = [&]() {
+    std::string FunctionNameStr =
+        getASTContext().BuiltinInfo.getName(BuiltinID);
+    llvm::StringRef FunctionName = FunctionNameStr;
+    // Skim off the details of whichever builtin was called to produce a better
+    // diagnostic, as it's unlikely that the user wrote the __builtin
+    // explicitly.
+    if (IsChkVariant) {
+      FunctionName = FunctionName.drop_front(std::strlen("__builtin___"));
+      FunctionName = FunctionName.drop_back(std::strlen("_chk"));
+    } else {
+      FunctionName.consume_front("__builtin_");
+    }
+    return FunctionName.str();
+  };
+
+  switch (BuiltinID) {
+  default:
+    return;
+  case Builtin::BI__builtin_strcat:
+  case Builtin::BIstrcat:
+  case Builtin::BI__builtin_stpcpy:
+  case Builtin::BIstpcpy:
+  case Builtin::BI__builtin_strcpy:
+  case Builtin::BIstrcpy: {
+    DiagID = diag::warn_fortify_strlen_overflow;
+    SourceSize = ComputeStrLenArgument(1);
+    DestinationSize = ComputeSizeArgument(0);
+    break;
+  }
+
+  case Builtin::BI__builtin___strcat_chk:
+  case Builtin::BI__builtin___stpcpy_chk:
+  case Builtin::BI__builtin___strcpy_chk: {
+    DiagID = diag::warn_fortify_strlen_overflow;
+    SourceSize = ComputeStrLenArgument(1);
+    DestinationSize = ComputeExplicitObjectSizeArgument(2);
+    IsChkVariant = true;
+    break;
+  }
+
+  case Builtin::BIscanf:
+  case Builtin::BIfscanf:
+  case Builtin::BIsscanf: {
+    unsigned FormatIndex = 1;
+    unsigned DataIndex = 2;
+    if (BuiltinID == Builtin::BIscanf) {
+      FormatIndex = 0;
+      DataIndex = 1;
+    }
+
+    const auto *FormatExpr =
+        TheCall->getArg(FormatIndex)->IgnoreParenImpCasts();
+
+    StringRef FormatStrRef;
+    size_t StrLen;
+    if (!ProcessFormatStringLiteral(FormatExpr, FormatStrRef, StrLen, Context))
+      return;
+
+    auto Diagnose = [&](unsigned ArgIndex, unsigned DestSize,
+                        unsigned SourceSize) {
+      DiagID = diag::warn_fortify_scanf_overflow;
+      unsigned Index = ArgIndex + DataIndex;
+      std::string FunctionName = GetFunctionName();
+      DiagRuntimeBehavior(TheCall->getArg(Index)->getBeginLoc(), TheCall,
+                          PDiag(DiagID) << FunctionName << (Index + 1)
+                                        << DestSize << SourceSize);
+    };
+
+    auto ShiftedComputeSizeArgument = [&](unsigned Index) {
+      return ComputeSizeArgument(Index + DataIndex);
+    };
+    ScanfDiagnosticFormatHandler H(ShiftedComputeSizeArgument, Diagnose);
+    const char *FormatBytes = FormatStrRef.data();
+    analyze_format_string::ParseScanfString(H, FormatBytes,
+                                            FormatBytes + StrLen, getLangOpts(),
+                                            Context.getTargetInfo());
+
+    // Unlike the other cases, in this one we have already issued the diagnostic
+    // here, so no need to continue (because unlike the other cases, here the
+    // diagnostic refers to the argument number).
+    return;
+  }
+
+  case Builtin::BIsprintf:
+  case Builtin::BI__builtin___sprintf_chk: {
+    size_t FormatIndex = BuiltinID == Builtin::BIsprintf ? 1 : 3;
+    auto *FormatExpr = TheCall->getArg(FormatIndex)->IgnoreParenImpCasts();
+
+    StringRef FormatStrRef;
+    size_t StrLen;
+    if (ProcessFormatStringLiteral(FormatExpr, FormatStrRef, StrLen, Context)) {
+      EstimateSizeFormatHandler H(FormatStrRef);
+      const char *FormatBytes = FormatStrRef.data();
+      if (!analyze_format_string::ParsePrintfString(
+              H, FormatBytes, FormatBytes + StrLen, getLangOpts(),
+              Context.getTargetInfo(), false)) {
+        DiagID = H.isKernelCompatible()
+                     ? diag::warn_format_overflow
+                     : diag::warn_format_overflow_non_kprintf;
+        SourceSize = llvm::APSInt::getUnsigned(H.getSizeLowerBound())
+                         .extOrTrunc(SizeTypeWidth);
+        if (BuiltinID == Builtin::BI__builtin___sprintf_chk) {
+          DestinationSize = ComputeExplicitObjectSizeArgument(2);
+          IsChkVariant = true;
+        } else {
+          DestinationSize = ComputeSizeArgument(0);
+        }
+        break;
+      }
+    }
+    return;
+  }
+  case Builtin::BI__builtin___memcpy_chk:
+  case Builtin::BI__builtin___memmove_chk:
+  case Builtin::BI__builtin___memset_chk:
+  case Builtin::BI__builtin___strlcat_chk:
+  case Builtin::BI__builtin___strlcpy_chk:
+  case Builtin::BI__builtin___strncat_chk:
+  case Builtin::BI__builtin___strncpy_chk:
+  case Builtin::BI__builtin___stpncpy_chk:
+  case Builtin::BI__builtin___memccpy_chk:
+  case Builtin::BI__builtin___mempcpy_chk: {
+    DiagID = diag::warn_builtin_chk_overflow;
+    SourceSize = ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 2);
+    DestinationSize =
+        ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1);
+    IsChkVariant = true;
+    break;
+  }
+
+  case Builtin::BI__builtin___snprintf_chk:
+  case Builtin::BI__builtin___vsnprintf_chk: {
+    DiagID = diag::warn_builtin_chk_overflow;
+    SourceSize = ComputeExplicitObjectSizeArgument(1);
+    DestinationSize = ComputeExplicitObjectSizeArgument(3);
+    IsChkVariant = true;
+    break;
+  }
+
+  case Builtin::BIstrncat:
+  case Builtin::BI__builtin_strncat:
+  case Builtin::BIstrncpy:
+  case Builtin::BI__builtin_strncpy:
+  case Builtin::BIstpncpy:
+  case Builtin::BI__builtin_stpncpy: {
+    // Whether these functions overflow depends on the runtime strlen of the
+    // string, not just the buffer size, so emitting the "always overflow"
+    // diagnostic isn't quite right. We should still diagnose passing a buffer
+    // size larger than the destination buffer though; this is a runtime abort
+    // in _FORTIFY_SOURCE mode, and is quite suspicious otherwise.
+    DiagID = diag::warn_fortify_source_size_mismatch;
+    SourceSize = ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1);
+    DestinationSize = ComputeSizeArgument(0);
+    break;
+  }
+
+  case Builtin::BImemcpy:
+  case Builtin::BI__builtin_memcpy:
+  case Builtin::BImemmove:
+  case Builtin::BI__builtin_memmove:
+  case Builtin::BImemset:
+  case Builtin::BI__builtin_memset:
+  case Builtin::BImempcpy:
+  case Builtin::BI__builtin_mempcpy: {
+    DiagID = diag::warn_fortify_source_overflow;
+    SourceSize = ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1);
+    DestinationSize = ComputeSizeArgument(0);
+    break;
+  }
+  case Builtin::BIsnprintf:
+  case Builtin::BI__builtin_snprintf:
+  case Builtin::BIvsnprintf:
+  case Builtin::BI__builtin_vsnprintf: {
+    DiagID = diag::warn_fortify_source_size_mismatch;
+    SourceSize = ComputeExplicitObjectSizeArgument(1);
+    const auto *FormatExpr = TheCall->getArg(2)->IgnoreParenImpCasts();
+    StringRef FormatStrRef;
+    size_t StrLen;
+    if (SourceSize &&
+        ProcessFormatStringLiteral(FormatExpr, FormatStrRef, StrLen, Context)) {
+      EstimateSizeFormatHandler H(FormatStrRef);
+      const char *FormatBytes = FormatStrRef.data();
+      if (!analyze_format_string::ParsePrintfString(
+              H, FormatBytes, FormatBytes + StrLen, getLangOpts(),
+              Context.getTargetInfo(), /*isFreeBSDKPrintf=*/false)) {
+        llvm::APSInt FormatSize =
+            llvm::APSInt::getUnsigned(H.getSizeLowerBound())
+                .extOrTrunc(SizeTypeWidth);
+        if (FormatSize > *SourceSize && *SourceSize != 0) {
+          unsigned TruncationDiagID =
+              H.isKernelCompatible() ? diag::warn_format_truncation
+                                     : diag::warn_format_truncation_non_kprintf;
+          SmallString<16> SpecifiedSizeStr;
+          SmallString<16> FormatSizeStr;
+          SourceSize->toString(SpecifiedSizeStr, /*Radix=*/10);
+          FormatSize.toString(FormatSizeStr, /*Radix=*/10);
+          DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall,
+                              PDiag(TruncationDiagID)
+                                  << GetFunctionName() << SpecifiedSizeStr
+                                  << FormatSizeStr);
+        }
+      }
+    }
+    DestinationSize = ComputeSizeArgument(0);
+  }
+  }
+
+  if (!SourceSize || !DestinationSize ||
+      llvm::APSInt::compareValues(*SourceSize, *DestinationSize) <= 0)
+    return;
+
+  std::string FunctionName = GetFunctionName();
+
+  SmallString<16> DestinationStr;
+  SmallString<16> SourceStr;
+  DestinationSize->toString(DestinationStr, /*Radix=*/10);
+  SourceSize->toString(SourceStr, /*Radix=*/10);
+  DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall,
+                      PDiag(DiagID)
+                          << FunctionName << DestinationStr << SourceStr);
+}
+
+static bool BuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall,
+                                 Scope::ScopeFlags NeededScopeFlags,
+                                 unsigned DiagID) {
+  // Scopes aren't available during instantiation. Fortunately, builtin
+  // functions cannot be template args so they cannot be formed through template
+  // instantiation. Therefore checking once during the parse is sufficient.
+  if (SemaRef.inTemplateInstantiation())
+    return false;
+
+  Scope *S = SemaRef.getCurScope();
+  while (S && !S->isSEHExceptScope())
+    S = S->getParent();
+  if (!S || !(S->getFlags() & NeededScopeFlags)) {
+    auto *DRE = cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+    SemaRef.Diag(TheCall->getExprLoc(), DiagID)
+        << DRE->getDecl()->getIdentifier();
+    return true;
+  }
+
+  return false;
+}
+
+// In OpenCL, __builtin_alloca_* should return a pointer to address space
+// that corresponds to the stack address space i.e private address space.
+static void builtinAllocaAddrSpace(Sema &S, CallExpr *TheCall) {
+  QualType RT = TheCall->getType();
+  assert((RT->isPointerType() && !(RT->getPointeeType().hasAddressSpace())) &&
+         "__builtin_alloca has invalid address space");
+
+  RT = RT->getPointeeType();
+  RT = S.Context.getAddrSpaceQualType(RT, LangAS::opencl_private);
+  TheCall->setType(S.Context.getPointerType(RT));
+}
+
+static bool checkBuiltinInferAllocToken(Sema &S, CallExpr *TheCall) {
+  if (S.checkArgCountAtLeast(TheCall, 1))
+    return true;
+
+  for (Expr *Arg : TheCall->arguments()) {
+    // If argument is dependent on a template parameter, we can't resolve now.
+    if (Arg->isTypeDependent() || Arg->isValueDependent())
+      continue;
+    // Reject void types.
+    QualType ArgTy = Arg->IgnoreParenImpCasts()->getType();
+    if (ArgTy->isVoidType())
+      return S.Diag(Arg->getBeginLoc(), diag::err_param_with_void_type);
+  }
+
+  TheCall->setType(S.Context.getSizeType());
+  return false;
+}
+
+namespace {
+enum PointerAuthOpKind {
+  PAO_Strip,
+  PAO_Sign,
+  PAO_Auth,
+  PAO_SignGeneric,
+  PAO_Discriminator,
+  PAO_BlendPointer,
+  PAO_BlendInteger
+};
+}
+
+bool Sema::checkPointerAuthEnabled(SourceLocation Loc, SourceRange Range) {
+  if (getLangOpts().PointerAuthIntrinsics)
+    return false;
+
+  Diag(Loc, diag::err_ptrauth_disabled) << Range;
+  return true;
+}
+
+static bool checkPointerAuthEnabled(Sema &S, Expr *E) {
+  return S.checkPointerAuthEnabled(E->getExprLoc(), E->getSourceRange());
+}
+
+static bool checkPointerAuthKey(Sema &S, Expr *&Arg) {
+  // Convert it to type 'int'.
+  if (convertArgumentToType(S, Arg, S.Context.IntTy))
+    return true;
+
+  // Value-dependent expressions are okay; wait for template instantiation.
+  if (Arg->isValueDependent())
+    return false;
+
+  unsigned KeyValue;
+  return S.checkConstantPointerAuthKey(Arg, KeyValue);
+}
+
+bool Sema::checkConstantPointerAuthKey(Expr *Arg, unsigned &Result) {
+  // Attempt to constant-evaluate the expression.
+  std::optional<llvm::APSInt> KeyValue = Arg->getIntegerConstantExpr(Context);
+  if (!KeyValue) {
+    Diag(Arg->getExprLoc(), diag::err_expr_not_ice)
+        << 0 << Arg->getSourceRange();
+    return true;
+  }
+
+  // Ask the target to validate the key parameter.
+  if (!Context.getTargetInfo().validatePointerAuthKey(*KeyValue)) {
+    llvm::SmallString<32> Value;
+    {
+      llvm::raw_svector_ostream Str(Value);
+      Str << *KeyValue;
+    }
+
+    Diag(Arg->getExprLoc(), diag::err_ptrauth_invalid_key)
+        << Value << Arg->getSourceRange();
+    return true;
+  }
+
+  Result = KeyValue->getZExtValue();
+  return false;
+}
+
+bool Sema::checkPointerAuthDiscriminatorArg(Expr *Arg,
+                                            PointerAuthDiscArgKind Kind,
+                                            unsigned &IntVal) {
+  if (!Arg) {
+    IntVal = 0;
+    return true;
+  }
+
+  std::optional<llvm::APSInt> Result = Arg->getIntegerConstantExpr(Context);
+  if (!Result) {
+    Diag(Arg->getExprLoc(), diag::err_ptrauth_arg_not_ice);
+    return false;
+  }
+
+  unsigned Max;
+  bool IsAddrDiscArg = false;
+
+  switch (Kind) {
+  case PointerAuthDiscArgKind::Addr:
+    Max = 1;
+    IsAddrDiscArg = true;
+    break;
+  case PointerAuthDiscArgKind::Extra:
+    Max = PointerAuthQualifier::MaxDiscriminator;
+    break;
+  };
+
+  if (*Result < 0 || *Result > Max) {
+    if (IsAddrDiscArg)
+      Diag(Arg->getExprLoc(), diag::err_ptrauth_address_discrimination_invalid)
+          << Result->getExtValue();
+    else
+      Diag(Arg->getExprLoc(), diag::err_ptrauth_extra_discriminator_invalid)
+          << Result->getExtValue() << Max;
+
+    return false;
+  };
+
+  IntVal = Result->getZExtValue();
+  return true;
+}
+
+static std::pair<const ValueDecl *, CharUnits>
+findConstantBaseAndOffset(Sema &S, Expr *E) {
+  // Must evaluate as a pointer.
+  Expr::EvalResult Result;
+  if (!E->EvaluateAsRValue(Result, S.Context) || !Result.Val.isLValue())
+    return {nullptr, CharUnits()};
+
+  const auto *BaseDecl =
+      Result.Val.getLValueBase().dyn_cast<const ValueDecl *>();
+  if (!BaseDecl)
+    return {nullptr, CharUnits()};
+
+  return {BaseDecl, Result.Val.getLValueOffset()};
+}
+
+static bool checkPointerAuthValue(Sema &S, Expr *&Arg, PointerAuthOpKind OpKind,
+                                  bool RequireConstant = false) {
+  if (Arg->hasPlaceholderType()) {
+    ExprResult R = S.CheckPlaceholderExpr(Arg);
+    if (R.isInvalid())
+      return true;
+    Arg = R.get();
+  }
+
+  auto AllowsPointer = [](PointerAuthOpKind OpKind) {
+    return OpKind != PAO_BlendInteger;
+  };
+  auto AllowsInteger = [](PointerAuthOpKind OpKind) {
+    return OpKind == PAO_Discriminator || OpKind == PAO_BlendInteger ||
+           OpKind == PAO_SignGeneric;
+  };
+
+  // Require the value to have the right range of type.
+  QualType ExpectedTy;
+  if (AllowsPointer(OpKind) && Arg->getType()->isPointerType()) {
+    ExpectedTy = Arg->getType().getUnqualifiedType();
+  } else if (AllowsPointer(OpKind) && Arg->getType()->isNullPtrType()) {
+    ExpectedTy = S.Context.VoidPtrTy;
+  } else if (AllowsInteger(OpKind) &&
+             Arg->getType()->isIntegralOrUnscopedEnumerationType()) {
+    ExpectedTy = S.Context.getUIntPtrType();
+
+  } else {
+    // Diagnose the failures.
+    S.Diag(Arg->getExprLoc(), diag::err_ptrauth_value_bad_type)
+        << unsigned(OpKind == PAO_Discriminator  ? 1
+                    : OpKind == PAO_BlendPointer ? 2
+                    : OpKind == PAO_BlendInteger ? 3
+                                                 : 0)
+        << unsigned(AllowsInteger(OpKind) ? (AllowsPointer(OpKind) ? 2 : 1) : 0)
+        << Arg->getType() << Arg->getSourceRange();
+    return true;
+  }
+
+  // Convert to that type.  This should just be an lvalue-to-rvalue
+  // conversion.
+  if (convertArgumentToType(S, Arg, ExpectedTy))
+    return true;
+
+  if (!RequireConstant) {
+    // Warn about null pointers for non-generic sign and auth operations.
+    if ((OpKind == PAO_Sign || OpKind == PAO_Auth) &&
+        Arg->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull)) {
+      S.Diag(Arg->getExprLoc(), OpKind == PAO_Sign
+                                    ? diag::warn_ptrauth_sign_null_pointer
+                                    : diag::warn_ptrauth_auth_null_pointer)
+          << Arg->getSourceRange();
+    }
+
+    return false;
+  }
+
+  // Perform special checking on the arguments to ptrauth_sign_constant.
+
+  // The main argument.
+  if (OpKind == PAO_Sign) {
+    // Require the value we're signing to have a special form.
+    auto [BaseDecl, Offset] = findConstantBaseAndOffset(S, Arg);
+    bool Invalid;
+
+    // Must be rooted in a declaration reference.
+    if (!BaseDecl)
+      Invalid = true;
+
+    // If it's a function declaration, we can't have an offset.
+    else if (isa<FunctionDecl>(BaseDecl))
+      Invalid = !Offset.isZero();
+
+    // Otherwise we're fine.
+    else
+      Invalid = false;
+
+    if (Invalid)
+      S.Diag(Arg->getExprLoc(), diag::err_ptrauth_bad_constant_pointer);
+    return Invalid;
+  }
+
+  // The discriminator argument.
+  assert(OpKind == PAO_Discriminator);
+
+  // Must be a pointer or integer or blend thereof.
+  Expr *Pointer = nullptr;
+  Expr *Integer = nullptr;
+  if (auto *Call = dyn_cast<CallExpr>(Arg->IgnoreParens())) {
+    if (Call->getBuiltinCallee() ==
+        Builtin::BI__builtin_ptrauth_blend_discriminator) {
+      Pointer = Call->getArg(0);
+      Integer = Call->getArg(1);
+    }
+  }
+  if (!Pointer && !Integer) {
+    if (Arg->getType()->isPointerType())
+      Pointer = Arg;
+    else
+      Integer = Arg;
+  }
+
+  // Check the pointer.
+  bool Invalid = false;
+  if (Pointer) {
+    assert(Pointer->getType()->isPointerType());
+
+    // TODO: if we're initializing a global, check that the address is
+    // somehow related to what we're initializing.  This probably will
+    // never really be feasible and we'll have to catch it at link-time.
+    auto [BaseDecl, Offset] = findConstantBaseAndOffset(S, Pointer);
+    if (!BaseDecl || !isa<VarDecl>(BaseDecl))
+      Invalid = true;
+  }
+
+  // Check the integer.
+  if (Integer) {
+    assert(Integer->getType()->isIntegerType());
+    if (!Integer->isEvaluatable(S.Context))
+      Invalid = true;
+  }
+
+  if (Invalid)
+    S.Diag(Arg->getExprLoc(), diag::err_ptrauth_bad_constant_discriminator);
+  return Invalid;
+}
+
+static ExprResult PointerAuthStrip(Sema &S, CallExpr *Call) {
+  if (S.checkArgCount(Call, 2))
+    return ExprError();
+  if (checkPointerAuthEnabled(S, Call))
+    return ExprError();
+  if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_Strip) ||
+      checkPointerAuthKey(S, Call->getArgs()[1]))
+    return ExprError();
+
+  Call->setType(Call->getArgs()[0]->getType());
+  return Call;
+}
+
+static ExprResult PointerAuthBlendDiscriminator(Sema &S, CallExpr *Call) {
+  if (S.checkArgCount(Call, 2))
+    return ExprError();
+  if (checkPointerAuthEnabled(S, Call))
+    return ExprError();
+  if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_BlendPointer) ||
+      checkPointerAuthValue(S, Call->getArgs()[1], PAO_BlendInteger))
+    return ExprError();
+
+  Call->setType(S.Context.getUIntPtrType());
+  return Call;
+}
+
+static ExprResult PointerAuthSignGenericData(Sema &S, CallExpr *Call) {
+  if (S.checkArgCount(Call, 2))
+    return ExprError();
+  if (checkPointerAuthEnabled(S, Call))
+    return ExprError();
+  if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_SignGeneric) ||
+      checkPointerAuthValue(S, Call->getArgs()[1], PAO_Discriminator))
+    return ExprError();
+
+  Call->setType(S.Context.getUIntPtrType());
+  return Call;
+}
+
+static ExprResult PointerAuthSignOrAuth(Sema &S, CallExpr *Call,
+                                        PointerAuthOpKind OpKind,
+                                        bool RequireConstant) {
+  if (S.checkArgCount(Call, 3))
+    return ExprError();
+  if (checkPointerAuthEnabled(S, Call))
+    return ExprError();
+  if (checkPointerAuthValue(S, Call->getArgs()[0], OpKind, RequireConstant) ||
+      checkPointerAuthKey(S, Call->getArgs()[1]) ||
+      checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator,
+                            RequireConstant))
+    return ExprError();
+
+  Call->setType(Call->getArgs()[0]->getType());
+  return Call;
+}
+
+static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) {
+  if (S.checkArgCount(Call, 5))
+    return ExprError();
+  if (checkPointerAuthEnabled(S, Call))
+    return ExprError();
+  if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_Auth) ||
+      checkPointerAuthKey(S, Call->getArgs()[1]) ||
+      checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator) ||
+      checkPointerAuthKey(S, Call->getArgs()[3]) ||
+      checkPointerAuthValue(S, Call->getArgs()[4], PAO_Discriminator))
+    return ExprError();
+
+  Call->setType(Call->getArgs()[0]->getType());
+  return Call;
+}
+
+static ExprResult PointerAuthAuthLoadRelativeAndSign(Sema &S, CallExpr *Call) {
+  if (S.checkArgCount(Call, 6))
+    return ExprError();
+  if (checkPointerAuthEnabled(S, Call))
+    return ExprError();
+  const Expr *AddendExpr = Call->getArg(5);
+  bool AddendIsConstInt = AddendExpr->isIntegerConstantExpr(S.Context);
+  if (!AddendIsConstInt) {
+    const Expr *Arg = Call->getArg(5)->IgnoreParenImpCasts();
+    DeclRefExpr *DRE = cast<DeclRefExpr>(Call->getCallee()->IgnoreParenCasts());
+    FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl());
+    S.Diag(Arg->getBeginLoc(), diag::err_constant_integer_last_arg_type)
+        << FDecl->getDeclName() << Arg->getSourceRange();
+  }
+  if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_Auth) ||
+      checkPointerAuthKey(S, Call->getArgs()[1]) ||
+      checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator) ||
+      checkPointerAuthKey(S, Call->getArgs()[3]) ||
+      checkPointerAuthValue(S, Call->getArgs()[4], PAO_Discriminator) ||
+      !AddendIsConstInt)
+    return ExprError();
+
+  Call->setType(Call->getArgs()[0]->getType());
+  return Call;
+}
+
+static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *Call) {
+  if (checkPointerAuthEnabled(S, Call))
+    return ExprError();
+
+  // We've already performed normal call type-checking.
+  const Expr *Arg = Call->getArg(0)->IgnoreParenImpCasts();
+
+  // Operand must be an ordinary or UTF-8 string literal.
+  const auto *Literal = dyn_cast<StringLiteral>(Arg);
+  if (!Literal || Literal->getCharByteWidth() != 1) {
+    S.Diag(Arg->getExprLoc(), diag::err_ptrauth_string_not_literal)
+        << (Literal ? 1 : 0) << Arg->getSourceRange();
+    return ExprError();
+  }
+
+  return Call;
+}
+
+static ExprResult GetVTablePointer(Sema &S, CallExpr *Call) {
+  if (S.checkArgCount(Call, 1))
+    return ExprError();
+  Expr *FirstArg = Call->getArg(0);
+  ExprResult FirstValue = S.DefaultFunctionArrayLvalueConversion(FirstArg);
+  if (FirstValue.isInvalid())
+    return ExprError();
+  Call->setArg(0, FirstValue.get());
+  QualType FirstArgType = FirstArg->getType();
+  if (FirstArgType->canDecayToPointerType() && FirstArgType->isArrayType())
+    FirstArgType = S.Context.getDecayedType(FirstArgType);
+
+  const CXXRecordDecl *FirstArgRecord = FirstArgType->getPointeeCXXRecordDecl();
+  if (!FirstArgRecord) {
+    S.Diag(FirstArg->getBeginLoc(), diag::err_get_vtable_pointer_incorrect_type)
+        << /*isPolymorphic=*/0 << FirstArgType;
+    return ExprError();
+  }
+  if (S.RequireCompleteType(
+          FirstArg->getBeginLoc(), FirstArgType->getPointeeType(),
+          diag::err_get_vtable_pointer_requires_complete_type)) {
+    return ExprError();
+  }
+
+  if (!FirstArgRecord->isPolymorphic()) {
+    S.Diag(FirstArg->getBeginLoc(), diag::err_get_vtable_pointer_incorrect_type)
+        << /*isPolymorphic=*/1 << FirstArgRecord;
+    return ExprError();
+  }
+  QualType ReturnType = S.Context.getPointerType(S.Context.VoidTy.withConst());
+  Call->setType(ReturnType);
+  return Call;
+}
+
+static ExprResult BuiltinLaunder(Sema &S, CallExpr *TheCall) {
+  if (S.checkArgCount(TheCall, 1))
+    return ExprError();
+
+  // Compute __builtin_launder's parameter type from the argument.
+  // The parameter type is:
+  //  * The type of the argument if it's not an array or function type,
+  //  Otherwise,
+  //  * The decayed argument type.
+  QualType ParamTy = [&]() {
+    QualType ArgTy = TheCall->getArg(0)->getType();
+    if (const ArrayType *Ty = ArgTy->getAsArrayTypeUnsafe())
+      return S.Context.getPointerType(Ty->getElementType());
+    if (ArgTy->isFunctionType()) {
+      return S.Context.getPointerType(ArgTy);
+    }
+    return ArgTy;
+  }();
+
+  TheCall->setType(ParamTy);
+
+  auto DiagSelect = [&]() -> std::optional<unsigned> {
+    if (!ParamTy->isPointerType())
+      return 0;
+    if (ParamTy->isFunctionPointerType())
+      return 1;
+    if (ParamTy->isVoidPointerType())
+      return 2;
+    return std::optional<unsigned>{};
+  }();
+  if (DiagSelect) {
+    S.Diag(TheCall->getBeginLoc(), diag::err_builtin_launder_invalid_arg)
+        << *DiagSelect << TheCall->getSourceRange();
+    return ExprError();
+  }
+
+  // We either have an incomplete class type, or we have a class template
+  // whose instantiation has not been forced. Example:
+  //
+  //   template <class T> struct Foo { T value; };
+  //   Foo<int> *p = nullptr;
+  //   auto *d = __builtin_launder(p);
+  if (S.RequireCompleteType(TheCall->getBeginLoc(), ParamTy->getPointeeType(),
+                            diag::err_incomplete_type))
+    return ExprError();
+
+  assert(ParamTy->getPointeeType()->isObjectType() &&
+         "Unhandled non-object pointer case");
+
+  InitializedEntity Entity =
+      InitializedEntity::InitializeParameter(S.Context, ParamTy, false);
+  ExprResult Arg =
+      S.PerformCopyInitialization(Entity, SourceLocation(), TheCall->getArg(0));
+  if (Arg.isInvalid())
+    return ExprError();
+  TheCall->setArg(0, Arg.get());
+
+  return TheCall;
+}
+
+static ExprResult BuiltinIsWithinLifetime(Sema &S, CallExpr *TheCall) {
+  if (S.checkArgCount(TheCall, 1))
+    return ExprError();
+
+  ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(0));
+  if (Arg.isInvalid())
+    return ExprError();
+  QualType ParamTy = Arg.get()->getType();
+  TheCall->setArg(0, Arg.get());
+  TheCall->setType(S.Context.BoolTy);
+
+  // Only accept pointers to objects as arguments, which should have object
+  // pointer or void pointer types.
+  if (const auto *PT = ParamTy->getAs<PointerType>()) {
+    // LWG4138: Function pointer types not allowed
+    if (PT->getPointeeType()->isFunctionType()) {
+      S.Diag(TheCall->getArg(0)->getExprLoc(),
+             diag::err_builtin_is_within_lifetime_invalid_arg)
+          << 1;
+      return ExprError();
+    }
+    // Disallow VLAs too since those shouldn't be able to
+    // be a template parameter for `std::is_within_lifetime`
+    if (PT->getPointeeType()->isVariableArrayType()) {
+      S.Diag(TheCall->getArg(0)->getExprLoc(), diag::err_vla_unsupported)
+          << 1 << "__builtin_is_within_lifetime";
+      return ExprError();
+    }
+  } else {
+    S.Diag(TheCall->getArg(0)->getExprLoc(),
+           diag::err_builtin_is_within_lifetime_invalid_arg)
+        << 0;
+    return ExprError();
+  }
+  return TheCall;
+}
+
+static ExprResult BuiltinTriviallyRelocate(Sema &S, CallExpr *TheCall) {
+  if (S.checkArgCount(TheCall, 3))
+    return ExprError();
+
+  QualType Dest = TheCall->getArg(0)->getType();
+  if (!Dest->isPointerType() || Dest.getCVRQualifiers() != 0) {
+    S.Diag(TheCall->getArg(0)->getExprLoc(),
+           diag::err_builtin_trivially_relocate_invalid_arg_type)
+        << /*a pointer*/ 0;
+    return ExprError();
+  }
+
+  QualType T = Dest->getPointeeType();
+  if (S.RequireCompleteType(TheCall->getBeginLoc(), T,
+                            diag::err_incomplete_type))
+    return ExprError();
+
+  if (T.isConstQualified() || !S.IsCXXTriviallyRelocatableType(T) ||
+      T->isIncompleteArrayType()) {
+    S.Diag(TheCall->getArg(0)->getExprLoc(),
+           diag::err_builtin_trivially_relocate_invalid_arg_type)
+        << (T.isConstQualified() ? /*non-const*/ 1 : /*relocatable*/ 2);
+    return ExprError();
+  }
+
+  TheCall->setType(Dest);
+
+  QualType Src = TheCall->getArg(1)->getType();
+  if (Src.getCanonicalType() != Dest.getCanonicalType()) {
+    S.Diag(TheCall->getArg(1)->getExprLoc(),
+           diag::err_builtin_trivially_relocate_invalid_arg_type)
+        << /*the same*/ 3;
+    return ExprError();
+  }
+
+  Expr *SizeExpr = TheCall->getArg(2);
+  ExprResult Size = S.DefaultLvalueConversion(SizeExpr);
+  if (Size.isInvalid())
+    return ExprError();
+
+  Size = S.tryConvertExprToType(Size.get(), S.getASTContext().getSizeType());
+  if (Size.isInvalid())
+    return ExprError();
+  SizeExpr = Size.get();
+  TheCall->setArg(2, SizeExpr);
+
+  return TheCall;
+}
+
+// Emit an error and return true if the current object format type is in the
+// list of unsupported types.
+static bool CheckBuiltinTargetNotInUnsupported(
+    Sema &S, unsigned BuiltinID, CallExpr *TheCall,
+    ArrayRef<llvm::Triple::ObjectFormatType> UnsupportedObjectFormatTypes) {
+  llvm::Triple::ObjectFormatType CurObjFormat =
+      S.getASTContext().getTargetInfo().getTriple().getObjectFormat();
+  if (llvm::is_contained(UnsupportedObjectFormatTypes, CurObjFormat)) {
+    S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
+        << TheCall->getSourceRange();
+    return true;
+  }
+  return false;
+}
+
+// Emit an error and return true if the current architecture is not in the list
+// of supported architectures.
+static bool
+CheckBuiltinTargetInSupported(Sema &S, CallExpr *TheCall,
+                              ArrayRef<llvm::Triple::ArchType> SupportedArchs) {
+  llvm::Triple::ArchType CurArch =
+      S.getASTContext().getTargetInfo().getTriple().getArch();
+  if (llvm::is_contained(SupportedArchs, CurArch))
+    return false;
+  S.Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
+      << TheCall->getSourceRange();
+  return true;
+}
+
+static void CheckNonNullArgument(Sema &S, const Expr *ArgExpr,
+                                 SourceLocation CallSiteLoc);
+
+bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
+                                      CallExpr *TheCall) {
+  switch (TI.getTriple().getArch()) {
+  default:
+    // Some builtins don't require additional checking, so just consider these
+    // acceptable.
+    return false;
+  case llvm::Triple::arm:
+  case llvm::Triple::armeb:
+  case llvm::Triple::thumb:
+  case llvm::Triple::thumbeb:
+    return ARM().CheckARMBuiltinFunctionCall(TI, BuiltinID, TheCall);
+  case llvm::Triple::aarch64:
+  case llvm::Triple::aarch64_32:
+  case llvm::Triple::aarch64_be:
+    return ARM().CheckAArch64BuiltinFunctionCall(TI, BuiltinID, TheCall);
+  case llvm::Triple::bpfeb:
+  case llvm::Triple::bpfel:
+    return BPF().CheckBPFBuiltinFunctionCall(BuiltinID, TheCall);
+  case llvm::Triple::dxil:
+    return DirectX().CheckDirectXBuiltinFunctionCall(BuiltinID, TheCall);
+  case llvm::Triple::hexagon:
+    return Hexagon().CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall);
+  case llvm::Triple::mips:
+  case llvm::Triple::mipsel:
+  case llvm::Triple::mips64:
+  case llvm::Triple::mips64el:
+    return MIPS().CheckMipsBuiltinFunctionCall(TI, BuiltinID, TheCall);
+  case llvm::Triple::spirv:
+  case llvm::Triple::spirv32:
+  case llvm::Triple::spirv64:
+    if (TI.getTriple().getOS() != llvm::Triple::OSType::AMDHSA)
+      return SPIRV().CheckSPIRVBuiltinFunctionCall(TI, BuiltinID, TheCall);
+    return false;
+  case llvm::Triple::systemz:
+    return SystemZ().CheckSystemZBuiltinFunctionCall(BuiltinID, TheCall);
+  case llvm::Triple::x86:
+  case llvm::Triple::x86_64:
+    return X86().CheckBuiltinFunctionCall(TI, BuiltinID, TheCall);
+  case llvm::Triple::ppc:
+  case llvm::Triple::ppcle:
+  case llvm::Triple::ppc64:
+  case llvm::Triple::ppc64le:
+    return PPC().CheckPPCBuiltinFunctionCall(TI, BuiltinID, TheCall);
+  case llvm::Triple::amdgcn:
+    return AMDGPU().CheckAMDGCNBuiltinFunctionCall(BuiltinID, TheCall);
+  case llvm::Triple::riscv32:
+  case llvm::Triple::riscv64:
+  case llvm::Triple::riscv32be:
+  case llvm::Triple::riscv64be:
+    return RISCV().CheckBuiltinFunctionCall(TI, BuiltinID, TheCall);
+  case llvm::Triple::loongarch32:
+  case llvm::Triple::loongarch64:
+    return LoongArch().CheckLoongArchBuiltinFunctionCall(TI, BuiltinID,
+                                                         TheCall);
+  case llvm::Triple::wasm32:
+  case llvm::Triple::wasm64:
+    return Wasm().CheckWebAssemblyBuiltinFunctionCall(TI, BuiltinID, TheCall);
+  case llvm::Triple::nvptx:
+  case llvm::Triple::nvptx64:
+    return NVPTX().CheckNVPTXBuiltinFunctionCall(TI, BuiltinID, TheCall);
+  }
+}
+
+static bool isValidMathElementType(QualType T) {
+  return T->isDependentType() ||
+         (T->isRealType() && !T->isBooleanType() && !T->isEnumeralType());
+}
+
+// Check if \p Ty is a valid type for the elementwise math builtins. If it is
+// not a valid type, emit an error message and return true. Otherwise return
+// false.
+static bool
+checkMathBuiltinElementType(Sema &S, SourceLocation Loc, QualType ArgTy,
+                            Sema::EltwiseBuiltinArgTyRestriction ArgTyRestr,
+                            int ArgOrdinal) {
+  QualType EltTy = ArgTy;
+  if (auto *VecTy = EltTy->getAs<VectorType>())
+    EltTy = VecTy->getElementType();
+
+  switch (ArgTyRestr) {
+  case Sema::EltwiseBuiltinArgTyRestriction::None:
+    if (!ArgTy->getAs<VectorType>() && !isValidMathElementType(ArgTy)) {
+      return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
+             << ArgOrdinal << /* vector */ 2 << /* integer */ 1 << /* fp */ 1
+             << ArgTy;
+    }
+    break;
+  case Sema::EltwiseBuiltinArgTyRestriction::FloatTy:
+    if (!EltTy->isRealFloatingType()) {
+      return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
+             << ArgOrdinal << /* scalar or vector */ 5 << /* no int */ 0
+             << /* floating-point */ 1 << ArgTy;
+    }
+    break;
+  case Sema::EltwiseBuiltinArgTyRestriction::IntegerTy:
+    if (!EltTy->isIntegerType()) {
+      return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
+             << ArgOrdinal << /* scalar or vector */ 5 << /* integer */ 1
+             << /* no fp */ 0 << ArgTy;
+    }
+    break;
+  case Sema::EltwiseBuiltinArgTyRestriction::SignedIntOrFloatTy:
+    if (!EltTy->isSignedIntegerType() && !EltTy->isRealFloatingType()) {
+      return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
+             << 1 << /* scalar or vector */ 5 << /* signed int */ 2
+             << /* or fp */ 1 << ArgTy;
+    }
+    break;
+  }
+
+  return false;
+}
+
+/// BuiltinCpu{Supports|Is} - Handle __builtin_cpu_{supports|is}(char *).
+/// This checks that the target supports the builtin and that the string
+/// argument is constant and valid.
+static bool BuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall,
+                       const TargetInfo *AuxTI, unsigned BuiltinID) {
+  assert((BuiltinID == Builtin::BI__builtin_cpu_supports ||
+          BuiltinID == Builtin::BI__builtin_cpu_is) &&
+         "Expecting __builtin_cpu_...");
+
+  bool IsCPUSupports = BuiltinID == Builtin::BI__builtin_cpu_supports;
+  const TargetInfo *TheTI = &TI;
+  auto SupportsBI = [=](const TargetInfo *TInfo) {
+    return TInfo && ((IsCPUSupports && TInfo->supportsCpuSupports()) ||
+                     (!IsCPUSupports && TInfo->supportsCpuIs()));
+  };
+  if (!SupportsBI(&TI) && SupportsBI(AuxTI))
+    TheTI = AuxTI;
+
+  if ((!IsCPUSupports && !TheTI->supportsCpuIs()) ||
+      (IsCPUSupports && !TheTI->supportsCpuSupports()))
+    return S.Diag(TheCall->getBeginLoc(),
+                  TI.getTriple().isOSAIX()
+                      ? diag::err_builtin_aix_os_unsupported
+                      : diag::err_builtin_target_unsupported)
+           << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
+
+  Expr *Arg = TheCall->getArg(0)->IgnoreParenImpCasts();
+  // Check if the argument is a string literal.
+  if (!isa<StringLiteral>(Arg))
+    return S.Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
+           << Arg->getSourceRange();
+
+  // Check the contents of the string.
+  StringRef Feature = cast<StringLiteral>(Arg)->getString();
+  if (IsCPUSupports && !TheTI->validateCpuSupports(Feature)) {
+    S.Diag(TheCall->getBeginLoc(), diag::warn_invalid_cpu_supports)
+        << Arg->getSourceRange();
+    return false;
+  }
+  if (!IsCPUSupports && !TheTI->validateCpuIs(Feature))
+    return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_is)
+           << Arg->getSourceRange();
+  return false;
+}
+
+/// Checks that __builtin_bswapg was called with a single argument, which is an
+/// unsigned integer, and overrides the return value type to the integer type.
+static bool BuiltinBswapg(Sema &S, CallExpr *TheCall) {
+  if (S.checkArgCount(TheCall, 1))
+    return true;
+  ExprResult ArgRes = S.DefaultLvalueConversion(TheCall->getArg(0));
+  if (ArgRes.isInvalid())
+    return true;
+
+  Expr *Arg = ArgRes.get();
+  TheCall->setArg(0, Arg);
+  if (Arg->isTypeDependent())
+    return false;
+
+  QualType ArgTy = Arg->getType();
+
+  if (!ArgTy->isIntegerType()) {
+    S.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+        << 1 << /*scalar=*/1 << /*unsigned integer=*/1 << /*floating point=*/0
+        << ArgTy;
+    return true;
+  }
+  if (const auto *BT = dyn_cast<BitIntType>(ArgTy)) {
+    if (BT->getNumBits() % 16 != 0 && BT->getNumBits() != 8 &&
+        BT->getNumBits() != 1) {
+      S.Diag(Arg->getBeginLoc(), diag::err_bswapg_invalid_bit_width)
+          << ArgTy << BT->getNumBits();
+      return true;
+    }
+  }
+  TheCall->setType(ArgTy);
+  return false;
+}
+
+/// Checks that __builtin_popcountg was called with a single argument, which is
+/// an unsigned integer.
+static bool BuiltinPopcountg(Sema &S, CallExpr *TheCall) {
+  if (S.checkArgCount(TheCall, 1))
+    return true;
+
+  ExprResult ArgRes = S.DefaultLvalueConversion(TheCall->getArg(0));
+  if (ArgRes.isInvalid())
+    return true;
+
+  Expr *Arg = ArgRes.get();
+  TheCall->setArg(0, Arg);
+
+  QualType ArgTy = Arg->getType();
+
+  if (!ArgTy->isUnsignedIntegerType() && !ArgTy->isExtVectorBoolType()) {
+    S.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+        << 1 << /* scalar */ 1 << /* unsigned integer ty */ 3 << /* no fp */ 0
+        << ArgTy;
+    return true;
+  }
+  return false;
+}
+
+/// Checks that __builtin_{clzg,ctzg} was called with a first argument, which is
+/// an unsigned integer, and an optional second argument, which is promoted to
+/// an 'int'.
+static bool BuiltinCountZeroBitsGeneric(Sema &S, CallExpr *TheCall) {
+  if (S.checkArgCountRange(TheCall, 1, 2))
+    return true;
+
+  ExprResult Arg0Res = S.DefaultLvalueConversion(TheCall->getArg(0));
+  if (Arg0Res.isInvalid())
+    return true;
+
+  Expr *Arg0 = Arg0Res.get();
+  TheCall->setArg(0, Arg0);
+
+  QualType Arg0Ty = Arg0->getType();
+
+  if (!Arg0Ty->isUnsignedIntegerType() && !Arg0Ty->isExtVectorBoolType()) {
+    S.Diag(Arg0->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+        << 1 << /* scalar */ 1 << /* unsigned integer ty */ 3 << /* no fp */ 0
+        << Arg0Ty;
+    return true;
+  }
+
+  if (TheCall->getNumArgs() > 1) {
+    ExprResult Arg1Res = S.UsualUnaryConversions(TheCall->getArg(1));
+    if (Arg1Res.isInvalid())
+      return true;
+
+    Expr *Arg1 = Arg1Res.get();
+    TheCall->setArg(1, Arg1);
+
+    QualType Arg1Ty = Arg1->getType();
+
+    if (!Arg1Ty->isSpecificBuiltinType(BuiltinType::Int)) {
+      S.Diag(Arg1->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+          << 2 << /* scalar */ 1 << /* 'int' ty */ 4 << /* no fp */ 0 << Arg1Ty;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+class RotateIntegerConverter : public Sema::ContextualImplicitConverter {
+  unsigned ArgIndex;
+  bool OnlyUnsigned;
+
+  Sema::SemaDiagnosticBuilder emitError(Sema &S, SourceLocation Loc,
+                                        QualType T) {
+    return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
+           << ArgIndex << /*scalar*/ 1
+           << (OnlyUnsigned ? /*unsigned integer*/ 3 : /*integer*/ 1)
+           << /*no fp*/ 0 << T;
+  }
+
+public:
+  RotateIntegerConverter(unsigned ArgIndex, bool OnlyUnsigned)
+      : ContextualImplicitConverter(/*Suppress=*/false,
+                                    /*SuppressConversion=*/true),
+        ArgIndex(ArgIndex), OnlyUnsigned(OnlyUnsigned) {}
+
+  bool match(QualType T) override {
+    return OnlyUnsigned ? T->isUnsignedIntegerType() : T->isIntegerType();
+  }
+
+  Sema::SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc,
+                                              QualType T) override {
+    return emitError(S, Loc, T);
+  }
+
+  Sema::SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc,
+                                                 QualType T) override {
+    return emitError(S, Loc, T);
+  }
+
+  Sema::SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc,
+                                                   QualType T,
+                                                   QualType ConvTy) override {
+    return emitError(S, Loc, T);
+  }
+
+  Sema::SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv,
+                                               QualType ConvTy) override {
+    return S.Diag(Conv->getLocation(), diag::note_conv_function_declared_at);
+  }
+
+  Sema::SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc,
+                                                QualType T) override {
+    return emitError(S, Loc, T);
+  }
+
+  Sema::SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv,
+                                            QualType ConvTy) override {
+    return S.Diag(Conv->getLocation(), diag::note_conv_function_declared_at);
+  }
+
+  Sema::SemaDiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc,
+                                                 QualType T,
+                                                 QualType ConvTy) override {
+    llvm_unreachable("conversion functions are permitted");
+  }
+};
+
+/// Checks that __builtin_stdc_rotate_{left,right} was called with two
+/// arguments, that the first argument is an unsigned integer type, and that
+/// the second argument is an integer type.
+static bool BuiltinRotateGeneric(Sema &S, CallExpr *TheCall) {
+  if (S.checkArgCount(TheCall, 2))
+    return true;
+
+  // First argument (value to rotate) must be unsigned integer type.
+  RotateIntegerConverter Arg0Converter(1, /*OnlyUnsigned=*/true);
+  ExprResult Arg0Res = S.PerformContextualImplicitConversion(
+      TheCall->getArg(0)->getBeginLoc(), TheCall->getArg(0), Arg0Converter);
+  if (Arg0Res.isInvalid())
+    return true;
+
+  Expr *Arg0 = Arg0Res.get();
+  TheCall->setArg(0, Arg0);
+
+  QualType Arg0Ty = Arg0->getType();
+  if (!Arg0Ty->isUnsignedIntegerType())
+    return true;
+
+  // Second argument (rotation count) must be integer type.
+  RotateIntegerConverter Arg1Converter(2, /*OnlyUnsigned=*/false);
+  ExprResult Arg1Res = S.PerformContextualImplicitConversion(
+      TheCall->getArg(1)->getBeginLoc(), TheCall->getArg(1), Arg1Converter);
+  if (Arg1Res.isInvalid())
+    return true;
+
+  Expr *Arg1 = Arg1Res.get();
+  TheCall->setArg(1, Arg1);
+
+  QualType Arg1Ty = Arg1->getType();
+  if (!Arg1Ty->isIntegerType())
+    return true;
+
+  TheCall->setType(Arg0Ty);
+  return false;
+}
+
+static bool CheckMaskedBuiltinArgs(Sema &S, Expr *MaskArg, Expr *PtrArg,
+                                   unsigned Pos, bool AllowConst,
+                                   bool AllowAS) {
+  QualType MaskTy = MaskArg->getType();
+  if (!MaskTy->isExtVectorBoolType())
+    return S.Diag(MaskArg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+           << 1 << /* vector of */ 4 << /* booleans */ 6 << /* no fp */ 0
+           << MaskTy;
+
+  QualType PtrTy = PtrArg->getType();
+  if (!PtrTy->isPointerType() || PtrTy->getPointeeType()->isVectorType())
+    return S.Diag(PtrArg->getExprLoc(), diag::err_vec_masked_load_store_ptr)
+           << Pos << "scalar pointer";
+
+  QualType PointeeTy = PtrTy->getPointeeType();
+  if (PointeeTy.isVolatileQualified() || PointeeTy->isAtomicType() ||
+      (!AllowConst && PointeeTy.isConstQualified()) ||
+      (!AllowAS && PointeeTy.hasAddressSpace())) {
+    QualType Target =
+        S.Context.getPointerType(PointeeTy.getAtomicUnqualifiedType());
+    return S.Diag(PtrArg->getExprLoc(),
+                  diag::err_typecheck_convert_incompatible)
+           << PtrTy << Target << /*different qualifiers=*/5
+           << /*qualifier difference=*/0 << /*parameter mismatch=*/3 << 2
+           << PtrTy << Target;
+  }
+  return false;
+}
+
+static bool ConvertMaskedBuiltinArgs(Sema &S, CallExpr *TheCall) {
+  bool TypeDependent = false;
+  for (unsigned Arg = 0, E = TheCall->getNumArgs(); Arg != E; ++Arg) {
+    ExprResult Converted =
+        S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(Arg));
+    if (Converted.isInvalid())
+      return true;
+    TheCall->setArg(Arg, Converted.get());
+    TypeDependent |= Converted.get()->isTypeDependent();
+  }
+
+  if (TypeDependent)
+    TheCall->setType(S.Context.DependentTy);
+  return false;
+}
+
+static ExprResult BuiltinMaskedLoad(Sema &S, CallExpr *TheCall) {
+  if (S.checkArgCountRange(TheCall, 2, 3))
+    return ExprError();
+
+  if (ConvertMaskedBuiltinArgs(S, TheCall))
+    return ExprError();
+
+  Expr *MaskArg = TheCall->getArg(0);
+  Expr *PtrArg = TheCall->getArg(1);
+  if (TheCall->isTypeDependent())
+    return TheCall;
+
+  if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 2, /*AllowConst=*/true,
+                             TheCall->getBuiltinCallee() ==
+                                 Builtin::BI__builtin_masked_load))
+    return ExprError();
+
+  QualType MaskTy = MaskArg->getType();
+  QualType PtrTy = PtrArg->getType();
+  QualType PointeeTy = PtrTy->getPointeeType();
+  const VectorType *MaskVecTy = MaskTy->getAs<VectorType>();
+
+  QualType RetTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(),
+                                              MaskVecTy->getNumElements());
+  if (TheCall->getNumArgs() == 3) {
+    Expr *PassThruArg = TheCall->getArg(2);
+    QualType PassThruTy = PassThruArg->getType();
+    if (!S.Context.hasSameType(PassThruTy, RetTy))
+      return S.Diag(PtrArg->getExprLoc(), diag::err_vec_masked_load_store_ptr)
+             << /* third argument */ 3 << RetTy;
+  }
+
+  TheCall->setType(RetTy);
+  return TheCall;
+}
+
+static ExprResult BuiltinMaskedStore(Sema &S, CallExpr *TheCall) {
+  if (S.checkArgCount(TheCall, 3))
+    return ExprError();
+
+  if (ConvertMaskedBuiltinArgs(S, TheCall))
+    return ExprError();
+
+  Expr *MaskArg = TheCall->getArg(0);
+  Expr *ValArg = TheCall->getArg(1);
+  Expr *PtrArg = TheCall->getArg(2);
+  if (TheCall->isTypeDependent())
+    return TheCall;
+
+  if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 3, /*AllowConst=*/false,
+                             TheCall->getBuiltinCallee() ==
+                                 Builtin::BI__builtin_masked_store))
+    return ExprError();
+
+  QualType MaskTy = MaskArg->getType();
+  QualType PtrTy = PtrArg->getType();
+  QualType ValTy = ValArg->getType();
+  if (!ValTy->isVectorType())
+    return ExprError(
+        S.Diag(ValArg->getExprLoc(), diag::err_vec_masked_load_store_ptr)
+        << 2 << "vector");
+
+  QualType PointeeTy = PtrTy->getPointeeType();
+  const VectorType *MaskVecTy = MaskTy->getAs<VectorType>();
+  QualType MemoryTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(),
+                                                 MaskVecTy->getNumElements());
+  if (!S.Context.hasSameType(ValTy.getUnqualifiedType(),
+                             MemoryTy.getUnqualifiedType()))
+    return ExprError(S.Diag(TheCall->getBeginLoc(),
+                            diag::err_vec_builtin_incompatible_vector)
+                     << TheCall->getDirectCallee() << /*isMorethantwoArgs*/ 2
+                     << SourceRange(TheCall->getArg(1)->getBeginLoc(),
+                                    TheCall->getArg(1)->getEndLoc()));
+
+  TheCall->setType(S.Context.VoidTy);
+  return TheCall;
+}
+
+static ExprResult BuiltinMaskedGather(Sema &S, CallExpr *TheCall) {
+  if (S.checkArgCountRange(TheCall, 3, 4))
+    return ExprError();
+
+  if (ConvertMaskedBuiltinArgs(S, TheCall))
+    return ExprError();
+
+  Expr *MaskArg = TheCall->getArg(0);
+  Expr *IdxArg = TheCall->getArg(1);
+  Expr *PtrArg = TheCall->getArg(2);
+  if (TheCall->isTypeDependent())
+    return TheCall;
+
+  if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 3, /*AllowConst=*/true,
+                             /*AllowAS=*/true))
+    return ExprError();
+
+  QualType IdxTy = IdxArg->getType();
+  const VectorType *IdxVecTy = IdxTy->getAs<VectorType>();
+  if (!IdxTy->isExtVectorType() || !IdxVecTy->getElementType()->isIntegerType())
+    return S.Diag(MaskArg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+           << 1 << /* vector of */ 4 << /* integer */ 1 << /* no fp */ 0
+           << IdxTy;
+
+  QualType MaskTy = MaskArg->getType();
+  QualType PtrTy = PtrArg->getType();
+  QualType PointeeTy = PtrTy->getPointeeType();
+  const VectorType *MaskVecTy = MaskTy->getAs<VectorType>();
+  if (MaskVecTy->getNumElements() != IdxVecTy->getNumElements())
+    return ExprError(
+        S.Diag(TheCall->getBeginLoc(), diag::err_vec_masked_load_store_size)
+        << S.getASTContext().BuiltinInfo.getQuotedName(
+               TheCall->getBuiltinCallee())
+        << MaskTy << IdxTy);
+
+  QualType RetTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(),
+                                              MaskVecTy->getNumElements());
+  if (TheCall->getNumArgs() == 4) {
+    Expr *PassThruArg = TheCall->getArg(3);
+    QualType PassThruTy = PassThruArg->getType();
+    if (!S.Context.hasSameType(PassThruTy, RetTy))
+      return S.Diag(PassThruArg->getExprLoc(),
+                    diag::err_vec_masked_load_store_ptr)
+             << /* fourth argument */ 4 << RetTy;
+  }
+
+  TheCall->setType(RetTy);
+  return TheCall;
+}
+
+static ExprResult BuiltinMaskedScatter(Sema &S, CallExpr *TheCall) {
+  if (S.checkArgCount(TheCall, 4))
+    return ExprError();
+
+  if (ConvertMaskedBuiltinArgs(S, TheCall))
+    return ExprError();
+
+  Expr *MaskArg = TheCall->getArg(0);
+  Expr *IdxArg = TheCall->getArg(1);
+  Expr *ValArg = TheCall->getArg(2);
+  Expr *PtrArg = TheCall->getArg(3);
+  if (TheCall->isTypeDependent())
+    return TheCall;
+
+  if (CheckMaskedBuiltinArgs(S, MaskArg, PtrArg, 4, /*AllowConst=*/false,
+                             /*AllowAS=*/true))
+    return ExprError();
+
+  QualType IdxTy = IdxArg->getType();
+  const VectorType *IdxVecTy = IdxTy->getAs<VectorType>();
+  if (!IdxTy->isExtVectorType() || !IdxVecTy->getElementType()->isIntegerType())
+    return S.Diag(MaskArg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+           << 2 << /* vector of */ 4 << /* integer */ 1 << /* no fp */ 0
+           << IdxTy;
+
+  QualType ValTy = ValArg->getType();
+  QualType MaskTy = MaskArg->getType();
+  QualType PtrTy = PtrArg->getType();
+  QualType PointeeTy = PtrTy->getPointeeType();
+
+  const VectorType *MaskVecTy = MaskTy->castAs<VectorType>();
+  const VectorType *ValVecTy = ValTy->castAs<VectorType>();
+  if (MaskVecTy->getNumElements() != IdxVecTy->getNumElements())
+    return ExprError(
+        S.Diag(TheCall->getBeginLoc(), diag::err_vec_masked_load_store_size)
+        << S.getASTContext().BuiltinInfo.getQuotedName(
+               TheCall->getBuiltinCallee())
+        << MaskTy << IdxTy);
+  if (MaskVecTy->getNumElements() != ValVecTy->getNumElements())
+    return ExprError(
+        S.Diag(TheCall->getBeginLoc(), diag::err_vec_masked_load_store_size)
+        << S.getASTContext().BuiltinInfo.getQuotedName(
+               TheCall->getBuiltinCallee())
+        << MaskTy << ValTy);
+
+  QualType ArgTy = S.Context.getExtVectorType(PointeeTy.getUnqualifiedType(),
+                                              MaskVecTy->getNumElements());
+  if (!S.Context.hasSameType(ValTy.getUnqualifiedType(), ArgTy))
+    return ExprError(S.Diag(TheCall->getBeginLoc(),
+                            diag::err_vec_builtin_incompatible_vector)
+                     << TheCall->getDirectCallee() << /*isMoreThanTwoArgs*/ 2
+                     << SourceRange(TheCall->getArg(1)->getBeginLoc(),
+                                    TheCall->getArg(1)->getEndLoc()));
+
+  TheCall->setType(S.Context.VoidTy);
+  return TheCall;
+}
+
+static ExprResult BuiltinInvoke(Sema &S, CallExpr *TheCall) {
+  SourceLocation Loc = TheCall->getBeginLoc();
+  MutableArrayRef Args(TheCall->getArgs(), TheCall->getNumArgs());
+  assert(llvm::none_of(Args, [](Expr *Arg) { return Arg->isTypeDependent(); }));
+
+  if (Args.size() == 0) {
+    S.Diag(TheCall->getBeginLoc(),
+           diag::err_typecheck_call_too_few_args_at_least)
+        << /*callee_type=*/0 << /*min_arg_count=*/1 << /*actual_arg_count=*/0
+        << /*is_non_object=*/0 << TheCall->getSourceRange();
+    return ExprError();
+  }
+
+  QualType FuncT = Args[0]->getType();
+
+  if (const auto *MPT = FuncT->getAs<MemberPointerType>()) {
+    if (Args.size() < 2) {
+      S.Diag(TheCall->getBeginLoc(),
+             diag::err_typecheck_call_too_few_args_at_least)
+          << /*callee_type=*/0 << /*min_arg_count=*/2 << /*actual_arg_count=*/1
+          << /*is_non_object=*/0 << TheCall->getSourceRange();
+      return ExprError();
+    }
+
+    const Type *MemPtrClass = MPT->getQualifier().getAsType();
+    QualType ObjectT = Args[1]->getType();
+
+    if (MPT->isMemberDataPointer() && S.checkArgCount(TheCall, 2))
+      return ExprError();
+
+    ExprResult ObjectArg = [&]() -> ExprResult {
+      // (1.1): (t1.*f)(t2, ..., tN) when f is a pointer to a member function of
+      // a class T and is_same_v<T, remove_cvref_t<decltype(t1)>> ||
+      // is_base_of_v<T, remove_cvref_t<decltype(t1)>> is true;
+      // (1.4): t1.*f when N=1 and f is a pointer to data member of a class T
+      // and is_same_v<T, remove_cvref_t<decltype(t1)>> ||
+      // is_base_of_v<T, remove_cvref_t<decltype(t1)>> is true;
+      if (S.Context.hasSameType(QualType(MemPtrClass, 0),
+                                S.BuiltinRemoveCVRef(ObjectT, Loc)) ||
+          S.BuiltinIsBaseOf(Args[1]->getBeginLoc(), QualType(MemPtrClass, 0),
+                            S.BuiltinRemoveCVRef(ObjectT, Loc))) {
+        return Args[1];
+      }
+
+      // (t1.get().*f)(t2, ..., tN) when f is a pointer to a member function of
+      // a class T and remove_cvref_t<decltype(t1)> is a specialization of
+      // reference_wrapper;
+      if (const auto *RD = ObjectT->getAsCXXRecordDecl()) {
+        if (RD->isInStdNamespace() &&
+            RD->getDeclName().getAsString() == "reference_wrapper") {
+          CXXScopeSpec SS;
+          IdentifierInfo *GetName = &S.Context.Idents.get("get");
+          UnqualifiedId GetID;
+          GetID.setIdentifier(GetName, Loc);
+
+          ExprResult MemExpr = S.ActOnMemberAccessExpr(
+              S.getCurScope(), Args[1], Loc, tok::period, SS,
+              /*TemplateKWLoc=*/SourceLocation(), GetID, nullptr);
+
+          if (MemExpr.isInvalid())
+            return ExprError();
+
+          return S.ActOnCallExpr(S.getCurScope(), MemExpr.get(), Loc, {}, Loc);
+        }
+      }
+
+      // ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a
+      // class T and t1 does not satisfy the previous two items;
+
+      return S.ActOnUnaryOp(S.getCurScope(), Loc, tok::star, Args[1]);
+    }();
+
+    if (ObjectArg.isInvalid())
+      return ExprError();
+
+    ExprResult BinOp = S.ActOnBinOp(S.getCurScope(), TheCall->getBeginLoc(),
+                                    tok::periodstar, ObjectArg.get(), Args[0]);
+    if (BinOp.isInvalid())
+      return ExprError();
+
+    if (MPT->isMemberDataPointer())
+      return BinOp;
+
+    auto *MemCall = new (S.Context)
+        ParenExpr(SourceLocation(), SourceLocation(), BinOp.get());
+
+    return S.ActOnCallExpr(S.getCurScope(), MemCall, TheCall->getBeginLoc(),
+                           Args.drop_front(2), TheCall->getRParenLoc());
+  }
+  return S.ActOnCallExpr(S.getCurScope(), Args.front(), TheCall->getBeginLoc(),
+                         Args.drop_front(), TheCall->getRParenLoc());
+}
+
+// Performs a similar job to Sema::UsualUnaryConversions, but without any
+// implicit promotion of integral/enumeration types.
+static ExprResult BuiltinVectorMathConversions(Sema &S, Expr *E) {
+  // First, convert to an r-value.
+  ExprResult Res = S.DefaultFunctionArrayLvalueConversion(E);
+  if (Res.isInvalid())
+    return ExprError();
+
+  // Promote floating-point types.
+  return S.UsualUnaryFPConversions(Res.get());
+}
+
+ExprResult
+Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
+                               CallExpr *TheCall) {
+  ExprResult TheCallResult(TheCall);
+
+  // Find out if any arguments are required to be integer constant expressions.
+  unsigned ICEArguments = 0;
+  ASTContext::GetBuiltinTypeError Error;
+  Context.GetBuiltinType(BuiltinID, Error, &ICEArguments);
+  if (Error != ASTContext::GE_None)
+    ICEArguments = 0;  // Don't diagnose previously diagnosed errors.
+
+  // If any arguments are required to be ICE's, check and diagnose.
+  for (unsigned ArgNo = 0; ICEArguments != 0; ++ArgNo) {
+    // Skip arguments not required to be ICE's.
+    if ((ICEArguments & (1 << ArgNo)) == 0) continue;
+
+    llvm::APSInt Result;
+    // If we don't have enough arguments, continue so we can issue better
+    // diagnostic in checkArgCount(...)
+    if (ArgNo < TheCall->getNumArgs() &&
+        BuiltinConstantArg(TheCall, ArgNo, Result))
+      return true;
+    ICEArguments &= ~(1 << ArgNo);
+  }
+
+  FPOptions FPO;
+  switch (BuiltinID) {
+  case Builtin::BI__builtin_cpu_supports:
+  case Builtin::BI__builtin_cpu_is:
+    if (BuiltinCpu(*this, Context.getTargetInfo(), TheCall,
+                   Context.getAuxTargetInfo(), BuiltinID))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_cpu_init:
+    if (!Context.getTargetInfo().supportsCpuInit()) {
+      Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
+          << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
+      return ExprError();
+    }
+    break;
+  case Builtin::BI__builtin___CFStringMakeConstantString:
+    // CFStringMakeConstantString is currently not implemented for GOFF (i.e.,
+    // on z/OS) and for XCOFF (i.e., on AIX). Emit unsupported
+    if (CheckBuiltinTargetNotInUnsupported(
+            *this, BuiltinID, TheCall,
+            {llvm::Triple::GOFF, llvm::Triple::XCOFF}))
+      return ExprError();
+    assert(TheCall->getNumArgs() == 1 &&
+           "Wrong # arguments to builtin CFStringMakeConstantString");
+    if (ObjC().CheckObjCString(TheCall->getArg(0)))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_ms_va_start:
+  case Builtin::BI__builtin_stdarg_start:
+  case Builtin::BI__builtin_va_start:
+  case Builtin::BI__builtin_c23_va_start:
+    if (BuiltinVAStart(BuiltinID, TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__va_start: {
+    switch (Context.getTargetInfo().getTriple().getArch()) {
+    case llvm::Triple::aarch64:
+    case llvm::Triple::arm:
+    case llvm::Triple::thumb:
+      if (BuiltinVAStartARMMicrosoft(TheCall))
+        return ExprError();
+      break;
+    default:
+      if (BuiltinVAStart(BuiltinID, TheCall))
+        return ExprError();
+      break;
+    }
+    break;
+  }
+
+  // The acquire, release, and no fence variants are ARM and AArch64 only.
+  case Builtin::BI_interlockedbittestandset_acq:
+  case Builtin::BI_interlockedbittestandset_rel:
+  case Builtin::BI_interlockedbittestandset_nf:
+  case Builtin::BI_interlockedbittestandreset_acq:
+  case Builtin::BI_interlockedbittestandreset_rel:
+  case Builtin::BI_interlockedbittestandreset_nf:
+    if (CheckBuiltinTargetInSupported(
+            *this, TheCall,
+            {llvm::Triple::arm, llvm::Triple::thumb, llvm::Triple::aarch64}))
+      return ExprError();
+    break;
+
+  // The 64-bit bittest variants are x64, ARM, and AArch64 only.
+  case Builtin::BI_bittest64:
+  case Builtin::BI_bittestandcomplement64:
+  case Builtin::BI_bittestandreset64:
+  case Builtin::BI_bittestandset64:
+  case Builtin::BI_interlockedbittestandreset64:
+  case Builtin::BI_interlockedbittestandset64:
+    if (CheckBuiltinTargetInSupported(
+            *this, TheCall,
+            {llvm::Triple::x86_64, llvm::Triple::arm, llvm::Triple::thumb,
+             llvm::Triple::aarch64, llvm::Triple::amdgcn}))
+      return ExprError();
+    break;
+
+  // The 64-bit acquire, release, and no fence variants are AArch64 only.
+  case Builtin::BI_interlockedbittestandreset64_acq:
+  case Builtin::BI_interlockedbittestandreset64_rel:
+  case Builtin::BI_interlockedbittestandreset64_nf:
+  case Builtin::BI_interlockedbittestandset64_acq:
+  case Builtin::BI_interlockedbittestandset64_rel:
+  case Builtin::BI_interlockedbittestandset64_nf:
+    if (CheckBuiltinTargetInSupported(*this, TheCall, {llvm::Triple::aarch64}))
+      return ExprError();
+    break;
+
+  case Builtin::BI__builtin_set_flt_rounds:
+    if (CheckBuiltinTargetInSupported(
+            *this, TheCall,
+            {llvm::Triple::x86, llvm::Triple::x86_64, llvm::Triple::arm,
+             llvm::Triple::thumb, llvm::Triple::aarch64, llvm::Triple::amdgcn,
+             llvm::Triple::ppc, llvm::Triple::ppc64, llvm::Triple::ppcle,
+             llvm::Triple::ppc64le}))
+      return ExprError();
+    break;
+
+  case Builtin::BI__builtin_isgreater:
+  case Builtin::BI__builtin_isgreaterequal:
+  case Builtin::BI__builtin_isless:
+  case Builtin::BI__builtin_islessequal:
+  case Builtin::BI__builtin_islessgreater:
+  case Builtin::BI__builtin_isunordered:
+    if (BuiltinUnorderedCompare(TheCall, BuiltinID))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_fpclassify:
+    if (BuiltinFPClassification(TheCall, 6, BuiltinID))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_isfpclass:
+    if (BuiltinFPClassification(TheCall, 2, BuiltinID))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_isfinite:
+  case Builtin::BI__builtin_isinf:
+  case Builtin::BI__builtin_isinf_sign:
+  case Builtin::BI__builtin_isnan:
+  case Builtin::BI__builtin_issignaling:
+  case Builtin::BI__builtin_isnormal:
+  case Builtin::BI__builtin_issubnormal:
+  case Builtin::BI__builtin_iszero:
+  case Builtin::BI__builtin_signbit:
+  case Builtin::BI__builtin_signbitf:
+  case Builtin::BI__builtin_signbitl:
+    if (BuiltinFPClassification(TheCall, 1, BuiltinID))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_shufflevector:
+    return BuiltinShuffleVector(TheCall);
+    // TheCall will be freed by the smart pointer here, but that's fine, since
+    // BuiltinShuffleVector guts it, but then doesn't release it.
+  case Builtin::BI__builtin_masked_load:
+  case Builtin::BI__builtin_masked_expand_load:
+    return BuiltinMaskedLoad(*this, TheCall);
+  case Builtin::BI__builtin_masked_store:
+  case Builtin::BI__builtin_masked_compress_store:
+    return BuiltinMaskedStore(*this, TheCall);
+  case Builtin::BI__builtin_masked_gather:
+    return BuiltinMaskedGather(*this, TheCall);
+  case Builtin::BI__builtin_masked_scatter:
+    return BuiltinMaskedScatter(*this, TheCall);
+  case Builtin::BI__builtin_invoke:
+    return BuiltinInvoke(*this, TheCall);
+  case Builtin::BI__builtin_prefetch:
+    if (BuiltinPrefetch(TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_alloca_with_align:
+  case Builtin::BI__builtin_alloca_with_align_uninitialized:
+    if (BuiltinAllocaWithAlign(TheCall))
+      return ExprError();
+    [[fallthrough]];
+  case Builtin::BI__builtin_alloca:
+  case Builtin::BI__builtin_alloca_uninitialized:
+    Diag(TheCall->getBeginLoc(), diag::warn_alloca)
+        << TheCall->getDirectCallee();
+    if (getLangOpts().OpenCL) {
+      builtinAllocaAddrSpace(*this, TheCall);
+    }
+    break;
+  case Builtin::BI__builtin_infer_alloc_token:
+    if (checkBuiltinInferAllocToken(*this, TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__arithmetic_fence:
+    if (BuiltinArithmeticFence(TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__assume:
+  case Builtin::BI__builtin_assume:
+    if (BuiltinAssume(TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_assume_aligned:
+    if (BuiltinAssumeAligned(TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_dynamic_object_size:
+  case Builtin::BI__builtin_object_size:
+    if (BuiltinConstantArgRange(TheCall, 1, 0, 3))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_longjmp:
+    if (BuiltinLongjmp(TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_setjmp:
+    if (BuiltinSetjmp(TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_classify_type:
+    if (checkArgCount(TheCall, 1))
+      return true;
+    TheCall->setType(Context.IntTy);
+    break;
+  case Builtin::BI__builtin_complex:
+    if (BuiltinComplex(TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_constant_p: {
+    if (checkArgCount(TheCall, 1))
+      return true;
+    ExprResult Arg = DefaultFunctionArrayLvalueConversion(TheCall->getArg(0));
+    if (Arg.isInvalid()) return true;
+    TheCall->setArg(0, Arg.get());
+    TheCall->setType(Context.IntTy);
+    break;
+  }
+  case Builtin::BI__builtin_launder:
+    return BuiltinLaunder(*this, TheCall);
+  case Builtin::BI__builtin_is_within_lifetime:
+    return BuiltinIsWithinLifetime(*this, TheCall);
+  case Builtin::BI__builtin_trivially_relocate:
+    return BuiltinTriviallyRelocate(*this, TheCall);
+
+  case Builtin::BI__sync_fetch_and_add:
+  case Builtin::BI__sync_fetch_and_add_1:
+  case Builtin::BI__sync_fetch_and_add_2:
+  case Builtin::BI__sync_fetch_and_add_4:
+  case Builtin::BI__sync_fetch_and_add_8:
+  case Builtin::BI__sync_fetch_and_add_16:
+  case Builtin::BI__sync_fetch_and_sub:
+  case Builtin::BI__sync_fetch_and_sub_1:
+  case Builtin::BI__sync_fetch_and_sub_2:
+  case Builtin::BI__sync_fetch_and_sub_4:
+  case Builtin::BI__sync_fetch_and_sub_8:
+  case Builtin::BI__sync_fetch_and_sub_16:
+  case Builtin::BI__sync_fetch_and_or:
+  case Builtin::BI__sync_fetch_and_or_1:
+  case Builtin::BI__sync_fetch_and_or_2:
+  case Builtin::BI__sync_fetch_and_or_4:
+  case Builtin::BI__sync_fetch_and_or_8:
+  case Builtin::BI__sync_fetch_and_or_16:
+  case Builtin::BI__sync_fetch_and_and:
+  case Builtin::BI__sync_fetch_and_and_1:
+  case Builtin::BI__sync_fetch_and_and_2:
+  case Builtin::BI__sync_fetch_and_and_4:
+  case Builtin::BI__sync_fetch_and_and_8:
+  case Builtin::BI__sync_fetch_and_and_16:
+  case Builtin::BI__sync_fetch_and_xor:
+  case Builtin::BI__sync_fetch_and_xor_1:
+  case Builtin::BI__sync_fetch_and_xor_2:
+  case Builtin::BI__sync_fetch_and_xor_4:
+  case Builtin::BI__sync_fetch_and_xor_8:
+  case Builtin::BI__sync_fetch_and_xor_16:
+  case Builtin::BI__sync_fetch_and_nand:
+  case Builtin::BI__sync_fetch_and_nand_1:
+  case Builtin::BI__sync_fetch_and_nand_2:
+  case Builtin::BI__sync_fetch_and_nand_4:
+  case Builtin::BI__sync_fetch_and_nand_8:
+  case Builtin::BI__sync_fetch_and_nand_16:
+  case Builtin::BI__sync_add_and_fetch:
+  case Builtin::BI__sync_add_and_fetch_1:
+  case Builtin::BI__sync_add_and_fetch_2:
+  case Builtin::BI__sync_add_and_fetch_4:
+  case Builtin::BI__sync_add_and_fetch_8:
+  case Builtin::BI__sync_add_and_fetch_16:
+  case Builtin::BI__sync_sub_and_fetch:
+  case Builtin::BI__sync_sub_and_fetch_1:
+  case Builtin::BI__sync_sub_and_fetch_2:
+  case Builtin::BI__sync_sub_and_fetch_4:
+  case Builtin::BI__sync_sub_and_fetch_8:
+  case Builtin::BI__sync_sub_and_fetch_16:
+  case Builtin::BI__sync_and_and_fetch:
+  case Builtin::BI__sync_and_and_fetch_1:
+  case Builtin::BI__sync_and_and_fetch_2:
+  case Builtin::BI__sync_and_and_fetch_4:
+  case Builtin::BI__sync_and_and_fetch_8:
+  case Builtin::BI__sync_and_and_fetch_16:
+  case Builtin::BI__sync_or_and_fetch:
+  case Builtin::BI__sync_or_and_fetch_1:
+  case Builtin::BI__sync_or_and_fetch_2:
+  case Builtin::BI__sync_or_and_fetch_4:
+  case Builtin::BI__sync_or_and_fetch_8:
+  case Builtin::BI__sync_or_and_fetch_16:
+  case Builtin::BI__sync_xor_and_fetch:
+  case Builtin::BI__sync_xor_and_fetch_1:
+  case Builtin::BI__sync_xor_and_fetch_2:
+  case Builtin::BI__sync_xor_and_fetch_4:
+  case Builtin::BI__sync_xor_and_fetch_8:
+  case Builtin::BI__sync_xor_and_fetch_16:
+  case Builtin::BI__sync_nand_and_fetch:
+  case Builtin::BI__sync_nand_and_fetch_1:
+  case Builtin::BI__sync_nand_and_fetch_2:
+  case Builtin::BI__sync_nand_and_fetch_4:
+  case Builtin::BI__sync_nand_and_fetch_8:
+  case Builtin::BI__sync_nand_and_fetch_16:
+  case Builtin::BI__sync_val_compare_and_swap:
+  case Builtin::BI__sync_val_compare_and_swap_1:
+  case Builtin::BI__sync_val_compare_and_swap_2:
+  case Builtin::BI__sync_val_compare_and_swap_4:
+  case Builtin::BI__sync_val_compare_and_swap_8:
+  case Builtin::BI__sync_val_compare_and_swap_16:
+  case Builtin::BI__sync_bool_compare_and_swap:
+  case Builtin::BI__sync_bool_compare_and_swap_1:
+  case Builtin::BI__sync_bool_compare_and_swap_2:
+  case Builtin::BI__sync_bool_compare_and_swap_4:
+  case Builtin::BI__sync_bool_compare_and_swap_8:
+  case Builtin::BI__sync_bool_compare_and_swap_16:
+  case Builtin::BI__sync_lock_test_and_set:
+  case Builtin::BI__sync_lock_test_and_set_1:
+  case Builtin::BI__sync_lock_test_and_set_2:
+  case Builtin::BI__sync_lock_test_and_set_4:
+  case Builtin::BI__sync_lock_test_and_set_8:
+  case Builtin::BI__sync_lock_test_and_set_16:
+  case Builtin::BI__sync_lock_release:
+  case Builtin::BI__sync_lock_release_1:
+  case Builtin::BI__sync_lock_release_2:
+  case Builtin::BI__sync_lock_release_4:
+  case Builtin::BI__sync_lock_release_8:
+  case Builtin::BI__sync_lock_release_16:
+  case Builtin::BI__sync_swap:
+  case Builtin::BI__sync_swap_1:
+  case Builtin::BI__sync_swap_2:
+  case Builtin::BI__sync_swap_4:
+  case Builtin::BI__sync_swap_8:
+  case Builtin::BI__sync_swap_16:
+    return BuiltinAtomicOverloaded(TheCallResult);
+  case Builtin::BI__sync_synchronize:
+    Diag(TheCall->getBeginLoc(), diag::warn_atomic_implicit_seq_cst)
+        << TheCall->getCallee()->getSourceRange();
+    break;
+  case Builtin::BI__builtin_nontemporal_load:
+  case Builtin::BI__builtin_nontemporal_store:
+    return BuiltinNontemporalOverloaded(TheCallResult);
+  case Builtin::BI__builtin_memcpy_inline: {
+    clang::Expr *SizeOp = TheCall->getArg(2);
+    // We warn about copying to or from `nullptr` pointers when `size` is
+    // greater than 0. When `size` is value dependent we cannot evaluate its
+    // value so we bail out.
+    if (SizeOp->isValueDependent())
+      break;
+    if (!SizeOp->EvaluateKnownConstInt(Context).isZero()) {
+      CheckNonNullArgument(*this, TheCall->getArg(0), TheCall->getExprLoc());
+      CheckNonNullArgument(*this, TheCall->getArg(1), TheCall->getExprLoc());
+    }
+    break;
+  }
+  case Builtin::BI__builtin_memset_inline: {
+    clang::Expr *SizeOp = TheCall->getArg(2);
+    // We warn about filling to `nullptr` pointers when `size` is greater than
+    // 0. When `size` is value dependent we cannot evaluate its value so we bail
+    // out.
+    if (SizeOp->isValueDependent())
+      break;
+    if (!SizeOp->EvaluateKnownConstInt(Context).isZero())
+      CheckNonNullArgument(*this, TheCall->getArg(0), TheCall->getExprLoc());
+    break;
+  }
+#define ATOMIC_BUILTIN(ID, TYPE, ATTRS)                                        \
+  case Builtin::BI##ID:                                                        \
+    return AtomicOpsOverloaded(TheCallResult, AtomicExpr::AO##ID);
+#include "clang/Basic/Builtins.inc"
+  case Builtin::BI__annotation:
+    if (BuiltinMSVCAnnotation(*this, TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_annotation:
+    if (BuiltinAnnotation(*this, TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_addressof:
+    if (BuiltinAddressof(*this, TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_function_start:
+    if (BuiltinFunctionStart(*this, TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_is_aligned:
+  case Builtin::BI__builtin_align_up:
+  case Builtin::BI__builtin_align_down:
+    if (BuiltinAlignment(*this, TheCall, BuiltinID))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_add_overflow:
+  case Builtin::BI__builtin_sub_overflow:
+  case Builtin::BI__builtin_mul_overflow:
+    if (BuiltinOverflow(*this, TheCall, BuiltinID))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_operator_new:
+  case Builtin::BI__builtin_operator_delete: {
+    bool IsDelete = BuiltinID == Builtin::BI__builtin_operator_delete;
+    ExprResult Res =
+        BuiltinOperatorNewDeleteOverloaded(TheCallResult, IsDelete);
+    return Res;
+  }
+  case Builtin::BI__builtin_dump_struct:
+    return BuiltinDumpStruct(*this, TheCall);
+  case Builtin::BI__builtin_expect_with_probability: {
+    // We first want to ensure we are called with 3 arguments
+    if (checkArgCount(TheCall, 3))
+      return ExprError();
+    // then check probability is constant float in range [0.0, 1.0]
+    const Expr *ProbArg = TheCall->getArg(2);
+    SmallVector<PartialDiagnosticAt, 8> Notes;
+    Expr::EvalResult Eval;
+    Eval.Diag = &Notes;
+    if ((!ProbArg->EvaluateAsConstantExpr(Eval, Context)) ||
+        !Eval.Val.isFloat()) {
+      Diag(ProbArg->getBeginLoc(), diag::err_probability_not_constant_float)
+          << ProbArg->getSourceRange();
+      for (const PartialDiagnosticAt &PDiag : Notes)
+        Diag(PDiag.first, PDiag.second);
+      return ExprError();
+    }
+    llvm::APFloat Probability = Eval.Val.getFloat();
+    bool LoseInfo = false;
+    Probability.convert(llvm::APFloat::IEEEdouble(),
+                        llvm::RoundingMode::Dynamic, &LoseInfo);
+    if (!(Probability >= llvm::APFloat(0.0) &&
+          Probability <= llvm::APFloat(1.0))) {
+      Diag(ProbArg->getBeginLoc(), diag::err_probability_out_of_range)
+          << ProbArg->getSourceRange();
+      return ExprError();
+    }
+    break;
+  }
+  case Builtin::BI__builtin_preserve_access_index:
+    if (BuiltinPreserveAI(*this, TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_call_with_static_chain:
+    if (BuiltinCallWithStaticChain(*this, TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__exception_code:
+  case Builtin::BI_exception_code:
+    if (BuiltinSEHScopeCheck(*this, TheCall, Scope::SEHExceptScope,
+                             diag::err_seh___except_block))
+      return ExprError();
+    break;
+  case Builtin::BI__exception_info:
+  case Builtin::BI_exception_info:
+    if (BuiltinSEHScopeCheck(*this, TheCall, Scope::SEHFilterScope,
+                             diag::err_seh___except_filter))
+      return ExprError();
+    break;
+  case Builtin::BI__GetExceptionInfo:
+    if (checkArgCount(TheCall, 1))
+      return ExprError();
+
+    if (CheckCXXThrowOperand(
+            TheCall->getBeginLoc(),
+            Context.getExceptionObjectType(FDecl->getParamDecl(0)->getType()),
+            TheCall))
+      return ExprError();
+
+    TheCall->setType(Context.VoidPtrTy);
+    break;
+  case Builtin::BIaddressof:
+  case Builtin::BI__addressof:
+  case Builtin::BIforward:
+  case Builtin::BIforward_like:
+  case Builtin::BImove:
+  case Builtin::BImove_if_noexcept:
+  case Builtin::BIas_const: {
+    // These are all expected to be of the form
+    //   T &/&&/* f(U &/&&)
+    // where T and U only differ in qualification.
+    if (checkArgCount(TheCall, 1))
+      return ExprError();
+    QualType Param = FDecl->getParamDecl(0)->getType();
+    QualType Result = FDecl->getReturnType();
+    bool ReturnsPointer = BuiltinID == Builtin::BIaddressof ||
+                          BuiltinID == Builtin::BI__addressof;
+    if (!(Param->isReferenceType() &&
+          (ReturnsPointer ? Result->isAnyPointerType()
+                          : Result->isReferenceType()) &&
+          Context.hasSameUnqualifiedType(Param->getPointeeType(),
+                                         Result->getPointeeType()))) {
+      Diag(TheCall->getBeginLoc(), diag::err_builtin_move_forward_unsupported)
+          << FDecl;
+      return ExprError();
+    }
+    break;
+  }
+  case Builtin::BI__builtin_ptrauth_strip:
+    return PointerAuthStrip(*this, TheCall);
+  case Builtin::BI__builtin_ptrauth_blend_discriminator:
+    return PointerAuthBlendDiscriminator(*this, TheCall);
+  case Builtin::BI__builtin_ptrauth_sign_constant:
+    return PointerAuthSignOrAuth(*this, TheCall, PAO_Sign,
+                                 /*RequireConstant=*/true);
+  case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
+    return PointerAuthSignOrAuth(*this, TheCall, PAO_Sign,
+                                 /*RequireConstant=*/false);
+  case Builtin::BI__builtin_ptrauth_auth:
+    return PointerAuthSignOrAuth(*this, TheCall, PAO_Auth,
+                                 /*RequireConstant=*/false);
+  case Builtin::BI__builtin_ptrauth_sign_generic_data:
+    return PointerAuthSignGenericData(*this, TheCall);
+  case Builtin::BI__builtin_ptrauth_auth_and_resign:
+    return PointerAuthAuthAndResign(*this, TheCall);
+  case Builtin::BI__builtin_ptrauth_auth_load_relative_and_sign:
+    return PointerAuthAuthLoadRelativeAndSign(*this, TheCall);
+  case Builtin::BI__builtin_ptrauth_string_discriminator:
+    return PointerAuthStringDiscriminator(*this, TheCall);
+
+  case Builtin::BI__builtin_get_vtable_pointer:
+    return GetVTablePointer(*this, TheCall);
+
+  // OpenCL v2.0, s6.13.16 - Pipe functions
+  case Builtin::BIread_pipe:
+  case Builtin::BIwrite_pipe:
+    // Since those two functions are declared with var args, we need a semantic
+    // check for the argument.
+    if (OpenCL().checkBuiltinRWPipe(TheCall))
+      return ExprError();
+    break;
+  case Builtin::BIreserve_read_pipe:
+  case Builtin::BIreserve_write_pipe:
+  case Builtin::BIwork_group_reserve_read_pipe:
+  case Builtin::BIwork_group_reserve_write_pipe:
+    if (OpenCL().checkBuiltinReserveRWPipe(TheCall))
+      return ExprError();
+    break;
+  case Builtin::BIsub_group_reserve_read_pipe:
+  case Builtin::BIsub_group_reserve_write_pipe:
+    if (OpenCL().checkSubgroupExt(TheCall) ||
+        OpenCL().checkBuiltinReserveRWPipe(TheCall))
+      return ExprError();
+    break;
+  case Builtin::BIcommit_read_pipe:
+  case Builtin::BIcommit_write_pipe:
+  case Builtin::BIwork_group_commit_read_pipe:
+  case Builtin::BIwork_group_commit_write_pipe:
+    if (OpenCL().checkBuiltinCommitRWPipe(TheCall))
+      return ExprError();
+    break;
+  case Builtin::BIsub_group_commit_read_pipe:
+  case Builtin::BIsub_group_commit_write_pipe:
+    if (OpenCL().checkSubgroupExt(TheCall) ||
+        OpenCL().checkBuiltinCommitRWPipe(TheCall))
+      return ExprError();
+    break;
+  case Builtin::BIget_pipe_num_packets:
+  case Builtin::BIget_pipe_max_packets:
+    if (OpenCL().checkBuiltinPipePackets(TheCall))
+      return ExprError();
+    break;
+  case Builtin::BIto_global:
+  case Builtin::BIto_local:
+  case Builtin::BIto_private:
+    if (OpenCL().checkBuiltinToAddr(BuiltinID, TheCall))
+      return ExprError();
+    break;
+  // OpenCL v2.0, s6.13.17 - Enqueue kernel functions.
+  case Builtin::BIenqueue_kernel:
+    if (OpenCL().checkBuiltinEnqueueKernel(TheCall))
+      return ExprError();
+    break;
+  case Builtin::BIget_kernel_work_group_size:
+  case Builtin::BIget_kernel_preferred_work_group_size_multiple:
+    if (OpenCL().checkBuiltinKernelWorkGroupSize(TheCall))
+      return ExprError();
+    break;
+  case Builtin::BIget_kernel_max_sub_group_size_for_ndrange:
+  case Builtin::BIget_kernel_sub_group_count_for_ndrange:
+    if (OpenCL().checkBuiltinNDRangeAndBlock(TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_os_log_format:
+    Cleanup.setExprNeedsCleanups(true);
+    [[fallthrough]];
+  case Builtin::BI__builtin_os_log_format_buffer_size:
+    if (BuiltinOSLogFormat(TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_frame_address:
+  case Builtin::BI__builtin_return_address: {
+    if (BuiltinConstantArgRange(TheCall, 0, 0, 0xFFFF))
+      return ExprError();
+
+    // -Wframe-address warning if non-zero passed to builtin
+    // return/frame address.
+    Expr::EvalResult Result;
+    if (!TheCall->getArg(0)->isValueDependent() &&
+        TheCall->getArg(0)->EvaluateAsInt(Result, getASTContext()) &&
+        Result.Val.getInt() != 0)
+      Diag(TheCall->getBeginLoc(), diag::warn_frame_address)
+          << ((BuiltinID == Builtin::BI__builtin_return_address)
+                  ? "__builtin_return_address"
+                  : "__builtin_frame_address")
+          << TheCall->getSourceRange();
+    break;
+  }
+
+  case Builtin::BI__builtin_nondeterministic_value: {
+    if (BuiltinNonDeterministicValue(TheCall))
+      return ExprError();
+    break;
+  }
+
+  // __builtin_elementwise_abs restricts the element type to signed integers or
+  // floating point types only.
+  case Builtin::BI__builtin_elementwise_abs:
+    if (PrepareBuiltinElementwiseMathOneArgCall(
+            TheCall, EltwiseBuiltinArgTyRestriction::SignedIntOrFloatTy))
+      return ExprError();
+    break;
+
+  // These builtins restrict the element type to floating point
+  // types only.
+  case Builtin::BI__builtin_elementwise_acos:
+  case Builtin::BI__builtin_elementwise_asin:
+  case Builtin::BI__builtin_elementwise_atan:
+  case Builtin::BI__builtin_elementwise_ceil:
+  case Builtin::BI__builtin_elementwise_cos:
+  case Builtin::BI__builtin_elementwise_cosh:
+  case Builtin::BI__builtin_elementwise_exp:
+  case Builtin::BI__builtin_elementwise_exp2:
+  case Builtin::BI__builtin_elementwise_exp10:
+  case Builtin::BI__builtin_elementwise_floor:
+  case Builtin::BI__builtin_elementwise_log:
+  case Builtin::BI__builtin_elementwise_log2:
+  case Builtin::BI__builtin_elementwise_log10:
+  case Builtin::BI__builtin_elementwise_roundeven:
+  case Builtin::BI__builtin_elementwise_round:
+  case Builtin::BI__builtin_elementwise_rint:
+  case Builtin::BI__builtin_elementwise_nearbyint:
+  case Builtin::BI__builtin_elementwise_sin:
+  case Builtin::BI__builtin_elementwise_sinh:
+  case Builtin::BI__builtin_elementwise_sqrt:
+  case Builtin::BI__builtin_elementwise_tan:
+  case Builtin::BI__builtin_elementwise_tanh:
+  case Builtin::BI__builtin_elementwise_trunc:
+  case Builtin::BI__builtin_elementwise_canonicalize:
+    if (PrepareBuiltinElementwiseMathOneArgCall(
+            TheCall, EltwiseBuiltinArgTyRestriction::FloatTy))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_elementwise_fma:
+    if (BuiltinElementwiseTernaryMath(TheCall))
+      return ExprError();
+    break;
+
+  case Builtin::BI__builtin_elementwise_ldexp: {
+    if (checkArgCount(TheCall, 2))
+      return ExprError();
+
+    ExprResult A = BuiltinVectorMathConversions(*this, TheCall->getArg(0));
+    if (A.isInvalid())
+      return ExprError();
+    QualType TyA = A.get()->getType();
+    if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA,
+                                    EltwiseBuiltinArgTyRestriction::FloatTy, 1))
+      return ExprError();
+
+    ExprResult Exp = UsualUnaryConversions(TheCall->getArg(1));
+    if (Exp.isInvalid())
+      return ExprError();
+    QualType TyExp = Exp.get()->getType();
+    if (checkMathBuiltinElementType(*this, Exp.get()->getBeginLoc(), TyExp,
+                                    EltwiseBuiltinArgTyRestriction::IntegerTy,
+                                    2))
+      return ExprError();
+
+    // Check the two arguments are either scalars or vectors of equal length.
+    const auto *Vec0 = TyA->getAs<VectorType>();
+    const auto *Vec1 = TyExp->getAs<VectorType>();
+    unsigned Arg0Length = Vec0 ? Vec0->getNumElements() : 0;
+    unsigned Arg1Length = Vec1 ? Vec1->getNumElements() : 0;
+    if (Arg0Length != Arg1Length) {
+      Diag(Exp.get()->getBeginLoc(),
+           diag::err_typecheck_vector_lengths_not_equal)
+          << TyA << TyExp << A.get()->getSourceRange()
+          << Exp.get()->getSourceRange();
+      return ExprError();
+    }
+
+    TheCall->setArg(0, A.get());
+    TheCall->setArg(1, Exp.get());
+    TheCall->setType(TyA);
+    break;
+  }
+
+  // These builtins restrict the element type to floating point
+  // types only, and take in two arguments.
+  case Builtin::BI__builtin_elementwise_minnum:
+  case Builtin::BI__builtin_elementwise_maxnum:
+  case Builtin::BI__builtin_elementwise_minimum:
+  case Builtin::BI__builtin_elementwise_maximum:
+  case Builtin::BI__builtin_elementwise_minimumnum:
+  case Builtin::BI__builtin_elementwise_maximumnum:
+  case Builtin::BI__builtin_elementwise_atan2:
+  case Builtin::BI__builtin_elementwise_fmod:
+  case Builtin::BI__builtin_elementwise_pow:
+    if (BuiltinElementwiseMath(TheCall,
+                               EltwiseBuiltinArgTyRestriction::FloatTy))
+      return ExprError();
+    break;
+  // These builtins restrict the element type to integer
+  // types only.
+  case Builtin::BI__builtin_elementwise_add_sat:
+  case Builtin::BI__builtin_elementwise_sub_sat:
+    if (BuiltinElementwiseMath(TheCall,
+                               EltwiseBuiltinArgTyRestriction::IntegerTy))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_elementwise_fshl:
+  case Builtin::BI__builtin_elementwise_fshr:
+    if (BuiltinElementwiseTernaryMath(
+            TheCall, EltwiseBuiltinArgTyRestriction::IntegerTy))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_elementwise_min:
+  case Builtin::BI__builtin_elementwise_max:
+    if (BuiltinElementwiseMath(TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_elementwise_popcount:
+  case Builtin::BI__builtin_elementwise_bitreverse:
+    if (PrepareBuiltinElementwiseMathOneArgCall(
+            TheCall, EltwiseBuiltinArgTyRestriction::IntegerTy))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_elementwise_copysign: {
+    if (checkArgCount(TheCall, 2))
+      return ExprError();
+
+    ExprResult Magnitude = UsualUnaryConversions(TheCall->getArg(0));
+    ExprResult Sign = UsualUnaryConversions(TheCall->getArg(1));
+    if (Magnitude.isInvalid() || Sign.isInvalid())
+      return ExprError();
+
+    QualType MagnitudeTy = Magnitude.get()->getType();
+    QualType SignTy = Sign.get()->getType();
+    if (checkMathBuiltinElementType(
+            *this, TheCall->getArg(0)->getBeginLoc(), MagnitudeTy,
+            EltwiseBuiltinArgTyRestriction::FloatTy, 1) ||
+        checkMathBuiltinElementType(
+            *this, TheCall->getArg(1)->getBeginLoc(), SignTy,
+            EltwiseBuiltinArgTyRestriction::FloatTy, 2)) {
+      return ExprError();
+    }
+
+    if (MagnitudeTy.getCanonicalType() != SignTy.getCanonicalType()) {
+      return Diag(Sign.get()->getBeginLoc(),
+                  diag::err_typecheck_call_different_arg_types)
+             << MagnitudeTy << SignTy;
+    }
+
+    TheCall->setArg(0, Magnitude.get());
+    TheCall->setArg(1, Sign.get());
+    TheCall->setType(Magnitude.get()->getType());
+    break;
+  }
+  case Builtin::BI__builtin_elementwise_clzg:
+  case Builtin::BI__builtin_elementwise_ctzg:
+    // These builtins can be unary or binary. Note for empty calls we call the
+    // unary checker in order to not emit an error that says the function
+    // expects 2 arguments, which would be misleading.
+    if (TheCall->getNumArgs() <= 1) {
+      if (PrepareBuiltinElementwiseMathOneArgCall(
+              TheCall, EltwiseBuiltinArgTyRestriction::IntegerTy))
+        return ExprError();
+    } else if (BuiltinElementwiseMath(
+                   TheCall, EltwiseBuiltinArgTyRestriction::IntegerTy))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_reduce_max:
+  case Builtin::BI__builtin_reduce_min: {
+    if (PrepareBuiltinReduceMathOneArgCall(TheCall))
+      return ExprError();
+
+    const Expr *Arg = TheCall->getArg(0);
+    const auto *TyA = Arg->getType()->getAs<VectorType>();
+
+    QualType ElTy;
+    if (TyA)
+      ElTy = TyA->getElementType();
+    else if (Arg->getType()->isSizelessVectorType())
+      ElTy = Arg->getType()->getSizelessVectorEltType(Context);
+
+    if (ElTy.isNull()) {
+      Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+          << 1 << /* vector ty */ 2 << /* no int */ 0 << /* no fp */ 0
+          << Arg->getType();
+      return ExprError();
+    }
+
+    TheCall->setType(ElTy);
+    break;
+  }
+  case Builtin::BI__builtin_reduce_maximum:
+  case Builtin::BI__builtin_reduce_minimum: {
+    if (PrepareBuiltinReduceMathOneArgCall(TheCall))
+      return ExprError();
+
+    const Expr *Arg = TheCall->getArg(0);
+    const auto *TyA = Arg->getType()->getAs<VectorType>();
+
+    QualType ElTy;
+    if (TyA)
+      ElTy = TyA->getElementType();
+    else if (Arg->getType()->isSizelessVectorType())
+      ElTy = Arg->getType()->getSizelessVectorEltType(Context);
+
+    if (ElTy.isNull() || !ElTy->isFloatingType()) {
+      Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+          << 1 << /* vector of */ 4 << /* no int */ 0 << /* fp */ 1
+          << Arg->getType();
+      return ExprError();
+    }
+
+    TheCall->setType(ElTy);
+    break;
+  }
+
+  // These builtins support vectors of integers only.
+  // TODO: ADD/MUL should support floating-point types.
+  case Builtin::BI__builtin_reduce_add:
+  case Builtin::BI__builtin_reduce_mul:
+  case Builtin::BI__builtin_reduce_xor:
+  case Builtin::BI__builtin_reduce_or:
+  case Builtin::BI__builtin_reduce_and: {
+    if (PrepareBuiltinReduceMathOneArgCall(TheCall))
+      return ExprError();
+
+    const Expr *Arg = TheCall->getArg(0);
+    const auto *TyA = Arg->getType()->getAs<VectorType>();
+
+    QualType ElTy;
+    if (TyA)
+      ElTy = TyA->getElementType();
+    else if (Arg->getType()->isSizelessVectorType())
+      ElTy = Arg->getType()->getSizelessVectorEltType(Context);
+
+    if (ElTy.isNull() || !ElTy->isIntegerType()) {
+      Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+          << 1 << /* vector of */ 4 << /* int */ 1 << /* no fp */ 0
+          << Arg->getType();
+      return ExprError();
+    }
+
+    TheCall->setType(ElTy);
+    break;
+  }
+
+  case Builtin::BI__builtin_matrix_transpose:
+    return BuiltinMatrixTranspose(TheCall, TheCallResult);
+
+  case Builtin::BI__builtin_matrix_column_major_load:
+    return BuiltinMatrixColumnMajorLoad(TheCall, TheCallResult);
+
+  case Builtin::BI__builtin_matrix_column_major_store:
+    return BuiltinMatrixColumnMajorStore(TheCall, TheCallResult);
+
+  case Builtin::BI__builtin_verbose_trap:
+    if (!checkBuiltinVerboseTrap(TheCall, *this))
+      return ExprError();
+    break;
+
+  case Builtin::BI__builtin_get_device_side_mangled_name: {
+    auto Check = [](CallExpr *TheCall) {
+      if (TheCall->getNumArgs() != 1)
+        return false;
+      auto *DRE = dyn_cast<DeclRefExpr>(TheCall->getArg(0)->IgnoreImpCasts());
+      if (!DRE)
+        return false;
+      auto *D = DRE->getDecl();
+      if (!isa<FunctionDecl>(D) && !isa<VarDecl>(D))
+        return false;
+      return D->hasAttr<CUDAGlobalAttr>() || D->hasAttr<CUDADeviceAttr>() ||
+             D->hasAttr<CUDAConstantAttr>() || D->hasAttr<HIPManagedAttr>();
+    };
+    if (!Check(TheCall)) {
+      Diag(TheCall->getBeginLoc(),
+           diag::err_hip_invalid_args_builtin_mangled_name);
+      return ExprError();
+    }
+    break;
+  }
+  case Builtin::BI__builtin_bswapg:
+    if (BuiltinBswapg(*this, TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_popcountg:
+    if (BuiltinPopcountg(*this, TheCall))
+      return ExprError();
+    break;
+  case Builtin::BI__builtin_clzg:
+  case Builtin::BI__builtin_ctzg:
+    if (BuiltinCountZeroBitsGeneric(*this, TheCall))
+      return ExprError();
+    break;
+
+  case Builtin::BI__builtin_stdc_rotate_left:
+  case Builtin::BI__builtin_stdc_rotate_right:
+    if (BuiltinRotateGeneric(*this, TheCall))
+      return ExprError();
+    break;
+
+  case Builtin::BI__builtin_allow_runtime_check: {
+    Expr *Arg = TheCall->getArg(0);
+    // Check if the argument is a string literal.
+    if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts())) {
+      Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
+          << Arg->getSourceRange();
+      return ExprError();
+    }
+    break;
+  }
+
+  case Builtin::BI__builtin_allow_sanitize_check: {
+    Expr *Arg = TheCall->getArg(0);
+    // Check if the argument is a string literal.
+    const StringLiteral *SanitizerName =
+        dyn_cast<StringLiteral>(Arg->IgnoreParenImpCasts());
+    if (!SanitizerName) {
+      Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
+          << Arg->getSourceRange();
+      return ExprError();
+    }
+    // Validate the sanitizer name.
+    if (!llvm::StringSwitch<bool>(SanitizerName->getString())
+             .Cases({"address", "thread", "memory", "hwaddress",
+                     "kernel-address", "kernel-memory", "kernel-hwaddress"},
+                    true)
+             .Default(false)) {
+      Diag(TheCall->getBeginLoc(), diag::err_invalid_builtin_argument)
+          << SanitizerName->getString() << "__builtin_allow_sanitize_check"
+          << Arg->getSourceRange();
+      return ExprError();
+    }
+    break;
+  }
+  case Builtin::BI__builtin_counted_by_ref:
+    if (BuiltinCountedByRef(TheCall))
+      return ExprError();
+    break;
+  }
+
+  if (getLangOpts().HLSL && HLSL().CheckBuiltinFunctionCall(BuiltinID, TheCall))
+    return ExprError();
+
+  // Since the target specific builtins for each arch overlap, only check those
+  // of the arch we are compiling for.
+  if (Context.BuiltinInfo.isTSBuiltin(BuiltinID)) {
+    if (Context.BuiltinInfo.isAuxBuiltinID(BuiltinID)) {
+      assert(Context.getAuxTargetInfo() &&
+             "Aux Target Builtin, but not an aux target?");
+
+      if (CheckTSBuiltinFunctionCall(
+              *Context.getAuxTargetInfo(),
+              Context.BuiltinInfo.getAuxBuiltinID(BuiltinID), TheCall))
+        return ExprError();
+    } else {
+      if (CheckTSBuiltinFunctionCall(Context.getTargetInfo(), BuiltinID,
+                                     TheCall))
+        return ExprError();
+    }
+  }
+
+  return TheCallResult;
+}
+
+bool Sema::ValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum) {
+  llvm::APSInt Result;
+  // We can't check the value of a dependent argument.
+  Expr *Arg = TheCall->getArg(ArgNum);
+  if (Arg->isTypeDependent() || Arg->isValueDependent())
+    return false;
+
+  // Check constant-ness first.
+  if (BuiltinConstantArg(TheCall, ArgNum, Result))
+    return true;
+
+  // Check contiguous run of 1s, 0xFF0000FF is also a run of 1s.
+  if (Result.isShiftedMask() || (~Result).isShiftedMask())
+    return false;
+
+  return Diag(TheCall->getBeginLoc(),
+              diag::err_argument_not_contiguous_bit_field)
+         << ArgNum << Arg->getSourceRange();
+}
+
+bool Sema::getFormatStringInfo(const Decl *D, unsigned FormatIdx,
+                               unsigned FirstArg, FormatStringInfo *FSI) {
+  bool HasImplicitThisParam = hasImplicitObjectParameter(D);
+  bool IsVariadic = false;
+  if (const FunctionType *FnTy = D->getFunctionType())
+    IsVariadic = cast<FunctionProtoType>(FnTy)->isVariadic();
+  else if (const auto *BD = dyn_cast<BlockDecl>(D))
+    IsVariadic = BD->isVariadic();
+  else if (const auto *OMD = dyn_cast<ObjCMethodDecl>(D))
+    IsVariadic = OMD->isVariadic();
+
+  return getFormatStringInfo(FormatIdx, FirstArg, HasImplicitThisParam,
+                             IsVariadic, FSI);
+}
+
+bool Sema::getFormatStringInfo(unsigned FormatIdx, unsigned FirstArg,
+                               bool HasImplicitThisParam, bool IsVariadic,
+                               FormatStringInfo *FSI) {
+  if (FirstArg == 0)
+    FSI->ArgPassingKind = FAPK_VAList;
+  else if (IsVariadic)
+    FSI->ArgPassingKind = FAPK_Variadic;
+  else
+    FSI->ArgPassingKind = FAPK_Fixed;
+  FSI->FormatIdx = FormatIdx - 1;
+  FSI->FirstDataArg = FSI->ArgPassingKind == FAPK_VAList ? 0 : FirstArg - 1;
+
+  // The way the format attribute works in GCC, the implicit this argument
+  // of member functions is counted. However, it doesn't appear in our own
+  // lists, so decrement format_idx in that case.
+  if (HasImplicitThisParam) {
+    if(FSI->FormatIdx == 0)
+      return false;
+    --FSI->FormatIdx;
+    if (FSI->FirstDataArg != 0)
+      --FSI->FirstDataArg;
+  }
+  return true;
+}
+
+/// Checks if a the given expression evaluates to null.
+///
+/// Returns true if the value evaluates to null.
+static bool CheckNonNullExpr(Sema &S, const Expr *Expr) {
+  // Treat (smart) pointers constructed from nullptr as null, whether we can
+  // const-evaluate them or not.
+  // This must happen first: the smart pointer expr might have _Nonnull type!
+  if (isa<CXXNullPtrLiteralExpr>(
+          IgnoreExprNodes(Expr, IgnoreImplicitAsWrittenSingleStep,
+                          IgnoreElidableImplicitConstructorSingleStep)))
+    return true;
+
+  // If the expression has non-null type, it doesn't evaluate to null.
+  if (auto nullability = Expr->IgnoreImplicit()->getType()->getNullability()) {
+    if (*nullability == NullabilityKind::NonNull)
+      return false;
+  }
+
+  // As a special case, transparent unions initialized with zero are
+  // considered null for the purposes of the nonnull attribute.
+  if (const RecordType *UT = Expr->getType()->getAsUnionType();
+      UT &&
+      UT->getDecl()->getMostRecentDecl()->hasAttr<TransparentUnionAttr>()) {
+    if (const auto *CLE = dyn_cast<CompoundLiteralExpr>(Expr))
+      if (const auto *ILE = dyn_cast<InitListExpr>(CLE->getInitializer()))
+        Expr = ILE->getInit(0);
+  }
+
+  bool Result;
+  return (!Expr->isValueDependent() &&
+          Expr->EvaluateAsBooleanCondition(Result, S.Context) &&
+          !Result);
+}
+
+static void CheckNonNullArgument(Sema &S,
+                                 const Expr *ArgExpr,
+                                 SourceLocation CallSiteLoc) {
+  if (CheckNonNullExpr(S, ArgExpr))
+    S.DiagRuntimeBehavior(CallSiteLoc, ArgExpr,
+                          S.PDiag(diag::warn_null_arg)
+                              << ArgExpr->getSourceRange());
+}
+
+/// Determine whether the given type has a non-null nullability annotation.
+static bool isNonNullType(QualType type) {
+  if (auto nullability = type->getNullability())
+    return *nullability == NullabilityKind::NonNull;
+
+  return false;
+}
+
+static void CheckNonNullArguments(Sema &S,
+                                  const NamedDecl *FDecl,
+                                  const FunctionProtoType *Proto,
+                                  ArrayRef<const Expr *> Args,
+                                  SourceLocation CallSiteLoc) {
+  assert((FDecl || Proto) && "Need a function declaration or prototype");
+
+  // Already checked by constant evaluator.
+  if (S.isConstantEvaluatedContext())
+    return;
+  // Check the attributes attached to the method/function itself.
+  llvm::SmallBitVector NonNullArgs;
+  if (FDecl) {
+    // Handle the nonnull attribute on the function/method declaration itself.
+    for (const auto *NonNull : FDecl->specific_attrs<NonNullAttr>()) {
+      if (!NonNull->args_size()) {
+        // Easy case: all pointer arguments are nonnull.
+        for (const auto *Arg : Args)
+          if (S.isValidPointerAttrType(Arg->getType()))
+            CheckNonNullArgument(S, Arg, CallSiteLoc);
+        return;
+      }
+
+      for (const ParamIdx &Idx : NonNull->args()) {
+        unsigned IdxAST = Idx.getASTIndex();
+        if (IdxAST >= Args.size())
+          continue;
+        if (NonNullArgs.empty())
+          NonNullArgs.resize(Args.size());
+        NonNullArgs.set(IdxAST);
+      }
+    }
+  }
+
+  if (FDecl && (isa<FunctionDecl>(FDecl) || isa<ObjCMethodDecl>(FDecl))) {
+    // Handle the nonnull attribute on the parameters of the
+    // function/method.
+    ArrayRef<ParmVarDecl*> parms;
+    if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(FDecl))
+      parms = FD->parameters();
+    else
+      parms = cast<ObjCMethodDecl>(FDecl)->parameters();
+
+    unsigned ParamIndex = 0;
+    for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end();
+         I != E; ++I, ++ParamIndex) {
+      const ParmVarDecl *PVD = *I;
+      if (PVD->hasAttr<NonNullAttr>() || isNonNullType(PVD->getType())) {
+        if (NonNullArgs.empty())
+          NonNullArgs.resize(Args.size());
+
+        NonNullArgs.set(ParamIndex);
+      }
+    }
+  } else {
+    // If we have a non-function, non-method declaration but no
+    // function prototype, try to dig out the function prototype.
+    if (!Proto) {
+      if (const ValueDecl *VD = dyn_cast<ValueDecl>(FDecl)) {
+        QualType type = VD->getType().getNonReferenceType();
+        if (auto pointerType = type->getAs<PointerType>())
+          type = pointerType->getPointeeType();
+        else if (auto blockType = type->getAs<BlockPointerType>())
+          type = blockType->getPointeeType();
+        // FIXME: data member pointers?
+
+        // Dig out the function prototype, if there is one.
+        Proto = type->getAs<FunctionProtoType>();
+      }
+    }
+
+    // Fill in non-null argument information from the nullability
+    // information on the parameter types (if we have them).
+    if (Proto) {
+      unsigned Index = 0;
+      for (auto paramType : Proto->getParamTypes()) {
+        if (isNonNullType(paramType)) {
+          if (NonNullArgs.empty())
+            NonNullArgs.resize(Args.size());
+
+          NonNullArgs.set(Index);
+        }
+
+        ++Index;
+      }
+    }
+  }
+
+  // Check for non-null arguments.
+  for (unsigned ArgIndex = 0, ArgIndexEnd = NonNullArgs.size();
+       ArgIndex != ArgIndexEnd; ++ArgIndex) {
+    if (NonNullArgs[ArgIndex])
+      CheckNonNullArgument(S, Args[ArgIndex], Args[ArgIndex]->getExprLoc());
+  }
+}
+
+void Sema::CheckArgAlignment(SourceLocation Loc, NamedDecl *FDecl,
+                             StringRef ParamName, QualType ArgTy,
+                             QualType ParamTy) {
+
+  // If a function accepts a pointer or reference type
+  if (!ParamTy->isPointerType() && !ParamTy->isReferenceType())
+    return;
+
+  // If the parameter is a pointer type, get the pointee type for the
+  // argument too. If the parameter is a reference type, don't try to get
+  // the pointee type for the argument.
+  if (ParamTy->isPointerType())
+    ArgTy = ArgTy->getPointeeType();
+
+  // Remove reference or pointer
+  ParamTy = ParamTy->getPointeeType();
+
+  // Find expected alignment, and the actual alignment of the passed object.
+  // getTypeAlignInChars requires complete types
+  if (ArgTy.isNull() || ParamTy->isDependentType() ||
+      ParamTy->isIncompleteType() || ArgTy->isIncompleteType() ||
+      ParamTy->isUndeducedType() || ArgTy->isUndeducedType())
+    return;
+
+  CharUnits ParamAlign = Context.getTypeAlignInChars(ParamTy);
+  CharUnits ArgAlign = Context.getTypeAlignInChars(ArgTy);
+
+  // If the argument is less aligned than the parameter, there is a
+  // potential alignment issue.
+  if (ArgAlign < ParamAlign)
+    Diag(Loc, diag::warn_param_mismatched_alignment)
+        << (int)ArgAlign.getQuantity() << (int)ParamAlign.getQuantity()
+        << ParamName << (FDecl != nullptr) << FDecl;
+}
+
+void Sema::checkLifetimeCaptureBy(FunctionDecl *FD, bool IsMemberFunction,
+                                  const Expr *ThisArg,
+                                  ArrayRef<const Expr *> Args) {
+  if (!FD || Args.empty())
+    return;
+  auto GetArgAt = [&](int Idx) -> const Expr * {
+    if (Idx == LifetimeCaptureByAttr::Global ||
+        Idx == LifetimeCaptureByAttr::Unknown)
+      return nullptr;
+    if (IsMemberFunction && Idx == 0)
+      return ThisArg;
+    return Args[Idx - IsMemberFunction];
+  };
+  auto HandleCaptureByAttr = [&](const LifetimeCaptureByAttr *Attr,
+                                 unsigned ArgIdx) {
+    if (!Attr)
+      return;
+
+    Expr *Captured = const_cast<Expr *>(GetArgAt(ArgIdx));
+    for (int CapturingParamIdx : Attr->params()) {
+      // lifetime_capture_by(this) case is handled in the lifetimebound expr
+      // initialization codepath.
+      if (CapturingParamIdx == LifetimeCaptureByAttr::This &&
+          isa<CXXConstructorDecl>(FD))
+        continue;
+      Expr *Capturing = const_cast<Expr *>(GetArgAt(CapturingParamIdx));
+      CapturingEntity CE{Capturing};
+      // Ensure that 'Captured' outlives the 'Capturing' entity.
+      checkCaptureByLifetime(*this, CE, Captured);
+    }
+  };
+  for (unsigned I = 0; I < FD->getNumParams(); ++I)
+    HandleCaptureByAttr(FD->getParamDecl(I)->getAttr<LifetimeCaptureByAttr>(),
+                        I + IsMemberFunction);
+  // Check when the implicit object param is captured.
+  if (IsMemberFunction) {
+    TypeSourceInfo *TSI = FD->getTypeSourceInfo();
+    if (!TSI)
+      return;
+    AttributedTypeLoc ATL;
+    for (TypeLoc TL = TSI->getTypeLoc();
+         (ATL = TL.getAsAdjusted<AttributedTypeLoc>());
+         TL = ATL.getModifiedLoc())
+      HandleCaptureByAttr(ATL.getAttrAs<LifetimeCaptureByAttr>(), 0);
+  }
+}
+
+void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
+                     const Expr *ThisArg, ArrayRef<const Expr *> Args,
+                     bool IsMemberFunction, SourceLocation Loc,
+                     SourceRange Range, VariadicCallType CallType) {
+  // FIXME: We should check as much as we can in the template definition.
+  if (CurContext->isDependentContext())
+    return;
+
+  // Printf and scanf checking.
+  llvm::SmallBitVector CheckedVarArgs;
+  if (FDecl) {
+    for (const auto *I : FDecl->specific_attrs<FormatMatchesAttr>()) {
+      // Only create vector if there are format attributes.
+      CheckedVarArgs.resize(Args.size());
+      CheckFormatString(I, Args, IsMemberFunction, CallType, Loc, Range,
+                        CheckedVarArgs);
+    }
+
+    for (const auto *I : FDecl->specific_attrs<FormatAttr>()) {
+      CheckedVarArgs.resize(Args.size());
+      CheckFormatArguments(I, Args, IsMemberFunction, CallType, Loc, Range,
+                           CheckedVarArgs);
+    }
+  }
+
+  // Refuse POD arguments that weren't caught by the format string
+  // checks above.
+  auto *FD = dyn_cast_or_null<FunctionDecl>(FDecl);
+  if (CallType != VariadicCallType::DoesNotApply &&
+      (!FD || FD->getBuiltinID() != Builtin::BI__noop)) {
+    unsigned NumParams = Proto ? Proto->getNumParams()
+                         : isa_and_nonnull<FunctionDecl>(FDecl)
+                             ? cast<FunctionDecl>(FDecl)->getNumParams()
+                         : isa_and_nonnull<ObjCMethodDecl>(FDecl)
+                             ? cast<ObjCMethodDecl>(FDecl)->param_size()
+                             : 0;
+
+    for (unsigned ArgIdx = NumParams; ArgIdx < Args.size(); ++ArgIdx) {
+      // Args[ArgIdx] can be null in malformed code.
+      if (const Expr *Arg = Args[ArgIdx]) {
+        if (CheckedVarArgs.empty() || !CheckedVarArgs[ArgIdx])
+          checkVariadicArgument(Arg, CallType);
+      }
+    }
+  }
+  if (FD)
+    checkLifetimeCaptureBy(FD, IsMemberFunction, ThisArg, Args);
+  if (FDecl || Proto) {
+    CheckNonNullArguments(*this, FDecl, Proto, Args, Loc);
+
+    // Type safety checking.
+    if (FDecl) {
+      for (const auto *I : FDecl->specific_attrs<ArgumentWithTypeTagAttr>())
+        CheckArgumentWithTypeTag(I, Args, Loc);
+    }
+  }
+
+  // Check that passed arguments match the alignment of original arguments.
+  // Try to get the missing prototype from the declaration.
+  if (!Proto && FDecl) {
+    const auto *FT = FDecl->getFunctionType();
+    if (isa_and_nonnull<FunctionProtoType>(FT))
+      Proto = cast<FunctionProtoType>(FDecl->getFunctionType());
+  }
+  if (Proto) {
+    // For variadic functions, we may have more args than parameters.
+    // For some K&R functions, we may have less args than parameters.
+    const auto N = std::min<unsigned>(Proto->getNumParams(), Args.size());
+    bool IsScalableRet = Proto->getReturnType()->isSizelessVectorType();
+    bool IsScalableArg = false;
+    for (unsigned ArgIdx = 0; ArgIdx < N; ++ArgIdx) {
+      // Args[ArgIdx] can be null in malformed code.
+      if (const Expr *Arg = Args[ArgIdx]) {
+        if (Arg->containsErrors())
+          continue;
+
+        if (Context.getTargetInfo().getTriple().isOSAIX() && FDecl && Arg &&
+            FDecl->hasLinkage() &&
+            FDecl->getFormalLinkage() != Linkage::Internal &&
+            CallType == VariadicCallType::DoesNotApply)
+          PPC().checkAIXMemberAlignment((Arg->getExprLoc()), Arg);
+
+        QualType ParamTy = Proto->getParamType(ArgIdx);
+        if (ParamTy->isSizelessVectorType())
+          IsScalableArg = true;
+        QualType ArgTy = Arg->getType();
+        CheckArgAlignment(Arg->getExprLoc(), FDecl, std::to_string(ArgIdx + 1),
+                          ArgTy, ParamTy);
+      }
+    }
+
+    // If the callee has an AArch64 SME attribute to indicate that it is an
+    // __arm_streaming function, then the caller requires SME to be available.
+    FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
+    if (ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask) {
+      if (auto *CallerFD = dyn_cast<FunctionDecl>(CurContext)) {
+        llvm::StringMap<bool> CallerFeatureMap;
+        Context.getFunctionFeatureMap(CallerFeatureMap, CallerFD);
+        if (!CallerFeatureMap.contains("sme"))
+          Diag(Loc, diag::err_sme_call_in_non_sme_target);
+      } else if (!Context.getTargetInfo().hasFeature("sme")) {
+        Diag(Loc, diag::err_sme_call_in_non_sme_target);
+      }
+    }
+
+    // If the call requires a streaming-mode change and has scalable vector
+    // arguments or return values, then warn the user that the streaming and
+    // non-streaming vector lengths may be different.
+    // When both streaming and non-streaming vector lengths are defined and
+    // mismatched, produce an error.
+    const auto *CallerFD = dyn_cast<FunctionDecl>(CurContext);
+    if (CallerFD && (!FD || !FD->getBuiltinID()) &&
+        (IsScalableArg || IsScalableRet)) {
+      bool IsCalleeStreaming =
+          ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask;
+      bool IsCalleeStreamingCompatible =
+          ExtInfo.AArch64SMEAttributes &
+          FunctionType::SME_PStateSMCompatibleMask;
+      SemaARM::ArmStreamingType CallerFnType = getArmStreamingFnType(CallerFD);
+      if (!IsCalleeStreamingCompatible &&
+          (CallerFnType == SemaARM::ArmStreamingCompatible ||
+           ((CallerFnType == SemaARM::ArmStreaming) ^ IsCalleeStreaming))) {
+        const LangOptions &LO = getLangOpts();
+        unsigned VL = LO.VScaleMin * 128;
+        unsigned SVL = LO.VScaleStreamingMin * 128;
+        bool IsVLMismatch = VL && SVL && VL != SVL;
+
+        auto EmitDiag = [&](bool IsArg) {
+          if (IsVLMismatch) {
+            if (CallerFnType == SemaARM::ArmStreamingCompatible)
+              // Emit warning for streaming-compatible callers
+              Diag(Loc, diag::warn_sme_streaming_compatible_vl_mismatch)
+                  << IsArg << IsCalleeStreaming << SVL << VL;
+            else
+              // Emit error otherwise
+              Diag(Loc, diag::err_sme_streaming_transition_vl_mismatch)
+                  << IsArg << SVL << VL;
+          } else
+            Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming)
+                << IsArg;
+        };
+
+        if (IsScalableArg)
+          EmitDiag(true);
+        if (IsScalableRet)
+          EmitDiag(false);
+      }
+    }
+
+    FunctionType::ArmStateValue CalleeArmZAState =
+        FunctionType::getArmZAState(ExtInfo.AArch64SMEAttributes);
+    FunctionType::ArmStateValue CalleeArmZT0State =
+        FunctionType::getArmZT0State(ExtInfo.AArch64SMEAttributes);
+    if (CalleeArmZAState != FunctionType::ARM_None ||
+        CalleeArmZT0State != FunctionType::ARM_None) {
+      bool CallerHasZAState = false;
+      bool CallerHasZT0State = false;
+      if (CallerFD) {
+        auto *Attr = CallerFD->getAttr<ArmNewAttr>();
+        if (Attr && Attr->isNewZA())
+          CallerHasZAState = true;
+        if (Attr && Attr->isNewZT0())
+          CallerHasZT0State = true;
+        if (const auto *FPT = CallerFD->getType()->getAs<FunctionProtoType>()) {
+          CallerHasZAState |=
+              FunctionType::getArmZAState(
+                  FPT->getExtProtoInfo().AArch64SMEAttributes) !=
+              FunctionType::ARM_None;
+          CallerHasZT0State |=
+              FunctionType::getArmZT0State(
+                  FPT->getExtProtoInfo().AArch64SMEAttributes) !=
+              FunctionType::ARM_None;
+        }
+      }
+
+      if (CalleeArmZAState != FunctionType::ARM_None && !CallerHasZAState)
+        Diag(Loc, diag::err_sme_za_call_no_za_state);
+
+      if (CalleeArmZT0State != FunctionType::ARM_None && !CallerHasZT0State)
+        Diag(Loc, diag::err_sme_zt0_call_no_zt0_state);
+
+      if (CallerHasZAState && CalleeArmZAState == FunctionType::ARM_None &&
+          CalleeArmZT0State != FunctionType::ARM_None) {
+        Diag(Loc, diag::err_sme_unimplemented_za_save_restore);
+        Diag(Loc, diag::note_sme_use_preserves_za);
+      }
+    }
+  }
+
+  if (FDecl && FDecl->hasAttr<AllocAlignAttr>()) {
+    auto *AA = FDecl->getAttr<AllocAlignAttr>();
+    const Expr *Arg = Args[AA->getParamIndex().getASTIndex()];
+    if (!Arg->isValueDependent()) {
+      Expr::EvalResult Align;
+      if (Arg->EvaluateAsInt(Align, Context)) {
+        const llvm::APSInt &I = Align.Val.getInt();
+        if (!I.isPowerOf2())
+          Diag(Arg->getExprLoc(), diag::warn_alignment_not_power_of_two)
+              << Arg->getSourceRange();
+
+        if (I > Sema::MaximumAlignment)
+          Diag(Arg->getExprLoc(), diag::warn_assume_aligned_too_great)
+              << Arg->getSourceRange() << Sema::MaximumAlignment;
+      }
+    }
+  }
+
+  if (FD)
+    diagnoseArgDependentDiagnoseIfAttrs(FD, ThisArg, Args, Loc);
+}
+
+void Sema::CheckConstrainedAuto(const AutoType *AutoT, SourceLocation Loc) {
+  if (TemplateDecl *Decl = AutoT->getTypeConstraintConcept()) {
+    DiagnoseUseOfDecl(Decl, Loc);
+  }
+}
+
+void Sema::CheckConstructorCall(FunctionDecl *FDecl, QualType ThisType,
+                                ArrayRef<const Expr *> Args,
+                                const FunctionProtoType *Proto,
+                                SourceLocation Loc) {
+  VariadicCallType CallType = Proto->isVariadic()
+                                  ? VariadicCallType::Constructor
+                                  : VariadicCallType::DoesNotApply;
+
+  auto *Ctor = cast<CXXConstructorDecl>(FDecl);
+  CheckArgAlignment(
+      Loc, FDecl, "'this'", Context.getPointerType(ThisType),
+      Context.getPointerType(Ctor->getFunctionObjectParameterType()));
+
+  checkCall(FDecl, Proto, /*ThisArg=*/nullptr, Args, /*IsMemberFunction=*/true,
+            Loc, SourceRange(), CallType);
+}
+
+bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
+                             const FunctionProtoType *Proto) {
+  bool IsMemberOperatorCall = isa<CXXOperatorCallExpr>(TheCall) &&
+                              isa<CXXMethodDecl>(FDecl);
+  bool IsMemberFunction = isa<CXXMemberCallExpr>(TheCall) ||
+                          IsMemberOperatorCall;
+  VariadicCallType CallType = getVariadicCallType(FDecl, Proto,
+                                                  TheCall->getCallee());
+  Expr** Args = TheCall->getArgs();
+  unsigned NumArgs = TheCall->getNumArgs();
+
+  Expr *ImplicitThis = nullptr;
+  if (IsMemberOperatorCall && !FDecl->hasCXXExplicitFunctionObjectParameter()) {
+    // If this is a call to a member operator, hide the first
+    // argument from checkCall.
+    // FIXME: Our choice of AST representation here is less than ideal.
+    ImplicitThis = Args[0];
+    ++Args;
+    --NumArgs;
+  } else if (IsMemberFunction && !FDecl->isStatic() &&
+             !FDecl->hasCXXExplicitFunctionObjectParameter())
+    ImplicitThis =
+        cast<CXXMemberCallExpr>(TheCall)->getImplicitObjectArgument();
+
+  if (ImplicitThis) {
+    // ImplicitThis may or may not be a pointer, depending on whether . or -> is
+    // used.
+    QualType ThisType = ImplicitThis->getType();
+    if (!ThisType->isPointerType()) {
+      assert(!ThisType->isReferenceType());
+      ThisType = Context.getPointerType(ThisType);
+    }
+
+    QualType ThisTypeFromDecl = Context.getPointerType(
+        cast<CXXMethodDecl>(FDecl)->getFunctionObjectParameterType());
+
+    CheckArgAlignment(TheCall->getRParenLoc(), FDecl, "'this'", ThisType,
+                      ThisTypeFromDecl);
+  }
+
+  checkCall(FDecl, Proto, ImplicitThis, llvm::ArrayRef(Args, NumArgs),
+            IsMemberFunction, TheCall->getRParenLoc(),
+            TheCall->getCallee()->getSourceRange(), CallType);
+
+  IdentifierInfo *FnInfo = FDecl->getIdentifier();
+  // None of the checks below are needed for functions that don't have
+  // simple names (e.g., C++ conversion functions).
+  if (!FnInfo)
+    return false;
+
+  // Enforce TCB except for builtin calls, which are always allowed.
+  if (FDecl->getBuiltinID() == 0)
+    CheckTCBEnforcement(TheCall->getExprLoc(), FDecl);
+
+  CheckAbsoluteValueFunction(TheCall, FDecl);
+  CheckMaxUnsignedZero(TheCall, FDecl);
+  CheckInfNaNFunction(TheCall, FDecl);
+
+  if (getLangOpts().ObjC)
+    ObjC().DiagnoseCStringFormatDirectiveInCFAPI(FDecl, Args, NumArgs);
+
+  unsigned CMId = FDecl->getMemoryFunctionKind();
+
+  // Handle memory setting and copying functions.
+  switch (CMId) {
+  case 0:
+    return false;
+  case Builtin::BIstrlcpy: // fallthrough
+  case Builtin::BIstrlcat:
+    CheckStrlcpycatArguments(TheCall, FnInfo);
+    break;
+  case Builtin::BIstrncat:
+    CheckStrncatArguments(TheCall, FnInfo);
+    break;
+  case Builtin::BIfree:
+    CheckFreeArguments(TheCall);
+    break;
+  default:
+    CheckMemaccessArguments(TheCall, CMId, FnInfo);
+  }
+
+  return false;
+}
+
+bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall,
+                            const FunctionProtoType *Proto) {
+  QualType Ty;
+  if (const auto *V = dyn_cast<VarDecl>(NDecl))
+    Ty = V->getType().getNonReferenceType();
+  else if (const auto *F = dyn_cast<FieldDecl>(NDecl))
+    Ty = F->getType().getNonReferenceType();
+  else
+    return false;
+
+  if (!Ty->isBlockPointerType() && !Ty->isFunctionPointerType() &&
+      !Ty->isFunctionProtoType())
+    return false;
+
+  VariadicCallType CallType;
+  if (!Proto || !Proto->isVariadic()) {
+    CallType = VariadicCallType::DoesNotApply;
+  } else if (Ty->isBlockPointerType()) {
+    CallType = VariadicCallType::Block;
+  } else { // Ty->isFunctionPointerType()
+    CallType = VariadicCallType::Function;
+  }
+
+  checkCall(NDecl, Proto, /*ThisArg=*/nullptr,
+            llvm::ArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
+            /*IsMemberFunction=*/false, TheCall->getRParenLoc(),
+            TheCall->getCallee()->getSourceRange(), CallType);
+
+  return false;
+}
+
+bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) {
+  VariadicCallType CallType = getVariadicCallType(/*FDecl=*/nullptr, Proto,
+                                                  TheCall->getCallee());
+  checkCall(/*FDecl=*/nullptr, Proto, /*ThisArg=*/nullptr,
+            llvm::ArrayRef(TheCall->getArgs(), TheCall->getNumArgs()),
+            /*IsMemberFunction=*/false, TheCall->getRParenLoc(),
+            TheCall->getCallee()->getSourceRange(), CallType);
+
+  return false;
+}
+
+static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) {
+  if (!llvm::isValidAtomicOrderingCABI(Ordering))
+    return false;
+
+  auto OrderingCABI = (llvm::AtomicOrderingCABI)Ordering;
+  switch (Op) {
+  case AtomicExpr::AO__c11_atomic_init:
+  case AtomicExpr::AO__opencl_atomic_init:
+    llvm_unreachable("There is no ordering argument for an init");
+
+  case AtomicExpr::AO__c11_atomic_load:
+  case AtomicExpr::AO__opencl_atomic_load:
+  case AtomicExpr::AO__hip_atomic_load:
+  case AtomicExpr::AO__atomic_load_n:
+  case AtomicExpr::AO__atomic_load:
+  case AtomicExpr::AO__scoped_atomic_load_n:
+  case AtomicExpr::AO__scoped_atomic_load:
+    return OrderingCABI != llvm::AtomicOrderingCABI::release &&
+           OrderingCABI != llvm::AtomicOrderingCABI::acq_rel;
+
+  case AtomicExpr::AO__c11_atomic_store:
+  case AtomicExpr::AO__opencl_atomic_store:
+  case AtomicExpr::AO__hip_atomic_store:
+  case AtomicExpr::AO__atomic_store:
+  case AtomicExpr::AO__atomic_store_n:
+  case AtomicExpr::AO__scoped_atomic_store:
+  case AtomicExpr::AO__scoped_atomic_store_n:
+  case AtomicExpr::AO__atomic_clear:
+    return OrderingCABI != llvm::AtomicOrderingCABI::consume &&
+           OrderingCABI != llvm::AtomicOrderingCABI::acquire &&
+           OrderingCABI != llvm::AtomicOrderingCABI::acq_rel;
+
+  default:
+    return true;
+  }
+}
+
+ExprResult Sema::AtomicOpsOverloaded(ExprResult TheCallResult,
+                                     AtomicExpr::AtomicOp Op) {
+  CallExpr *TheCall = cast<CallExpr>(TheCallResult.get());
+  DeclRefExpr *DRE =cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+  MultiExprArg Args{TheCall->getArgs(), TheCall->getNumArgs()};
+  return BuildAtomicExpr({TheCall->getBeginLoc(), TheCall->getEndLoc()},
+                         DRE->getSourceRange(), TheCall->getRParenLoc(), Args,
+                         Op);
+}
+
+ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange,
+                                 SourceLocation RParenLoc, MultiExprArg Args,
+                                 AtomicExpr::AtomicOp Op,
+                                 AtomicArgumentOrder ArgOrder) {
+  // All the non-OpenCL operations take one of the following forms.
+  // The OpenCL operations take the __c11 forms with one extra argument for
+  // synchronization scope.
+  enum {
+    // C    __c11_atomic_init(A *, C)
+    Init,
+
+    // C    __c11_atomic_load(A *, int)
+    Load,
+
+    // void __atomic_load(A *, CP, int)
+    LoadCopy,
+
+    // void __atomic_store(A *, CP, int)
+    Copy,
+
+    // C    __c11_atomic_add(A *, M, int)
+    Arithmetic,
+
+    // C    __atomic_exchange_n(A *, CP, int)
+    Xchg,
+
+    // void __atomic_exchange(A *, C *, CP, int)
+    GNUXchg,
+
+    // bool __c11_atomic_compare_exchange_strong(A *, C *, CP, int, int)
+    C11CmpXchg,
+
+    // bool __atomic_compare_exchange(A *, C *, CP, bool, int, int)
+    GNUCmpXchg,
+
+    // bool __atomic_test_and_set(A *, int)
+    TestAndSetByte,
+
+    // void __atomic_clear(A *, int)
+    ClearByte,
+  } Form = Init;
+
+  const unsigned NumForm = ClearByte + 1;
+  const unsigned NumArgs[] = {2, 2, 3, 3, 3, 3, 4, 5, 6, 2, 2};
+  const unsigned NumVals[] = {1, 0, 1, 1, 1, 1, 2, 2, 3, 0, 0};
+  // where:
+  //   C is an appropriate type,
+  //   A is volatile _Atomic(C) for __c11 builtins and is C for GNU builtins,
+  //   CP is C for __c11 builtins and GNU _n builtins and is C * otherwise,
+  //   M is C if C is an integer, and ptrdiff_t if C is a pointer, and
+  //   the int parameters are for orderings.
+
+  static_assert(sizeof(NumArgs)/sizeof(NumArgs[0]) == NumForm
+      && sizeof(NumVals)/sizeof(NumVals[0]) == NumForm,
+      "need to update code for modified forms");
+  static_assert(AtomicExpr::AO__atomic_add_fetch == 0 &&
+                    AtomicExpr::AO__atomic_xor_fetch + 1 ==
+                        AtomicExpr::AO__c11_atomic_compare_exchange_strong,
+                "need to update code for modified C11 atomics");
+  bool IsOpenCL = Op >= AtomicExpr::AO__opencl_atomic_compare_exchange_strong &&
+                  Op <= AtomicExpr::AO__opencl_atomic_store;
+  bool IsHIP = Op >= AtomicExpr::AO__hip_atomic_compare_exchange_strong &&
+               Op <= AtomicExpr::AO__hip_atomic_store;
+  bool IsScoped = Op >= AtomicExpr::AO__scoped_atomic_add_fetch &&
+                  Op <= AtomicExpr::AO__scoped_atomic_xor_fetch;
+  bool IsC11 = (Op >= AtomicExpr::AO__c11_atomic_compare_exchange_strong &&
+                Op <= AtomicExpr::AO__c11_atomic_store) ||
+               IsOpenCL;
+  bool IsN = Op == AtomicExpr::AO__atomic_load_n ||
+             Op == AtomicExpr::AO__atomic_store_n ||
+             Op == AtomicExpr::AO__atomic_exchange_n ||
+             Op == AtomicExpr::AO__atomic_compare_exchange_n ||
+             Op == AtomicExpr::AO__scoped_atomic_load_n ||
+             Op == AtomicExpr::AO__scoped_atomic_store_n ||
+             Op == AtomicExpr::AO__scoped_atomic_exchange_n ||
+             Op == AtomicExpr::AO__scoped_atomic_compare_exchange_n;
+  // Bit mask for extra allowed value types other than integers for atomic
+  // arithmetic operations. Add/sub allow pointer and floating point. Min/max
+  // allow floating point.
+  enum ArithOpExtraValueType {
+    AOEVT_None = 0,
+    AOEVT_Pointer = 1,
+    AOEVT_FP = 2,
+  };
+  unsigned ArithAllows = AOEVT_None;
+
+  switch (Op) {
+  case AtomicExpr::AO__c11_atomic_init:
+  case AtomicExpr::AO__opencl_atomic_init:
+    Form = Init;
+    break;
+
+  case AtomicExpr::AO__c11_atomic_load:
+  case AtomicExpr::AO__opencl_atomic_load:
+  case AtomicExpr::AO__hip_atomic_load:
+  case AtomicExpr::AO__atomic_load_n:
+  case AtomicExpr::AO__scoped_atomic_load_n:
+    Form = Load;
+    break;
+
+  case AtomicExpr::AO__atomic_load:
+  case AtomicExpr::AO__scoped_atomic_load:
+    Form = LoadCopy;
+    break;
+
+  case AtomicExpr::AO__c11_atomic_store:
+  case AtomicExpr::AO__opencl_atomic_store:
+  case AtomicExpr::AO__hip_atomic_store:
+  case AtomicExpr::AO__atomic_store:
+  case AtomicExpr::AO__atomic_store_n:
+  case AtomicExpr::AO__scoped_atomic_store:
+  case AtomicExpr::AO__scoped_atomic_store_n:
+    Form = Copy;
+    break;
+  case AtomicExpr::AO__atomic_fetch_add:
+  case AtomicExpr::AO__atomic_fetch_sub:
+  case AtomicExpr::AO__atomic_add_fetch:
+  case AtomicExpr::AO__atomic_sub_fetch:
+  case AtomicExpr::AO__scoped_atomic_fetch_add:
+  case AtomicExpr::AO__scoped_atomic_fetch_sub:
+  case AtomicExpr::AO__scoped_atomic_add_fetch:
+  case AtomicExpr::AO__scoped_atomic_sub_fetch:
+  case AtomicExpr::AO__c11_atomic_fetch_add:
+  case AtomicExpr::AO__c11_atomic_fetch_sub:
+  case AtomicExpr::AO__opencl_atomic_fetch_add:
+  case AtomicExpr::AO__opencl_atomic_fetch_sub:
+  case AtomicExpr::AO__hip_atomic_fetch_add:
+  case AtomicExpr::AO__hip_atomic_fetch_sub:
+    ArithAllows = AOEVT_Pointer | AOEVT_FP;
+    Form = Arithmetic;
+    break;
+  case AtomicExpr::AO__atomic_fetch_max:
+  case AtomicExpr::AO__atomic_fetch_min:
+  case AtomicExpr::AO__atomic_max_fetch:
+  case AtomicExpr::AO__atomic_min_fetch:
+  case AtomicExpr::AO__scoped_atomic_fetch_max:
+  case AtomicExpr::AO__scoped_atomic_fetch_min:
+  case AtomicExpr::AO__scoped_atomic_max_fetch:
+  case AtomicExpr::AO__scoped_atomic_min_fetch:
+  case AtomicExpr::AO__c11_atomic_fetch_max:
+  case AtomicExpr::AO__c11_atomic_fetch_min:
+  case AtomicExpr::AO__opencl_atomic_fetch_max:
+  case AtomicExpr::AO__opencl_atomic_fetch_min:
+  case AtomicExpr::AO__hip_atomic_fetch_max:
+  case AtomicExpr::AO__hip_atomic_fetch_min:
+    ArithAllows = AOEVT_FP;
+    Form = Arithmetic;
+    break;
+  case AtomicExpr::AO__c11_atomic_fetch_and:
+  case AtomicExpr::AO__c11_atomic_fetch_or:
+  case AtomicExpr::AO__c11_atomic_fetch_xor:
+  case AtomicExpr::AO__hip_atomic_fetch_and:
+  case AtomicExpr::AO__hip_atomic_fetch_or:
+  case AtomicExpr::AO__hip_atomic_fetch_xor:
+  case AtomicExpr::AO__c11_atomic_fetch_nand:
+  case AtomicExpr::AO__opencl_atomic_fetch_and:
+  case AtomicExpr::AO__opencl_atomic_fetch_or:
+  case AtomicExpr::AO__opencl_atomic_fetch_xor:
+  case AtomicExpr::AO__atomic_fetch_and:
+  case AtomicExpr::AO__atomic_fetch_or:
+  case AtomicExpr::AO__atomic_fetch_xor:
+  case AtomicExpr::AO__atomic_fetch_nand:
+  case AtomicExpr::AO__atomic_and_fetch:
+  case AtomicExpr::AO__atomic_or_fetch:
+  case AtomicExpr::AO__atomic_xor_fetch:
+  case AtomicExpr::AO__atomic_nand_fetch:
+  case AtomicExpr::AO__atomic_fetch_uinc:
+  case AtomicExpr::AO__atomic_fetch_udec:
+  case AtomicExpr::AO__scoped_atomic_fetch_and:
+  case AtomicExpr::AO__scoped_atomic_fetch_or:
+  case AtomicExpr::AO__scoped_atomic_fetch_xor:
+  case AtomicExpr::AO__scoped_atomic_fetch_nand:
+  case AtomicExpr::AO__scoped_atomic_and_fetch:
+  case AtomicExpr::AO__scoped_atomic_or_fetch:
+  case AtomicExpr::AO__scoped_atomic_xor_fetch:
+  case AtomicExpr::AO__scoped_atomic_nand_fetch:
+  case AtomicExpr::AO__scoped_atomic_fetch_uinc:
+  case AtomicExpr::AO__scoped_atomic_fetch_udec:
+    Form = Arithmetic;
+    break;
+
+  case AtomicExpr::AO__c11_atomic_exchange:
+  case AtomicExpr::AO__hip_atomic_exchange:
+  case AtomicExpr::AO__opencl_atomic_exchange:
+  case AtomicExpr::AO__atomic_exchange_n:
+  case AtomicExpr::AO__scoped_atomic_exchange_n:
+    Form = Xchg;
+    break;
+
+  case AtomicExpr::AO__atomic_exchange:
+  case AtomicExpr::AO__scoped_atomic_exchange:
+    Form = GNUXchg;
+    break;
+
+  case AtomicExpr::AO__c11_atomic_compare_exchange_strong:
+  case AtomicExpr::AO__c11_atomic_compare_exchange_weak:
+  case AtomicExpr::AO__hip_atomic_compare_exchange_strong:
+  case AtomicExpr::AO__opencl_atomic_compare_exchange_strong:
+  case AtomicExpr::AO__opencl_atomic_compare_exchange_weak:
+  case AtomicExpr::AO__hip_atomic_compare_exchange_weak:
+    Form = C11CmpXchg;
+    break;
+
+  case AtomicExpr::AO__atomic_compare_exchange:
+  case AtomicExpr::AO__atomic_compare_exchange_n:
+  case AtomicExpr::AO__scoped_atomic_compare_exchange:
+  case AtomicExpr::AO__scoped_atomic_compare_exchange_n:
+    Form = GNUCmpXchg;
+    break;
+
+  case AtomicExpr::AO__atomic_test_and_set:
+    Form = TestAndSetByte;
+    break;
+
+  case AtomicExpr::AO__atomic_clear:
+    Form = ClearByte;
+    break;
+  }
+
+  unsigned AdjustedNumArgs = NumArgs[Form];
+  if ((IsOpenCL || IsHIP || IsScoped) &&
+      Op != AtomicExpr::AO__opencl_atomic_init)
+    ++AdjustedNumArgs;
+  // Check we have the right number of arguments.
+  if (Args.size() < AdjustedNumArgs) {
+    Diag(CallRange.getEnd(), diag::err_typecheck_call_too_few_args)
+        << 0 << AdjustedNumArgs << static_cast<unsigned>(Args.size())
+        << /*is non object*/ 0 << ExprRange;
+    return ExprError();
+  } else if (Args.size() > AdjustedNumArgs) {
+    Diag(Args[AdjustedNumArgs]->getBeginLoc(),
+         diag::err_typecheck_call_too_many_args)
+        << 0 << AdjustedNumArgs << static_cast<unsigned>(Args.size())
+        << /*is non object*/ 0 << ExprRange;
+    return ExprError();
+  }
+
+  // Inspect the first argument of the atomic operation.
+  Expr *Ptr = Args[0];
+  ExprResult ConvertedPtr = DefaultFunctionArrayLvalueConversion(Ptr);
+  if (ConvertedPtr.isInvalid())
+    return ExprError();
+
+  Ptr = ConvertedPtr.get();
+  const PointerType *pointerType = Ptr->getType()->getAs<PointerType>();
+  if (!pointerType) {
+    Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer)
+        << Ptr->getType() << 0 << Ptr->getSourceRange();
+    return ExprError();
+  }
+
+  // For a __c11 builtin, this should be a pointer to an _Atomic type.
+  QualType AtomTy = pointerType->getPointeeType(); // 'A'
+  QualType ValType = AtomTy; // 'C'
+  if (IsC11) {
+    if (!AtomTy->isAtomicType()) {
+      Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic)
+          << Ptr->getType() << Ptr->getSourceRange();
+      return ExprError();
+    }
+    if ((Form != Load && Form != LoadCopy && AtomTy.isConstQualified()) ||
+        AtomTy.getAddressSpace() == LangAS::opencl_constant) {
+      Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_non_const_atomic)
+          << (AtomTy.isConstQualified() ? 0 : 1) << Ptr->getType()
+          << Ptr->getSourceRange();
+      return ExprError();
+    }
+    ValType = AtomTy->castAs<AtomicType>()->getValueType();
+  } else if (Form != Load && Form != LoadCopy) {
+    if (ValType.isConstQualified()) {
+      Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_non_const_pointer)
+          << Ptr->getType() << Ptr->getSourceRange();
+      return ExprError();
+    }
+  }
+
+  if (Form != TestAndSetByte && Form != ClearByte) {
+    // Pointer to object of size zero is not allowed.
+    if (RequireCompleteType(Ptr->getBeginLoc(), AtomTy,
+                            diag::err_incomplete_type))
+      return ExprError();
+
+    if (Context.getTypeInfoInChars(AtomTy).Width.isZero()) {
+      Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer)
+          << Ptr->getType() << 1 << Ptr->getSourceRange();
+      return ExprError();
+    }
+  } else {
+    // The __atomic_clear and __atomic_test_and_set intrinsics accept any
+    // non-const pointer type, including void* and pointers to incomplete
+    // structs, but only access the first byte.
+    AtomTy = Context.CharTy;
+    AtomTy = AtomTy.withCVRQualifiers(
+        pointerType->getPointeeType().getCVRQualifiers());
+    QualType PointerQT = Context.getPointerType(AtomTy);
+    pointerType = PointerQT->getAs<PointerType>();
+    Ptr = ImpCastExprToType(Ptr, PointerQT, CK_BitCast).get();
+    ValType = AtomTy;
+  }
+
+  PointerAuthQualifier PointerAuth = AtomTy.getPointerAuth();
+  if (PointerAuth && PointerAuth.isAddressDiscriminated()) {
+    Diag(ExprRange.getBegin(),
+         diag::err_atomic_op_needs_non_address_discriminated_pointer)
+        << 0 << Ptr->getType() << Ptr->getSourceRange();
+    return ExprError();
+  }
+
+  // For an arithmetic operation, the implied arithmetic must be well-formed.
+  if (Form == Arithmetic) {
+    // GCC does not enforce these rules for GNU atomics, but we do to help catch
+    // trivial type errors.
+    auto IsAllowedValueType = [&](QualType ValType,
+                                  unsigned AllowedType) -> bool {
+      if (ValType->isIntegerType())
+        return true;
+      if (ValType->isPointerType())
+        return AllowedType & AOEVT_Pointer;
+      if (!(ValType->isFloatingType() && (AllowedType & AOEVT_FP)))
+        return false;
+      // LLVM Parser does not allow atomicrmw with x86_fp80 type.
+      if (ValType->isSpecificBuiltinType(BuiltinType::LongDouble) &&
+          &Context.getTargetInfo().getLongDoubleFormat() ==
+              &llvm::APFloat::x87DoubleExtended())
+        return false;
+      return true;
+    };
+    if (!IsAllowedValueType(ValType, ArithAllows)) {
+      auto DID = ArithAllows & AOEVT_FP
+                     ? (ArithAllows & AOEVT_Pointer
+                            ? diag::err_atomic_op_needs_atomic_int_ptr_or_fp
+                            : diag::err_atomic_op_needs_atomic_int_or_fp)
+                     : diag::err_atomic_op_needs_atomic_int;
+      Diag(ExprRange.getBegin(), DID)
+          << IsC11 << Ptr->getType() << Ptr->getSourceRange();
+      return ExprError();
+    }
+    if (IsC11 && ValType->isPointerType() &&
+        RequireCompleteType(Ptr->getBeginLoc(), ValType->getPointeeType(),
+                            diag::err_incomplete_type)) {
+      return ExprError();
+    }
+  } else if (IsN && !ValType->isIntegerType() && !ValType->isPointerType()) {
+    // For __atomic_*_n operations, the value type must be a scalar integral or
+    // pointer type which is 1, 2, 4, 8 or 16 bytes in length.
+    Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int_or_ptr)
+        << IsC11 << Ptr->getType() << Ptr->getSourceRange();
+    return ExprError();
+  }
+
+  if (!IsC11 && !AtomTy.isTriviallyCopyableType(Context) &&
+      !AtomTy->isScalarType()) {
+    // For GNU atomics, require a trivially-copyable type. This is not part of
+    // the GNU atomics specification but we enforce it for consistency with
+    // other atomics which generally all require a trivially-copyable type. This
+    // is because atomics just copy bits.
+    Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_trivial_copy)
+        << Ptr->getType() << Ptr->getSourceRange();
+    return ExprError();
+  }
+
+  switch (ValType.getObjCLifetime()) {
+  case Qualifiers::OCL_None:
+  case Qualifiers::OCL_ExplicitNone:
+    // okay
+    break;
+
+  case Qualifiers::OCL_Weak:
+  case Qualifiers::OCL_Strong:
+  case Qualifiers::OCL_Autoreleasing:
+    // FIXME: Can this happen? By this point, ValType should be known
+    // to be trivially copyable.
+    Diag(ExprRange.getBegin(), diag::err_arc_atomic_ownership)
+        << ValType << Ptr->getSourceRange();
+    return ExprError();
+  }
+
+  // All atomic operations have an overload which takes a pointer to a volatile
+  // 'A'.  We shouldn't let the volatile-ness of the pointee-type inject itself
+  // into the result or the other operands. Similarly atomic_load takes a
+  // pointer to a const 'A'.
+  ValType.removeLocalVolatile();
+  ValType.removeLocalConst();
+  QualType ResultType = ValType;
+  if (Form == Copy || Form == LoadCopy || Form == GNUXchg || Form == Init ||
+      Form == ClearByte)
+    ResultType = Context.VoidTy;
+  else if (Form == C11CmpXchg || Form == GNUCmpXchg || Form == TestAndSetByte)
+    ResultType = Context.BoolTy;
+
+  // The type of a parameter passed 'by value'. In the GNU atomics, such
+  // arguments are actually passed as pointers.
+  QualType ByValType = ValType; // 'CP'
+  bool IsPassedByAddress = false;
+  if (!IsC11 && !IsHIP && !IsN) {
+    ByValType = Ptr->getType();
+    IsPassedByAddress = true;
+  }
+
+  SmallVector<Expr *, 5> APIOrderedArgs;
+  if (ArgOrder == Sema::AtomicArgumentOrder::AST) {
+    APIOrderedArgs.push_back(Args[0]);
+    switch (Form) {
+    case Init:
+    case Load:
+      APIOrderedArgs.push_back(Args[1]); // Val1/Order
+      break;
+    case LoadCopy:
+    case Copy:
+    case Arithmetic:
+    case Xchg:
+      APIOrderedArgs.push_back(Args[2]); // Val1
+      APIOrderedArgs.push_back(Args[1]); // Order
+      break;
+    case GNUXchg:
+      APIOrderedArgs.push_back(Args[2]); // Val1
+      APIOrderedArgs.push_back(Args[3]); // Val2
+      APIOrderedArgs.push_back(Args[1]); // Order
+      break;
+    case C11CmpXchg:
+      APIOrderedArgs.push_back(Args[2]); // Val1
+      APIOrderedArgs.push_back(Args[4]); // Val2
+      APIOrderedArgs.push_back(Args[1]); // Order
+      APIOrderedArgs.push_back(Args[3]); // OrderFail
+      break;
+    case GNUCmpXchg:
+      APIOrderedArgs.push_back(Args[2]); // Val1
+      APIOrderedArgs.push_back(Args[4]); // Val2
+      APIOrderedArgs.push_back(Args[5]); // Weak
+      APIOrderedArgs.push_back(Args[1]); // Order
+      APIOrderedArgs.push_back(Args[3]); // OrderFail
+      break;
+    case TestAndSetByte:
+    case ClearByte:
+      APIOrderedArgs.push_back(Args[1]); // Order
+      break;
+    }
+  } else
+    APIOrderedArgs.append(Args.begin(), Args.end());
+
+  // The first argument's non-CV pointer type is used to deduce the type of
+  // subsequent arguments, except for:
+  //  - weak flag (always converted to bool)
+  //  - memory order (always converted to int)
+  //  - scope  (always converted to int)
+  for (unsigned i = 0; i != APIOrderedArgs.size(); ++i) {
+    QualType Ty;
+    if (i < NumVals[Form] + 1) {
+      switch (i) {
+      case 0:
+        // The first argument is always a pointer. It has a fixed type.
+        // It is always dereferenced, a nullptr is undefined.
+        CheckNonNullArgument(*this, APIOrderedArgs[i], ExprRange.getBegin());
+        // Nothing else to do: we already know all we want about this pointer.
+        continue;
+      case 1:
+        // The second argument is the non-atomic operand. For arithmetic, this
+        // is always passed by value, and for a compare_exchange it is always
+        // passed by address. For the rest, GNU uses by-address and C11 uses
+        // by-value.
+        assert(Form != Load);
+        if (Form == Arithmetic && ValType->isPointerType())
+          Ty = Context.getPointerDiffType();
+        else if (Form == Init || Form == Arithmetic)
+          Ty = ValType;
+        else if (Form == Copy || Form == Xchg) {
+          if (IsPassedByAddress) {
+            // The value pointer is always dereferenced, a nullptr is undefined.
+            CheckNonNullArgument(*this, APIOrderedArgs[i],
+                                 ExprRange.getBegin());
+          }
+          Ty = ByValType;
+        } else {
+          Expr *ValArg = APIOrderedArgs[i];
+          // The value pointer is always dereferenced, a nullptr is undefined.
+          CheckNonNullArgument(*this, ValArg, ExprRange.getBegin());
+          LangAS AS = LangAS::Default;
+          // Keep address space of non-atomic pointer type.
+          if (const PointerType *PtrTy =
+                  ValArg->getType()->getAs<PointerType>()) {
+            AS = PtrTy->getPointeeType().getAddressSpace();
+          }
+          Ty = Context.getPointerType(
+              Context.getAddrSpaceQualType(ValType.getUnqualifiedType(), AS));
+        }
+        break;
+      case 2:
+        // The third argument to compare_exchange / GNU exchange is the desired
+        // value, either by-value (for the C11 and *_n variant) or as a pointer.
+        if (IsPassedByAddress)
+          CheckNonNullArgument(*this, APIOrderedArgs[i], ExprRange.getBegin());
+        Ty = ByValType;
+        break;
+      case 3:
+        // The fourth argument to GNU compare_exchange is a 'weak' flag.
+        Ty = Context.BoolTy;
+        break;
+      }
+    } else {
+      // The order(s) and scope are always converted to int.
+      Ty = Context.IntTy;
+    }
+
+    InitializedEntity Entity =
+        InitializedEntity::InitializeParameter(Context, Ty, false);
+    ExprResult Arg = APIOrderedArgs[i];
+    Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg);
+    if (Arg.isInvalid())
+      return true;
+    APIOrderedArgs[i] = Arg.get();
+  }
+
+  // Permute the arguments into a 'consistent' order.
+  SmallVector<Expr*, 5> SubExprs;
+  SubExprs.push_back(Ptr);
+  switch (Form) {
+  case Init:
+    // Note, AtomicExpr::getVal1() has a special case for this atomic.
+    SubExprs.push_back(APIOrderedArgs[1]); // Val1
+    break;
+  case Load:
+  case TestAndSetByte:
+  case ClearByte:
+    SubExprs.push_back(APIOrderedArgs[1]); // Order
+    break;
+  case LoadCopy:
+  case Copy:
+  case Arithmetic:
+  case Xchg:
+    SubExprs.push_back(APIOrderedArgs[2]); // Order
+    SubExprs.push_back(APIOrderedArgs[1]); // Val1
+    break;
+  case GNUXchg:
+    // Note, AtomicExpr::getVal2() has a special case for this atomic.
+    SubExprs.push_back(APIOrderedArgs[3]); // Order
+    SubExprs.push_back(APIOrderedArgs[1]); // Val1
+    SubExprs.push_back(APIOrderedArgs[2]); // Val2
+    break;
+  case C11CmpXchg:
+    SubExprs.push_back(APIOrderedArgs[3]); // Order
+    SubExprs.push_back(APIOrderedArgs[1]); // Val1
+    SubExprs.push_back(APIOrderedArgs[4]); // OrderFail
+    SubExprs.push_back(APIOrderedArgs[2]); // Val2
+    break;
+  case GNUCmpXchg:
+    SubExprs.push_back(APIOrderedArgs[4]); // Order
+    SubExprs.push_back(APIOrderedArgs[1]); // Val1
+    SubExprs.push_back(APIOrderedArgs[5]); // OrderFail
+    SubExprs.push_back(APIOrderedArgs[2]); // Val2
+    SubExprs.push_back(APIOrderedArgs[3]); // Weak
+    break;
+  }
+
+  // If the memory orders are constants, check they are valid.
+  if (SubExprs.size() >= 2 && Form != Init) {
+    std::optional<llvm::APSInt> Success =
+        SubExprs[1]->getIntegerConstantExpr(Context);
+    if (Success && !isValidOrderingForOp(Success->getSExtValue(), Op)) {
+      Diag(SubExprs[1]->getBeginLoc(),
+           diag::warn_atomic_op_has_invalid_memory_order)
+          << /*success=*/(Form == C11CmpXchg || Form == GNUCmpXchg)
+          << SubExprs[1]->getSourceRange();
+    }
+    if (SubExprs.size() >= 5) {
+      if (std::optional<llvm::APSInt> Failure =
+              SubExprs[3]->getIntegerConstantExpr(Context)) {
+        if (!llvm::is_contained(
+                {llvm::AtomicOrderingCABI::relaxed,
+                 llvm::AtomicOrderingCABI::consume,
+                 llvm::AtomicOrderingCABI::acquire,
+                 llvm::AtomicOrderingCABI::seq_cst},
+                (llvm::AtomicOrderingCABI)Failure->getSExtValue())) {
+          Diag(SubExprs[3]->getBeginLoc(),
+               diag::warn_atomic_op_has_invalid_memory_order)
+              << /*failure=*/2 << SubExprs[3]->getSourceRange();
+        }
+      }
+    }
+  }
+
+  if (auto ScopeModel = AtomicExpr::getScopeModel(Op)) {
+    auto *Scope = Args[Args.size() - 1];
+    if (std::optional<llvm::APSInt> Result =
+            Scope->getIntegerConstantExpr(Context)) {
+      if (!ScopeModel->isValid(Result->getZExtValue()))
+        Diag(Scope->getBeginLoc(), diag::err_atomic_op_has_invalid_sync_scope)
+            << Scope->getSourceRange();
+    }
+    SubExprs.push_back(Scope);
+  }
+
+  AtomicExpr *AE = new (Context)
+      AtomicExpr(ExprRange.getBegin(), SubExprs, ResultType, Op, RParenLoc);
+
+  if ((Op == AtomicExpr::AO__c11_atomic_load ||
+       Op == AtomicExpr::AO__c11_atomic_store ||
+       Op == AtomicExpr::AO__opencl_atomic_load ||
+       Op == AtomicExpr::AO__hip_atomic_load ||
+       Op == AtomicExpr::AO__opencl_atomic_store ||
+       Op == AtomicExpr::AO__hip_atomic_store) &&
+      Context.AtomicUsesUnsupportedLibcall(AE))
+    Diag(AE->getBeginLoc(), diag::err_atomic_load_store_uses_lib)
+        << ((Op == AtomicExpr::AO__c11_atomic_load ||
+             Op == AtomicExpr::AO__opencl_atomic_load ||
+             Op == AtomicExpr::AO__hip_atomic_load)
+                ? 0
+                : 1);
+
+  if (ValType->isBitIntType()) {
+    Diag(Ptr->getExprLoc(), diag::err_atomic_builtin_bit_int_prohibit);
+    return ExprError();
+  }
+
+  return AE;
+}
+
+/// checkBuiltinArgument - Given a call to a builtin function, perform
+/// normal type-checking on the given argument, updating the call in
+/// place.  This is useful when a builtin function requires custom
+/// type-checking for some of its arguments but not necessarily all of
+/// them.
+///
+/// Returns true on error.
+static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) {
+  FunctionDecl *Fn = E->getDirectCallee();
+  assert(Fn && "builtin call without direct callee!");
+
+  ParmVarDecl *Param = Fn->getParamDecl(ArgIndex);
+  InitializedEntity Entity =
+    InitializedEntity::InitializeParameter(S.Context, Param);
+
+  ExprResult Arg = E->getArg(ArgIndex);
+  Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg);
+  if (Arg.isInvalid())
+    return true;
+
+  E->setArg(ArgIndex, Arg.get());
+  return false;
+}
+
+ExprResult Sema::BuiltinAtomicOverloaded(ExprResult TheCallResult) {
+  CallExpr *TheCall = static_cast<CallExpr *>(TheCallResult.get());
+  Expr *Callee = TheCall->getCallee();
+  DeclRefExpr *DRE = cast<DeclRefExpr>(Callee->IgnoreParenCasts());
+  FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl());
+
+  // Ensure that we have at least one argument to do type inference from.
+  if (TheCall->getNumArgs() < 1) {
+    Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least)
+        << 0 << 1 << TheCall->getNumArgs() << /*is non object*/ 0
+        << Callee->getSourceRange();
+    return ExprError();
+  }
+
+  // Inspect the first argument of the atomic builtin.  This should always be
+  // a pointer type, whose element is an integral scalar or pointer type.
+  // Because it is a pointer type, we don't have to worry about any implicit
+  // casts here.
+  // FIXME: We don't allow floating point scalars as input.
+  Expr *FirstArg = TheCall->getArg(0);
+  ExprResult FirstArgResult = DefaultFunctionArrayLvalueConversion(FirstArg);
+  if (FirstArgResult.isInvalid())
+    return ExprError();
+  FirstArg = FirstArgResult.get();
+  TheCall->setArg(0, FirstArg);
+
+  const PointerType *pointerType = FirstArg->getType()->getAs<PointerType>();
+  if (!pointerType) {
+    Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer)
+        << FirstArg->getType() << 0 << FirstArg->getSourceRange();
+    return ExprError();
+  }
+
+  QualType ValType = pointerType->getPointeeType();
+  if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
+      !ValType->isBlockPointerType()) {
+    Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_must_be_pointer_intptr)
+        << FirstArg->getType() << 0 << FirstArg->getSourceRange();
+    return ExprError();
+  }
+  PointerAuthQualifier PointerAuth = ValType.getPointerAuth();
+  if (PointerAuth && PointerAuth.isAddressDiscriminated()) {
+    Diag(FirstArg->getBeginLoc(),
+         diag::err_atomic_op_needs_non_address_discriminated_pointer)
+        << 1 << ValType << FirstArg->getSourceRange();
+    return ExprError();
+  }
+
+  if (ValType.isConstQualified()) {
+    Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_cannot_be_const)
+        << FirstArg->getType() << FirstArg->getSourceRange();
+    return ExprError();
+  }
+
+  switch (ValType.getObjCLifetime()) {
+  case Qualifiers::OCL_None:
+  case Qualifiers::OCL_ExplicitNone:
+    // okay
+    break;
+
+  case Qualifiers::OCL_Weak:
+  case Qualifiers::OCL_Strong:
+  case Qualifiers::OCL_Autoreleasing:
+    Diag(DRE->getBeginLoc(), diag::err_arc_atomic_ownership)
+        << ValType << FirstArg->getSourceRange();
+    return ExprError();
+  }
+
+  // Strip any qualifiers off ValType.
+  ValType = ValType.getUnqualifiedType();
+
+  // The majority of builtins return a value, but a few have special return
+  // types, so allow them to override appropriately below.
+  QualType ResultType = ValType;
+
+  // We need to figure out which concrete builtin this maps onto.  For example,
+  // __sync_fetch_and_add with a 2 byte object turns into
+  // __sync_fetch_and_add_2.
+#define BUILTIN_ROW(x) \
+  { Builtin::BI##x##_1, Builtin::BI##x##_2, Builtin::BI##x##_4, \
+    Builtin::BI##x##_8, Builtin::BI##x##_16 }
+
+  static const unsigned BuiltinIndices[][5] = {
+    BUILTIN_ROW(__sync_fetch_and_add),
+    BUILTIN_ROW(__sync_fetch_and_sub),
+    BUILTIN_ROW(__sync_fetch_and_or),
+    BUILTIN_ROW(__sync_fetch_and_and),
+    BUILTIN_ROW(__sync_fetch_and_xor),
+    BUILTIN_ROW(__sync_fetch_and_nand),
+
+    BUILTIN_ROW(__sync_add_and_fetch),
+    BUILTIN_ROW(__sync_sub_and_fetch),
+    BUILTIN_ROW(__sync_and_and_fetch),
+    BUILTIN_ROW(__sync_or_and_fetch),
+    BUILTIN_ROW(__sync_xor_and_fetch),
+    BUILTIN_ROW(__sync_nand_and_fetch),
+
+    BUILTIN_ROW(__sync_val_compare_and_swap),
+    BUILTIN_ROW(__sync_bool_compare_and_swap),
+    BUILTIN_ROW(__sync_lock_test_and_set),
+    BUILTIN_ROW(__sync_lock_release),
+    BUILTIN_ROW(__sync_swap)
+  };
+#undef BUILTIN_ROW
+
+  // Determine the index of the size.
+  unsigned SizeIndex;
+  switch (Context.getTypeSizeInChars(ValType).getQuantity()) {
+  case 1: SizeIndex = 0; break;
+  case 2: SizeIndex = 1; break;
+  case 4: SizeIndex = 2; break;
+  case 8: SizeIndex = 3; break;
+  case 16: SizeIndex = 4; break;
+  default:
+    Diag(DRE->getBeginLoc(), diag::err_atomic_builtin_pointer_size)
+        << FirstArg->getType() << FirstArg->getSourceRange();
+    return ExprError();
+  }
+
+  // Each of these builtins has one pointer argument, followed by some number of
+  // values (0, 1 or 2) followed by a potentially empty varags list of stuff
+  // that we ignore.  Find out which row of BuiltinIndices to read from as well
+  // as the number of fixed args.
+  unsigned BuiltinID = FDecl->getBuiltinID();
+  unsigned BuiltinIndex, NumFixed = 1;
+  bool WarnAboutSemanticsChange = false;
+  switch (BuiltinID) {
+  default: llvm_unreachable("Unknown overloaded atomic builtin!");
+  case Builtin::BI__sync_fetch_and_add:
+  case Builtin::BI__sync_fetch_and_add_1:
+  case Builtin::BI__sync_fetch_and_add_2:
+  case Builtin::BI__sync_fetch_and_add_4:
+  case Builtin::BI__sync_fetch_and_add_8:
+  case Builtin::BI__sync_fetch_and_add_16:
+    BuiltinIndex = 0;
+    break;
+
+  case Builtin::BI__sync_fetch_and_sub:
+  case Builtin::BI__sync_fetch_and_sub_1:
+  case Builtin::BI__sync_fetch_and_sub_2:
+  case Builtin::BI__sync_fetch_and_sub_4:
+  case Builtin::BI__sync_fetch_and_sub_8:
+  case Builtin::BI__sync_fetch_and_sub_16:
+    BuiltinIndex = 1;
+    break;
+
+  case Builtin::BI__sync_fetch_and_or:
+  case Builtin::BI__sync_fetch_and_or_1:
+  case Builtin::BI__sync_fetch_and_or_2:
+  case Builtin::BI__sync_fetch_and_or_4:
+  case Builtin::BI__sync_fetch_and_or_8:
+  case Builtin::BI__sync_fetch_and_or_16:
+    BuiltinIndex = 2;
+    break;
+
+  case Builtin::BI__sync_fetch_and_and:
+  case Builtin::BI__sync_fetch_and_and_1:
+  case Builtin::BI__sync_fetch_and_and_2:
+  case Builtin::BI__sync_fetch_and_and_4:
+  case Builtin::BI__sync_fetch_and_and_8:
+  case Builtin::BI__sync_fetch_and_and_16:
+    BuiltinIndex = 3;
+    break;
+
+  case Builtin::BI__sync_fetch_and_xor:
+  case Builtin::BI__sync_fetch_and_xor_1:
+  case Builtin::BI__sync_fetch_and_xor_2:
+  case Builtin::BI__sync_fetch_and_xor_4:
+  case Builtin::BI__sync_fetch_and_xor_8:
+  case Builtin::BI__sync_fetch_and_xor_16:
+    BuiltinIndex = 4;
+    break;
+
+  case Builtin::BI__sync_fetch_and_nand:
+  case Builtin::BI__sync_fetch_and_nand_1:
+  case Builtin::BI__sync_fetch_and_nand_2:
+  case Builtin::BI__sync_fetch_and_nand_4:
+  case Builtin::BI__sync_fetch_and_nand_8:
+  case Builtin::BI__sync_fetch_and_nand_16:
+    BuiltinIndex = 5;
+    WarnAboutSemanticsChange = true;
+    break;
+
+  case Builtin::BI__sync_add_and_fetch:
+  case Builtin::BI__sync_add_and_fetch_1:
+  case Builtin::BI__sync_add_and_fetch_2:
+  case Builtin::BI__sync_add_and_fetch_4:
+  case Builtin::BI__sync_add_and_fetch_8:
+  case Builtin::BI__sync_add_and_fetch_16:
+    BuiltinIndex = 6;
+    break;
+
+  case Builtin::BI__sync_sub_and_fetch:
+  case Builtin::BI__sync_sub_and_fetch_1:
+  case Builtin::BI__sync_sub_and_fetch_2:
+  case Builtin::BI__sync_sub_and_fetch_4:
+  case Builtin::BI__sync_sub_and_fetch_8:
+  case Builtin::BI__sync_sub_and_fetch_16:
+    BuiltinIndex = 7;
+    break;
+
+  case Builtin::BI__sync_and_and_fetch:
+  case Builtin::BI__sync_and_and_fetch_1:
+  case Builtin::BI__sync_and_and_fetch_2:
+  case Builtin::BI__sync_and_and_fetch_4:
+  case Builtin::BI__sync_and_and_fetch_8:
+  case Builtin::BI__sync_and_and_fetch_16:
+    BuiltinIndex = 8;
+    break;
+
+  case Builtin::BI__sync_or_and_fetch:
+  case Builtin::BI__sync_or_and_fetch_1:
+  case Builtin::BI__sync_or_and_fetch_2:
+  case Builtin::BI__sync_or_and_fetch_4:
+  case Builtin::BI__sync_or_and_fetch_8:
+  case Builtin::BI__sync_or_and_fetch_16:
+    BuiltinIndex = 9;
+    break;
+
+  case Builtin::BI__sync_xor_and_fetch:
+  case Builtin::BI__sync_xor_and_fetch_1:
+  case Builtin::BI__sync_xor_and_fetch_2:
+  case Builtin::BI__sync_xor_and_fetch_4:
+  case Builtin::BI__sync_xor_and_fetch_8:
+  case Builtin::BI__sync_xor_and_fetch_16:
+    BuiltinIndex = 10;
+    break;
+
+  case Builtin::BI__sync_nand_and_fetch:
+  case Builtin::BI__sync_nand_and_fetch_1:
+  case Builtin::BI__sync_nand_and_fetch_2:
+  case Builtin::BI__sync_nand_and_fetch_4:
+  case Builtin::BI__sync_nand_and_fetch_8:
+  case Builtin::BI__sync_nand_and_fetch_16:
+    BuiltinIndex = 11;
+    WarnAboutSemanticsChange = true;
+    break;
+
+  case Builtin::BI__sync_val_compare_and_swap:
+  case Builtin::BI__sync_val_compare_and_swap_1:
+  case Builtin::BI__sync_val_compare_and_swap_2:
+  case Builtin::BI__sync_val_compare_and_swap_4:
+  case Builtin::BI__sync_val_compare_and_swap_8:
+  case Builtin::BI__sync_val_compare_and_swap_16:
+    BuiltinIndex = 12;
+    NumFixed = 2;
+    break;
+
+  case Builtin::BI__sync_bool_compare_and_swap:
+  case Builtin::BI__sync_bool_compare_and_swap_1:
+  case Builtin::BI__sync_bool_compare_and_swap_2:
+  case Builtin::BI__sync_bool_compare_and_swap_4:
+  case Builtin::BI__sync_bool_compare_and_swap_8:
+  case Builtin::BI__sync_bool_compare_and_swap_16:
+    BuiltinIndex = 13;
+    NumFixed = 2;
+    ResultType = Context.BoolTy;
+    break;
+
+  case Builtin::BI__sync_lock_test_and_set:
+  case Builtin::BI__sync_lock_test_and_set_1:
+  case Builtin::BI__sync_lock_test_and_set_2:
+  case Builtin::BI__sync_lock_test_and_set_4:
+  case Builtin::BI__sync_lock_test_and_set_8:
+  case Builtin::BI__sync_lock_test_and_set_16:
+    BuiltinIndex = 14;
+    break;
+
+  case Builtin::BI__sync_lock_release:
+  case Builtin::BI__sync_lock_release_1:
+  case Builtin::BI__sync_lock_release_2:
+  case Builtin::BI__sync_lock_release_4:
+  case Builtin::BI__sync_lock_release_8:
+  case Builtin::BI__sync_lock_release_16:
+    BuiltinIndex = 15;
+    NumFixed = 0;
+    ResultType = Context.VoidTy;
+    break;
+
+  case Builtin::BI__sync_swap:
+  case Builtin::BI__sync_swap_1:
+  case Builtin::BI__sync_swap_2:
+  case Builtin::BI__sync_swap_4:
+  case Builtin::BI__sync_swap_8:
+  case Builtin::BI__sync_swap_16:
+    BuiltinIndex = 16;
+    break;
+  }
+
+  // Now that we know how many fixed arguments we expect, first check that we
+  // have at least that many.
+  if (TheCall->getNumArgs() < 1+NumFixed) {
+    Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least)
+        << 0 << 1 + NumFixed << TheCall->getNumArgs() << /*is non object*/ 0
+        << Callee->getSourceRange();
+    return ExprError();
+  }
+
+  Diag(TheCall->getEndLoc(), diag::warn_atomic_implicit_seq_cst)
+      << Callee->getSourceRange();
+
+  if (WarnAboutSemanticsChange) {
+    Diag(TheCall->getEndLoc(), diag::warn_sync_fetch_and_nand_semantics_change)
+        << Callee->getSourceRange();
+  }
+
+  // Get the decl for the concrete builtin from this, we can tell what the
+  // concrete integer type we should convert to is.
+  unsigned NewBuiltinID = BuiltinIndices[BuiltinIndex][SizeIndex];
+  std::string NewBuiltinName = Context.BuiltinInfo.getName(NewBuiltinID);
+  FunctionDecl *NewBuiltinDecl;
+  if (NewBuiltinID == BuiltinID)
+    NewBuiltinDecl = FDecl;
+  else {
+    // Perform builtin lookup to avoid redeclaring it.
+    DeclarationName DN(&Context.Idents.get(NewBuiltinName));
+    LookupResult Res(*this, DN, DRE->getBeginLoc(), LookupOrdinaryName);
+    LookupName(Res, TUScope, /*AllowBuiltinCreation=*/true);
+    assert(Res.getFoundDecl());
+    NewBuiltinDecl = dyn_cast<FunctionDecl>(Res.getFoundDecl());
+    if (!NewBuiltinDecl)
+      return ExprError();
+  }
+
+  // The first argument --- the pointer --- has a fixed type; we
+  // deduce the types of the rest of the arguments accordingly.  Walk
+  // the remaining arguments, converting them to the deduced value type.
+  for (unsigned i = 0; i != NumFixed; ++i) {
+    ExprResult Arg = TheCall->getArg(i+1);
+
+    // GCC does an implicit conversion to the pointer or integer ValType.  This
+    // can fail in some cases (1i -> int**), check for this error case now.
+    // Initialize the argument.
+    InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
+                                                   ValType, /*consume*/ false);
+    Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg);
+    if (Arg.isInvalid())
+      return ExprError();
+
+    // Okay, we have something that *can* be converted to the right type.  Check
+    // to see if there is a potentially weird extension going on here.  This can
+    // happen when you do an atomic operation on something like an char* and
+    // pass in 42.  The 42 gets converted to char.  This is even more strange
+    // for things like 45.123 -> char, etc.
+    // FIXME: Do this check.
+    TheCall->setArg(i+1, Arg.get());
+  }
+
+  // Create a new DeclRefExpr to refer to the new decl.
+  DeclRefExpr *NewDRE = DeclRefExpr::Create(
+      Context, DRE->getQualifierLoc(), SourceLocation(), NewBuiltinDecl,
+      /*enclosing*/ false, DRE->getLocation(), Context.BuiltinFnTy,
+      DRE->getValueKind(), nullptr, nullptr, DRE->isNonOdrUse());
+
+  // Set the callee in the CallExpr.
+  // FIXME: This loses syntactic information.
+  QualType CalleePtrTy = Context.getPointerType(NewBuiltinDecl->getType());
+  ExprResult PromotedCall = ImpCastExprToType(NewDRE, CalleePtrTy,
+                                              CK_BuiltinFnToFnPtr);
+  TheCall->setCallee(PromotedCall.get());
+
+  // Change the result type of the call to match the original value type. This
+  // is arbitrary, but the codegen for these builtins ins design to handle it
+  // gracefully.
+  TheCall->setType(ResultType);
+
+  // Prohibit problematic uses of bit-precise integer types with atomic
+  // builtins. The arguments would have already been converted to the first
+  // argument's type, so only need to check the first argument.
+  const auto *BitIntValType = ValType->getAs<BitIntType>();
+  if (BitIntValType && !llvm::isPowerOf2_64(BitIntValType->getNumBits())) {
+    Diag(FirstArg->getExprLoc(), diag::err_atomic_builtin_ext_int_size);
+    return ExprError();
+  }
+
+  return TheCallResult;
+}
+
+ExprResult Sema::BuiltinNontemporalOverloaded(ExprResult TheCallResult) {
+  CallExpr *TheCall = (CallExpr *)TheCallResult.get();
+  DeclRefExpr *DRE =
+      cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+  FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl());
+  unsigned BuiltinID = FDecl->getBuiltinID();
+  assert((BuiltinID == Builtin::BI__builtin_nontemporal_store ||
+          BuiltinID == Builtin::BI__builtin_nontemporal_load) &&
+         "Unexpected nontemporal load/store builtin!");
+  bool isStore = BuiltinID == Builtin::BI__builtin_nontemporal_store;
+  unsigned numArgs = isStore ? 2 : 1;
+
+  // Ensure that we have the proper number of arguments.
+  if (checkArgCount(TheCall, numArgs))
+    return ExprError();
+
+  // Inspect the last argument of the nontemporal builtin.  This should always
+  // be a pointer type, from which we imply the type of the memory access.
+  // Because it is a pointer type, we don't have to worry about any implicit
+  // casts here.
+  Expr *PointerArg = TheCall->getArg(numArgs - 1);
+  ExprResult PointerArgResult =
+      DefaultFunctionArrayLvalueConversion(PointerArg);
+
+  if (PointerArgResult.isInvalid())
+    return ExprError();
+  PointerArg = PointerArgResult.get();
+  TheCall->setArg(numArgs - 1, PointerArg);
+
+  const PointerType *pointerType = PointerArg->getType()->getAs<PointerType>();
+  if (!pointerType) {
+    Diag(DRE->getBeginLoc(), diag::err_nontemporal_builtin_must_be_pointer)
+        << PointerArg->getType() << PointerArg->getSourceRange();
+    return ExprError();
+  }
+
+  QualType ValType = pointerType->getPointeeType();
+
+  // Strip any qualifiers off ValType.
+  ValType = ValType.getUnqualifiedType();
+  if (!ValType->isIntegerType() && !ValType->isAnyPointerType() &&
+      !ValType->isBlockPointerType() && !ValType->isFloatingType() &&
+      !ValType->isVectorType()) {
+    Diag(DRE->getBeginLoc(),
+         diag::err_nontemporal_builtin_must_be_pointer_intfltptr_or_vector)
+        << PointerArg->getType() << PointerArg->getSourceRange();
+    return ExprError();
+  }
+
+  if (!isStore) {
+    TheCall->setType(ValType);
+    return TheCallResult;
+  }
+
+  ExprResult ValArg = TheCall->getArg(0);
+  InitializedEntity Entity = InitializedEntity::InitializeParameter(
+      Context, ValType, /*consume*/ false);
+  ValArg = PerformCopyInitialization(Entity, SourceLocation(), ValArg);
+  if (ValArg.isInvalid())
+    return ExprError();
+
+  TheCall->setArg(0, ValArg.get());
+  TheCall->setType(Context.VoidTy);
+  return TheCallResult;
+}
+
+/// CheckObjCString - Checks that the format string argument to the os_log()
+/// and os_trace() functions is correct, and converts it to const char *.
+ExprResult Sema::CheckOSLogFormatStringArg(Expr *Arg) {
+  Arg = Arg->IgnoreParenCasts();
+  auto *Literal = dyn_cast<StringLiteral>(Arg);
+  if (!Literal) {
+    if (auto *ObjcLiteral = dyn_cast<ObjCStringLiteral>(Arg)) {
+      Literal = ObjcLiteral->getString();
+    }
+  }
+
+  if (!Literal || (!Literal->isOrdinary() && !Literal->isUTF8())) {
+    return ExprError(
+        Diag(Arg->getBeginLoc(), diag::err_os_log_format_not_string_constant)
+        << Arg->getSourceRange());
+  }
+
+  ExprResult Result(Literal);
+  QualType ResultTy = Context.getPointerType(Context.CharTy.withConst());
+  InitializedEntity Entity =
+      InitializedEntity::InitializeParameter(Context, ResultTy, false);
+  Result = PerformCopyInitialization(Entity, SourceLocation(), Result);
+  return Result;
+}
+
+/// Check that the user is calling the appropriate va_start builtin for the
+/// target and calling convention.
+static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) {
+  const llvm::Triple &TT = S.Context.getTargetInfo().getTriple();
+  bool IsX64 = TT.getArch() == llvm::Triple::x86_64;
+  bool IsAArch64 = (TT.getArch() == llvm::Triple::aarch64 ||
+                    TT.getArch() == llvm::Triple::aarch64_32);
+  bool IsWindowsOrUEFI = TT.isOSWindows() || TT.isUEFI();
+  bool IsMSVAStart = BuiltinID == Builtin::BI__builtin_ms_va_start;
+  if (IsX64 || IsAArch64) {
+    CallingConv CC = CC_C;
+    if (const FunctionDecl *FD = S.getCurFunctionDecl())
+      CC = FD->getType()->castAs<FunctionType>()->getCallConv();
+    if (IsMSVAStart) {
+      // Don't allow this in System V ABI functions.
+      if (CC == CC_X86_64SysV || (!IsWindowsOrUEFI && CC != CC_Win64))
+        return S.Diag(Fn->getBeginLoc(),
+                      diag::err_ms_va_start_used_in_sysv_function);
+    } else {
+      // On x86-64/AArch64 Unix, don't allow this in Win64 ABI functions.
+      // On x64 Windows, don't allow this in System V ABI functions.
+      // (Yes, that means there's no corresponding way to support variadic
+      // System V ABI functions on Windows.)
+      if ((IsWindowsOrUEFI && CC == CC_X86_64SysV) ||
+          (!IsWindowsOrUEFI && CC == CC_Win64))
+        return S.Diag(Fn->getBeginLoc(),
+                      diag::err_va_start_used_in_wrong_abi_function)
+               << !IsWindowsOrUEFI;
+    }
+    return false;
+  }
+
+  if (IsMSVAStart)
+    return S.Diag(Fn->getBeginLoc(), diag::err_builtin_x64_aarch64_only);
+  return false;
+}
+
+static bool checkVAStartIsInVariadicFunction(Sema &S, Expr *Fn,
+                                             ParmVarDecl **LastParam = nullptr) {
+  // Determine whether the current function, block, or obj-c method is variadic
+  // and get its parameter list.
+  bool IsVariadic = false;
+  ArrayRef<ParmVarDecl *> Params;
+  DeclContext *Caller = S.CurContext;
+  if (auto *Block = dyn_cast<BlockDecl>(Caller)) {
+    IsVariadic = Block->isVariadic();
+    Params = Block->parameters();
+  } else if (auto *FD = dyn_cast<FunctionDecl>(Caller)) {
+    IsVariadic = FD->isVariadic();
+    Params = FD->parameters();
+  } else if (auto *MD = dyn_cast<ObjCMethodDecl>(Caller)) {
+    IsVariadic = MD->isVariadic();
+    // FIXME: This isn't correct for methods (results in bogus warning).
+    Params = MD->parameters();
+  } else if (isa<CapturedDecl>(Caller)) {
+    // We don't support va_start in a CapturedDecl.
+    S.Diag(Fn->getBeginLoc(), diag::err_va_start_captured_stmt);
+    return true;
+  } else {
+    // This must be some other declcontext that parses exprs.
+    S.Diag(Fn->getBeginLoc(), diag::err_va_start_outside_function);
+    return true;
+  }
+
+  if (!IsVariadic) {
+    S.Diag(Fn->getBeginLoc(), diag::err_va_start_fixed_function);
+    return true;
+  }
+
+  if (LastParam)
+    *LastParam = Params.empty() ? nullptr : Params.back();
+
+  return false;
+}
+
+bool Sema::BuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
+  Expr *Fn = TheCall->getCallee();
+  if (checkVAStartABI(*this, BuiltinID, Fn))
+    return true;
+
+  if (BuiltinID == Builtin::BI__builtin_c23_va_start) {
+    // This builtin requires one argument (the va_list), allows two arguments,
+    // but diagnoses more than two arguments. e.g.,
+    //   __builtin_c23_va_start(); // error
+    //   __builtin_c23_va_start(list); // ok
+    //   __builtin_c23_va_start(list, param); // ok
+    //   __builtin_c23_va_start(list, anything, anything); // error
+    // This differs from the GCC behavior in that they accept the last case
+    // with a warning, but it doesn't seem like a useful behavior to allow.
+    if (checkArgCountRange(TheCall, 1, 2))
+      return true;
+  } else {
+    // In C23 mode, va_start only needs one argument. However, the builtin still
+    // requires two arguments (which matches the behavior of the GCC builtin),
+    // <stdarg.h> passes `0` as the second argument in C23 mode.
+    if (checkArgCount(TheCall, 2))
+      return true;
+  }
+
+  // Type-check the first argument normally.
+  if (checkBuiltinArgument(*this, TheCall, 0))
+    return true;
+
+  // Check that the current function is variadic, and get its last parameter.
+  ParmVarDecl *LastParam;
+  if (checkVAStartIsInVariadicFunction(*this, Fn, &LastParam))
+    return true;
+
+  // Verify that the second argument to the builtin is the last non-variadic
+  // argument of the current function or method. In C23 mode, if the call is
+  // not to __builtin_c23_va_start, and the second argument is an integer
+  // constant expression with value 0, then we don't bother with this check.
+  // For __builtin_c23_va_start, we only perform the check for the second
+  // argument being the last argument to the current function if there is a
+  // second argument present.
+  if (BuiltinID == Builtin::BI__builtin_c23_va_start &&
+      TheCall->getNumArgs() < 2) {
+    Diag(TheCall->getExprLoc(), diag::warn_c17_compat_va_start_one_arg);
+    return false;
+  }
+
+  const Expr *Arg = TheCall->getArg(1)->IgnoreParenCasts();
+  if (std::optional<llvm::APSInt> Val =
+          TheCall->getArg(1)->getIntegerConstantExpr(Context);
+      Val && LangOpts.C23 && *Val == 0 &&
+      BuiltinID != Builtin::BI__builtin_c23_va_start) {
+    Diag(TheCall->getExprLoc(), diag::warn_c17_compat_va_start_one_arg);
+    return false;
+  }
+
+  // These are valid if SecondArgIsLastNonVariadicArgument is false after the
+  // next block.
+  QualType Type;
+  SourceLocation ParamLoc;
+  bool IsCRegister = false;
+  bool SecondArgIsLastNonVariadicArgument = false;
+  if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Arg)) {
+    if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(DR->getDecl())) {
+      SecondArgIsLastNonVariadicArgument = PV == LastParam;
+
+      Type = PV->getType();
+      ParamLoc = PV->getLocation();
+      IsCRegister =
+          PV->getStorageClass() == SC_Register && !getLangOpts().CPlusPlus;
+    }
+  }
+
+  if (!SecondArgIsLastNonVariadicArgument)
+    Diag(TheCall->getArg(1)->getBeginLoc(),
+         diag::warn_second_arg_of_va_start_not_last_non_variadic_param);
+  else if (IsCRegister || Type->isReferenceType() ||
+           Type->isSpecificBuiltinType(BuiltinType::Float) || [=] {
+             // Promotable integers are UB, but enumerations need a bit of
+             // extra checking to see what their promotable type actually is.
+             if (!Context.isPromotableIntegerType(Type))
+               return false;
+             const auto *ED = Type->getAsEnumDecl();
+             if (!ED)
+               return true;
+             return !Context.typesAreCompatible(ED->getPromotionType(), Type);
+           }()) {
+    unsigned Reason = 0;
+    if (Type->isReferenceType())  Reason = 1;
+    else if (IsCRegister)         Reason = 2;
+    Diag(Arg->getBeginLoc(), diag::warn_va_start_type_is_undefined) << Reason;
+    Diag(ParamLoc, diag::note_parameter_type) << Type;
+  }
+
+  return false;
+}
+
+bool Sema::BuiltinVAStartARMMicrosoft(CallExpr *Call) {
+  auto IsSuitablyTypedFormatArgument = [this](const Expr *Arg) -> bool {
+    const LangOptions &LO = getLangOpts();
+
+    if (LO.CPlusPlus)
+      return Arg->getType()
+                 .getCanonicalType()
+                 .getTypePtr()
+                 ->getPointeeType()
+                 .withoutLocalFastQualifiers() == Context.CharTy;
+
+    // In C, allow aliasing through `char *`, this is required for AArch64 at
+    // least.
+    return true;
+  };
+
+  // void __va_start(va_list *ap, const char *named_addr, size_t slot_size,
+  //                 const char *named_addr);
+
+  Expr *Func = Call->getCallee();
+
+  if (Call->getNumArgs() < 3)
+    return Diag(Call->getEndLoc(),
+                diag::err_typecheck_call_too_few_args_at_least)
+           << 0 /*function call*/ << 3 << Call->getNumArgs()
+           << /*is non object*/ 0;
+
+  // Type-check the first argument normally.
+  if (checkBuiltinArgument(*this, Call, 0))
+    return true;
+
+  // Check that the current function is variadic.
+  if (checkVAStartIsInVariadicFunction(*this, Func))
+    return true;
+
+  // __va_start on Windows does not validate the parameter qualifiers
+
+  const Expr *Arg1 = Call->getArg(1)->IgnoreParens();
+  const Type *Arg1Ty = Arg1->getType().getCanonicalType().getTypePtr();
+
+  const Expr *Arg2 = Call->getArg(2)->IgnoreParens();
+  const Type *Arg2Ty = Arg2->getType().getCanonicalType().getTypePtr();
+
+  const QualType &ConstCharPtrTy =
+      Context.getPointerType(Context.CharTy.withConst());
+  if (!Arg1Ty->isPointerType() || !IsSuitablyTypedFormatArgument(Arg1))
+    Diag(Arg1->getBeginLoc(), diag::err_typecheck_convert_incompatible)
+        << Arg1->getType() << ConstCharPtrTy << 1 /* different class */
+        << 0                                      /* qualifier difference */
+        << 3                                      /* parameter mismatch */
+        << 2 << Arg1->getType() << ConstCharPtrTy;
+
+  const QualType SizeTy = Context.getSizeType();
+  if (!Context.hasSameType(
+          Arg2Ty->getCanonicalTypeInternal().withoutLocalFastQualifiers(),
+          SizeTy))
+    Diag(Arg2->getBeginLoc(), diag::err_typecheck_convert_incompatible)
+        << Arg2->getType() << SizeTy << 1 /* different class */
+        << 0                              /* qualifier difference */
+        << 3                              /* parameter mismatch */
+        << 3 << Arg2->getType() << SizeTy;
+
+  return false;
+}
+
+bool Sema::BuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID) {
+  if (checkArgCount(TheCall, 2))
+    return true;
+
+  if (BuiltinID == Builtin::BI__builtin_isunordered &&
+      TheCall->getFPFeaturesInEffect(getLangOpts()).getNoHonorNaNs())
+    Diag(TheCall->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled)
+        << 1 << 0 << TheCall->getSourceRange();
+
+  ExprResult OrigArg0 = TheCall->getArg(0);
+  ExprResult OrigArg1 = TheCall->getArg(1);
+
+  // Do standard promotions between the two arguments, returning their common
+  // type.
+  QualType Res = UsualArithmeticConversions(
+      OrigArg0, OrigArg1, TheCall->getExprLoc(), ArithConvKind::Comparison);
+  if (OrigArg0.isInvalid() || OrigArg1.isInvalid())
+    return true;
+
+  // Make sure any conversions are pushed back into the call; this is
+  // type safe since unordered compare builtins are declared as "_Bool
+  // foo(...)".
+  TheCall->setArg(0, OrigArg0.get());
+  TheCall->setArg(1, OrigArg1.get());
+
+  if (OrigArg0.get()->isTypeDependent() || OrigArg1.get()->isTypeDependent())
+    return false;
+
+  // If the common type isn't a real floating type, then the arguments were
+  // invalid for this operation.
+  if (Res.isNull() || !Res->isRealFloatingType())
+    return Diag(OrigArg0.get()->getBeginLoc(),
+                diag::err_typecheck_call_invalid_ordered_compare)
+           << OrigArg0.get()->getType() << OrigArg1.get()->getType()
+           << SourceRange(OrigArg0.get()->getBeginLoc(),
+                          OrigArg1.get()->getEndLoc());
+
+  return false;
+}
+
+bool Sema::BuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs,
+                                   unsigned BuiltinID) {
+  if (checkArgCount(TheCall, NumArgs))
+    return true;
+
+  FPOptions FPO = TheCall->getFPFeaturesInEffect(getLangOpts());
+  if (FPO.getNoHonorInfs() && (BuiltinID == Builtin::BI__builtin_isfinite ||
+                               BuiltinID == Builtin::BI__builtin_isinf ||
+                               BuiltinID == Builtin::BI__builtin_isinf_sign))
+    Diag(TheCall->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled)
+        << 0 << 0 << TheCall->getSourceRange();
+
+  if (FPO.getNoHonorNaNs() && (BuiltinID == Builtin::BI__builtin_isnan ||
+                               BuiltinID == Builtin::BI__builtin_isunordered))
+    Diag(TheCall->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled)
+        << 1 << 0 << TheCall->getSourceRange();
+
+  bool IsFPClass = NumArgs == 2;
+
+  // Find out position of floating-point argument.
+  unsigned FPArgNo = IsFPClass ? 0 : NumArgs - 1;
+
+  // We can count on all parameters preceding the floating-point just being int.
+  // Try all of those.
+  for (unsigned i = 0; i < FPArgNo; ++i) {
+    Expr *Arg = TheCall->getArg(i);
+
+    if (Arg->isTypeDependent())
+      return false;
+
+    ExprResult Res = PerformImplicitConversion(Arg, Context.IntTy,
+                                               AssignmentAction::Passing);
+
+    if (Res.isInvalid())
+      return true;
+    TheCall->setArg(i, Res.get());
+  }
+
+  Expr *OrigArg = TheCall->getArg(FPArgNo);
+
+  if (OrigArg->isTypeDependent())
+    return false;
+
+  // Usual Unary Conversions will convert half to float, which we want for
+  // machines that use fp16 conversion intrinsics. Else, we wnat to leave the
+  // type how it is, but do normal L->Rvalue conversions.
+  if (Context.getTargetInfo().useFP16ConversionIntrinsics()) {
+    ExprResult Res = UsualUnaryConversions(OrigArg);
+
+    if (!Res.isUsable())
+      return true;
+    OrigArg = Res.get();
+  } else {
+    ExprResult Res = DefaultFunctionArrayLvalueConversion(OrigArg);
+
+    if (!Res.isUsable())
+      return true;
+    OrigArg = Res.get();
+  }
+  TheCall->setArg(FPArgNo, OrigArg);
+
+  QualType VectorResultTy;
+  QualType ElementTy = OrigArg->getType();
+  // TODO: When all classification function are implemented with is_fpclass,
+  // vector argument can be supported in all of them.
+  if (ElementTy->isVectorType() && IsFPClass) {
+    VectorResultTy = GetSignedVectorType(ElementTy);
+    ElementTy = ElementTy->castAs<VectorType>()->getElementType();
+  }
+
+  // This operation requires a non-_Complex floating-point number.
+  if (!ElementTy->isRealFloatingType())
+    return Diag(OrigArg->getBeginLoc(),
+                diag::err_typecheck_call_invalid_unary_fp)
+           << OrigArg->getType() << OrigArg->getSourceRange();
+
+  // __builtin_isfpclass has integer parameter that specify test mask. It is
+  // passed in (...), so it should be analyzed completely here.
+  if (IsFPClass)
+    if (BuiltinConstantArgRange(TheCall, 1, 0, llvm::fcAllFlags))
+      return true;
+
+  // TODO: enable this code to all classification functions.
+  if (IsFPClass) {
+    QualType ResultTy;
+    if (!VectorResultTy.isNull())
+      ResultTy = VectorResultTy;
+    else
+      ResultTy = Context.IntTy;
+    TheCall->setType(ResultTy);
+  }
+
+  return false;
+}
+
+bool Sema::BuiltinComplex(CallExpr *TheCall) {
+  if (checkArgCount(TheCall, 2))
+    return true;
+
+  bool Dependent = false;
+  for (unsigned I = 0; I != 2; ++I) {
+    Expr *Arg = TheCall->getArg(I);
+    QualType T = Arg->getType();
+    if (T->isDependentType()) {
+      Dependent = true;
+      continue;
+    }
+
+    // Despite supporting _Complex int, GCC requires a real floating point type
+    // for the operands of __builtin_complex.
+    if (!T->isRealFloatingType()) {
+      return Diag(Arg->getBeginLoc(), diag::err_typecheck_call_requires_real_fp)
+             << Arg->getType() << Arg->getSourceRange();
+    }
+
+    ExprResult Converted = DefaultLvalueConversion(Arg);
+    if (Converted.isInvalid())
+      return true;
+    TheCall->setArg(I, Converted.get());
+  }
+
+  if (Dependent) {
+    TheCall->setType(Context.DependentTy);
+    return false;
+  }
+
+  Expr *Real = TheCall->getArg(0);
+  Expr *Imag = TheCall->getArg(1);
+  if (!Context.hasSameType(Real->getType(), Imag->getType())) {
+    return Diag(Real->getBeginLoc(),
+                diag::err_typecheck_call_different_arg_types)
+           << Real->getType() << Imag->getType()
+           << Real->getSourceRange() << Imag->getSourceRange();
+  }
+
+  TheCall->setType(Context.getComplexType(Real->getType()));
+  return false;
+}
+
+/// BuiltinShuffleVector - Handle __builtin_shufflevector.
+// This is declared to take (...), so we have to check everything.
+ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) {
+  unsigned NumArgs = TheCall->getNumArgs();
+  if (NumArgs < 2)
+    return ExprError(Diag(TheCall->getEndLoc(),
+                          diag::err_typecheck_call_too_few_args_at_least)
+                     << 0 /*function call*/ << 2 << NumArgs
+                     << /*is non object*/ 0 << TheCall->getSourceRange());
+
+  // Determine which of the following types of shufflevector we're checking:
+  // 1) unary, vector mask: (lhs, mask)
+  // 2) binary, scalar mask: (lhs, rhs, index, ..., index)
+  QualType ResType = TheCall->getArg(0)->getType();
+  unsigned NumElements = 0;
+
+  if (!TheCall->getArg(0)->isTypeDependent() &&
+      !TheCall->getArg(1)->isTypeDependent()) {
+    QualType LHSType = TheCall->getArg(0)->getType();
+    QualType RHSType = TheCall->getArg(1)->getType();
+
+    if (!LHSType->isVectorType() || !RHSType->isVectorType())
+      return ExprError(
+          Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_non_vector)
+          << TheCall->getDirectCallee() << /*isMoreThanTwoArgs*/ false
+          << SourceRange(TheCall->getArg(0)->getBeginLoc(),
+                         TheCall->getArg(1)->getEndLoc()));
+
+    NumElements = LHSType->castAs<VectorType>()->getNumElements();
+    unsigned NumResElements = NumArgs - 2;
+
+    // Check to see if we have a call with 2 vector arguments, the unary shuffle
+    // with mask.  If so, verify that RHS is an integer vector type with the
+    // same number of elts as lhs.
+    if (NumArgs == 2) {
+      if (!RHSType->hasIntegerRepresentation() ||
+          RHSType->castAs<VectorType>()->getNumElements() != NumElements)
+        return ExprError(Diag(TheCall->getBeginLoc(),
+                              diag::err_vec_builtin_incompatible_vector)
+                         << TheCall->getDirectCallee()
+                         << /*isMoreThanTwoArgs*/ false
+                         << SourceRange(TheCall->getArg(1)->getBeginLoc(),
+                                        TheCall->getArg(1)->getEndLoc()));
+    } else if (!Context.hasSameUnqualifiedType(LHSType, RHSType)) {
+      return ExprError(Diag(TheCall->getBeginLoc(),
+                            diag::err_vec_builtin_incompatible_vector)
+                       << TheCall->getDirectCallee()
+                       << /*isMoreThanTwoArgs*/ false
+                       << SourceRange(TheCall->getArg(0)->getBeginLoc(),
+                                      TheCall->getArg(1)->getEndLoc()));
+    } else if (NumElements != NumResElements) {
+      QualType EltType = LHSType->castAs<VectorType>()->getElementType();
+      ResType = ResType->isExtVectorType()
+                    ? Context.getExtVectorType(EltType, NumResElements)
+                    : Context.getVectorType(EltType, NumResElements,
+                                            VectorKind::Generic);
+    }
+  }
+
+  for (unsigned I = 2; I != NumArgs; ++I) {
+    Expr *Arg = TheCall->getArg(I);
+    if (Arg->isTypeDependent() || Arg->isValueDependent())
+      continue;
+
+    std::optional<llvm::APSInt> Result = Arg->getIntegerConstantExpr(Context);
+    if (!Result)
+      return ExprError(Diag(TheCall->getBeginLoc(),
+                            diag::err_shufflevector_nonconstant_argument)
+                       << Arg->getSourceRange());
+
+    // Allow -1 which will be translated to undef in the IR.
+    if (Result->isSigned() && Result->isAllOnes())
+      ;
+    else if (Result->getActiveBits() > 64 ||
+             Result->getZExtValue() >= NumElements * 2)
+      return ExprError(Diag(TheCall->getBeginLoc(),
+                            diag::err_shufflevector_argument_too_large)
+                       << Arg->getSourceRange());
+
+    TheCall->setArg(I, ConstantExpr::Create(Context, Arg, APValue(*Result)));
+  }
+
+  auto *Result = new (Context) ShuffleVectorExpr(
+      Context, ArrayRef(TheCall->getArgs(), NumArgs), ResType,
+      TheCall->getCallee()->getBeginLoc(), TheCall->getRParenLoc());
+
+  // All moved to Result.
+  TheCall->shrinkNumArgs(0);
+  return Result;
+}
+
+ExprResult Sema::ConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo,
+                                   SourceLocation BuiltinLoc,
+                                   SourceLocation RParenLoc) {
+  ExprValueKind VK = VK_PRValue;
+  ExprObjectKind OK = OK_Ordinary;
+  QualType DstTy = TInfo->getType();
+  QualType SrcTy = E->getType();
+
+  if (!SrcTy->isVectorType() && !SrcTy->isDependentType())
+    return ExprError(Diag(BuiltinLoc,
+                          diag::err_convertvector_non_vector)
+                     << E->getSourceRange());
+  if (!DstTy->isVectorType() && !DstTy->isDependentType())
+    return ExprError(Diag(BuiltinLoc, diag::err_builtin_non_vector_type)
+                     << "second"
+                     << "__builtin_convertvector");
+
+  if (!SrcTy->isDependentType() && !DstTy->isDependentType()) {
+    unsigned SrcElts = SrcTy->castAs<VectorType>()->getNumElements();
+    unsigned DstElts = DstTy->castAs<VectorType>()->getNumElements();
+    if (SrcElts != DstElts)
+      return ExprError(Diag(BuiltinLoc,
+                            diag::err_convertvector_incompatible_vector)
+                       << E->getSourceRange());
+  }
+
+  return ConvertVectorExpr::Create(Context, E, TInfo, DstTy, VK, OK, BuiltinLoc,
+                                   RParenLoc, CurFPFeatureOverrides());
+}
+
+bool Sema::BuiltinPrefetch(CallExpr *TheCall) {
+  unsigned NumArgs = TheCall->getNumArgs();
+
+  if (NumArgs > 3)
+    return Diag(TheCall->getEndLoc(),
+                diag::err_typecheck_call_too_many_args_at_most)
+           << 0 /*function call*/ << 3 << NumArgs << /*is non object*/ 0
+           << TheCall->getSourceRange();
+
+  // Argument 0 is checked for us and the remaining arguments must be
+  // constant integers.
+  for (unsigned i = 1; i != NumArgs; ++i)
+    if (BuiltinConstantArgRange(TheCall, i, 0, i == 1 ? 1 : 3))
+      return true;
+
+  return false;
+}
+
+bool Sema::BuiltinArithmeticFence(CallExpr *TheCall) {
+  if (!Context.getTargetInfo().checkArithmeticFenceSupported())
+    return Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported)
+           << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
+  if (checkArgCount(TheCall, 1))
+    return true;
+  Expr *Arg = TheCall->getArg(0);
+  if (Arg->isInstantiationDependent())
+    return false;
+
+  QualType ArgTy = Arg->getType();
+  if (!ArgTy->hasFloatingRepresentation())
+    return Diag(TheCall->getEndLoc(), diag::err_typecheck_expect_flt_or_vector)
+           << ArgTy;
+  if (Arg->isLValue()) {
+    ExprResult FirstArg = DefaultLvalueConversion(Arg);
+    TheCall->setArg(0, FirstArg.get());
+  }
+  TheCall->setType(TheCall->getArg(0)->getType());
+  return false;
+}
+
+bool Sema::BuiltinAssume(CallExpr *TheCall) {
+  Expr *Arg = TheCall->getArg(0);
+  if (Arg->isInstantiationDependent()) return false;
+
+  if (Arg->HasSideEffects(Context))
+    Diag(Arg->getBeginLoc(), diag::warn_assume_side_effects)
+        << Arg->getSourceRange()
+        << cast<FunctionDecl>(TheCall->getCalleeDecl())->getIdentifier();
+
+  return false;
+}
+
+bool Sema::BuiltinAllocaWithAlign(CallExpr *TheCall) {
+  // The alignment must be a constant integer.
+  Expr *Arg = TheCall->getArg(1);
+
+  // We can't check the value of a dependent argument.
+  if (!Arg->isTypeDependent() && !Arg->isValueDependent()) {
+    if (const auto *UE =
+            dyn_cast<UnaryExprOrTypeTraitExpr>(Arg->IgnoreParenImpCasts()))
+      if (UE->getKind() == UETT_AlignOf ||
+          UE->getKind() == UETT_PreferredAlignOf)
+        Diag(TheCall->getBeginLoc(), diag::warn_alloca_align_alignof)
+            << Arg->getSourceRange();
+
+    llvm::APSInt Result = Arg->EvaluateKnownConstInt(Context);
+
+    if (!Result.isPowerOf2())
+      return Diag(TheCall->getBeginLoc(), diag::err_alignment_not_power_of_two)
+             << Arg->getSourceRange();
+
+    if (Result < Context.getCharWidth())
+      return Diag(TheCall->getBeginLoc(), diag::err_alignment_too_small)
+             << (unsigned)Context.getCharWidth() << Arg->getSourceRange();
+
+    if (Result > std::numeric_limits<int32_t>::max())
+      return Diag(TheCall->getBeginLoc(), diag::err_alignment_too_big)
+             << std::numeric_limits<int32_t>::max() << Arg->getSourceRange();
+  }
+
+  return false;
+}
+
+bool Sema::BuiltinAssumeAligned(CallExpr *TheCall) {
+  if (checkArgCountRange(TheCall, 2, 3))
+    return true;
+
+  unsigned NumArgs = TheCall->getNumArgs();
+  Expr *FirstArg = TheCall->getArg(0);
+
+  {
+    ExprResult FirstArgResult =
+        DefaultFunctionArrayLvalueConversion(FirstArg);
+    if (!FirstArgResult.get()->getType()->isPointerType()) {
+      Diag(TheCall->getBeginLoc(), diag::err_builtin_assume_aligned_invalid_arg)
+          << TheCall->getSourceRange();
+      return true;
+    }
+    TheCall->setArg(0, FirstArgResult.get());
+  }
+
+  // The alignment must be a constant integer.
+  Expr *SecondArg = TheCall->getArg(1);
+
+  // We can't check the value of a dependent argument.
+  if (!SecondArg->isValueDependent()) {
+    llvm::APSInt Result;
+    if (BuiltinConstantArg(TheCall, 1, Result))
+      return true;
+
+    if (!Result.isPowerOf2())
+      return Diag(TheCall->getBeginLoc(), diag::err_alignment_not_power_of_two)
+             << SecondArg->getSourceRange();
+
+    if (Result > Sema::MaximumAlignment)
+      Diag(TheCall->getBeginLoc(), diag::warn_assume_aligned_too_great)
+          << SecondArg->getSourceRange() << Sema::MaximumAlignment;
+
+    TheCall->setArg(1,
+                    ConstantExpr::Create(Context, SecondArg, APValue(Result)));
+  }
+
+  if (NumArgs > 2) {
+    Expr *ThirdArg = TheCall->getArg(2);
+    if (convertArgumentToType(*this, ThirdArg, Context.getSizeType()))
+      return true;
+    TheCall->setArg(2, ThirdArg);
+  }
+
+  return false;
+}
+
+bool Sema::BuiltinOSLogFormat(CallExpr *TheCall) {
+  unsigned BuiltinID =
+      cast<FunctionDecl>(TheCall->getCalleeDecl())->getBuiltinID();
+  bool IsSizeCall = BuiltinID == Builtin::BI__builtin_os_log_format_buffer_size;
+
+  unsigned NumArgs = TheCall->getNumArgs();
+  unsigned NumRequiredArgs = IsSizeCall ? 1 : 2;
+  if (NumArgs < NumRequiredArgs) {
+    return Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args)
+           << 0 /* function call */ << NumRequiredArgs << NumArgs
+           << /*is non object*/ 0 << TheCall->getSourceRange();
+  }
+  if (NumArgs >= NumRequiredArgs + 0x100) {
+    return Diag(TheCall->getEndLoc(),
+                diag::err_typecheck_call_too_many_args_at_most)
+           << 0 /* function call */ << (NumRequiredArgs + 0xff) << NumArgs
+           << /*is non object*/ 0 << TheCall->getSourceRange();
+  }
+  unsigned i = 0;
+
+  // For formatting call, check buffer arg.
+  if (!IsSizeCall) {
+    ExprResult Arg(TheCall->getArg(i));
+    InitializedEntity Entity = InitializedEntity::InitializeParameter(
+        Context, Context.VoidPtrTy, false);
+    Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg);
+    if (Arg.isInvalid())
+      return true;
+    TheCall->setArg(i, Arg.get());
+    i++;
+  }
+
+  // Check string literal arg.
+  unsigned FormatIdx = i;
+  {
+    ExprResult Arg = CheckOSLogFormatStringArg(TheCall->getArg(i));
+    if (Arg.isInvalid())
+      return true;
+    TheCall->setArg(i, Arg.get());
+    i++;
+  }
+
+  // Make sure variadic args are scalar.
+  unsigned FirstDataArg = i;
+  while (i < NumArgs) {
+    ExprResult Arg = DefaultVariadicArgumentPromotion(
+        TheCall->getArg(i), VariadicCallType::Function, nullptr);
+    if (Arg.isInvalid())
+      return true;
+    CharUnits ArgSize = Context.getTypeSizeInChars(Arg.get()->getType());
+    if (ArgSize.getQuantity() >= 0x100) {
+      return Diag(Arg.get()->getEndLoc(), diag::err_os_log_argument_too_big)
+             << i << (int)ArgSize.getQuantity() << 0xff
+             << TheCall->getSourceRange();
+    }
+    TheCall->setArg(i, Arg.get());
+    i++;
+  }
+
+  // Check formatting specifiers. NOTE: We're only doing this for the non-size
+  // call to avoid duplicate diagnostics.
+  if (!IsSizeCall) {
+    llvm::SmallBitVector CheckedVarArgs(NumArgs, false);
+    ArrayRef<const Expr *> Args(TheCall->getArgs(), TheCall->getNumArgs());
+    bool Success = CheckFormatArguments(
+        Args, FAPK_Variadic, nullptr, FormatIdx, FirstDataArg,
+        FormatStringType::OSLog, VariadicCallType::Function,
+        TheCall->getBeginLoc(), SourceRange(), CheckedVarArgs);
+    if (!Success)
+      return true;
+  }
+
+  if (IsSizeCall) {
+    TheCall->setType(Context.getSizeType());
+  } else {
+    TheCall->setType(Context.VoidPtrTy);
+  }
+  return false;
+}
+
+bool Sema::BuiltinConstantArg(CallExpr *TheCall, unsigned ArgNum,
+                              llvm::APSInt &Result) {
+  Expr *Arg = TheCall->getArg(ArgNum);
+
+  if (Arg->isTypeDependent() || Arg->isValueDependent())
+    return false;
+
+  std::optional<llvm::APSInt> R = Arg->getIntegerConstantExpr(Context);
+  if (!R) {
+    auto *DRE = cast<DeclRefExpr>(TheCall->getCallee()->IgnoreParenCasts());
+    auto *FDecl = cast<FunctionDecl>(DRE->getDecl());
+    return Diag(TheCall->getBeginLoc(), diag::err_constant_integer_arg_type)
+           << FDecl->getDeclName() << Arg->getSourceRange();
+  }
+  Result = *R;
+
+  return false;
+}
+
+bool Sema::BuiltinConstantArgRange(CallExpr *TheCall, unsigned ArgNum, int Low,
+                                   int High, bool RangeIsError) {
+  if (isConstantEvaluatedContext())
+    return false;
+  llvm::APSInt Result;
+
+  // We can't check the value of a dependent argument.
+  Expr *Arg = TheCall->getArg(ArgNum);
+  if (Arg->isTypeDependent() || Arg->isValueDependent())
+    return false;
+
+  // Check constant-ness first.
+  if (BuiltinConstantArg(TheCall, ArgNum, Result))
+    return true;
+
+  if (Result.getSExtValue() < Low || Result.getSExtValue() > High) {
+    if (RangeIsError)
+      return Diag(TheCall->getBeginLoc(), diag::err_argument_invalid_range)
+             << toString(Result, 10) << Low << High << Arg->getSourceRange();
+    else
+      // Defer the warning until we know if the code will be emitted so that
+      // dead code can ignore this.
+      DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall,
+                          PDiag(diag::warn_argument_invalid_range)
+                              << toString(Result, 10) << Low << High
+                              << Arg->getSourceRange());
+  }
+
+  return false;
+}
+
+bool Sema::BuiltinConstantArgMultiple(CallExpr *TheCall, unsigned ArgNum,
+                                      unsigned Num) {
+  llvm::APSInt Result;
+
+  // We can't check the value of a dependent argument.
+  Expr *Arg = TheCall->getArg(ArgNum);
+  if (Arg->isTypeDependent() || Arg->isValueDependent())
+    return false;
+
+  // Check constant-ness first.
+  if (BuiltinConstantArg(TheCall, ArgNum, Result))
+    return true;
+
+  if (Result.getSExtValue() % Num != 0)
+    return Diag(TheCall->getBeginLoc(), diag::err_argument_not_multiple)
+           << Num << Arg->getSourceRange();
+
+  return false;
+}
+
+bool Sema::BuiltinConstantArgPower2(CallExpr *TheCall, unsigned ArgNum) {
+  llvm::APSInt Result;
+
+  // We can't check the value of a dependent argument.
+  Expr *Arg = TheCall->getArg(ArgNum);
+  if (Arg->isTypeDependent() || Arg->isValueDependent())
+    return false;
+
+  // Check constant-ness first.
+  if (BuiltinConstantArg(TheCall, ArgNum, Result))
+    return true;
+
+  if (Result.isPowerOf2())
+    return false;
+
+  return Diag(TheCall->getBeginLoc(), diag::err_argument_not_power_of_2)
+         << Arg->getSourceRange();
+}
+
+static bool IsShiftedByte(llvm::APSInt Value) {
+  if (Value.isNegative())
+    return false;
+
+  // Check if it's a shifted byte, by shifting it down
+  while (true) {
+    // If the value fits in the bottom byte, the check passes.
+    if (Value < 0x100)
+      return true;
+
+    // Otherwise, if the value has _any_ bits in the bottom byte, the check
+    // fails.
+    if ((Value & 0xFF) != 0)
+      return false;
+
+    // If the bottom 8 bits are all 0, but something above that is nonzero,
+    // then shifting the value right by 8 bits won't affect whether it's a
+    // shifted byte or not. So do that, and go round again.
+    Value >>= 8;
+  }
+}
+
+bool Sema::BuiltinConstantArgShiftedByte(CallExpr *TheCall, unsigned ArgNum,
+                                         unsigned ArgBits) {
+  llvm::APSInt Result;
+
+  // We can't check the value of a dependent argument.
+  Expr *Arg = TheCall->getArg(ArgNum);
+  if (Arg->isTypeDependent() || Arg->isValueDependent())
+    return false;
+
+  // Check constant-ness first.
+  if (BuiltinConstantArg(TheCall, ArgNum, Result))
+    return true;
+
+  // Truncate to the given size.
+  Result = Result.getLoBits(ArgBits);
+  Result.setIsUnsigned(true);
+
+  if (IsShiftedByte(Result))
+    return false;
+
+  return Diag(TheCall->getBeginLoc(), diag::err_argument_not_shifted_byte)
+         << Arg->getSourceRange();
+}
+
+bool Sema::BuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall,
+                                               unsigned ArgNum,
+                                               unsigned ArgBits) {
+  llvm::APSInt Result;
+
+  // We can't check the value of a dependent argument.
+  Expr *Arg = TheCall->getArg(ArgNum);
+  if (Arg->isTypeDependent() || Arg->isValueDependent())
+    return false;
+
+  // Check constant-ness first.
+  if (BuiltinConstantArg(TheCall, ArgNum, Result))
+    return true;
+
+  // Truncate to the given size.
+  Result = Result.getLoBits(ArgBits);
+  Result.setIsUnsigned(true);
+
+  // Check to see if it's in either of the required forms.
+  if (IsShiftedByte(Result) ||
+      (Result > 0 && Result < 0x10000 && (Result & 0xFF) == 0xFF))
+    return false;
+
+  return Diag(TheCall->getBeginLoc(),
+              diag::err_argument_not_shifted_byte_or_xxff)
+         << Arg->getSourceRange();
+}
+
+bool Sema::BuiltinLongjmp(CallExpr *TheCall) {
+  if (!Context.getTargetInfo().hasSjLjLowering())
+    return Diag(TheCall->getBeginLoc(), diag::err_builtin_longjmp_unsupported)
+           << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
+
+  Expr *Arg = TheCall->getArg(1);
+  llvm::APSInt Result;
+
+  // TODO: This is less than ideal. Overload this to take a value.
+  if (BuiltinConstantArg(TheCall, 1, Result))
+    return true;
+
+  if (Result != 1)
+    return Diag(TheCall->getBeginLoc(), diag::err_builtin_longjmp_invalid_val)
+           << SourceRange(Arg->getBeginLoc(), Arg->getEndLoc());
+
+  return false;
+}
+
+bool Sema::BuiltinSetjmp(CallExpr *TheCall) {
+  if (!Context.getTargetInfo().hasSjLjLowering())
+    return Diag(TheCall->getBeginLoc(), diag::err_builtin_setjmp_unsupported)
+           << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc());
+  return false;
+}
+
+bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
+  if (checkArgCount(TheCall, 1))
+    return true;
+
+  ExprResult ArgRes = UsualUnaryConversions(TheCall->getArg(0));
+  if (ArgRes.isInvalid())
+    return true;
+
+  // For simplicity, we support only limited expressions for the argument.
+  // Specifically a flexible array member or a pointer with counted_by:
+  // 'ptr->array' or 'ptr->pointer'. This allows us to reject arguments with
+  // complex casting, which really shouldn't be a huge problem.
+  const Expr *Arg = ArgRes.get()->IgnoreParenImpCasts();
+  if (!Arg->getType()->isPointerType() && !Arg->getType()->isArrayType())
+    return Diag(Arg->getBeginLoc(),
+                diag::err_builtin_counted_by_ref_invalid_arg)
+           << Arg->getSourceRange();
+
+  if (Arg->HasSideEffects(Context))
+    return Diag(Arg->getBeginLoc(),
+                diag::err_builtin_counted_by_ref_has_side_effects)
+           << Arg->getSourceRange();
+
+  if (const auto *ME = dyn_cast<MemberExpr>(Arg)) {
+    const auto *CATy =
+        ME->getMemberDecl()->getType()->getAs<CountAttributedType>();
+
+    if (CATy && CATy->getKind() == CountAttributedType::CountedBy) {
+      // Member has counted_by attribute - return pointer to count field
+      const auto *MemberDecl = cast<FieldDecl>(ME->getMemberDecl());
+      if (const FieldDecl *CountFD = MemberDecl->findCountedByField()) {
+        TheCall->setType(Context.getPointerType(CountFD->getType()));
+        return false;
+      }
+    }
+
+    // FAMs and pointers without counted_by return void*
+    QualType MemberTy = ME->getMemberDecl()->getType();
+    if (!MemberTy->isArrayType() && !MemberTy->isPointerType())
+      return Diag(Arg->getBeginLoc(),
+                  diag::err_builtin_counted_by_ref_invalid_arg)
+             << Arg->getSourceRange();
+  } else {
+    return Diag(Arg->getBeginLoc(),
+                diag::err_builtin_counted_by_ref_invalid_arg)
+           << Arg->getSourceRange();
+  }
+
+  TheCall->setType(Context.getPointerType(Context.VoidTy));
+  return false;
+}
+
+/// The result of __builtin_counted_by_ref cannot be assigned to a variable.
+/// It allows leaking and modification of bounds safety information.
+bool Sema::CheckInvalidBuiltinCountedByRef(const Expr *E,
+                                           BuiltinCountedByRefKind K) {
+  const CallExpr *CE =
+      E ? dyn_cast<CallExpr>(E->IgnoreParenImpCasts()) : nullptr;
+  if (!CE || CE->getBuiltinCallee() != Builtin::BI__builtin_counted_by_ref)
+    return false;
+
+  switch (K) {
+  case BuiltinCountedByRefKind::Assignment:
+  case BuiltinCountedByRefKind::Initializer:
+    Diag(E->getExprLoc(),
+         diag::err_builtin_counted_by_ref_cannot_leak_reference)
+        << 0 << E->getSourceRange();
+    break;
+  case BuiltinCountedByRefKind::FunctionArg:
+    Diag(E->getExprLoc(),
+         diag::err_builtin_counted_by_ref_cannot_leak_reference)
+        << 1 << E->getSourceRange();
+    break;
+  case BuiltinCountedByRefKind::ReturnArg:
+    Diag(E->getExprLoc(),
+         diag::err_builtin_counted_by_ref_cannot_leak_reference)
+        << 2 << E->getSourceRange();
+    break;
+  case BuiltinCountedByRefKind::ArraySubscript:
+    Diag(E->getExprLoc(), diag::err_builtin_counted_by_ref_invalid_use)
+        << 0 << E->getSourceRange();
+    break;
+  case BuiltinCountedByRefKind::BinaryExpr:
+    Diag(E->getExprLoc(), diag::err_builtin_counted_by_ref_invalid_use)
+        << 1 << E->getSourceRange();
+    break;
+  }
+
+  return true;
+}
+
+namespace {
+
+class UncoveredArgHandler {
+  enum { Unknown = -1, AllCovered = -2 };
+
+  signed FirstUncoveredArg = Unknown;
+  SmallVector<const Expr *, 4> DiagnosticExprs;
+
+public:
+  UncoveredArgHandler() = default;
+
+  bool hasUncoveredArg() const {
+    return (FirstUncoveredArg >= 0);
+  }
+
+  unsigned getUncoveredArg() const {
+    assert(hasUncoveredArg() && "no uncovered argument");
+    return FirstUncoveredArg;
+  }
+
+  void setAllCovered() {
+    // A string has been found with all arguments covered, so clear out
+    // the diagnostics.
+    DiagnosticExprs.clear();
+    FirstUncoveredArg = AllCovered;
+  }
+
+  void Update(signed NewFirstUncoveredArg, const Expr *StrExpr) {
+    assert(NewFirstUncoveredArg >= 0 && "Outside range");
+
+    // Don't update if a previous string covers all arguments.
+    if (FirstUncoveredArg == AllCovered)
+      return;
+
+    // UncoveredArgHandler tracks the highest uncovered argument index
+    // and with it all the strings that match this index.
+    if (NewFirstUncoveredArg == FirstUncoveredArg)
+      DiagnosticExprs.push_back(StrExpr);
+    else if (NewFirstUncoveredArg > FirstUncoveredArg) {
+      DiagnosticExprs.clear();
+      DiagnosticExprs.push_back(StrExpr);
+      FirstUncoveredArg = NewFirstUncoveredArg;
+    }
+  }
+
+  void Diagnose(Sema &S, bool IsFunctionCall, const Expr *ArgExpr);
+};
+
+enum StringLiteralCheckType {
+  SLCT_NotALiteral,
+  SLCT_UncheckedLiteral,
+  SLCT_CheckedLiteral
+};
+
+} // namespace
+
+static void sumOffsets(llvm::APSInt &Offset, llvm::APSInt Addend,
+                                     BinaryOperatorKind BinOpKind,
+                                     bool AddendIsRight) {
+  unsigned BitWidth = Offset.getBitWidth();
+  unsigned AddendBitWidth = Addend.getBitWidth();
+  // There might be negative interim results.
+  if (Addend.isUnsigned()) {
+    Addend = Addend.zext(++AddendBitWidth);
+    Addend.setIsSigned(true);
+  }
+  // Adjust the bit width of the APSInts.
+  if (AddendBitWidth > BitWidth) {
+    Offset = Offset.sext(AddendBitWidth);
+    BitWidth = AddendBitWidth;
+  } else if (BitWidth > AddendBitWidth) {
+    Addend = Addend.sext(BitWidth);
+  }
+
+  bool Ov = false;
+  llvm::APSInt ResOffset = Offset;
+  if (BinOpKind == BO_Add)
+    ResOffset = Offset.sadd_ov(Addend, Ov);
+  else {
+    assert(AddendIsRight && BinOpKind == BO_Sub &&
+           "operator must be add or sub with addend on the right");
+    ResOffset = Offset.ssub_ov(Addend, Ov);
+  }
+
+  // We add an offset to a pointer here so we should support an offset as big as
+  // possible.
+  if (Ov) {
+    assert(BitWidth <= std::numeric_limits<unsigned>::max() / 2 &&
+           "index (intermediate) result too big");
+    Offset = Offset.sext(2 * BitWidth);
+    sumOffsets(Offset, Addend, BinOpKind, AddendIsRight);
+    return;
+  }
+
+  Offset = ResOffset;
+}
+
+namespace {
+
+// This is a wrapper class around StringLiteral to support offsetted string
+// literals as format strings. It takes the offset into account when returning
+// the string and its length or the source locations to display notes correctly.
+class FormatStringLiteral {
+  const StringLiteral *FExpr;
+  int64_t Offset;
+
+public:
+  FormatStringLiteral(const StringLiteral *fexpr, int64_t Offset = 0)
+      : FExpr(fexpr), Offset(Offset) {}
+
+  const StringLiteral *getFormatString() const { return FExpr; }
+
+  StringRef getString() const { return FExpr->getString().drop_front(Offset); }
+
+  unsigned getByteLength() const {
+    return FExpr->getByteLength() - getCharByteWidth() * Offset;
+  }
+
+  unsigned getLength() const { return FExpr->getLength() - Offset; }
+  unsigned getCharByteWidth() const { return FExpr->getCharByteWidth(); }
+
+  StringLiteralKind getKind() const { return FExpr->getKind(); }
+
+  QualType getType() const { return FExpr->getType(); }
+
+  bool isAscii() const { return FExpr->isOrdinary(); }
+  bool isWide() const { return FExpr->isWide(); }
+  bool isUTF8() const { return FExpr->isUTF8(); }
+  bool isUTF16() const { return FExpr->isUTF16(); }
+  bool isUTF32() const { return FExpr->isUTF32(); }
+  bool isPascal() const { return FExpr->isPascal(); }
+
+  SourceLocation getLocationOfByte(
+      unsigned ByteNo, const SourceManager &SM, const LangOptions &Features,
+      const TargetInfo &Target, unsigned *StartToken = nullptr,
+      unsigned *StartTokenByteOffset = nullptr) const {
+    return FExpr->getLocationOfByte(ByteNo + Offset, SM, Features, Target,
+                                    StartToken, StartTokenByteOffset);
+  }
+
+  SourceLocation getBeginLoc() const LLVM_READONLY {
+    return FExpr->getBeginLoc().getLocWithOffset(Offset);
+  }
+
+  SourceLocation getEndLoc() const LLVM_READONLY { return FExpr->getEndLoc(); }
+};
+
+} // namespace
+
+static void CheckFormatString(
+    Sema &S, const FormatStringLiteral *FExpr,
+    const StringLiteral *ReferenceFormatString, const Expr *OrigFormatExpr,
+    ArrayRef<const Expr *> Args, Sema::FormatArgumentPassingKind APK,
+    unsigned format_idx, unsigned firstDataArg, FormatStringType Type,
+    bool inFunctionCall, VariadicCallType CallType,
+    llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg,
+    bool IgnoreStringsWithoutSpecifiers);
+
+static const Expr *maybeConstEvalStringLiteral(ASTContext &Context,
+                                               const Expr *E);
+
+// Determine if an expression is a string literal or constant string.
+// If this function returns false on the arguments to a function expecting a
+// format string, we will usually need to emit a warning.
+// True string literals are then checked by CheckFormatString.
+static StringLiteralCheckType
+checkFormatStringExpr(Sema &S, const StringLiteral *ReferenceFormatString,
+                      const Expr *E, ArrayRef<const Expr *> Args,
+                      Sema::FormatArgumentPassingKind APK, unsigned format_idx,
+                      unsigned firstDataArg, FormatStringType Type,
+                      VariadicCallType CallType, bool InFunctionCall,
+                      llvm::SmallBitVector &CheckedVarArgs,
+                      UncoveredArgHandler &UncoveredArg, llvm::APSInt Offset,
+                      std::optional<unsigned> *CallerFormatParamIdx = nullptr,
+                      bool IgnoreStringsWithoutSpecifiers = false) {
+  if (S.isConstantEvaluatedContext())
+    return SLCT_NotALiteral;
+tryAgain:
+  assert(Offset.isSigned() && "invalid offset");
+
+  if (E->isTypeDependent() || E->isValueDependent())
+    return SLCT_NotALiteral;
+
+  E = E->IgnoreParenCasts();
+
+  if (E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull))
+    // Technically -Wformat-nonliteral does not warn about this case.
+    // The behavior of printf and friends in this case is implementation
+    // dependent.  Ideally if the format string cannot be null then
+    // it should have a 'nonnull' attribute in the function prototype.
+    return SLCT_UncheckedLiteral;
+
+  switch (E->getStmtClass()) {
+  case Stmt::InitListExprClass:
+    // Handle expressions like {"foobar"}.
+    if (const clang::Expr *SLE = maybeConstEvalStringLiteral(S.Context, E)) {
+      return checkFormatStringExpr(S, ReferenceFormatString, SLE, Args, APK,
+                                   format_idx, firstDataArg, Type, CallType,
+                                   /*InFunctionCall*/ false, CheckedVarArgs,
+                                   UncoveredArg, Offset, CallerFormatParamIdx,
+                                   IgnoreStringsWithoutSpecifiers);
+    }
+    return SLCT_NotALiteral;
+  case Stmt::BinaryConditionalOperatorClass:
+  case Stmt::ConditionalOperatorClass: {
+    // The expression is a literal if both sub-expressions were, and it was
+    // completely checked only if both sub-expressions were checked.
+    const AbstractConditionalOperator *C =
+        cast<AbstractConditionalOperator>(E);
+
+    // Determine whether it is necessary to check both sub-expressions, for
+    // example, because the condition expression is a constant that can be
+    // evaluated at compile time.
+    bool CheckLeft = true, CheckRight = true;
+
+    bool Cond;
+    if (C->getCond()->EvaluateAsBooleanCondition(
+            Cond, S.getASTContext(), S.isConstantEvaluatedContext())) {
+      if (Cond)
+        CheckRight = false;
+      else
+        CheckLeft = false;
+    }
+
+    // We need to maintain the offsets for the right and the left hand side
+    // separately to check if every possible indexed expression is a valid
+    // string literal. They might have different offsets for different string
+    // literals in the end.
+    StringLiteralCheckType Left;
+    if (!CheckLeft)
+      Left = SLCT_UncheckedLiteral;
+    else {
+      Left = checkFormatStringExpr(S, ReferenceFormatString, C->getTrueExpr(),
+                                   Args, APK, format_idx, firstDataArg, Type,
+                                   CallType, InFunctionCall, CheckedVarArgs,
+                                   UncoveredArg, Offset, CallerFormatParamIdx,
+                                   IgnoreStringsWithoutSpecifiers);
+      if (Left == SLCT_NotALiteral || !CheckRight) {
+        return Left;
+      }
+    }
+
+    StringLiteralCheckType Right = checkFormatStringExpr(
+        S, ReferenceFormatString, C->getFalseExpr(), Args, APK, format_idx,
+        firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs,
+        UncoveredArg, Offset, CallerFormatParamIdx,
+        IgnoreStringsWithoutSpecifiers);
+
+    return (CheckLeft && Left < Right) ? Left : Right;
+  }
+
+  case Stmt::ImplicitCastExprClass:
+    E = cast<ImplicitCastExpr>(E)->getSubExpr();
+    goto tryAgain;
+
+  case Stmt::OpaqueValueExprClass:
+    if (const Expr *src = cast<OpaqueValueExpr>(E)->getSourceExpr()) {
+      E = src;
+      goto tryAgain;
+    }
+    return SLCT_NotALiteral;
+
+  case Stmt::PredefinedExprClass:
+    // While __func__, etc., are technically not string literals, they
+    // cannot contain format specifiers and thus are not a security
+    // liability.
+    return SLCT_UncheckedLiteral;
+
+  case Stmt::DeclRefExprClass: {
+    const DeclRefExpr *DR = cast<DeclRefExpr>(E);
+
+    // As an exception, do not flag errors for variables binding to
+    // const string literals.
+    if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+      bool isConstant = false;
+      QualType T = DR->getType();
+
+      if (const ArrayType *AT = S.Context.getAsArrayType(T)) {
+        isConstant = AT->getElementType().isConstant(S.Context);
+      } else if (const PointerType *PT = T->getAs<PointerType>()) {
+        isConstant = T.isConstant(S.Context) &&
+                     PT->getPointeeType().isConstant(S.Context);
+      } else if (T->isObjCObjectPointerType()) {
+        // In ObjC, there is usually no "const ObjectPointer" type,
+        // so don't check if the pointee type is constant.
+        isConstant = T.isConstant(S.Context);
+      }
+
+      if (isConstant) {
+        if (const Expr *Init = VD->getAnyInitializer()) {
+          // Look through initializers like const char c[] = { "foo" }
+          if (const InitListExpr *InitList = dyn_cast<InitListExpr>(Init)) {
+            if (InitList->isStringLiteralInit())
+              Init = InitList->getInit(0)->IgnoreParenImpCasts();
+          }
+          return checkFormatStringExpr(
+              S, ReferenceFormatString, Init, Args, APK, format_idx,
+              firstDataArg, Type, CallType, /*InFunctionCall=*/false,
+              CheckedVarArgs, UncoveredArg, Offset, CallerFormatParamIdx);
+        }
+      }
+
+      // When the format argument is an argument of this function, and this
+      // function also has the format attribute, there are several interactions
+      // for which there shouldn't be a warning. For instance, when calling
+      // v*printf from a function that has the printf format attribute, we
+      // should not emit a warning about using `fmt`, even though it's not
+      // constant, because the arguments have already been checked for the
+      // caller of `logmessage`:
+      //
+      //  __attribute__((format(printf, 1, 2)))
+      //  void logmessage(char const *fmt, ...) {
+      //    va_list ap;
+      //    va_start(ap, fmt);
+      //    vprintf(fmt, ap);  /* do not emit a warning about "fmt" */
+      //    ...
+      // }
+      //
+      // Another interaction that we need to support is using a format string
+      // specified by the format_matches attribute:
+      //
+      //  __attribute__((format_matches(printf, 1, "%s %d")))
+      //  void logmessage(char const *fmt, const char *a, int b) {
+      //    printf(fmt, a, b); /* do not emit a warning about "fmt" */
+      //    printf(fmt, 123.4); /* emit warnings that "%s %d" is incompatible */
+      //    ...
+      // }
+      //
+      // Yet another interaction that we need to support is calling a variadic
+      // format function from a format function that has fixed arguments. For
+      // instance:
+      //
+      //  __attribute__((format(printf, 1, 2)))
+      //  void logstring(char const *fmt, char const *str) {
+      //    printf(fmt, str);  /* do not emit a warning about "fmt" */
+      //  }
+      //
+      // Same (and perhaps more relatably) for the variadic template case:
+      //
+      //  template<typename... Args>
+      //  __attribute__((format(printf, 1, 2)))
+      //  void log(const char *fmt, Args&&... args) {
+      //    printf(fmt, forward<Args>(args)...);
+      //           /* do not emit a warning about "fmt" */
+      //  }
+      //
+      // Due to implementation difficulty, we only check the format, not the
+      // format arguments, in all cases.
+      //
+      if (const auto *PV = dyn_cast<ParmVarDecl>(VD)) {
+        if (CallerFormatParamIdx)
+          *CallerFormatParamIdx = PV->getFunctionScopeIndex();
+        if (const auto *D = dyn_cast<Decl>(PV->getDeclContext())) {
+          for (const auto *PVFormatMatches :
+               D->specific_attrs<FormatMatchesAttr>()) {
+            Sema::FormatStringInfo CalleeFSI;
+            if (!Sema::getFormatStringInfo(D, PVFormatMatches->getFormatIdx(),
+                                           0, &CalleeFSI))
+              continue;
+            if (PV->getFunctionScopeIndex() == CalleeFSI.FormatIdx) {
+              // If using the wrong type of format string, emit a diagnostic
+              // here and stop checking to avoid irrelevant diagnostics.
+              if (Type != S.GetFormatStringType(PVFormatMatches)) {
+                S.Diag(Args[format_idx]->getBeginLoc(),
+                       diag::warn_format_string_type_incompatible)
+                    << PVFormatMatches->getType()->getName()
+                    << S.GetFormatStringTypeName(Type);
+                if (!InFunctionCall) {
+                  S.Diag(PVFormatMatches->getFormatString()->getBeginLoc(),
+                         diag::note_format_string_defined);
+                }
+                return SLCT_UncheckedLiteral;
+              }
+              return checkFormatStringExpr(
+                  S, ReferenceFormatString, PVFormatMatches->getFormatString(),
+                  Args, APK, format_idx, firstDataArg, Type, CallType,
+                  /*InFunctionCall*/ false, CheckedVarArgs, UncoveredArg,
+                  Offset, CallerFormatParamIdx, IgnoreStringsWithoutSpecifiers);
+            }
+          }
+
+          for (const auto *PVFormat : D->specific_attrs<FormatAttr>()) {
+            Sema::FormatStringInfo CallerFSI;
+            if (!Sema::getFormatStringInfo(D, PVFormat->getFormatIdx(),
+                                           PVFormat->getFirstArg(), &CallerFSI))
+              continue;
+            if (PV->getFunctionScopeIndex() == CallerFSI.FormatIdx) {
+              // We also check if the formats are compatible.
+              // We can't pass a 'scanf' string to a 'printf' function.
+              if (Type != S.GetFormatStringType(PVFormat)) {
+                S.Diag(Args[format_idx]->getBeginLoc(),
+                       diag::warn_format_string_type_incompatible)
+                    << PVFormat->getType()->getName()
+                    << S.GetFormatStringTypeName(Type);
+                if (!InFunctionCall) {
+                  S.Diag(E->getBeginLoc(), diag::note_format_string_defined);
+                }
+                return SLCT_UncheckedLiteral;
+              }
+              // Lastly, check that argument passing kinds transition in a
+              // way that makes sense:
+              // from a caller with FAPK_VAList, allow FAPK_VAList
+              // from a caller with FAPK_Fixed, allow FAPK_Fixed
+              // from a caller with FAPK_Fixed, allow FAPK_Variadic
+              // from a caller with FAPK_Variadic, allow FAPK_VAList
+              switch (combineFAPK(CallerFSI.ArgPassingKind, APK)) {
+              case combineFAPK(Sema::FAPK_VAList, Sema::FAPK_VAList):
+              case combineFAPK(Sema::FAPK_Fixed, Sema::FAPK_Fixed):
+              case combineFAPK(Sema::FAPK_Fixed, Sema::FAPK_Variadic):
+              case combineFAPK(Sema::FAPK_Variadic, Sema::FAPK_VAList):
+                return SLCT_UncheckedLiteral;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    return SLCT_NotALiteral;
+  }
+
+  case Stmt::CallExprClass:
+  case Stmt::CXXMemberCallExprClass: {
+    const CallExpr *CE = cast<CallExpr>(E);
+    if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
+      bool IsFirst = true;
+      StringLiteralCheckType CommonResult;
+      for (const auto *FA : ND->specific_attrs<FormatArgAttr>()) {
+        const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex());
+        StringLiteralCheckType Result = checkFormatStringExpr(
+            S, ReferenceFormatString, Arg, Args, APK, format_idx, firstDataArg,
+            Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg,
+            Offset, CallerFormatParamIdx, IgnoreStringsWithoutSpecifiers);
+        if (IsFirst) {
+          CommonResult = Result;
+          IsFirst = false;
+        }
+      }
+      if (!IsFirst)
+        return CommonResult;
+
+      if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
+        unsigned BuiltinID = FD->getBuiltinID();
+        if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
+            BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {
+          const Expr *Arg = CE->getArg(0);
+          return checkFormatStringExpr(
+              S, ReferenceFormatString, Arg, Args, APK, format_idx,
+              firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs,
+              UncoveredArg, Offset, CallerFormatParamIdx,
+              IgnoreStringsWithoutSpecifiers);
+        }
+      }
+    }
+    if (const Expr *SLE = maybeConstEvalStringLiteral(S.Context, E))
+      return checkFormatStringExpr(S, ReferenceFormatString, SLE, Args, APK,
+                                   format_idx, firstDataArg, Type, CallType,
+                                   /*InFunctionCall*/ false, CheckedVarArgs,
+                                   UncoveredArg, Offset, CallerFormatParamIdx,
+                                   IgnoreStringsWithoutSpecifiers);
+    return SLCT_NotALiteral;
+  }
+  case Stmt::ObjCMessageExprClass: {
+    const auto *ME = cast<ObjCMessageExpr>(E);
+    if (const auto *MD = ME->getMethodDecl()) {
+      if (const auto *FA = MD->getAttr<FormatArgAttr>()) {
+        // As a special case heuristic, if we're using the method -[NSBundle
+        // localizedStringForKey:value:table:], ignore any key strings that lack
+        // format specifiers. The idea is that if the key doesn't have any
+        // format specifiers then its probably just a key to map to the
+        // localized strings. If it does have format specifiers though, then its
+        // likely that the text of the key is the format string in the
+        // programmer's language, and should be checked.
+        const ObjCInterfaceDecl *IFace;
+        if (MD->isInstanceMethod() && (IFace = MD->getClassInterface()) &&
+            IFace->getIdentifier()->isStr("NSBundle") &&
+            MD->getSelector().isKeywordSelector(
+                {"localizedStringForKey", "value", "table"})) {
+          IgnoreStringsWithoutSpecifiers = true;
+        }
+
+        const Expr *Arg = ME->getArg(FA->getFormatIdx().getASTIndex());
+        return checkFormatStringExpr(
+            S, ReferenceFormatString, Arg, Args, APK, format_idx, firstDataArg,
+            Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg,
+            Offset, CallerFormatParamIdx, IgnoreStringsWithoutSpecifiers);
+      }
+    }
+
+    return SLCT_NotALiteral;
+  }
+  case Stmt::ObjCStringLiteralClass:
+  case Stmt::StringLiteralClass: {
+    const StringLiteral *StrE = nullptr;
+
+    if (const ObjCStringLiteral *ObjCFExpr = dyn_cast<ObjCStringLiteral>(E))
+      StrE = ObjCFExpr->getString();
+    else
+      StrE = cast<StringLiteral>(E);
+
+    if (StrE) {
+      if (Offset.isNegative() || Offset > StrE->getLength()) {
+        // TODO: It would be better to have an explicit warning for out of
+        // bounds literals.
+        return SLCT_NotALiteral;
+      }
+      FormatStringLiteral FStr(StrE, Offset.sextOrTrunc(64).getSExtValue());
+      CheckFormatString(S, &FStr, ReferenceFormatString, E, Args, APK,
+                        format_idx, firstDataArg, Type, InFunctionCall,
+                        CallType, CheckedVarArgs, UncoveredArg,
+                        IgnoreStringsWithoutSpecifiers);
+      return SLCT_CheckedLiteral;
+    }
+
+    return SLCT_NotALiteral;
+  }
+  case Stmt::BinaryOperatorClass: {
+    const BinaryOperator *BinOp = cast<BinaryOperator>(E);
+
+    // A string literal + an int offset is still a string literal.
+    if (BinOp->isAdditiveOp()) {
+      Expr::EvalResult LResult, RResult;
+
+      bool LIsInt = BinOp->getLHS()->EvaluateAsInt(
+          LResult, S.Context, Expr::SE_NoSideEffects,
+          S.isConstantEvaluatedContext());
+      bool RIsInt = BinOp->getRHS()->EvaluateAsInt(
+          RResult, S.Context, Expr::SE_NoSideEffects,
+          S.isConstantEvaluatedContext());
+
+      if (LIsInt != RIsInt) {
+        BinaryOperatorKind BinOpKind = BinOp->getOpcode();
+
+        if (LIsInt) {
+          if (BinOpKind == BO_Add) {
+            sumOffsets(Offset, LResult.Val.getInt(), BinOpKind, RIsInt);
+            E = BinOp->getRHS();
+            goto tryAgain;
+          }
+        } else {
+          sumOffsets(Offset, RResult.Val.getInt(), BinOpKind, RIsInt);
+          E = BinOp->getLHS();
+          goto tryAgain;
+        }
+      }
+    }
+
+    return SLCT_NotALiteral;
+  }
+  case Stmt::UnaryOperatorClass: {
+    const UnaryOperator *UnaOp = cast<UnaryOperator>(E);
+    auto ASE = dyn_cast<ArraySubscriptExpr>(UnaOp->getSubExpr());
+    if (UnaOp->getOpcode() == UO_AddrOf && ASE) {
+      Expr::EvalResult IndexResult;
+      if (ASE->getRHS()->EvaluateAsInt(IndexResult, S.Context,
+                                       Expr::SE_NoSideEffects,
+                                       S.isConstantEvaluatedContext())) {
+        sumOffsets(Offset, IndexResult.Val.getInt(), BO_Add,
+                   /*RHS is int*/ true);
+        E = ASE->getBase();
+        goto tryAgain;
+      }
+    }
+
+    return SLCT_NotALiteral;
+  }
+
+  default:
+    return SLCT_NotALiteral;
+  }
+}
+
+// If this expression can be evaluated at compile-time,
+// check if the result is a StringLiteral and return it
+// otherwise return nullptr
+static const Expr *maybeConstEvalStringLiteral(ASTContext &Context,
+                                               const Expr *E) {
+  Expr::EvalResult Result;
+  if (E->EvaluateAsRValue(Result, Context) && Result.Val.isLValue()) {
+    const auto *LVE = Result.Val.getLValueBase().dyn_cast<const Expr *>();
+    if (isa_and_nonnull<StringLiteral>(LVE))
+      return LVE;
+  }
+  return nullptr;
+}
+
+StringRef Sema::GetFormatStringTypeName(FormatStringType FST) {
+  switch (FST) {
+  case FormatStringType::Scanf:
+    return "scanf";
+  case FormatStringType::Printf:
+    return "printf";
+  case FormatStringType::NSString:
+    return "NSString";
+  case FormatStringType::Strftime:
+    return "strftime";
+  case FormatStringType::Strfmon:
+    return "strfmon";
+  case FormatStringType::Kprintf:
+    return "kprintf";
+  case FormatStringType::FreeBSDKPrintf:
+    return "freebsd_kprintf";
+  case FormatStringType::OSLog:
+    return "os_log";
+  default:
+    return "<unknown>";
+  }
+}
+
+FormatStringType Sema::GetFormatStringType(StringRef Flavor) {
+  return llvm::StringSwitch<FormatStringType>(Flavor)
+      .Cases({"gnu_scanf", "scanf"}, FormatStringType::Scanf)
+      .Cases({"gnu_printf", "printf", "printf0", "syslog"},
+             FormatStringType::Printf)
+      .Cases({"NSString", "CFString"}, FormatStringType::NSString)
+      .Cases({"gnu_strftime", "strftime"}, FormatStringType::Strftime)
+      .Cases({"gnu_strfmon", "strfmon"}, FormatStringType::Strfmon)
+      .Cases({"kprintf", "cmn_err", "vcmn_err", "zcmn_err"},
+             FormatStringType::Kprintf)
+      .Case("freebsd_kprintf", FormatStringType::FreeBSDKPrintf)
+      .Case("os_trace", FormatStringType::OSLog)
+      .Case("os_log", FormatStringType::OSLog)
+      .Default(FormatStringType::Unknown);
+}
+
+FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) {
+  return GetFormatStringType(Format->getType()->getName());
+}
+
+FormatStringType Sema::GetFormatStringType(const FormatMatchesAttr *Format) {
+  return GetFormatStringType(Format->getType()->getName());
+}
+
+bool Sema::CheckFormatArguments(const FormatAttr *Format,
+                                ArrayRef<const Expr *> Args, bool IsCXXMember,
+                                VariadicCallType CallType, SourceLocation Loc,
+                                SourceRange Range,
+                                llvm::SmallBitVector &CheckedVarArgs) {
+  FormatStringInfo FSI;
+  if (getFormatStringInfo(Format->getFormatIdx(), Format->getFirstArg(),
+                          IsCXXMember,
+                          CallType != VariadicCallType::DoesNotApply, &FSI))
+    return CheckFormatArguments(
+        Args, FSI.ArgPassingKind, nullptr, FSI.FormatIdx, FSI.FirstDataArg,
+        GetFormatStringType(Format), CallType, Loc, Range, CheckedVarArgs);
+  return false;
+}
+
+bool Sema::CheckFormatString(const FormatMatchesAttr *Format,
+                             ArrayRef<const Expr *> Args, bool IsCXXMember,
+                             VariadicCallType CallType, SourceLocation Loc,
+                             SourceRange Range,
+                             llvm::SmallBitVector &CheckedVarArgs) {
+  FormatStringInfo FSI;
+  if (getFormatStringInfo(Format->getFormatIdx(), 0, IsCXXMember, false,
+                          &FSI)) {
+    FSI.ArgPassingKind = Sema::FAPK_Elsewhere;
+    return CheckFormatArguments(Args, FSI.ArgPassingKind,
+                                Format->getFormatString(), FSI.FormatIdx,
+                                FSI.FirstDataArg, GetFormatStringType(Format),
+                                CallType, Loc, Range, CheckedVarArgs);
+  }
+  return false;
+}
+
+static bool CheckMissingFormatAttribute(
+    Sema *S, ArrayRef<const Expr *> Args, Sema::FormatArgumentPassingKind APK,
+    StringLiteral *ReferenceFormatString, unsigned FormatIdx,
+    unsigned FirstDataArg, FormatStringType FormatType, unsigned CallerParamIdx,
+    SourceLocation Loc) {
+  if (S->getDiagnostics().isIgnored(diag::warn_missing_format_attribute, Loc))
+    return false;
+
+  DeclContext *DC = S->CurContext;
+  if (!isa<ObjCMethodDecl>(DC) && !isa<FunctionDecl>(DC) && !isa<BlockDecl>(DC))
+    return false;
+  Decl *Caller = cast<Decl>(DC)->getCanonicalDecl();
+
+  unsigned NumCallerParams = getFunctionOrMethodNumParams(Caller);
+
+  // Find the offset to convert between attribute and parameter indexes.
+  unsigned CallerArgumentIndexOffset =
+      hasImplicitObjectParameter(Caller) ? 2 : 1;
+
+  unsigned FirstArgumentIndex = -1;
+  switch (APK) {
+  case Sema::FormatArgumentPassingKind::FAPK_Fixed:
+  case Sema::FormatArgumentPassingKind::FAPK_Variadic: {
+    // As an extension, clang allows the format attribute on non-variadic
+    // functions.
+    // Caller must have fixed arguments to pass them to a fixed or variadic
+    // function. Try to match caller and callee arguments. If successful, then
+    // emit a diag with the caller idx, otherwise we can't determine the callee
+    // arguments.
+    unsigned NumCalleeArgs = Args.size() - FirstDataArg;
+    if (NumCalleeArgs == 0 || NumCallerParams < NumCalleeArgs) {
+      // There aren't enough arguments in the caller to pass to callee.
+      return false;
+    }
+    for (unsigned CalleeIdx = Args.size() - 1, CallerIdx = NumCallerParams - 1;
+         CalleeIdx >= FirstDataArg; --CalleeIdx, --CallerIdx) {
+      const auto *Arg =
+          dyn_cast<DeclRefExpr>(Args[CalleeIdx]->IgnoreParenCasts());
+      if (!Arg)
+        return false;
+      const auto *Param = dyn_cast<ParmVarDecl>(Arg->getDecl());
+      if (!Param || Param->getFunctionScopeIndex() != CallerIdx)
+        return false;
+    }
+    FirstArgumentIndex =
+        NumCallerParams + CallerArgumentIndexOffset - NumCalleeArgs;
+    break;
+  }
+  case Sema::FormatArgumentPassingKind::FAPK_VAList:
+    // Caller arguments are either variadic or a va_list.
+    FirstArgumentIndex = isFunctionOrMethodVariadic(Caller)
+                             ? (NumCallerParams + CallerArgumentIndexOffset)
+                             : 0;
+    break;
+  case Sema::FormatArgumentPassingKind::FAPK_Elsewhere:
+    // The callee has a format_matches attribute. We will emit that instead.
+    if (!ReferenceFormatString)
+      return false;
+    break;
+  }
+
+  // Emit the diagnostic and fixit.
+  unsigned FormatStringIndex = CallerParamIdx + CallerArgumentIndexOffset;
+  StringRef FormatTypeName = S->GetFormatStringTypeName(FormatType);
+  NamedDecl *ND = dyn_cast<NamedDecl>(Caller);
+  do {
+    std::string Attr, Fixit;
+    llvm::raw_string_ostream AttrOS(Attr);
+    if (APK != Sema::FormatArgumentPassingKind::FAPK_Elsewhere) {
+      AttrOS << "format(" << FormatTypeName << ", " << FormatStringIndex << ", "
+             << FirstArgumentIndex << ")";
+    } else {
+      AttrOS << "format_matches(" << FormatTypeName << ", " << FormatStringIndex
+             << ", \"";
+      AttrOS.write_escaped(ReferenceFormatString->getString());
+      AttrOS << "\")";
+    }
+    AttrOS.flush();
+    auto DB = S->Diag(Loc, diag::warn_missing_format_attribute) << Attr;
+    if (ND)
+      DB << ND;
+    else
+      DB << "block";
+
+    // Blocks don't provide a correct end loc, so skip emitting a fixit.
+    if (isa<BlockDecl>(Caller))
+      break;
+
+    SourceLocation SL;
+    llvm::raw_string_ostream IS(Fixit);
+    // The attribute goes at the start of the declaration in C/C++ functions
+    // and methods, but after the declaration for Objective-C methods.
+    if (isa<ObjCMethodDecl>(Caller)) {
+      IS << ' ';
+      SL = Caller->getEndLoc();
+    }
+    const LangOptions &LO = S->getLangOpts();
+    if (LO.C23 || LO.CPlusPlus11)
+      IS << "[[gnu::" << Attr << "]]";
+    else if (LO.ObjC || LO.GNUMode)
+      IS << "__attribute__((" << Attr << "))";
+    else
+      break;
+    if (!isa<ObjCMethodDecl>(Caller)) {
+      IS << ' ';
+      SL = Caller->getBeginLoc();
+    }
+    IS.flush();
+
+    DB << FixItHint::CreateInsertion(SL, Fixit);
+  } while (false);
+
+  // Add implicit format or format_matches attribute.
+  if (APK != Sema::FormatArgumentPassingKind::FAPK_Elsewhere) {
+    Caller->addAttr(FormatAttr::CreateImplicit(
+        S->getASTContext(), &S->getASTContext().Idents.get(FormatTypeName),
+        FormatStringIndex, FirstArgumentIndex));
+  } else {
+    Caller->addAttr(FormatMatchesAttr::CreateImplicit(
+        S->getASTContext(), &S->getASTContext().Idents.get(FormatTypeName),
+        FormatStringIndex, ReferenceFormatString));
+  }
+
+  {
+    auto DB = S->Diag(Caller->getLocation(), diag::note_entity_declared_at);
+    if (ND)
+      DB << ND;
+    else
+      DB << "block";
+  }
+  return true;
+}
+
+bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
+                                Sema::FormatArgumentPassingKind APK,
+                                StringLiteral *ReferenceFormatString,
+                                unsigned format_idx, unsigned firstDataArg,
+                                FormatStringType Type,
+                                VariadicCallType CallType, SourceLocation Loc,
+                                SourceRange Range,
+                                llvm::SmallBitVector &CheckedVarArgs) {
+  // CHECK: printf/scanf-like function is called with no format string.
+  if (format_idx >= Args.size()) {
+    Diag(Loc, diag::warn_missing_format_string) << Range;
+    return false;
+  }
+
+  const Expr *OrigFormatExpr = Args[format_idx]->IgnoreParenCasts();
+
+  // CHECK: format string is not a string literal.
+  //
+  // Dynamically generated format strings are difficult to
+  // automatically vet at compile time.  Requiring that format strings
+  // are string literals: (1) permits the checking of format strings by
+  // the compiler and thereby (2) can practically remove the source of
+  // many format string exploits.
+
+  // Format string can be either ObjC string (e.g. @"%d") or
+  // C string (e.g. "%d")
+  // ObjC string uses the same format specifiers as C string, so we can use
+  // the same format string checking logic for both ObjC and C strings.
+  UncoveredArgHandler UncoveredArg;
+  std::optional<unsigned> CallerParamIdx;
+  StringLiteralCheckType CT = checkFormatStringExpr(
+      *this, ReferenceFormatString, OrigFormatExpr, Args, APK, format_idx,
+      firstDataArg, Type, CallType,
+      /*IsFunctionCall*/ true, CheckedVarArgs, UncoveredArg,
+      /*no string offset*/ llvm::APSInt(64, false) = 0, &CallerParamIdx);
+
+  // Generate a diagnostic where an uncovered argument is detected.
+  if (UncoveredArg.hasUncoveredArg()) {
+    unsigned ArgIdx = UncoveredArg.getUncoveredArg() + firstDataArg;
+    assert(ArgIdx < Args.size() && "ArgIdx outside bounds");
+    UncoveredArg.Diagnose(*this, /*IsFunctionCall*/true, Args[ArgIdx]);
+  }
+
+  if (CT != SLCT_NotALiteral)
+    // Literal format string found, check done!
+    return CT == SLCT_CheckedLiteral;
+
+  // Do not emit diag when the string param is a macro expansion and the
+  // format is either NSString or CFString. This is a hack to prevent
+  // diag when using the NSLocalizedString and CFCopyLocalizedString macros
+  // which are usually used in place of NS and CF string literals.
+  SourceLocation FormatLoc = Args[format_idx]->getBeginLoc();
+  if (Type == FormatStringType::NSString &&
+      SourceMgr.isInSystemMacro(FormatLoc))
+    return false;
+
+  if (CallerParamIdx && CheckMissingFormatAttribute(
+                            this, Args, APK, ReferenceFormatString, format_idx,
+                            firstDataArg, Type, *CallerParamIdx, Loc))
+    return false;
+
+  // Strftime is particular as it always uses a single 'time' argument,
+  // so it is safe to pass a non-literal string.
+  if (Type == FormatStringType::Strftime)
+    return false;
+
+  // If there are no arguments specified, warn with -Wformat-security, otherwise
+  // warn only with -Wformat-nonliteral.
+  if (Args.size() == firstDataArg) {
+    Diag(FormatLoc, diag::warn_format_nonliteral_noargs)
+      << OrigFormatExpr->getSourceRange();
+    switch (Type) {
+    default:
+      break;
+    case FormatStringType::Kprintf:
+    case FormatStringType::FreeBSDKPrintf:
+    case FormatStringType::Printf:
+      Diag(FormatLoc, diag::note_format_security_fixit)
+        << FixItHint::CreateInsertion(FormatLoc, "\"%s\", ");
+      break;
+    case FormatStringType::NSString:
+      Diag(FormatLoc, diag::note_format_security_fixit)
+        << FixItHint::CreateInsertion(FormatLoc, "@\"%@\", ");
+      break;
+    }
+  } else {
+    Diag(FormatLoc, diag::warn_format_nonliteral)
+      << OrigFormatExpr->getSourceRange();
+  }
+  return false;
+}
+
+namespace {
+
+class CheckFormatHandler : public analyze_format_string::FormatStringHandler {
+protected:
+  Sema &S;
+  const FormatStringLiteral *FExpr;
+  const Expr *OrigFormatExpr;
+  const FormatStringType FSType;
+  const unsigned FirstDataArg;
+  const unsigned NumDataArgs;
+  const char *Beg; // Start of format string.
+  const Sema::FormatArgumentPassingKind ArgPassingKind;
+  ArrayRef<const Expr *> Args;
+  unsigned FormatIdx;
+  llvm::SmallBitVector CoveredArgs;
+  bool usesPositionalArgs = false;
+  bool atFirstArg = true;
+  bool inFunctionCall;
+  VariadicCallType CallType;
+  llvm::SmallBitVector &CheckedVarArgs;
+  UncoveredArgHandler &UncoveredArg;
+
+public:
+  CheckFormatHandler(Sema &s, const FormatStringLiteral *fexpr,
+                     const Expr *origFormatExpr, const FormatStringType type,
+                     unsigned firstDataArg, unsigned numDataArgs,
+                     const char *beg, Sema::FormatArgumentPassingKind APK,
+                     ArrayRef<const Expr *> Args, unsigned formatIdx,
+                     bool inFunctionCall, VariadicCallType callType,
+                     llvm::SmallBitVector &CheckedVarArgs,
+                     UncoveredArgHandler &UncoveredArg)
+      : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), FSType(type),
+        FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), Beg(beg),
+        ArgPassingKind(APK), Args(Args), FormatIdx(formatIdx),
+        inFunctionCall(inFunctionCall), CallType(callType),
+        CheckedVarArgs(CheckedVarArgs), UncoveredArg(UncoveredArg) {
+    CoveredArgs.resize(numDataArgs);
+    CoveredArgs.reset();
+  }
+
+  bool HasFormatArguments() const {
+    return ArgPassingKind == Sema::FAPK_Fixed ||
+           ArgPassingKind == Sema::FAPK_Variadic;
+  }
+
+  void DoneProcessing();
+
+  void HandleIncompleteSpecifier(const char *startSpecifier,
+                                 unsigned specifierLen) override;
+
+  void HandleInvalidLengthModifier(
+                           const analyze_format_string::FormatSpecifier &FS,
+                           const analyze_format_string::ConversionSpecifier &CS,
+                           const char *startSpecifier, unsigned specifierLen,
+                           unsigned DiagID);
+
+  void HandleNonStandardLengthModifier(
+                    const analyze_format_string::FormatSpecifier &FS,
+                    const char *startSpecifier, unsigned specifierLen);
+
+  void HandleNonStandardConversionSpecifier(
+                    const analyze_format_string::ConversionSpecifier &CS,
+                    const char *startSpecifier, unsigned specifierLen);
+
+  void HandlePosition(const char *startPos, unsigned posLen) override;
+
+  void HandleInvalidPosition(const char *startSpecifier,
+                             unsigned specifierLen,
+                             analyze_format_string::PositionContext p) override;
+
+  void HandleZeroPosition(const char *startPos, unsigned posLen) override;
+
+  void HandleNullChar(const char *nullCharacter) override;
+
+  template <typename Range>
+  static void
+  EmitFormatDiagnostic(Sema &S, bool inFunctionCall, const Expr *ArgumentExpr,
+                       const PartialDiagnostic &PDiag, SourceLocation StringLoc,
+                       bool IsStringLocation, Range StringRange,
+                       ArrayRef<FixItHint> Fixit = {});
+
+protected:
+  bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc,
+                                        const char *startSpec,
+                                        unsigned specifierLen,
+                                        const char *csStart, unsigned csLen);
+
+  void HandlePositionalNonpositionalArgs(SourceLocation Loc,
+                                         const char *startSpec,
+                                         unsigned specifierLen);
+
+  SourceRange getFormatStringRange();
+  CharSourceRange getSpecifierRange(const char *startSpecifier,
+                                    unsigned specifierLen);
+  SourceLocation getLocationOfByte(const char *x);
+
+  const Expr *getDataArg(unsigned i) const;
+
+  bool CheckNumArgs(const analyze_format_string::FormatSpecifier &FS,
+                    const analyze_format_string::ConversionSpecifier &CS,
+                    const char *startSpecifier, unsigned specifierLen,
+                    unsigned argIndex);
+
+  template <typename Range>
+  void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc,
+                            bool IsStringLocation, Range StringRange,
+                            ArrayRef<FixItHint> Fixit = {});
+};
+
+} // namespace
+
+SourceRange CheckFormatHandler::getFormatStringRange() {
+  return OrigFormatExpr->getSourceRange();
+}
+
+CharSourceRange CheckFormatHandler::
+getSpecifierRange(const char *startSpecifier, unsigned specifierLen) {
+  SourceLocation Start = getLocationOfByte(startSpecifier);
+  SourceLocation End   = getLocationOfByte(startSpecifier + specifierLen - 1);
+
+  // Advance the end SourceLocation by one due to half-open ranges.
+  End = End.getLocWithOffset(1);
+
+  return CharSourceRange::getCharRange(Start, End);
+}
+
+SourceLocation CheckFormatHandler::getLocationOfByte(const char *x) {
+  return FExpr->getLocationOfByte(x - Beg, S.getSourceManager(),
+                                  S.getLangOpts(), S.Context.getTargetInfo());
+}
+
+void CheckFormatHandler::HandleIncompleteSpecifier(const char *startSpecifier,
+                                                   unsigned specifierLen){
+  EmitFormatDiagnostic(S.PDiag(diag::warn_printf_incomplete_specifier),
+                       getLocationOfByte(startSpecifier),
+                       /*IsStringLocation*/true,
+                       getSpecifierRange(startSpecifier, specifierLen));
+}
+
+void CheckFormatHandler::HandleInvalidLengthModifier(
+    const analyze_format_string::FormatSpecifier &FS,
+    const analyze_format_string::ConversionSpecifier &CS,
+    const char *startSpecifier, unsigned specifierLen, unsigned DiagID) {
+  using namespace analyze_format_string;
+
+  const LengthModifier &LM = FS.getLengthModifier();
+  CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength());
+
+  // See if we know how to fix this length modifier.
+  std::optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
+  if (FixedLM) {
+    EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(),
+                         getLocationOfByte(LM.getStart()),
+                         /*IsStringLocation*/true,
+                         getSpecifierRange(startSpecifier, specifierLen));
+
+    S.Diag(getLocationOfByte(LM.getStart()), diag::note_format_fix_specifier)
+      << FixedLM->toString()
+      << FixItHint::CreateReplacement(LMRange, FixedLM->toString());
+
+  } else {
+    FixItHint Hint;
+    if (DiagID == diag::warn_format_nonsensical_length)
+      Hint = FixItHint::CreateRemoval(LMRange);
+
+    EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(),
+                         getLocationOfByte(LM.getStart()),
+                         /*IsStringLocation*/true,
+                         getSpecifierRange(startSpecifier, specifierLen),
+                         Hint);
+  }
+}
+
+void CheckFormatHandler::HandleNonStandardLengthModifier(
+    const analyze_format_string::FormatSpecifier &FS,
+    const char *startSpecifier, unsigned specifierLen) {
+  using namespace analyze_format_string;
+
+  const LengthModifier &LM = FS.getLengthModifier();
+  CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength());
+
+  // See if we know how to fix this length modifier.
+  std::optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier();
+  if (FixedLM) {
+    EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
+                           << LM.toString() << 0,
+                         getLocationOfByte(LM.getStart()),
+                         /*IsStringLocation*/true,
+                         getSpecifierRange(startSpecifier, specifierLen));
+
+    S.Diag(getLocationOfByte(LM.getStart()), diag::note_format_fix_specifier)
+      << FixedLM->toString()
+      << FixItHint::CreateReplacement(LMRange, FixedLM->toString());
+
+  } else {
+    EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
+                           << LM.toString() << 0,
+                         getLocationOfByte(LM.getStart()),
+                         /*IsStringLocation*/true,
+                         getSpecifierRange(startSpecifier, specifierLen));
+  }
+}
+
+void CheckFormatHandler::HandleNonStandardConversionSpecifier(
+    const analyze_format_string::ConversionSpecifier &CS,
+    const char *startSpecifier, unsigned specifierLen) {
+  using namespace analyze_format_string;
+
+  // See if we know how to fix this conversion specifier.
+  std::optional<ConversionSpecifier> FixedCS = CS.getStandardSpecifier();
+  if (FixedCS) {
+    EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
+                          << CS.toString() << /*conversion specifier*/1,
+                         getLocationOfByte(CS.getStart()),
+                         /*IsStringLocation*/true,
+                         getSpecifierRange(startSpecifier, specifierLen));
+
+    CharSourceRange CSRange = getSpecifierRange(CS.getStart(), CS.getLength());
+    S.Diag(getLocationOfByte(CS.getStart()), diag::note_format_fix_specifier)
+      << FixedCS->toString()
+      << FixItHint::CreateReplacement(CSRange, FixedCS->toString());
+  } else {
+    EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard)
+                          << CS.toString() << /*conversion specifier*/1,
+                         getLocationOfByte(CS.getStart()),
+                         /*IsStringLocation*/true,
+                         getSpecifierRange(startSpecifier, specifierLen));
+  }
+}
+
+void CheckFormatHandler::HandlePosition(const char *startPos,
+                                        unsigned posLen) {
+  if (!S.getDiagnostics().isIgnored(
+          diag::warn_format_non_standard_positional_arg, SourceLocation()))
+    EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard_positional_arg),
+                         getLocationOfByte(startPos),
+                         /*IsStringLocation*/ true,
+                         getSpecifierRange(startPos, posLen));
+}
+
+void CheckFormatHandler::HandleInvalidPosition(
+    const char *startSpecifier, unsigned specifierLen,
+    analyze_format_string::PositionContext p) {
+  if (!S.getDiagnostics().isIgnored(
+          diag::warn_format_invalid_positional_specifier, SourceLocation()))
+    EmitFormatDiagnostic(
+        S.PDiag(diag::warn_format_invalid_positional_specifier) << (unsigned)p,
+        getLocationOfByte(startSpecifier), /*IsStringLocation*/ true,
+        getSpecifierRange(startSpecifier, specifierLen));
+}
+
+void CheckFormatHandler::HandleZeroPosition(const char *startPos,
+                                            unsigned posLen) {
+  if (!S.getDiagnostics().isIgnored(diag::warn_format_zero_positional_specifier,
+                                    SourceLocation()))
+    EmitFormatDiagnostic(S.PDiag(diag::warn_format_zero_positional_specifier),
+                         getLocationOfByte(startPos),
+                         /*IsStringLocation*/ true,
+                         getSpecifierRange(startPos, posLen));
+}
+
+void CheckFormatHandler::HandleNullChar(const char *nullCharacter) {
+  if (!isa<ObjCStringLiteral>(OrigFormatExpr)) {
+    // The presence of a null character is likely an error.
+    EmitFormatDiagnostic(
+      S.PDiag(diag::warn_printf_format_string_contains_null_char),
+      getLocationOfByte(nullCharacter), /*IsStringLocation*/true,
+      getFormatStringRange());
+  }
+}
+
+// Note that this may return NULL if there was an error parsing or building
+// one of the argument expressions.
+const Expr *CheckFormatHandler::getDataArg(unsigned i) const {
+  return Args[FirstDataArg + i];
+}
+
+void CheckFormatHandler::DoneProcessing() {
+  // Does the number of data arguments exceed the number of
+  // format conversions in the format string?
+  if (HasFormatArguments()) {
+    // Find any arguments that weren't covered.
+    CoveredArgs.flip();
+    signed notCoveredArg = CoveredArgs.find_first();
+    if (notCoveredArg >= 0) {
+      assert((unsigned)notCoveredArg < NumDataArgs);
+      UncoveredArg.Update(notCoveredArg, OrigFormatExpr);
+    } else {
+      UncoveredArg.setAllCovered();
+    }
+  }
+}
+
+void UncoveredArgHandler::Diagnose(Sema &S, bool IsFunctionCall,
+                                   const Expr *ArgExpr) {
+  assert(hasUncoveredArg() && !DiagnosticExprs.empty() &&
+         "Invalid state");
+
+  if (!ArgExpr)
+    return;
+
+  SourceLocation Loc = ArgExpr->getBeginLoc();
+
+  if (S.getSourceManager().isInSystemMacro(Loc))
+    return;
+
+  PartialDiagnostic PDiag = S.PDiag(diag::warn_printf_data_arg_not_used);
+  for (auto E : DiagnosticExprs)
+    PDiag << E->getSourceRange();
+
+  CheckFormatHandler::EmitFormatDiagnostic(
+                                  S, IsFunctionCall, DiagnosticExprs[0],
+                                  PDiag, Loc, /*IsStringLocation*/false,
+                                  DiagnosticExprs[0]->getSourceRange());
+}
+
+bool
+CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex,
+                                                     SourceLocation Loc,
+                                                     const char *startSpec,
+                                                     unsigned specifierLen,
+                                                     const char *csStart,
+                                                     unsigned csLen) {
+  bool keepGoing = true;
+  if (argIndex < NumDataArgs) {
+    // Consider the argument coverered, even though the specifier doesn't
+    // make sense.
+    CoveredArgs.set(argIndex);
+  }
+  else {
+    // If argIndex exceeds the number of data arguments we
+    // don't issue a warning because that is just a cascade of warnings (and
+    // they may have intended '%%' anyway). We don't want to continue processing
+    // the format string after this point, however, as we will like just get
+    // gibberish when trying to match arguments.
+    keepGoing = false;
+  }
+
+  StringRef Specifier(csStart, csLen);
+
+  // If the specifier in non-printable, it could be the first byte of a UTF-8
+  // sequence. In that case, print the UTF-8 code point. If not, print the byte
+  // hex value.
+  std::string CodePointStr;
+  if (!llvm::sys::locale::isPrint(*csStart)) {
+    llvm::UTF32 CodePoint;
+    const llvm::UTF8 **B = reinterpret_cast<const llvm::UTF8 **>(&csStart);
+    const llvm::UTF8 *E =
+        reinterpret_cast<const llvm::UTF8 *>(csStart + csLen);
+    llvm::ConversionResult Result =
+        llvm::convertUTF8Sequence(B, E, &CodePoint, llvm::strictConversion);
+
+    if (Result != llvm::conversionOK) {
+      unsigned char FirstChar = *csStart;
+      CodePoint = (llvm::UTF32)FirstChar;
+    }
+
+    llvm::raw_string_ostream OS(CodePointStr);
+    if (CodePoint < 256)
+      OS << "\\x" << llvm::format("%02x", CodePoint);
+    else if (CodePoint <= 0xFFFF)
+      OS << "\\u" << llvm::format("%04x", CodePoint);
+    else
+      OS << "\\U" << llvm::format("%08x", CodePoint);
+    Specifier = CodePointStr;
+  }
+
+  EmitFormatDiagnostic(
+      S.PDiag(diag::warn_format_invalid_conversion) << Specifier, Loc,
+      /*IsStringLocation*/ true, getSpecifierRange(startSpec, specifierLen));
+
+  return keepGoing;
+}
+
+void
+CheckFormatHandler::HandlePositionalNonpositionalArgs(SourceLocation Loc,
+                                                      const char *startSpec,
+                                                      unsigned specifierLen) {
+  EmitFormatDiagnostic(
+    S.PDiag(diag::warn_format_mix_positional_nonpositional_args),
+    Loc, /*isStringLoc*/true, getSpecifierRange(startSpec, specifierLen));
+}
+
+bool
+CheckFormatHandler::CheckNumArgs(
+  const analyze_format_string::FormatSpecifier &FS,
+  const analyze_format_string::ConversionSpecifier &CS,
+  const char *startSpecifier, unsigned specifierLen, unsigned argIndex) {
+
+  if (HasFormatArguments() && argIndex >= NumDataArgs) {
+    PartialDiagnostic PDiag = FS.usesPositionalArg()
+      ? (S.PDiag(diag::warn_printf_positional_arg_exceeds_data_args)
+           << (argIndex+1) << NumDataArgs)
+      : S.PDiag(diag::warn_printf_insufficient_data_args);
+    EmitFormatDiagnostic(
+      PDiag, getLocationOfByte(CS.getStart()), /*IsStringLocation*/true,
+      getSpecifierRange(startSpecifier, specifierLen));
+
+    // Since more arguments than conversion tokens are given, by extension
+    // all arguments are covered, so mark this as so.
+    UncoveredArg.setAllCovered();
+    return false;
+  }
+  return true;
+}
+
+template<typename Range>
+void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag,
+                                              SourceLocation Loc,
+                                              bool IsStringLocation,
+                                              Range StringRange,
+                                              ArrayRef<FixItHint> FixIt) {
+  EmitFormatDiagnostic(S, inFunctionCall, Args[FormatIdx], PDiag,
+                       Loc, IsStringLocation, StringRange, FixIt);
+}
+
+/// If the format string is not within the function call, emit a note
+/// so that the function call and string are in diagnostic messages.
+///
+/// \param InFunctionCall if true, the format string is within the function
+/// call and only one diagnostic message will be produced.  Otherwise, an
+/// extra note will be emitted pointing to location of the format string.
+///
+/// \param ArgumentExpr the expression that is passed as the format string
+/// argument in the function call.  Used for getting locations when two
+/// diagnostics are emitted.
+///
+/// \param PDiag the callee should already have provided any strings for the
+/// diagnostic message.  This function only adds locations and fixits
+/// to diagnostics.
+///
+/// \param Loc primary location for diagnostic.  If two diagnostics are
+/// required, one will be at Loc and a new SourceLocation will be created for
+/// the other one.
+///
+/// \param IsStringLocation if true, Loc points to the format string should be
+/// used for the note.  Otherwise, Loc points to the argument list and will
+/// be used with PDiag.
+///
+/// \param StringRange some or all of the string to highlight.  This is
+/// templated so it can accept either a CharSourceRange or a SourceRange.
+///
+/// \param FixIt optional fix it hint for the format string.
+template <typename Range>
+void CheckFormatHandler::EmitFormatDiagnostic(
+    Sema &S, bool InFunctionCall, const Expr *ArgumentExpr,
+    const PartialDiagnostic &PDiag, SourceLocation Loc, bool IsStringLocation,
+    Range StringRange, ArrayRef<FixItHint> FixIt) {
+  if (InFunctionCall) {
+    const Sema::SemaDiagnosticBuilder &D = S.Diag(Loc, PDiag);
+    D << StringRange;
+    D << FixIt;
+  } else {
+    S.Diag(IsStringLocation ? ArgumentExpr->getExprLoc() : Loc, PDiag)
+      << ArgumentExpr->getSourceRange();
+
+    const Sema::SemaDiagnosticBuilder &Note =
+      S.Diag(IsStringLocation ? Loc : StringRange.getBegin(),
+             diag::note_format_string_defined);
+
+    Note << StringRange;
+    Note << FixIt;
+  }
+}
+
+//===--- CHECK: Printf format string checking -----------------------------===//
+
+namespace {
+
+class CheckPrintfHandler : public CheckFormatHandler {
+public:
+  CheckPrintfHandler(Sema &s, const FormatStringLiteral *fexpr,
+                     const Expr *origFormatExpr, const FormatStringType type,
+                     unsigned firstDataArg, unsigned numDataArgs, bool isObjC,
+                     const char *beg, Sema::FormatArgumentPassingKind APK,
+                     ArrayRef<const Expr *> Args, unsigned formatIdx,
+                     bool inFunctionCall, VariadicCallType CallType,
+                     llvm::SmallBitVector &CheckedVarArgs,
+                     UncoveredArgHandler &UncoveredArg)
+      : CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg,
+                           numDataArgs, beg, APK, Args, formatIdx,
+                           inFunctionCall, CallType, CheckedVarArgs,
+                           UncoveredArg) {}
+
+  bool isObjCContext() const { return FSType == FormatStringType::NSString; }
+
+  /// Returns true if '%@' specifiers are allowed in the format string.
+  bool allowsObjCArg() const {
+    return FSType == FormatStringType::NSString ||
+           FSType == FormatStringType::OSLog ||
+           FSType == FormatStringType::OSTrace;
+  }
+
+  bool HandleInvalidPrintfConversionSpecifier(
+                                      const analyze_printf::PrintfSpecifier &FS,
+                                      const char *startSpecifier,
+                                      unsigned specifierLen) override;
+
+  void handleInvalidMaskType(StringRef MaskType) override;
+
+  bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
+                             const char *startSpecifier, unsigned specifierLen,
+                             const TargetInfo &Target) override;
+  bool checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
+                       const char *StartSpecifier,
+                       unsigned SpecifierLen,
+                       const Expr *E);
+
+  bool HandleAmount(const analyze_format_string::OptionalAmount &Amt, unsigned k,
+                    const char *startSpecifier, unsigned specifierLen);
+  void HandleInvalidAmount(const analyze_printf::PrintfSpecifier &FS,
+                           const analyze_printf::OptionalAmount &Amt,
+                           unsigned type,
+                           const char *startSpecifier, unsigned specifierLen);
+  void HandleFlag(const analyze_printf::PrintfSpecifier &FS,
+                  const analyze_printf::OptionalFlag &flag,
+                  const char *startSpecifier, unsigned specifierLen);
+  void HandleIgnoredFlag(const analyze_printf::PrintfSpecifier &FS,
+                         const analyze_printf::OptionalFlag &ignoredFlag,
+                         const analyze_printf::OptionalFlag &flag,
+                         const char *startSpecifier, unsigned specifierLen);
+  bool checkForCStrMembers(const analyze_printf::ArgType &AT,
+                           const Expr *E);
+
+  void HandleEmptyObjCModifierFlag(const char *startFlag,
+                                   unsigned flagLen) override;
+
+  void HandleInvalidObjCModifierFlag(const char *startFlag,
+                                            unsigned flagLen) override;
+
+  void
+  HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,
+                                       const char *flagsEnd,
+                                       const char *conversionPosition) override;
+};
+
+/// Keeps around the information needed to verify that two specifiers are
+/// compatible.
+class EquatableFormatArgument {
+public:
+  enum SpecifierSensitivity : unsigned {
+    SS_None,
+    SS_Private,
+    SS_Public,
+    SS_Sensitive
+  };
+
+  enum FormatArgumentRole : unsigned {
+    FAR_Data,
+    FAR_FieldWidth,
+    FAR_Precision,
+    FAR_Auxiliary, // FreeBSD kernel %b and %D
+  };
+
+private:
+  analyze_format_string::ArgType ArgType;
+  analyze_format_string::LengthModifier::Kind LengthMod;
+  StringRef SpecifierLetter;
+  CharSourceRange Range;
+  SourceLocation ElementLoc;
+  FormatArgumentRole Role : 2;
+  SpecifierSensitivity Sensitivity : 2; // only set for FAR_Data
+  unsigned Position : 14;
+  unsigned ModifierFor : 14; // not set for FAR_Data
+
+  void EmitDiagnostic(Sema &S, PartialDiagnostic PDiag, const Expr *FmtExpr,
+                      bool InFunctionCall) const;
+
+public:
+  EquatableFormatArgument(CharSourceRange Range, SourceLocation ElementLoc,
+                          analyze_format_string::LengthModifier::Kind LengthMod,
+                          StringRef SpecifierLetter,
+                          analyze_format_string::ArgType ArgType,
+                          FormatArgumentRole Role,
+                          SpecifierSensitivity Sensitivity, unsigned Position,
+                          unsigned ModifierFor)
+      : ArgType(ArgType), LengthMod(LengthMod),
+        SpecifierLetter(SpecifierLetter), Range(Range), ElementLoc(ElementLoc),
+        Role(Role), Sensitivity(Sensitivity), Position(Position),
+        ModifierFor(ModifierFor) {}
+
+  unsigned getPosition() const { return Position; }
+  SourceLocation getSourceLocation() const { return ElementLoc; }
+  CharSourceRange getSourceRange() const { return Range; }
+  analyze_format_string::LengthModifier getLengthModifier() const {
+    return analyze_format_string::LengthModifier(nullptr, LengthMod);
+  }
+  void setModifierFor(unsigned V) { ModifierFor = V; }
+
+  std::string buildFormatSpecifier() const {
+    std::string result;
+    llvm::raw_string_ostream(result)
+        << getLengthModifier().toString() << SpecifierLetter;
+    return result;
+  }
+
+  bool VerifyCompatible(Sema &S, const EquatableFormatArgument &Other,
+                        const Expr *FmtExpr, bool InFunctionCall) const;
+};
+
+/// Turns format strings into lists of EquatableSpecifier objects.
+class DecomposePrintfHandler : public CheckPrintfHandler {
+  llvm::SmallVectorImpl<EquatableFormatArgument> &Specs;
+  bool HadError;
+
+  DecomposePrintfHandler(Sema &s, const FormatStringLiteral *fexpr,
+                         const Expr *origFormatExpr,
+                         const FormatStringType type, unsigned firstDataArg,
+                         unsigned numDataArgs, bool isObjC, const char *beg,
+                         Sema::FormatArgumentPassingKind APK,
+                         ArrayRef<const Expr *> Args, unsigned formatIdx,
+                         bool inFunctionCall, VariadicCallType CallType,
+                         llvm::SmallBitVector &CheckedVarArgs,
+                         UncoveredArgHandler &UncoveredArg,
+                         llvm::SmallVectorImpl<EquatableFormatArgument> &Specs)
+      : CheckPrintfHandler(s, fexpr, origFormatExpr, type, firstDataArg,
+                           numDataArgs, isObjC, beg, APK, Args, formatIdx,
+                           inFunctionCall, CallType, CheckedVarArgs,
+                           UncoveredArg),
+        Specs(Specs), HadError(false) {}
+
+public:
+  static bool
+  GetSpecifiers(Sema &S, const FormatStringLiteral *FSL, const Expr *FmtExpr,
+                FormatStringType type, bool IsObjC, bool InFunctionCall,
+                llvm::SmallVectorImpl<EquatableFormatArgument> &Args);
+
+  virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
+                                     const char *startSpecifier,
+                                     unsigned specifierLen,
+                                     const TargetInfo &Target) override;
+};
+
+} // namespace
+
+bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier(
+    const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier,
+    unsigned specifierLen) {
+  const analyze_printf::PrintfConversionSpecifier &CS =
+    FS.getConversionSpecifier();
+
+  return HandleInvalidConversionSpecifier(FS.getArgIndex(),
+                                          getLocationOfByte(CS.getStart()),
+                                          startSpecifier, specifierLen,
+                                          CS.getStart(), CS.getLength());
+}
+
+void CheckPrintfHandler::handleInvalidMaskType(StringRef MaskType) {
+  S.Diag(getLocationOfByte(MaskType.data()), diag::err_invalid_mask_type_size);
+}
+
+// Error out if struct or complex type argments are passed to os_log.
+static bool isInvalidOSLogArgTypeForCodeGen(FormatStringType FSType,
+                                            QualType T) {
+  if (FSType != FormatStringType::OSLog)
+    return false;
+  return T->isRecordType() || T->isComplexType();
+}
+
+bool CheckPrintfHandler::HandleAmount(
+    const analyze_format_string::OptionalAmount &Amt, unsigned k,
+    const char *startSpecifier, unsigned specifierLen) {
+  if (Amt.hasDataArgument()) {
+    if (HasFormatArguments()) {
+      unsigned argIndex = Amt.getArgIndex();
+      if (argIndex >= NumDataArgs) {
+        EmitFormatDiagnostic(S.PDiag(diag::warn_printf_asterisk_missing_arg)
+                                 << k,
+                             getLocationOfByte(Amt.getStart()),
+                             /*IsStringLocation*/ true,
+                             getSpecifierRange(startSpecifier, specifierLen));
+        // Don't do any more checking.  We will just emit
+        // spurious errors.
+        return false;
+      }
+
+      // Type check the data argument.  It should be an 'int'.
+      // Although not in conformance with C99, we also allow the argument to be
+      // an 'unsigned int' as that is a reasonably safe case.  GCC also
+      // doesn't emit a warning for that case.
+      CoveredArgs.set(argIndex);
+      const Expr *Arg = getDataArg(argIndex);
+      if (!Arg)
+        return false;
+
+      QualType T = Arg->getType();
+
+      const analyze_printf::ArgType &AT = Amt.getArgType(S.Context);
+      assert(AT.isValid());
+
+      if (!AT.matchesType(S.Context, T)) {
+        unsigned DiagID = isInvalidOSLogArgTypeForCodeGen(FSType, T)
+                              ? diag::err_printf_asterisk_wrong_type
+                              : diag::warn_printf_asterisk_wrong_type;
+        EmitFormatDiagnostic(S.PDiag(DiagID)
+                                 << k << AT.getRepresentativeTypeName(S.Context)
+                                 << T << Arg->getSourceRange(),
+                             getLocationOfByte(Amt.getStart()),
+                             /*IsStringLocation*/ true,
+                             getSpecifierRange(startSpecifier, specifierLen));
+        // Don't do any more checking.  We will just emit
+        // spurious errors.
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+void CheckPrintfHandler::HandleInvalidAmount(
+                                      const analyze_printf::PrintfSpecifier &FS,
+                                      const analyze_printf::OptionalAmount &Amt,
+                                      unsigned type,
+                                      const char *startSpecifier,
+                                      unsigned specifierLen) {
+  const analyze_printf::PrintfConversionSpecifier &CS =
+    FS.getConversionSpecifier();
+
+  FixItHint fixit =
+    Amt.getHowSpecified() == analyze_printf::OptionalAmount::Constant
+      ? FixItHint::CreateRemoval(getSpecifierRange(Amt.getStart(),
+                                 Amt.getConstantLength()))
+      : FixItHint();
+
+  EmitFormatDiagnostic(S.PDiag(diag::warn_printf_nonsensical_optional_amount)
+                         << type << CS.toString(),
+                       getLocationOfByte(Amt.getStart()),
+                       /*IsStringLocation*/true,
+                       getSpecifierRange(startSpecifier, specifierLen),
+                       fixit);
+}
+
+void CheckPrintfHandler::HandleFlag(const analyze_printf::PrintfSpecifier &FS,
+                                    const analyze_printf::OptionalFlag &flag,
+                                    const char *startSpecifier,
+                                    unsigned specifierLen) {
+  // Warn about pointless flag with a fixit removal.
+  const analyze_printf::PrintfConversionSpecifier &CS =
+    FS.getConversionSpecifier();
+  EmitFormatDiagnostic(S.PDiag(diag::warn_printf_nonsensical_flag)
+                         << flag.toString() << CS.toString(),
+                       getLocationOfByte(flag.getPosition()),
+                       /*IsStringLocation*/true,
+                       getSpecifierRange(startSpecifier, specifierLen),
+                       FixItHint::CreateRemoval(
+                         getSpecifierRange(flag.getPosition(), 1)));
+}
+
+void CheckPrintfHandler::HandleIgnoredFlag(
+                                const analyze_printf::PrintfSpecifier &FS,
+                                const analyze_printf::OptionalFlag &ignoredFlag,
+                                const analyze_printf::OptionalFlag &flag,
+                                const char *startSpecifier,
+                                unsigned specifierLen) {
+  // Warn about ignored flag with a fixit removal.
+  EmitFormatDiagnostic(S.PDiag(diag::warn_printf_ignored_flag)
+                         << ignoredFlag.toString() << flag.toString(),
+                       getLocationOfByte(ignoredFlag.getPosition()),
+                       /*IsStringLocation*/true,
+                       getSpecifierRange(startSpecifier, specifierLen),
+                       FixItHint::CreateRemoval(
+                         getSpecifierRange(ignoredFlag.getPosition(), 1)));
+}
+
+void CheckPrintfHandler::HandleEmptyObjCModifierFlag(const char *startFlag,
+                                                     unsigned flagLen) {
+  // Warn about an empty flag.
+  EmitFormatDiagnostic(S.PDiag(diag::warn_printf_empty_objc_flag),
+                       getLocationOfByte(startFlag),
+                       /*IsStringLocation*/true,
+                       getSpecifierRange(startFlag, flagLen));
+}
+
+void CheckPrintfHandler::HandleInvalidObjCModifierFlag(const char *startFlag,
+                                                       unsigned flagLen) {
+  // Warn about an invalid flag.
+  auto Range = getSpecifierRange(startFlag, flagLen);
+  StringRef flag(startFlag, flagLen);
+  EmitFormatDiagnostic(S.PDiag(diag::warn_printf_invalid_objc_flag) << flag,
+                      getLocationOfByte(startFlag),
+                      /*IsStringLocation*/true,
+                      Range, FixItHint::CreateRemoval(Range));
+}
+
+void CheckPrintfHandler::HandleObjCFlagsWithNonObjCConversion(
+    const char *flagsStart, const char *flagsEnd, const char *conversionPosition) {
+    // Warn about using '[...]' without a '@' conversion.
+    auto Range = getSpecifierRange(flagsStart, flagsEnd - flagsStart + 1);
+    auto diag = diag::warn_printf_ObjCflags_without_ObjCConversion;
+    EmitFormatDiagnostic(S.PDiag(diag) << StringRef(conversionPosition, 1),
+                         getLocationOfByte(conversionPosition),
+                         /*IsStringLocation*/ true, Range,
+                         FixItHint::CreateRemoval(Range));
+}
+
+void EquatableFormatArgument::EmitDiagnostic(Sema &S, PartialDiagnostic PDiag,
+                                             const Expr *FmtExpr,
+                                             bool InFunctionCall) const {
+  CheckFormatHandler::EmitFormatDiagnostic(S, InFunctionCall, FmtExpr, PDiag,
+                                           ElementLoc, true, Range);
+}
+
+bool EquatableFormatArgument::VerifyCompatible(
+    Sema &S, const EquatableFormatArgument &Other, const Expr *FmtExpr,
+    bool InFunctionCall) const {
+  using MK = analyze_format_string::ArgType::MatchKind;
+  if (Role != Other.Role) {
+    // diagnose and stop
+    EmitDiagnostic(
+        S, S.PDiag(diag::warn_format_cmp_role_mismatch) << Role << Other.Role,
+        FmtExpr, InFunctionCall);
+    S.Diag(Other.ElementLoc, diag::note_format_cmp_with) << 0 << Other.Range;
+    return false;
+  }
+
+  if (Role != FAR_Data) {
+    if (ModifierFor != Other.ModifierFor) {
+      // diagnose and stop
+      EmitDiagnostic(S,
+                     S.PDiag(diag::warn_format_cmp_modifierfor_mismatch)
+                         << (ModifierFor + 1) << (Other.ModifierFor + 1),
+                     FmtExpr, InFunctionCall);
+      S.Diag(Other.ElementLoc, diag::note_format_cmp_with) << 0 << Other.Range;
+      return false;
+    }
+    return true;
+  }
+
+  bool HadError = false;
+  if (Sensitivity != Other.Sensitivity) {
+    // diagnose and continue
+    EmitDiagnostic(S,
+                   S.PDiag(diag::warn_format_cmp_sensitivity_mismatch)
+                       << Sensitivity << Other.Sensitivity,
+                   FmtExpr, InFunctionCall);
+    HadError = S.Diag(Other.ElementLoc, diag::note_format_cmp_with)
+               << 0 << Other.Range;
+  }
+
+  switch (ArgType.matchesArgType(S.Context, Other.ArgType)) {
+  case MK::Match:
+    break;
+
+  case MK::MatchPromotion:
+    // Per consensus reached at https://discourse.llvm.org/t/-/83076/12,
+    // MatchPromotion is treated as a failure by format_matches.
+  case MK::NoMatch:
+  case MK::NoMatchTypeConfusion:
+  case MK::NoMatchPromotionTypeConfusion:
+    EmitDiagnostic(S,
+                   S.PDiag(diag::warn_format_cmp_specifier_mismatch)
+                       << buildFormatSpecifier()
+                       << Other.buildFormatSpecifier(),
+                   FmtExpr, InFunctionCall);
+    HadError = S.Diag(Other.ElementLoc, diag::note_format_cmp_with)
+               << 0 << Other.Range;
+    break;
+
+  case MK::NoMatchPedantic:
+    EmitDiagnostic(S,
+                   S.PDiag(diag::warn_format_cmp_specifier_mismatch_pedantic)
+                       << buildFormatSpecifier()
+                       << Other.buildFormatSpecifier(),
+                   FmtExpr, InFunctionCall);
+    HadError = S.Diag(Other.ElementLoc, diag::note_format_cmp_with)
+               << 0 << Other.Range;
+    break;
+
+  case MK::NoMatchSignedness:
+    EmitDiagnostic(S,
+                   S.PDiag(diag::warn_format_cmp_specifier_sign_mismatch)
+                       << buildFormatSpecifier()
+                       << Other.buildFormatSpecifier(),
+                   FmtExpr, InFunctionCall);
+    HadError = S.Diag(Other.ElementLoc, diag::note_format_cmp_with)
+               << 0 << Other.Range;
+    break;
+  }
+  return !HadError;
+}
+
+bool DecomposePrintfHandler::GetSpecifiers(
+    Sema &S, const FormatStringLiteral *FSL, const Expr *FmtExpr,
+    FormatStringType Type, bool IsObjC, bool InFunctionCall,
+    llvm::SmallVectorImpl<EquatableFormatArgument> &Args) {
+  StringRef Data = FSL->getString();
+  const char *Str = Data.data();
+  llvm::SmallBitVector BV;
+  UncoveredArgHandler UA;
+  const Expr *PrintfArgs[] = {FSL->getFormatString()};
+  DecomposePrintfHandler H(S, FSL, FSL->getFormatString(), Type, 0, 0, IsObjC,
+                           Str, Sema::FAPK_Elsewhere, PrintfArgs, 0,
+                           InFunctionCall, VariadicCallType::DoesNotApply, BV,
+                           UA, Args);
+
+  if (!analyze_format_string::ParsePrintfString(
+          H, Str, Str + Data.size(), S.getLangOpts(), S.Context.getTargetInfo(),
+          Type == FormatStringType::FreeBSDKPrintf))
+    H.DoneProcessing();
+  if (H.HadError)
+    return false;
+
+  llvm::stable_sort(Args, [](const EquatableFormatArgument &A,
+                             const EquatableFormatArgument &B) {
+    return A.getPosition() < B.getPosition();
+  });
+  return true;
+}
+
+bool DecomposePrintfHandler::HandlePrintfSpecifier(
+    const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier,
+    unsigned specifierLen, const TargetInfo &Target) {
+  if (!CheckPrintfHandler::HandlePrintfSpecifier(FS, startSpecifier,
+                                                 specifierLen, Target)) {
+    HadError = true;
+    return false;
+  }
+
+  // Do not add any specifiers to the list for %%. This is possibly incorrect
+  // if using a precision/width with a data argument, but that combination is
+  // meaningless and we wouldn't know which format to attach the
+  // precision/width to.
+  const auto &CS = FS.getConversionSpecifier();
+  if (CS.getKind() == analyze_format_string::ConversionSpecifier::PercentArg)
+    return true;
+
+  // have to patch these to have the right ModifierFor if they are used
+  const unsigned Unset = ~0;
+  unsigned FieldWidthIndex = Unset;
+  unsigned PrecisionIndex = Unset;
+
+  // field width?
+  const auto &FieldWidth = FS.getFieldWidth();
+  if (!FieldWidth.isInvalid() && FieldWidth.hasDataArgument()) {
+    FieldWidthIndex = Specs.size();
+    Specs.emplace_back(getSpecifierRange(startSpecifier, specifierLen),
+                       getLocationOfByte(FieldWidth.getStart()),
+                       analyze_format_string::LengthModifier::None, "*",
+                       FieldWidth.getArgType(S.Context),
+                       EquatableFormatArgument::FAR_FieldWidth,
+                       EquatableFormatArgument::SS_None,
+                       FieldWidth.usesPositionalArg()
+                           ? FieldWidth.getPositionalArgIndex() - 1
+                           : FieldWidthIndex,
+                       0);
+  }
+  // precision?
+  const auto &Precision = FS.getPrecision();
+  if (!Precision.isInvalid() && Precision.hasDataArgument()) {
+    PrecisionIndex = Specs.size();
+    Specs.emplace_back(
+        getSpecifierRange(startSpecifier, specifierLen),
+        getLocationOfByte(Precision.getStart()),
+        analyze_format_string::LengthModifier::None, ".*",
+        Precision.getArgType(S.Context), EquatableFormatArgument::FAR_Precision,
+        EquatableFormatArgument::SS_None,
+        Precision.usesPositionalArg() ? Precision.getPositionalArgIndex() - 1
+                                      : PrecisionIndex,
+        0);
+  }
+
+  // this specifier
+  unsigned SpecIndex =
+      FS.usesPositionalArg() ? FS.getPositionalArgIndex() - 1 : Specs.size();
+  if (FieldWidthIndex != Unset)
+    Specs[FieldWidthIndex].setModifierFor(SpecIndex);
+  if (PrecisionIndex != Unset)
+    Specs[PrecisionIndex].setModifierFor(SpecIndex);
+
+  EquatableFormatArgument::SpecifierSensitivity Sensitivity;
+  if (FS.isPrivate())
+    Sensitivity = EquatableFormatArgument::SS_Private;
+  else if (FS.isPublic())
+    Sensitivity = EquatableFormatArgument::SS_Public;
+  else if (FS.isSensitive())
+    Sensitivity = EquatableFormatArgument::SS_Sensitive;
+  else
+    Sensitivity = EquatableFormatArgument::SS_None;
+
+  Specs.emplace_back(
+      getSpecifierRange(startSpecifier, specifierLen),
+      getLocationOfByte(CS.getStart()), FS.getLengthModifier().getKind(),
+      CS.getCharacters(), FS.getArgType(S.Context, isObjCContext()),
+      EquatableFormatArgument::FAR_Data, Sensitivity, SpecIndex, 0);
+
+  // auxiliary argument?
+  if (CS.getKind() == analyze_format_string::ConversionSpecifier::FreeBSDbArg ||
+      CS.getKind() == analyze_format_string::ConversionSpecifier::FreeBSDDArg) {
+    Specs.emplace_back(getSpecifierRange(startSpecifier, specifierLen),
+                       getLocationOfByte(CS.getStart()),
+                       analyze_format_string::LengthModifier::None,
+                       CS.getCharacters(),
+                       analyze_format_string::ArgType::CStrTy,
+                       EquatableFormatArgument::FAR_Auxiliary, Sensitivity,
+                       SpecIndex + 1, SpecIndex);
+  }
+  return true;
+}
+
+// Determines if the specified is a C++ class or struct containing
+// a member with the specified name and kind (e.g. a CXXMethodDecl named
+// "c_str()").
+template<typename MemberKind>
+static llvm::SmallPtrSet<MemberKind*, 1>
+CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) {
+  auto *RD = Ty->getAsCXXRecordDecl();
+  llvm::SmallPtrSet<MemberKind*, 1> Results;
+
+  if (!RD || !(RD->isBeingDefined() || RD->isCompleteDefinition()))
+    return Results;
+
+  LookupResult R(S, &S.Context.Idents.get(Name), SourceLocation(),
+                 Sema::LookupMemberName);
+  R.suppressDiagnostics();
+
+  // We just need to include all members of the right kind turned up by the
+  // filter, at this point.
+  if (S.LookupQualifiedName(R, RD))
+    for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+      NamedDecl *decl = (*I)->getUnderlyingDecl();
+      if (MemberKind *FK = dyn_cast<MemberKind>(decl))
+        Results.insert(FK);
+    }
+  return Results;
+}
+
+/// Check if we could call '.c_str()' on an object.
+///
+/// FIXME: This returns the wrong results in some cases (if cv-qualifiers don't
+/// allow the call, or if it would be ambiguous).
+bool Sema::hasCStrMethod(const Expr *E) {
+  using MethodSet = llvm::SmallPtrSet<CXXMethodDecl *, 1>;
+
+  MethodSet Results =
+      CXXRecordMembersNamed<CXXMethodDecl>("c_str", *this, E->getType());
+  for (MethodSet::iterator MI = Results.begin(), ME = Results.end();
+       MI != ME; ++MI)
+    if ((*MI)->getMinRequiredArguments() == 0)
+      return true;
+  return false;
+}
+
+// Check if a (w)string was passed when a (w)char* was needed, and offer a
+// better diagnostic if so. AT is assumed to be valid.
+// Returns true when a c_str() conversion method is found.
+bool CheckPrintfHandler::checkForCStrMembers(
+    const analyze_printf::ArgType &AT, const Expr *E) {
+  using MethodSet = llvm::SmallPtrSet<CXXMethodDecl *, 1>;
+
+  MethodSet Results =
+      CXXRecordMembersNamed<CXXMethodDecl>("c_str", S, E->getType());
+
+  for (MethodSet::iterator MI = Results.begin(), ME = Results.end();
+       MI != ME; ++MI) {
+    const CXXMethodDecl *Method = *MI;
+    if (Method->getMinRequiredArguments() == 0 &&
+        AT.matchesType(S.Context, Method->getReturnType())) {
+      // FIXME: Suggest parens if the expression needs them.
+      SourceLocation EndLoc = S.getLocForEndOfToken(E->getEndLoc());
+      S.Diag(E->getBeginLoc(), diag::note_printf_c_str)
+          << "c_str()" << FixItHint::CreateInsertion(EndLoc, ".c_str()");
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool CheckPrintfHandler::HandlePrintfSpecifier(
+    const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier,
+    unsigned specifierLen, const TargetInfo &Target) {
+  using namespace analyze_format_string;
+  using namespace analyze_printf;
+
+  const PrintfConversionSpecifier &CS = FS.getConversionSpecifier();
+
+  if (FS.consumesDataArgument()) {
+    if (atFirstArg) {
+        atFirstArg = false;
+        usesPositionalArgs = FS.usesPositionalArg();
+    }
+    else if (usesPositionalArgs != FS.usesPositionalArg()) {
+      HandlePositionalNonpositionalArgs(getLocationOfByte(CS.getStart()),
+                                        startSpecifier, specifierLen);
+      return false;
+    }
+  }
+
+  // First check if the field width, precision, and conversion specifier
+  // have matching data arguments.
+  if (!HandleAmount(FS.getFieldWidth(), /* field width */ 0,
+                    startSpecifier, specifierLen)) {
+    return false;
+  }
+
+  if (!HandleAmount(FS.getPrecision(), /* precision */ 1,
+                    startSpecifier, specifierLen)) {
+    return false;
+  }
+
+  if (!CS.consumesDataArgument()) {
+    // FIXME: Technically specifying a precision or field width here
+    // makes no sense.  Worth issuing a warning at some point.
+    return true;
+  }
+
+  // Consume the argument.
+  unsigned argIndex = FS.getArgIndex();
+  if (argIndex < NumDataArgs) {
+    // The check to see if the argIndex is valid will come later.
+    // We set the bit here because we may exit early from this
+    // function if we encounter some other error.
+    CoveredArgs.set(argIndex);
+  }
+
+  // FreeBSD kernel extensions.
+  if (CS.getKind() == ConversionSpecifier::FreeBSDbArg ||
+      CS.getKind() == ConversionSpecifier::FreeBSDDArg) {
+    // We need at least two arguments.
+    if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex + 1))
+      return false;
+
+    if (HasFormatArguments()) {
+      // Claim the second argument.
+      CoveredArgs.set(argIndex + 1);
+
+      // Type check the first argument (int for %b, pointer for %D)
+      const Expr *Ex = getDataArg(argIndex);
+      const analyze_printf::ArgType &AT =
+          (CS.getKind() == ConversionSpecifier::FreeBSDbArg)
+              ? ArgType(S.Context.IntTy)
+              : ArgType::CPointerTy;
+      if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType()))
+        EmitFormatDiagnostic(
+            S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
+                << AT.getRepresentativeTypeName(S.Context) << Ex->getType()
+                << false << Ex->getSourceRange(),
+            Ex->getBeginLoc(), /*IsStringLocation*/ false,
+            getSpecifierRange(startSpecifier, specifierLen));
+
+      // Type check the second argument (char * for both %b and %D)
+      Ex = getDataArg(argIndex + 1);
+      const analyze_printf::ArgType &AT2 = ArgType::CStrTy;
+      if (AT2.isValid() && !AT2.matchesType(S.Context, Ex->getType()))
+        EmitFormatDiagnostic(
+            S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
+                << AT2.getRepresentativeTypeName(S.Context) << Ex->getType()
+                << false << Ex->getSourceRange(),
+            Ex->getBeginLoc(), /*IsStringLocation*/ false,
+            getSpecifierRange(startSpecifier, specifierLen));
+    }
+    return true;
+  }
+
+  // Check for using an Objective-C specific conversion specifier
+  // in a non-ObjC literal.
+  if (!allowsObjCArg() && CS.isObjCArg()) {
+    return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier,
+                                                  specifierLen);
+  }
+
+  // %P can only be used with os_log.
+  if (FSType != FormatStringType::OSLog &&
+      CS.getKind() == ConversionSpecifier::PArg) {
+    return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier,
+                                                  specifierLen);
+  }
+
+  // %n is not allowed with os_log.
+  if (FSType == FormatStringType::OSLog &&
+      CS.getKind() == ConversionSpecifier::nArg) {
+    EmitFormatDiagnostic(S.PDiag(diag::warn_os_log_format_narg),
+                         getLocationOfByte(CS.getStart()),
+                         /*IsStringLocation*/ false,
+                         getSpecifierRange(startSpecifier, specifierLen));
+
+    return true;
+  }
+
+  // Only scalars are allowed for os_trace.
+  if (FSType == FormatStringType::OSTrace &&
+      (CS.getKind() == ConversionSpecifier::PArg ||
+       CS.getKind() == ConversionSpecifier::sArg ||
+       CS.getKind() == ConversionSpecifier::ObjCObjArg)) {
+    return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier,
+                                                  specifierLen);
+  }
+
+  // Check for use of public/private annotation outside of os_log().
+  if (FSType != FormatStringType::OSLog) {
+    if (FS.isPublic().isSet()) {
+      EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_annotation)
+                               << "public",
+                           getLocationOfByte(FS.isPublic().getPosition()),
+                           /*IsStringLocation*/ false,
+                           getSpecifierRange(startSpecifier, specifierLen));
+    }
+    if (FS.isPrivate().isSet()) {
+      EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_annotation)
+                               << "private",
+                           getLocationOfByte(FS.isPrivate().getPosition()),
+                           /*IsStringLocation*/ false,
+                           getSpecifierRange(startSpecifier, specifierLen));
+    }
+  }
+
+  const llvm::Triple &Triple = Target.getTriple();
+  if (CS.getKind() == ConversionSpecifier::nArg &&
+      (Triple.isAndroid() || Triple.isOSFuchsia())) {
+    EmitFormatDiagnostic(S.PDiag(diag::warn_printf_narg_not_supported),
+                         getLocationOfByte(CS.getStart()),
+                         /*IsStringLocation*/ false,
+                         getSpecifierRange(startSpecifier, specifierLen));
+  }
+
+  // Check for invalid use of field width
+  if (!FS.hasValidFieldWidth()) {
+    HandleInvalidAmount(FS, FS.getFieldWidth(), /* field width */ 0,
+        startSpecifier, specifierLen);
+  }
+
+  // Check for invalid use of precision
+  if (!FS.hasValidPrecision()) {
+    HandleInvalidAmount(FS, FS.getPrecision(), /* precision */ 1,
+        startSpecifier, specifierLen);
+  }
+
+  // Precision is mandatory for %P specifier.
+  if (CS.getKind() == ConversionSpecifier::PArg &&
+      FS.getPrecision().getHowSpecified() == OptionalAmount::NotSpecified) {
+    EmitFormatDiagnostic(S.PDiag(diag::warn_format_P_no_precision),
+                         getLocationOfByte(startSpecifier),
+                         /*IsStringLocation*/ false,
+                         getSpecifierRange(startSpecifier, specifierLen));
+  }
+
+  // Check each flag does not conflict with any other component.
+  if (!FS.hasValidThousandsGroupingPrefix())
+    HandleFlag(FS, FS.hasThousandsGrouping(), startSpecifier, specifierLen);
+  if (!FS.hasValidLeadingZeros())
+    HandleFlag(FS, FS.hasLeadingZeros(), startSpecifier, specifierLen);
+  if (!FS.hasValidPlusPrefix())
+    HandleFlag(FS, FS.hasPlusPrefix(), startSpecifier, specifierLen);
+  if (!FS.hasValidSpacePrefix())
+    HandleFlag(FS, FS.hasSpacePrefix(), startSpecifier, specifierLen);
+  if (!FS.hasValidAlternativeForm())
+    HandleFlag(FS, FS.hasAlternativeForm(), startSpecifier, specifierLen);
+  if (!FS.hasValidLeftJustified())
+    HandleFlag(FS, FS.isLeftJustified(), startSpecifier, specifierLen);
+
+  // Check that flags are not ignored by another flag
+  if (FS.hasSpacePrefix() && FS.hasPlusPrefix()) // ' ' ignored by '+'
+    HandleIgnoredFlag(FS, FS.hasSpacePrefix(), FS.hasPlusPrefix(),
+        startSpecifier, specifierLen);
+  if (FS.hasLeadingZeros() && FS.isLeftJustified()) // '0' ignored by '-'
+    HandleIgnoredFlag(FS, FS.hasLeadingZeros(), FS.isLeftJustified(),
+            startSpecifier, specifierLen);
+
+  // Check the length modifier is valid with the given conversion specifier.
+  if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo(),
+                                 S.getLangOpts()))
+    HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
+                                diag::warn_format_nonsensical_length);
+  else if (!FS.hasStandardLengthModifier())
+    HandleNonStandardLengthModifier(FS, startSpecifier, specifierLen);
+  else if (!FS.hasStandardLengthConversionCombination())
+    HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
+                                diag::warn_format_non_standard_conversion_spec);
+
+  if (!FS.hasStandardConversionSpecifier(S.getLangOpts()))
+    HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen);
+
+  // The remaining checks depend on the data arguments.
+  if (!HasFormatArguments())
+    return true;
+
+  if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex))
+    return false;
+
+  const Expr *Arg = getDataArg(argIndex);
+  if (!Arg)
+    return true;
+
+  return checkFormatExpr(FS, startSpecifier, specifierLen, Arg);
+}
+
+static bool requiresParensToAddCast(const Expr *E) {
+  // FIXME: We should have a general way to reason about operator
+  // precedence and whether parens are actually needed here.
+  // Take care of a few common cases where they aren't.
+  const Expr *Inside = E->IgnoreImpCasts();
+  if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(Inside))
+    Inside = POE->getSyntacticForm()->IgnoreImpCasts();
+
+  switch (Inside->getStmtClass()) {
+  case Stmt::ArraySubscriptExprClass:
+  case Stmt::CallExprClass:
+  case Stmt::CharacterLiteralClass:
+  case Stmt::CXXBoolLiteralExprClass:
+  case Stmt::DeclRefExprClass:
+  case Stmt::FloatingLiteralClass:
+  case Stmt::IntegerLiteralClass:
+  case Stmt::MemberExprClass:
+  case Stmt::ObjCArrayLiteralClass:
+  case Stmt::ObjCBoolLiteralExprClass:
+  case Stmt::ObjCBoxedExprClass:
+  case Stmt::ObjCDictionaryLiteralClass:
+  case Stmt::ObjCEncodeExprClass:
+  case Stmt::ObjCIvarRefExprClass:
+  case Stmt::ObjCMessageExprClass:
+  case Stmt::ObjCPropertyRefExprClass:
+  case Stmt::ObjCStringLiteralClass:
+  case Stmt::ObjCSubscriptRefExprClass:
+  case Stmt::ParenExprClass:
+  case Stmt::StringLiteralClass:
+  case Stmt::UnaryOperatorClass:
+    return false;
+  default:
+    return true;
+  }
+}
+
+static std::pair<QualType, StringRef>
+shouldNotPrintDirectly(const ASTContext &Context,
+                       QualType IntendedTy,
+                       const Expr *E) {
+  // Use a 'while' to peel off layers of typedefs.
+  QualType TyTy = IntendedTy;
+  while (const TypedefType *UserTy = TyTy->getAs<TypedefType>()) {
+    StringRef Name = UserTy->getDecl()->getName();
+    QualType CastTy = llvm::StringSwitch<QualType>(Name)
+      .Case("CFIndex", Context.getNSIntegerType())
+      .Case("NSInteger", Context.getNSIntegerType())
+      .Case("NSUInteger", Context.getNSUIntegerType())
+      .Case("SInt32", Context.IntTy)
+      .Case("UInt32", Context.UnsignedIntTy)
+      .Default(QualType());
+
+    if (!CastTy.isNull())
+      return std::make_pair(CastTy, Name);
+
+    TyTy = UserTy->desugar();
+  }
+
+  // Strip parens if necessary.
+  if (const ParenExpr *PE = dyn_cast<ParenExpr>(E))
+    return shouldNotPrintDirectly(Context,
+                                  PE->getSubExpr()->getType(),
+                                  PE->getSubExpr());
+
+  // If this is a conditional expression, then its result type is constructed
+  // via usual arithmetic conversions and thus there might be no necessary
+  // typedef sugar there.  Recurse to operands to check for NSInteger &
+  // Co. usage condition.
+  if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+    QualType TrueTy, FalseTy;
+    StringRef TrueName, FalseName;
+
+    std::tie(TrueTy, TrueName) =
+      shouldNotPrintDirectly(Context,
+                             CO->getTrueExpr()->getType(),
+                             CO->getTrueExpr());
+    std::tie(FalseTy, FalseName) =
+      shouldNotPrintDirectly(Context,
+                             CO->getFalseExpr()->getType(),
+                             CO->getFalseExpr());
+
+    if (TrueTy == FalseTy)
+      return std::make_pair(TrueTy, TrueName);
+    else if (TrueTy.isNull())
+      return std::make_pair(FalseTy, FalseName);
+    else if (FalseTy.isNull())
+      return std::make_pair(TrueTy, TrueName);
+  }
+
+  return std::make_pair(QualType(), StringRef());
+}
+
+/// Return true if \p ICE is an implicit argument promotion of an arithmetic
+/// type. Bit-field 'promotions' from a higher ranked type to a lower ranked
+/// type do not count.
+static bool
+isArithmeticArgumentPromotion(Sema &S, const ImplicitCastExpr *ICE) {
+  QualType From = ICE->getSubExpr()->getType();
+  QualType To = ICE->getType();
+  // It's an integer promotion if the destination type is the promoted
+  // source type.
+  if (ICE->getCastKind() == CK_IntegralCast &&
+      S.Context.isPromotableIntegerType(From) &&
+      S.Context.getPromotedIntegerType(From) == To)
+    return true;
+  // Look through vector types, since we do default argument promotion for
+  // those in OpenCL.
+  if (const auto *VecTy = From->getAs<ExtVectorType>())
+    From = VecTy->getElementType();
+  if (const auto *VecTy = To->getAs<ExtVectorType>())
+    To = VecTy->getElementType();
+  // It's a floating promotion if the source type is a lower rank.
+  return ICE->getCastKind() == CK_FloatingCast &&
+         S.Context.getFloatingTypeOrder(From, To) < 0;
+}
+
+static analyze_format_string::ArgType::MatchKind
+handleFormatSignedness(analyze_format_string::ArgType::MatchKind Match,
+                       DiagnosticsEngine &Diags, SourceLocation Loc) {
+  if (Match == analyze_format_string::ArgType::NoMatchSignedness) {
+    if (Diags.isIgnored(
+            diag::warn_format_conversion_argument_type_mismatch_signedness,
+            Loc) ||
+        Diags.isIgnored(
+            // Arbitrary -Wformat diagnostic to detect -Wno-format:
+            diag::warn_format_conversion_argument_type_mismatch, Loc)) {
+      return analyze_format_string::ArgType::Match;
+    }
+  }
+  return Match;
+}
+
+bool
+CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
+                                    const char *StartSpecifier,
+                                    unsigned SpecifierLen,
+                                    const Expr *E) {
+  using namespace analyze_format_string;
+  using namespace analyze_printf;
+
+  // Now type check the data expression that matches the
+  // format specifier.
+  const analyze_printf::ArgType &AT = FS.getArgType(S.Context, isObjCContext());
+  if (!AT.isValid())
+    return true;
+
+  QualType ExprTy = E->getType();
+  while (const TypeOfExprType *TET = dyn_cast<TypeOfExprType>(ExprTy)) {
+    ExprTy = TET->getUnderlyingExpr()->getType();
+  }
+
+  // When using the format attribute in C++, you can receive a function or an
+  // array that will necessarily decay to a pointer when passed to the final
+  // format consumer. Apply decay before type comparison.
+  if (ExprTy->canDecayToPointerType())
+    ExprTy = S.Context.getDecayedType(ExprTy);
+
+  // Diagnose attempts to print a boolean value as a character. Unlike other
+  // -Wformat diagnostics, this is fine from a type perspective, but it still
+  // doesn't make sense.
+  if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::cArg &&
+      E->isKnownToHaveBooleanValue()) {
+    const CharSourceRange &CSR =
+        getSpecifierRange(StartSpecifier, SpecifierLen);
+    SmallString<4> FSString;
+    llvm::raw_svector_ostream os(FSString);
+    FS.toString(os);
+    EmitFormatDiagnostic(S.PDiag(diag::warn_format_bool_as_character)
+                             << FSString,
+                         E->getExprLoc(), false, CSR);
+    return true;
+  }
+
+  // Diagnose attempts to use '%P' with ObjC object types, which will result in
+  // dumping raw class data (like is-a pointer), not actual data.
+  if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::PArg &&
+      ExprTy->isObjCObjectPointerType()) {
+    const CharSourceRange &CSR =
+        getSpecifierRange(StartSpecifier, SpecifierLen);
+    EmitFormatDiagnostic(S.PDiag(diag::warn_format_P_with_objc_pointer),
+                         E->getExprLoc(), false, CSR);
+    return true;
+  }
+
+  ArgType::MatchKind ImplicitMatch = ArgType::NoMatch;
+  ArgType::MatchKind Match = AT.matchesType(S.Context, ExprTy);
+  ArgType::MatchKind OrigMatch = Match;
+
+  Match = handleFormatSignedness(Match, S.getDiagnostics(), E->getExprLoc());
+  if (Match == ArgType::Match)
+    return true;
+
+  // NoMatchPromotionTypeConfusion should be only returned in ImplictCastExpr
+  assert(Match != ArgType::NoMatchPromotionTypeConfusion);
+
+  // Look through argument promotions for our error message's reported type.
+  // This includes the integral and floating promotions, but excludes array
+  // and function pointer decay (seeing that an argument intended to be a
+  // string has type 'char [6]' is probably more confusing than 'char *') and
+  // certain bitfield promotions (bitfields can be 'demoted' to a lesser type).
+  if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+    if (isArithmeticArgumentPromotion(S, ICE)) {
+      E = ICE->getSubExpr();
+      ExprTy = E->getType();
+
+      // Check if we didn't match because of an implicit cast from a 'char'
+      // or 'short' to an 'int'.  This is done because printf is a varargs
+      // function.
+      if (ICE->getType() == S.Context.IntTy ||
+          ICE->getType() == S.Context.UnsignedIntTy) {
+        // All further checking is done on the subexpression
+        ImplicitMatch = AT.matchesType(S.Context, ExprTy);
+        if (OrigMatch == ArgType::NoMatchSignedness &&
+            ImplicitMatch != ArgType::NoMatchSignedness)
+          // If the original match was a signedness match this match on the
+          // implicit cast type also need to be signedness match otherwise we
+          // might introduce new unexpected warnings from -Wformat-signedness.
+          return true;
+        ImplicitMatch = handleFormatSignedness(
+            ImplicitMatch, S.getDiagnostics(), E->getExprLoc());
+        if (ImplicitMatch == ArgType::Match)
+          return true;
+      }
+    }
+  } else if (const CharacterLiteral *CL = dyn_cast<CharacterLiteral>(E)) {
+    // Special case for 'a', which has type 'int' in C.
+    // Note, however, that we do /not/ want to treat multibyte constants like
+    // 'MooV' as characters! This form is deprecated but still exists. In
+    // addition, don't treat expressions as of type 'char' if one byte length
+    // modifier is provided.
+    if (ExprTy == S.Context.IntTy &&
+        FS.getLengthModifier().getKind() != LengthModifier::AsChar)
+      if (llvm::isUIntN(S.Context.getCharWidth(), CL->getValue())) {
+        ExprTy = S.Context.CharTy;
+        // To improve check results, we consider a character literal in C
+        // to be a 'char' rather than an 'int'. 'printf("%hd", 'a');' is
+        // more likely a type confusion situation, so we will suggest to
+        // use '%hhd' instead by discarding the MatchPromotion.
+        if (Match == ArgType::MatchPromotion)
+          Match = ArgType::NoMatch;
+      }
+  }
+  if (Match == ArgType::MatchPromotion) {
+    // WG14 N2562 only clarified promotions in *printf
+    // For NSLog in ObjC, just preserve -Wformat behavior
+    if (!S.getLangOpts().ObjC &&
+        ImplicitMatch != ArgType::NoMatchPromotionTypeConfusion &&
+        ImplicitMatch != ArgType::NoMatchTypeConfusion)
+      return true;
+    Match = ArgType::NoMatch;
+  }
+  if (ImplicitMatch == ArgType::NoMatchPedantic ||
+      ImplicitMatch == ArgType::NoMatchTypeConfusion)
+    Match = ImplicitMatch;
+  assert(Match != ArgType::MatchPromotion);
+
+  // Look through unscoped enums to their underlying type.
+  bool IsEnum = false;
+  bool IsScopedEnum = false;
+  QualType IntendedTy = ExprTy;
+  if (const auto *ED = ExprTy->getAsEnumDecl()) {
+    IntendedTy = ED->getIntegerType();
+    if (!ED->isScoped()) {
+      ExprTy = IntendedTy;
+      // This controls whether we're talking about the underlying type or not,
+      // which we only want to do when it's an unscoped enum.
+      IsEnum = true;
+    } else {
+      IsScopedEnum = true;
+    }
+  }
+
+  // %C in an Objective-C context prints a unichar, not a wchar_t.
+  // If the argument is an integer of some kind, believe the %C and suggest
+  // a cast instead of changing the conversion specifier.
+  if (isObjCContext() &&
+      FS.getConversionSpecifier().getKind() == ConversionSpecifier::CArg) {
+    if (ExprTy->isIntegralOrUnscopedEnumerationType() &&
+        !ExprTy->isCharType()) {
+      // 'unichar' is defined as a typedef of unsigned short, but we should
+      // prefer using the typedef if it is visible.
+      IntendedTy = S.Context.UnsignedShortTy;
+
+      // While we are here, check if the value is an IntegerLiteral that happens
+      // to be within the valid range.
+      if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(E)) {
+        const llvm::APInt &V = IL->getValue();
+        if (V.getActiveBits() <= S.Context.getTypeSize(IntendedTy))
+          return true;
+      }
+
+      LookupResult Result(S, &S.Context.Idents.get("unichar"), E->getBeginLoc(),
+                          Sema::LookupOrdinaryName);
+      if (S.LookupName(Result, S.getCurScope())) {
+        NamedDecl *ND = Result.getFoundDecl();
+        if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(ND))
+          if (TD->getUnderlyingType() == IntendedTy)
+            IntendedTy =
+                S.Context.getTypedefType(ElaboratedTypeKeyword::None,
+                                         /*Qualifier=*/std::nullopt, TD);
+      }
+    }
+  }
+
+  // Special-case some of Darwin's platform-independence types by suggesting
+  // casts to primitive types that are known to be large enough.
+  bool ShouldNotPrintDirectly = false; StringRef CastTyName;
+  if (S.Context.getTargetInfo().getTriple().isOSDarwin()) {
+    QualType CastTy;
+    std::tie(CastTy, CastTyName) = shouldNotPrintDirectly(S.Context, IntendedTy, E);
+    if (!CastTy.isNull()) {
+      // %zi/%zu and %td/%tu are OK to use for NSInteger/NSUInteger of type int
+      // (long in ASTContext). Only complain to pedants or when they're the
+      // underlying type of a scoped enum (which always needs a cast).
+      if (!IsScopedEnum &&
+          (CastTyName == "NSInteger" || CastTyName == "NSUInteger") &&
+          (AT.isSizeT() || AT.isPtrdiffT()) &&
+          AT.matchesType(S.Context, CastTy))
+        Match = ArgType::NoMatchPedantic;
+      IntendedTy = CastTy;
+      ShouldNotPrintDirectly = true;
+    }
+  }
+
+  // We may be able to offer a FixItHint if it is a supported type.
+  PrintfSpecifier fixedFS = FS;
+  bool Success =
+      fixedFS.fixType(IntendedTy, S.getLangOpts(), S.Context, isObjCContext());
+
+  if (Success) {
+    // Get the fix string from the fixed format specifier
+    SmallString<16> buf;
+    llvm::raw_svector_ostream os(buf);
+    fixedFS.toString(os);
+
+    CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen);
+
+    if (IntendedTy == ExprTy && !ShouldNotPrintDirectly && !IsScopedEnum) {
+      unsigned Diag;
+      switch (Match) {
+      case ArgType::Match:
+      case ArgType::MatchPromotion:
+      case ArgType::NoMatchPromotionTypeConfusion:
+        llvm_unreachable("expected non-matching");
+      case ArgType::NoMatchSignedness:
+        Diag = diag::warn_format_conversion_argument_type_mismatch_signedness;
+        break;
+      case ArgType::NoMatchPedantic:
+        Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
+        break;
+      case ArgType::NoMatchTypeConfusion:
+        Diag = diag::warn_format_conversion_argument_type_mismatch_confusion;
+        break;
+      case ArgType::NoMatch:
+        Diag = diag::warn_format_conversion_argument_type_mismatch;
+        break;
+      }
+
+      // In this case, the specifier is wrong and should be changed to match
+      // the argument.
+      EmitFormatDiagnostic(S.PDiag(Diag)
+                               << AT.getRepresentativeTypeName(S.Context)
+                               << IntendedTy << IsEnum << E->getSourceRange(),
+                           E->getBeginLoc(),
+                           /*IsStringLocation*/ false, SpecRange,
+                           FixItHint::CreateReplacement(SpecRange, os.str()));
+    } else {
+      // The canonical type for formatting this value is different from the
+      // actual type of the expression. (This occurs, for example, with Darwin's
+      // NSInteger on 32-bit platforms, where it is typedef'd as 'int', but
+      // should be printed as 'long' for 64-bit compatibility.)
+      // Rather than emitting a normal format/argument mismatch, we want to
+      // add a cast to the recommended type (and correct the format string
+      // if necessary). We should also do so for scoped enumerations.
+      SmallString<16> CastBuf;
+      llvm::raw_svector_ostream CastFix(CastBuf);
+      CastFix << (S.LangOpts.CPlusPlus ? "static_cast<" : "(");
+      IntendedTy.print(CastFix, S.Context.getPrintingPolicy());
+      CastFix << (S.LangOpts.CPlusPlus ? ">" : ")");
+
+      SmallVector<FixItHint,4> Hints;
+      ArgType::MatchKind IntendedMatch = AT.matchesType(S.Context, IntendedTy);
+      IntendedMatch = handleFormatSignedness(IntendedMatch, S.getDiagnostics(),
+                                             E->getExprLoc());
+      if ((IntendedMatch != ArgType::Match) || ShouldNotPrintDirectly)
+        Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str()));
+
+      if (const CStyleCastExpr *CCast = dyn_cast<CStyleCastExpr>(E)) {
+        // If there's already a cast present, just replace it.
+        SourceRange CastRange(CCast->getLParenLoc(), CCast->getRParenLoc());
+        Hints.push_back(FixItHint::CreateReplacement(CastRange, CastFix.str()));
+
+      } else if (!requiresParensToAddCast(E) && !S.LangOpts.CPlusPlus) {
+        // If the expression has high enough precedence,
+        // just write the C-style cast.
+        Hints.push_back(
+            FixItHint::CreateInsertion(E->getBeginLoc(), CastFix.str()));
+      } else {
+        // Otherwise, add parens around the expression as well as the cast.
+        CastFix << "(";
+        Hints.push_back(
+            FixItHint::CreateInsertion(E->getBeginLoc(), CastFix.str()));
+
+        // We don't use getLocForEndOfToken because it returns invalid source
+        // locations for macro expansions (by design).
+        SourceLocation EndLoc = S.SourceMgr.getSpellingLoc(E->getEndLoc());
+        SourceLocation After = EndLoc.getLocWithOffset(
+            Lexer::MeasureTokenLength(EndLoc, S.SourceMgr, S.LangOpts));
+        Hints.push_back(FixItHint::CreateInsertion(After, ")"));
+      }
+
+      if (ShouldNotPrintDirectly && !IsScopedEnum) {
+        // The expression has a type that should not be printed directly.
+        // We extract the name from the typedef because we don't want to show
+        // the underlying type in the diagnostic.
+        StringRef Name;
+        if (const auto *TypedefTy = ExprTy->getAs<TypedefType>())
+          Name = TypedefTy->getDecl()->getName();
+        else
+          Name = CastTyName;
+        unsigned Diag = Match == ArgType::NoMatchPedantic
+                            ? diag::warn_format_argument_needs_cast_pedantic
+                            : diag::warn_format_argument_needs_cast;
+        EmitFormatDiagnostic(S.PDiag(Diag) << Name << IntendedTy << IsEnum
+                                           << E->getSourceRange(),
+                             E->getBeginLoc(), /*IsStringLocation=*/false,
+                             SpecRange, Hints);
+      } else {
+        // In this case, the expression could be printed using a different
+        // specifier, but we've decided that the specifier is probably correct
+        // and we should cast instead. Just use the normal warning message.
+
+        unsigned Diag =
+            IsScopedEnum
+                ? diag::warn_format_conversion_argument_type_mismatch_pedantic
+                : diag::warn_format_conversion_argument_type_mismatch;
+
+        EmitFormatDiagnostic(
+            S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy
+                          << IsEnum << E->getSourceRange(),
+            E->getBeginLoc(), /*IsStringLocation*/ false, SpecRange, Hints);
+      }
+    }
+  } else {
+    const CharSourceRange &CSR = getSpecifierRange(StartSpecifier,
+                                                   SpecifierLen);
+    // Since the warning for passing non-POD types to variadic functions
+    // was deferred until now, we emit a warning for non-POD
+    // arguments here.
+    bool EmitTypeMismatch = false;
+    switch (S.isValidVarArgType(ExprTy)) {
+    case VarArgKind::Valid:
+    case VarArgKind::ValidInCXX11: {
+      unsigned Diag;
+      switch (Match) {
+      case ArgType::Match:
+      case ArgType::MatchPromotion:
+      case ArgType::NoMatchPromotionTypeConfusion:
+        llvm_unreachable("expected non-matching");
+      case ArgType::NoMatchSignedness:
+        Diag = diag::warn_format_conversion_argument_type_mismatch_signedness;
+        break;
+      case ArgType::NoMatchPedantic:
+        Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic;
+        break;
+      case ArgType::NoMatchTypeConfusion:
+        Diag = diag::warn_format_conversion_argument_type_mismatch_confusion;
+        break;
+      case ArgType::NoMatch:
+        Diag = isInvalidOSLogArgTypeForCodeGen(FSType, ExprTy)
+                   ? diag::err_format_conversion_argument_type_mismatch
+                   : diag::warn_format_conversion_argument_type_mismatch;
+        break;
+      }
+
+      EmitFormatDiagnostic(
+          S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy
+                        << IsEnum << CSR << E->getSourceRange(),
+          E->getBeginLoc(), /*IsStringLocation*/ false, CSR);
+      break;
+    }
+    case VarArgKind::Undefined:
+    case VarArgKind::MSVCUndefined:
+      if (CallType == VariadicCallType::DoesNotApply) {
+        EmitTypeMismatch = true;
+      } else {
+        EmitFormatDiagnostic(
+            S.PDiag(diag::warn_non_pod_vararg_with_format_string)
+                << S.getLangOpts().CPlusPlus11 << ExprTy << CallType
+                << AT.getRepresentativeTypeName(S.Context) << CSR
+                << E->getSourceRange(),
+            E->getBeginLoc(), /*IsStringLocation*/ false, CSR);
+        checkForCStrMembers(AT, E);
+      }
+      break;
+
+    case VarArgKind::Invalid:
+      if (CallType == VariadicCallType::DoesNotApply)
+        EmitTypeMismatch = true;
+      else if (ExprTy->isObjCObjectType())
+        EmitFormatDiagnostic(
+            S.PDiag(diag::err_cannot_pass_objc_interface_to_vararg_format)
+                << S.getLangOpts().CPlusPlus11 << ExprTy << CallType
+                << AT.getRepresentativeTypeName(S.Context) << CSR
+                << E->getSourceRange(),
+            E->getBeginLoc(), /*IsStringLocation*/ false, CSR);
+      else
+        // FIXME: If this is an initializer list, suggest removing the braces
+        // or inserting a cast to the target type.
+        S.Diag(E->getBeginLoc(), diag::err_cannot_pass_to_vararg_format)
+            << isa<InitListExpr>(E) << ExprTy << CallType
+            << AT.getRepresentativeTypeName(S.Context) << E->getSourceRange();
+      break;
+    }
+
+    if (EmitTypeMismatch) {
+      // The function is not variadic, so we do not generate warnings about
+      // being allowed to pass that object as a variadic argument. Instead,
+      // since there are inherently no printf specifiers for types which cannot
+      // be passed as variadic arguments, emit a plain old specifier mismatch
+      // argument.
+      EmitFormatDiagnostic(
+          S.PDiag(diag::warn_format_conversion_argument_type_mismatch)
+              << AT.getRepresentativeTypeName(S.Context) << ExprTy << false
+              << E->getSourceRange(),
+          E->getBeginLoc(), false, CSR);
+    }
+
+    assert(FirstDataArg + FS.getArgIndex() < CheckedVarArgs.size() &&
+           "format string specifier index out of range");
+    CheckedVarArgs[FirstDataArg + FS.getArgIndex()] = true;
+  }
+
+  return true;
+}
+
+//===--- CHECK: Scanf format string checking ------------------------------===//
+
+namespace {
+
+class CheckScanfHandler : public CheckFormatHandler {
+public:
+  CheckScanfHandler(Sema &s, const FormatStringLiteral *fexpr,
+                    const Expr *origFormatExpr, FormatStringType type,
+                    unsigned firstDataArg, unsigned numDataArgs,
+                    const char *beg, Sema::FormatArgumentPassingKind APK,
+                    ArrayRef<const Expr *> Args, unsigned formatIdx,
+                    bool inFunctionCall, VariadicCallType CallType,
+                    llvm::SmallBitVector &CheckedVarArgs,
+                    UncoveredArgHandler &UncoveredArg)
+      : CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg,
+                           numDataArgs, beg, APK, Args, formatIdx,
+                           inFunctionCall, CallType, CheckedVarArgs,
+                           UncoveredArg) {}
+
+  bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
+                            const char *startSpecifier,
+                            unsigned specifierLen) override;
+
+  bool HandleInvalidScanfConversionSpecifier(
+          const analyze_scanf::ScanfSpecifier &FS,
+          const char *startSpecifier,
+          unsigned specifierLen) override;
+
+  void HandleIncompleteScanList(const char *start, const char *end) override;
+};
+
+} // namespace
+
+void CheckScanfHandler::HandleIncompleteScanList(const char *start,
+                                                 const char *end) {
+  EmitFormatDiagnostic(S.PDiag(diag::warn_scanf_scanlist_incomplete),
+                       getLocationOfByte(end), /*IsStringLocation*/true,
+                       getSpecifierRange(start, end - start));
+}
+
+bool CheckScanfHandler::HandleInvalidScanfConversionSpecifier(
+                                        const analyze_scanf::ScanfSpecifier &FS,
+                                        const char *startSpecifier,
+                                        unsigned specifierLen) {
+  const analyze_scanf::ScanfConversionSpecifier &CS =
+    FS.getConversionSpecifier();
+
+  return HandleInvalidConversionSpecifier(FS.getArgIndex(),
+                                          getLocationOfByte(CS.getStart()),
+                                          startSpecifier, specifierLen,
+                                          CS.getStart(), CS.getLength());
+}
+
+bool CheckScanfHandler::HandleScanfSpecifier(
+                                       const analyze_scanf::ScanfSpecifier &FS,
+                                       const char *startSpecifier,
+                                       unsigned specifierLen) {
+  using namespace analyze_scanf;
+  using namespace analyze_format_string;
+
+  const ScanfConversionSpecifier &CS = FS.getConversionSpecifier();
+
+  // Handle case where '%' and '*' don't consume an argument.  These shouldn't
+  // be used to decide if we are using positional arguments consistently.
+  if (FS.consumesDataArgument()) {
+    if (atFirstArg) {
+      atFirstArg = false;
+      usesPositionalArgs = FS.usesPositionalArg();
+    }
+    else if (usesPositionalArgs != FS.usesPositionalArg()) {
+      HandlePositionalNonpositionalArgs(getLocationOfByte(CS.getStart()),
+                                        startSpecifier, specifierLen);
+      return false;
+    }
+  }
+
+  // Check if the field with is non-zero.
+  const OptionalAmount &Amt = FS.getFieldWidth();
+  if (Amt.getHowSpecified() == OptionalAmount::Constant) {
+    if (Amt.getConstantAmount() == 0) {
+      const CharSourceRange &R = getSpecifierRange(Amt.getStart(),
+                                                   Amt.getConstantLength());
+      EmitFormatDiagnostic(S.PDiag(diag::warn_scanf_nonzero_width),
+                           getLocationOfByte(Amt.getStart()),
+                           /*IsStringLocation*/true, R,
+                           FixItHint::CreateRemoval(R));
+    }
+  }
+
+  if (!FS.consumesDataArgument()) {
+    // FIXME: Technically specifying a precision or field width here
+    // makes no sense.  Worth issuing a warning at some point.
+    return true;
+  }
+
+  // Consume the argument.
+  unsigned argIndex = FS.getArgIndex();
+  if (argIndex < NumDataArgs) {
+      // The check to see if the argIndex is valid will come later.
+      // We set the bit here because we may exit early from this
+      // function if we encounter some other error.
+    CoveredArgs.set(argIndex);
+  }
+
+  // Check the length modifier is valid with the given conversion specifier.
+  if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo(),
+                                 S.getLangOpts()))
+    HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
+                                diag::warn_format_nonsensical_length);
+  else if (!FS.hasStandardLengthModifier())
+    HandleNonStandardLengthModifier(FS, startSpecifier, specifierLen);
+  else if (!FS.hasStandardLengthConversionCombination())
+    HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen,
+                                diag::warn_format_non_standard_conversion_spec);
+
+  if (!FS.hasStandardConversionSpecifier(S.getLangOpts()))
+    HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen);
+
+  // The remaining checks depend on the data arguments.
+  if (!HasFormatArguments())
+    return true;
+
+  if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex))
+    return false;
+
+  // Check that the argument type matches the format specifier.
+  const Expr *Ex = getDataArg(argIndex);
+  if (!Ex)
+    return true;
+
+  const analyze_format_string::ArgType &AT = FS.getArgType(S.Context);
+
+  if (!AT.isValid()) {
+    return true;
+  }
+
+  analyze_format_string::ArgType::MatchKind Match =
+      AT.matchesType(S.Context, Ex->getType());
+  Match = handleFormatSignedness(Match, S.getDiagnostics(), Ex->getExprLoc());
+  if (Match == analyze_format_string::ArgType::Match)
+    return true;
+  bool Pedantic = Match == analyze_format_string::ArgType::NoMatchPedantic;
+  bool Signedness = Match == analyze_format_string::ArgType::NoMatchSignedness;
+
+  ScanfSpecifier fixedFS = FS;
+  bool Success = fixedFS.fixType(Ex->getType(), Ex->IgnoreImpCasts()->getType(),
+                                 S.getLangOpts(), S.Context);
+
+  unsigned Diag =
+      Pedantic ? diag::warn_format_conversion_argument_type_mismatch_pedantic
+      : Signedness
+          ? diag::warn_format_conversion_argument_type_mismatch_signedness
+          : diag::warn_format_conversion_argument_type_mismatch;
+
+  if (Success) {
+    // Get the fix string from the fixed format specifier.
+    SmallString<128> buf;
+    llvm::raw_svector_ostream os(buf);
+    fixedFS.toString(os);
+
+    EmitFormatDiagnostic(
+        S.PDiag(Diag) << AT.getRepresentativeTypeName(S.Context)
+                      << Ex->getType() << false << Ex->getSourceRange(),
+        Ex->getBeginLoc(),
+        /*IsStringLocation*/ false,
+        getSpecifierRange(startSpecifier, specifierLen),
+        FixItHint::CreateReplacement(
+            getSpecifierRange(startSpecifier, specifierLen), os.str()));
+  } else {
+    EmitFormatDiagnostic(S.PDiag(Diag)
+                             << AT.getRepresentativeTypeName(S.Context)
+                             << Ex->getType() << false << Ex->getSourceRange(),
+                         Ex->getBeginLoc(),
+                         /*IsStringLocation*/ false,
+                         getSpecifierRange(startSpecifier, specifierLen));
+  }
+
+  return true;
+}
+
+static bool CompareFormatSpecifiers(Sema &S, const StringLiteral *Ref,
+                                    ArrayRef<EquatableFormatArgument> RefArgs,
+                                    const StringLiteral *Fmt,
+                                    ArrayRef<EquatableFormatArgument> FmtArgs,
+                                    const Expr *FmtExpr, bool InFunctionCall) {
+  bool HadError = false;
+  auto FmtIter = FmtArgs.begin(), FmtEnd = FmtArgs.end();
+  auto RefIter = RefArgs.begin(), RefEnd = RefArgs.end();
+  while (FmtIter < FmtEnd && RefIter < RefEnd) {
+    // In positional-style format strings, the same specifier can appear
+    // multiple times (like %2$i %2$d). Specifiers in both RefArgs and FmtArgs
+    // are sorted by getPosition(), and we process each range of equal
+    // getPosition() values as one group.
+    // RefArgs are taken from a string literal that was given to
+    // attribute(format_matches), and if we got this far, we have already
+    // verified that if it has positional specifiers that appear in multiple
+    // locations, then they are all mutually compatible. What's left for us to
+    // do is verify that all specifiers with the same position in FmtArgs are
+    // compatible with the RefArgs specifiers. We check each specifier from
+    // FmtArgs against the first member of the RefArgs group.
+    for (; FmtIter < FmtEnd; ++FmtIter) {
+      // Clang does not diagnose missing format specifiers in positional-style
+      // strings (TODO: which it probably should do, as it is UB to skip over a
+      // format argument). Skip specifiers if needed.
+      if (FmtIter->getPosition() < RefIter->getPosition())
+        continue;
+
+      // Delimits a new getPosition() value.
+      if (FmtIter->getPosition() > RefIter->getPosition())
+        break;
+
+      HadError |=
+          !FmtIter->VerifyCompatible(S, *RefIter, FmtExpr, InFunctionCall);
+    }
+
+    // Jump RefIter to the start of the next group.
+    RefIter = std::find_if(RefIter + 1, RefEnd, [=](const auto &Arg) {
+      return Arg.getPosition() != RefIter->getPosition();
+    });
+  }
+
+  if (FmtIter < FmtEnd) {
+    CheckFormatHandler::EmitFormatDiagnostic(
+        S, InFunctionCall, FmtExpr,
+        S.PDiag(diag::warn_format_cmp_specifier_arity) << 1,
+        FmtExpr->getBeginLoc(), false, FmtIter->getSourceRange());
+    HadError = S.Diag(Ref->getBeginLoc(), diag::note_format_cmp_with) << 1;
+  } else if (RefIter < RefEnd) {
+    CheckFormatHandler::EmitFormatDiagnostic(
+        S, InFunctionCall, FmtExpr,
+        S.PDiag(diag::warn_format_cmp_specifier_arity) << 0,
+        FmtExpr->getBeginLoc(), false, Fmt->getSourceRange());
+    HadError = S.Diag(Ref->getBeginLoc(), diag::note_format_cmp_with)
+               << 1 << RefIter->getSourceRange();
+  }
+  return !HadError;
+}
+
+static void CheckFormatString(
+    Sema &S, const FormatStringLiteral *FExpr,
+    const StringLiteral *ReferenceFormatString, const Expr *OrigFormatExpr,
+    ArrayRef<const Expr *> Args, Sema::FormatArgumentPassingKind APK,
+    unsigned format_idx, unsigned firstDataArg, FormatStringType Type,
+    bool inFunctionCall, VariadicCallType CallType,
+    llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg,
+    bool IgnoreStringsWithoutSpecifiers) {
+  // CHECK: is the format string a wide literal?
+  if (!FExpr->isAscii() && !FExpr->isUTF8()) {
+    CheckFormatHandler::EmitFormatDiagnostic(
+        S, inFunctionCall, Args[format_idx],
+        S.PDiag(diag::warn_format_string_is_wide_literal), FExpr->getBeginLoc(),
+        /*IsStringLocation*/ true, OrigFormatExpr->getSourceRange());
+    return;
+  }
+
+  // Str - The format string.  NOTE: this is NOT null-terminated!
+  StringRef StrRef = FExpr->getString();
+  const char *Str = StrRef.data();
+  // Account for cases where the string literal is truncated in a declaration.
+  const ConstantArrayType *T =
+    S.Context.getAsConstantArrayType(FExpr->getType());
+  assert(T && "String literal not of constant array type!");
+  size_t TypeSize = T->getZExtSize();
+  size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size());
+  const unsigned numDataArgs = Args.size() - firstDataArg;
+
+  if (IgnoreStringsWithoutSpecifiers &&
+      !analyze_format_string::parseFormatStringHasFormattingSpecifiers(
+          Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo()))
+    return;
+
+  // Emit a warning if the string literal is truncated and does not contain an
+  // embedded null character.
+  if (TypeSize <= StrRef.size() && !StrRef.substr(0, TypeSize).contains('\0')) {
+    CheckFormatHandler::EmitFormatDiagnostic(
+        S, inFunctionCall, Args[format_idx],
+        S.PDiag(diag::warn_printf_format_string_not_null_terminated),
+        FExpr->getBeginLoc(),
+        /*IsStringLocation=*/true, OrigFormatExpr->getSourceRange());
+    return;
+  }
+
+  // CHECK: empty format string?
+  if (StrLen == 0 && numDataArgs > 0) {
+    CheckFormatHandler::EmitFormatDiagnostic(
+        S, inFunctionCall, Args[format_idx],
+        S.PDiag(diag::warn_empty_format_string), FExpr->getBeginLoc(),
+        /*IsStringLocation*/ true, OrigFormatExpr->getSourceRange());
+    return;
+  }
+
+  if (Type == FormatStringType::Printf || Type == FormatStringType::NSString ||
+      Type == FormatStringType::Kprintf ||
+      Type == FormatStringType::FreeBSDKPrintf ||
+      Type == FormatStringType::OSLog || Type == FormatStringType::OSTrace) {
+    bool IsObjC =
+        Type == FormatStringType::NSString || Type == FormatStringType::OSTrace;
+    if (ReferenceFormatString == nullptr) {
+      CheckPrintfHandler H(S, FExpr, OrigFormatExpr, Type, firstDataArg,
+                           numDataArgs, IsObjC, Str, APK, Args, format_idx,
+                           inFunctionCall, CallType, CheckedVarArgs,
+                           UncoveredArg);
+
+      if (!analyze_format_string::ParsePrintfString(
+              H, Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo(),
+              Type == FormatStringType::Kprintf ||
+                  Type == FormatStringType::FreeBSDKPrintf))
+        H.DoneProcessing();
+    } else {
+      S.CheckFormatStringsCompatible(
+          Type, ReferenceFormatString, FExpr->getFormatString(),
+          inFunctionCall ? nullptr : Args[format_idx]);
+    }
+  } else if (Type == FormatStringType::Scanf) {
+    CheckScanfHandler H(S, FExpr, OrigFormatExpr, Type, firstDataArg,
+                        numDataArgs, Str, APK, Args, format_idx, inFunctionCall,
+                        CallType, CheckedVarArgs, UncoveredArg);
+
+    if (!analyze_format_string::ParseScanfString(
+            H, Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo()))
+      H.DoneProcessing();
+  } // TODO: handle other formats
+}
+
+bool Sema::CheckFormatStringsCompatible(
+    FormatStringType Type, const StringLiteral *AuthoritativeFormatString,
+    const StringLiteral *TestedFormatString, const Expr *FunctionCallArg) {
+  if (Type != FormatStringType::Printf && Type != FormatStringType::NSString &&
+      Type != FormatStringType::Kprintf &&
+      Type != FormatStringType::FreeBSDKPrintf &&
+      Type != FormatStringType::OSLog && Type != FormatStringType::OSTrace)
+    return true;
+
+  bool IsObjC =
+      Type == FormatStringType::NSString || Type == FormatStringType::OSTrace;
+  llvm::SmallVector<EquatableFormatArgument, 9> RefArgs, FmtArgs;
+  FormatStringLiteral RefLit = AuthoritativeFormatString;
+  FormatStringLiteral TestLit = TestedFormatString;
+  const Expr *Arg;
+  bool DiagAtStringLiteral;
+  if (FunctionCallArg) {
+    Arg = FunctionCallArg;
+    DiagAtStringLiteral = false;
+  } else {
+    Arg = TestedFormatString;
+    DiagAtStringLiteral = true;
+  }
+  if (DecomposePrintfHandler::GetSpecifiers(*this, &RefLit,
+                                            AuthoritativeFormatString, Type,
+                                            IsObjC, true, RefArgs) &&
+      DecomposePrintfHandler::GetSpecifiers(*this, &TestLit, Arg, Type, IsObjC,
+                                            DiagAtStringLiteral, FmtArgs)) {
+    return CompareFormatSpecifiers(*this, AuthoritativeFormatString, RefArgs,
+                                   TestedFormatString, FmtArgs, Arg,
+                                   DiagAtStringLiteral);
+  }
+  return false;
+}
+
+bool Sema::ValidateFormatString(FormatStringType Type,
+                                const StringLiteral *Str) {
+  if (Type != FormatStringType::Printf && Type != FormatStringType::NSString &&
+      Type != FormatStringType::Kprintf &&
+      Type != FormatStringType::FreeBSDKPrintf &&
+      Type != FormatStringType::OSLog && Type != FormatStringType::OSTrace)
+    return true;
+
+  FormatStringLiteral RefLit = Str;
+  llvm::SmallVector<EquatableFormatArgument, 9> Args;
+  bool IsObjC =
+      Type == FormatStringType::NSString || Type == FormatStringType::OSTrace;
+  if (!DecomposePrintfHandler::GetSpecifiers(*this, &RefLit, Str, Type, IsObjC,
+                                             true, Args))
+    return false;
+
+  // Group arguments by getPosition() value, and check that each member of the
+  // group is compatible with the first member. This verifies that when
+  // positional arguments are used multiple times (such as %2$i %2$d), all uses
+  // are mutually compatible. As an optimization, don't test the first member
+  // against itself.
+  bool HadError = false;
+  auto Iter = Args.begin();
+  auto End = Args.end();
+  while (Iter != End) {
+    const auto &FirstInGroup = *Iter;
+    for (++Iter;
+         Iter != End && Iter->getPosition() == FirstInGroup.getPosition();
+         ++Iter) {
+      HadError |= !Iter->VerifyCompatible(*this, FirstInGroup, Str, true);
+    }
+  }
+  return !HadError;
+}
+
+bool Sema::FormatStringHasSArg(const StringLiteral *FExpr) {
+  // Str - The format string.  NOTE: this is NOT null-terminated!
+  StringRef StrRef = FExpr->getString();
+  const char *Str = StrRef.data();
+  // Account for cases where the string literal is truncated in a declaration.
+  const ConstantArrayType *T = Context.getAsConstantArrayType(FExpr->getType());
+  assert(T && "String literal not of constant array type!");
+  size_t TypeSize = T->getZExtSize();
+  size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size());
+  return analyze_format_string::ParseFormatStringHasSArg(Str, Str + StrLen,
+                                                         getLangOpts(),
+                                                         Context.getTargetInfo());
+}
+
+//===--- CHECK: Warn on use of wrong absolute value function. -------------===//
+
+// Returns the related absolute value function that is larger, of 0 if one
+// does not exist.
+static unsigned getLargerAbsoluteValueFunction(unsigned AbsFunction) {
+  switch (AbsFunction) {
+  default:
+    return 0;
+
+  case Builtin::BI__builtin_abs:
+    return Builtin::BI__builtin_labs;
+  case Builtin::BI__builtin_labs:
+    return Builtin::BI__builtin_llabs;
+  case Builtin::BI__builtin_llabs:
+    return 0;
+
+  case Builtin::BI__builtin_fabsf:
+    return Builtin::BI__builtin_fabs;
+  case Builtin::BI__builtin_fabs:
+    return Builtin::BI__builtin_fabsl;
+  case Builtin::BI__builtin_fabsl:
+    return 0;
+
+  case Builtin::BI__builtin_cabsf:
+    return Builtin::BI__builtin_cabs;
+  case Builtin::BI__builtin_cabs:
+    return Builtin::BI__builtin_cabsl;
+  case Builtin::BI__builtin_cabsl:
+    return 0;
+
+  case Builtin::BIabs:
+    return Builtin::BIlabs;
+  case Builtin::BIlabs:
+    return Builtin::BIllabs;
+  case Builtin::BIllabs:
+    return 0;
+
+  case Builtin::BIfabsf:
+    return Builtin::BIfabs;
+  case Builtin::BIfabs:
+    return Builtin::BIfabsl;
+  case Builtin::BIfabsl:
+    return 0;
+
+  case Builtin::BIcabsf:
+   return Builtin::BIcabs;
+  case Builtin::BIcabs:
+    return Builtin::BIcabsl;
+  case Builtin::BIcabsl:
+    return 0;
+  }
+}
+
+// Returns the argument type of the absolute value function.
+static QualType getAbsoluteValueArgumentType(ASTContext &Context,
+                                             unsigned AbsType) {
+  if (AbsType == 0)
+    return QualType();
+
+  ASTContext::GetBuiltinTypeError Error = ASTContext::GE_None;
+  QualType BuiltinType = Context.GetBuiltinType(AbsType, Error);
+  if (Error != ASTContext::GE_None)
+    return QualType();
+
+  const FunctionProtoType *FT = BuiltinType->getAs<FunctionProtoType>();
+  if (!FT)
+    return QualType();
+
+  if (FT->getNumParams() != 1)
+    return QualType();
+
+  return FT->getParamType(0);
+}
+
+// Returns the best absolute value function, or zero, based on type and
+// current absolute value function.
+static unsigned getBestAbsFunction(ASTContext &Context, QualType ArgType,
+                                   unsigned AbsFunctionKind) {
+  unsigned BestKind = 0;
+  uint64_t ArgSize = Context.getTypeSize(ArgType);
+  for (unsigned Kind = AbsFunctionKind; Kind != 0;
+       Kind = getLargerAbsoluteValueFunction(Kind)) {
+    QualType ParamType = getAbsoluteValueArgumentType(Context, Kind);
+    if (Context.getTypeSize(ParamType) >= ArgSize) {
+      if (BestKind == 0)
+        BestKind = Kind;
+      else if (Context.hasSameType(ParamType, ArgType)) {
+        BestKind = Kind;
+        break;
+      }
+    }
+  }
+  return BestKind;
+}
+
+enum AbsoluteValueKind {
+  AVK_Integer,
+  AVK_Floating,
+  AVK_Complex
+};
+
+static AbsoluteValueKind getAbsoluteValueKind(QualType T) {
+  if (T->isIntegralOrEnumerationType())
+    return AVK_Integer;
+  if (T->isRealFloatingType())
+    return AVK_Floating;
+  if (T->isAnyComplexType())
+    return AVK_Complex;
+
+  llvm_unreachable("Type not integer, floating, or complex");
+}
+
+// Changes the absolute value function to a different type.  Preserves whether
+// the function is a builtin.
+static unsigned changeAbsFunction(unsigned AbsKind,
+                                  AbsoluteValueKind ValueKind) {
+  switch (ValueKind) {
+  case AVK_Integer:
+    switch (AbsKind) {
+    default:
+      return 0;
+    case Builtin::BI__builtin_fabsf:
+    case Builtin::BI__builtin_fabs:
+    case Builtin::BI__builtin_fabsl:
+    case Builtin::BI__builtin_cabsf:
+    case Builtin::BI__builtin_cabs:
+    case Builtin::BI__builtin_cabsl:
+      return Builtin::BI__builtin_abs;
+    case Builtin::BIfabsf:
+    case Builtin::BIfabs:
+    case Builtin::BIfabsl:
+    case Builtin::BIcabsf:
+    case Builtin::BIcabs:
+    case Builtin::BIcabsl:
+      return Builtin::BIabs;
+    }
+  case AVK_Floating:
+    switch (AbsKind) {
+    default:
+      return 0;
+    case Builtin::BI__builtin_abs:
+    case Builtin::BI__builtin_labs:
+    case Builtin::BI__builtin_llabs:
+    case Builtin::BI__builtin_cabsf:
+    case Builtin::BI__builtin_cabs:
+    case Builtin::BI__builtin_cabsl:
+      return Builtin::BI__builtin_fabsf;
+    case Builtin::BIabs:
+    case Builtin::BIlabs:
+    case Builtin::BIllabs:
+    case Builtin::BIcabsf:
+    case Builtin::BIcabs:
+    case Builtin::BIcabsl:
+      return Builtin::BIfabsf;
+    }
+  case AVK_Complex:
+    switch (AbsKind) {
+    default:
+      return 0;
+    case Builtin::BI__builtin_abs:
+    case Builtin::BI__builtin_labs:
+    case Builtin::BI__builtin_llabs:
+    case Builtin::BI__builtin_fabsf:
+    case Builtin::BI__builtin_fabs:
+    case Builtin::BI__builtin_fabsl:
+      return Builtin::BI__builtin_cabsf;
+    case Builtin::BIabs:
+    case Builtin::BIlabs:
+    case Builtin::BIllabs:
+    case Builtin::BIfabsf:
+    case Builtin::BIfabs:
+    case Builtin::BIfabsl:
+      return Builtin::BIcabsf;
+    }
+  }
+  llvm_unreachable("Unable to convert function");
+}
+
+static unsigned getAbsoluteValueFunctionKind(const FunctionDecl *FDecl) {
+  const IdentifierInfo *FnInfo = FDecl->getIdentifier();
+  if (!FnInfo)
+    return 0;
+
+  switch (FDecl->getBuiltinID()) {
+  default:
+    return 0;
+  case Builtin::BI__builtin_abs:
+  case Builtin::BI__builtin_fabs:
+  case Builtin::BI__builtin_fabsf:
+  case Builtin::BI__builtin_fabsl:
+  case Builtin::BI__builtin_labs:
+  case Builtin::BI__builtin_llabs:
+  case Builtin::BI__builtin_cabs:
+  case Builtin::BI__builtin_cabsf:
+  case Builtin::BI__builtin_cabsl:
+  case Builtin::BIabs:
+  case Builtin::BIlabs:
+  case Builtin::BIllabs:
+  case Builtin::BIfabs:
+  case Builtin::BIfabsf:
+  case Builtin::BIfabsl:
+  case Builtin::BIcabs:
+  case Builtin::BIcabsf:
+  case Builtin::BIcabsl:
+    return FDecl->getBuiltinID();
+  }
+  llvm_unreachable("Unknown Builtin type");
+}
+
+// If the replacement is valid, emit a note with replacement function.
+// Additionally, suggest including the proper header if not already included.
+static void emitReplacement(Sema &S, SourceLocation Loc, SourceRange Range,
+                            unsigned AbsKind, QualType ArgType) {
+  bool EmitHeaderHint = true;
+  const char *HeaderName = nullptr;
+  std::string FunctionName;
+  if (S.getLangOpts().CPlusPlus && !ArgType->isAnyComplexType()) {
+    FunctionName = "std::abs";
+    if (ArgType->isIntegralOrEnumerationType()) {
+      HeaderName = "cstdlib";
+    } else if (ArgType->isRealFloatingType()) {
+      HeaderName = "cmath";
+    } else {
+      llvm_unreachable("Invalid Type");
+    }
+
+    // Lookup all std::abs
+    if (NamespaceDecl *Std = S.getStdNamespace()) {
+      LookupResult R(S, &S.Context.Idents.get("abs"), Loc, Sema::LookupAnyName);
+      R.suppressDiagnostics();
+      S.LookupQualifiedName(R, Std);
+
+      for (const auto *I : R) {
+        const FunctionDecl *FDecl = nullptr;
+        if (const UsingShadowDecl *UsingD = dyn_cast<UsingShadowDecl>(I)) {
+          FDecl = dyn_cast<FunctionDecl>(UsingD->getTargetDecl());
+        } else {
+          FDecl = dyn_cast<FunctionDecl>(I);
+        }
+        if (!FDecl)
+          continue;
+
+        // Found std::abs(), check that they are the right ones.
+        if (FDecl->getNumParams() != 1)
+          continue;
+
+        // Check that the parameter type can handle the argument.
+        QualType ParamType = FDecl->getParamDecl(0)->getType();
+        if (getAbsoluteValueKind(ArgType) == getAbsoluteValueKind(ParamType) &&
+            S.Context.getTypeSize(ArgType) <=
+                S.Context.getTypeSize(ParamType)) {
+          // Found a function, don't need the header hint.
+          EmitHeaderHint = false;
+          break;
+        }
+      }
+    }
+  } else {
+    FunctionName = S.Context.BuiltinInfo.getName(AbsKind);
+    HeaderName = S.Context.BuiltinInfo.getHeaderName(AbsKind);
+
+    if (HeaderName) {
+      DeclarationName DN(&S.Context.Idents.get(FunctionName));
+      LookupResult R(S, DN, Loc, Sema::LookupAnyName);
+      R.suppressDiagnostics();
+      S.LookupName(R, S.getCurScope());
+
+      if (R.isSingleResult()) {
+        FunctionDecl *FD = dyn_cast<FunctionDecl>(R.getFoundDecl());
+        if (FD && FD->getBuiltinID() == AbsKind) {
+          EmitHeaderHint = false;
+        } else {
+          return;
+        }
+      } else if (!R.empty()) {
+        return;
+      }
+    }
+  }
+
+  S.Diag(Loc, diag::note_replace_abs_function)
+      << FunctionName << FixItHint::CreateReplacement(Range, FunctionName);
+
+  if (!HeaderName)
+    return;
+
+  if (!EmitHeaderHint)
+    return;
+
+  S.Diag(Loc, diag::note_include_header_or_declare) << HeaderName
+                                                    << FunctionName;
+}
+
+template <std::size_t StrLen>
+static bool IsStdFunction(const FunctionDecl *FDecl,
+                          const char (&Str)[StrLen]) {
+  if (!FDecl)
+    return false;
+  if (!FDecl->getIdentifier() || !FDecl->getIdentifier()->isStr(Str))
+    return false;
+  if (!FDecl->isInStdNamespace())
+    return false;
+
+  return true;
+}
+
+enum class MathCheck { NaN, Inf };
+static bool IsInfOrNanFunction(StringRef calleeName, MathCheck Check) {
+  auto MatchesAny = [&](std::initializer_list<llvm::StringRef> names) {
+    return llvm::is_contained(names, calleeName);
+  };
+
+  switch (Check) {
+  case MathCheck::NaN:
+    return MatchesAny({"__builtin_nan", "__builtin_nanf", "__builtin_nanl",
+                       "__builtin_nanf16", "__builtin_nanf128"});
+  case MathCheck::Inf:
+    return MatchesAny({"__builtin_inf", "__builtin_inff", "__builtin_infl",
+                       "__builtin_inff16", "__builtin_inff128"});
+  }
+  llvm_unreachable("unknown MathCheck");
+}
+
+static bool IsInfinityFunction(const FunctionDecl *FDecl) {
+  if (FDecl->getName() != "infinity")
+    return false;
+
+  if (const CXXMethodDecl *MDecl = dyn_cast<CXXMethodDecl>(FDecl)) {
+    const CXXRecordDecl *RDecl = MDecl->getParent();
+    if (RDecl->getName() != "numeric_limits")
+      return false;
+
+    if (const NamespaceDecl *NSDecl =
+            dyn_cast<NamespaceDecl>(RDecl->getDeclContext()))
+      return NSDecl->isStdNamespace();
+  }
+
+  return false;
+}
+
+void Sema::CheckInfNaNFunction(const CallExpr *Call,
+                               const FunctionDecl *FDecl) {
+  if (!FDecl->getIdentifier())
+    return;
+
+  FPOptions FPO = Call->getFPFeaturesInEffect(getLangOpts());
+  if (FPO.getNoHonorNaNs() &&
+      (IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered") ||
+       IsInfOrNanFunction(FDecl->getName(), MathCheck::NaN))) {
+    Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled)
+        << 1 << 0 << Call->getSourceRange();
+    return;
+  }
+
+  if (FPO.getNoHonorInfs() &&
+      (IsStdFunction(FDecl, "isinf") || IsStdFunction(FDecl, "isfinite") ||
+       IsInfinityFunction(FDecl) ||
+       IsInfOrNanFunction(FDecl->getName(), MathCheck::Inf))) {
+    Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled)
+        << 0 << 0 << Call->getSourceRange();
+  }
+}
+
+void Sema::CheckAbsoluteValueFunction(const CallExpr *Call,
+                                      const FunctionDecl *FDecl) {
+  if (Call->getNumArgs() != 1)
+    return;
+
+  unsigned AbsKind = getAbsoluteValueFunctionKind(FDecl);
+  bool IsStdAbs = IsStdFunction(FDecl, "abs");
+  if (AbsKind == 0 && !IsStdAbs)
+    return;
+
+  QualType ArgType = Call->getArg(0)->IgnoreParenImpCasts()->getType();
+  QualType ParamType = Call->getArg(0)->getType();
+
+  // Unsigned types cannot be negative.  Suggest removing the absolute value
+  // function call.
+  if (ArgType->isUnsignedIntegerType()) {
+    std::string FunctionName =
+        IsStdAbs ? "std::abs" : Context.BuiltinInfo.getName(AbsKind);
+    Diag(Call->getExprLoc(), diag::warn_unsigned_abs) << ArgType << ParamType;
+    Diag(Call->getExprLoc(), diag::note_remove_abs)
+        << FunctionName
+        << FixItHint::CreateRemoval(Call->getCallee()->getSourceRange());
+    return;
+  }
+
+  // Taking the absolute value of a pointer is very suspicious, they probably
+  // wanted to index into an array, dereference a pointer, call a function, etc.
+  if (ArgType->isPointerType() || ArgType->canDecayToPointerType()) {
+    unsigned DiagType = 0;
+    if (ArgType->isFunctionType())
+      DiagType = 1;
+    else if (ArgType->isArrayType())
+      DiagType = 2;
+
+    Diag(Call->getExprLoc(), diag::warn_pointer_abs) << DiagType << ArgType;
+    return;
+  }
+
+  // std::abs has overloads which prevent most of the absolute value problems
+  // from occurring.
+  if (IsStdAbs)
+    return;
+
+  AbsoluteValueKind ArgValueKind = getAbsoluteValueKind(ArgType);
+  AbsoluteValueKind ParamValueKind = getAbsoluteValueKind(ParamType);
+
+  // The argument and parameter are the same kind.  Check if they are the right
+  // size.
+  if (ArgValueKind == ParamValueKind) {
+    if (Context.getTypeSize(ArgType) <= Context.getTypeSize(ParamType))
+      return;
+
+    unsigned NewAbsKind = getBestAbsFunction(Context, ArgType, AbsKind);
+    Diag(Call->getExprLoc(), diag::warn_abs_too_small)
+        << FDecl << ArgType << ParamType;
+
+    if (NewAbsKind == 0)
+      return;
+
+    emitReplacement(*this, Call->getExprLoc(),
+                    Call->getCallee()->getSourceRange(), NewAbsKind, ArgType);
+    return;
+  }
+
+  // ArgValueKind != ParamValueKind
+  // The wrong type of absolute value function was used.  Attempt to find the
+  // proper one.
+  unsigned NewAbsKind = changeAbsFunction(AbsKind, ArgValueKind);
+  NewAbsKind = getBestAbsFunction(Context, ArgType, NewAbsKind);
+  if (NewAbsKind == 0)
+    return;
+
+  Diag(Call->getExprLoc(), diag::warn_wrong_absolute_value_type)
+      << FDecl << ParamValueKind << ArgValueKind;
+
+  emitReplacement(*this, Call->getExprLoc(),
+                  Call->getCallee()->getSourceRange(), NewAbsKind, ArgType);
+}
+
+//===--- CHECK: Warn on use of std::max and unsigned zero. r---------------===//
+void Sema::CheckMaxUnsignedZero(const CallExpr *Call,
+                                const FunctionDecl *FDecl) {
+  if (!Call || !FDecl) return;
+
+  // Ignore template specializations and macros.
+  if (inTemplateInstantiation()) return;
+  if (Call->getExprLoc().isMacroID()) return;
+
+  // Only care about the one template argument, two function parameter std::max
+  if (Call->getNumArgs() != 2) return;
+  if (!IsStdFunction(FDecl, "max")) return;
+  const auto * ArgList = FDecl->getTemplateSpecializationArgs();
+  if (!ArgList) return;
+  if (ArgList->size() != 1) return;
+
+  // Check that template type argument is unsigned integer.
+  const auto& TA = ArgList->get(0);
+  if (TA.getKind() != TemplateArgument::Type) return;
+  QualType ArgType = TA.getAsType();
+  if (!ArgType->isUnsignedIntegerType()) return;
+
+  // See if either argument is a literal zero.
+  auto IsLiteralZeroArg = [](const Expr* E) -> bool {
+    const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E);
+    if (!MTE) return false;
+    const auto *Num = dyn_cast<IntegerLiteral>(MTE->getSubExpr());
+    if (!Num) return false;
+    if (Num->getValue() != 0) return false;
+    return true;
+  };
+
+  const Expr *FirstArg = Call->getArg(0);
+  const Expr *SecondArg = Call->getArg(1);
+  const bool IsFirstArgZero = IsLiteralZeroArg(FirstArg);
+  const bool IsSecondArgZero = IsLiteralZeroArg(SecondArg);
+
+  // Only warn when exactly one argument is zero.
+  if (IsFirstArgZero == IsSecondArgZero) return;
+
+  SourceRange FirstRange = FirstArg->getSourceRange();
+  SourceRange SecondRange = SecondArg->getSourceRange();
+
+  SourceRange ZeroRange = IsFirstArgZero ? FirstRange : SecondRange;
+
+  Diag(Call->getExprLoc(), diag::warn_max_unsigned_zero)
+      << IsFirstArgZero << Call->getCallee()->getSourceRange() << ZeroRange;
+
+  // Deduce what parts to remove so that "std::max(0u, foo)" becomes "(foo)".
+  SourceRange RemovalRange;
+  if (IsFirstArgZero) {
+    RemovalRange = SourceRange(FirstRange.getBegin(),
+                               SecondRange.getBegin().getLocWithOffset(-1));
+  } else {
+    RemovalRange = SourceRange(getLocForEndOfToken(FirstRange.getEnd()),
+                               SecondRange.getEnd());
+  }
+
+  Diag(Call->getExprLoc(), diag::note_remove_max_call)
+        << FixItHint::CreateRemoval(Call->getCallee()->getSourceRange())
+        << FixItHint::CreateRemoval(RemovalRange);
+}
+
+//===--- CHECK: Standard memory functions ---------------------------------===//
+
+/// Takes the expression passed to the size_t parameter of functions
+/// such as memcmp, strncat, etc and warns if it's a comparison.
+///
+/// This is to catch typos like `if (memcmp(&a, &b, sizeof(a) > 0))`.
+static bool CheckMemorySizeofForComparison(Sema &S, const Expr *E,
+                                           const IdentifierInfo *FnName,
+                                           SourceLocation FnLoc,
+                                           SourceLocation RParenLoc) {
+  const auto *Size = dyn_cast<BinaryOperator>(E);
+  if (!Size)
+    return false;
+
+  // if E is binop and op is <=>, >, <, >=, <=, ==, &&, ||:
+  if (!Size->isComparisonOp() && !Size->isLogicalOp())
+    return false;
+
+  SourceRange SizeRange = Size->getSourceRange();
+  S.Diag(Size->getOperatorLoc(), diag::warn_memsize_comparison)
+      << SizeRange << FnName;
+  S.Diag(FnLoc, diag::note_memsize_comparison_paren)
+      << FnName
+      << FixItHint::CreateInsertion(
+             S.getLocForEndOfToken(Size->getLHS()->getEndLoc()), ")")
+      << FixItHint::CreateRemoval(RParenLoc);
+  S.Diag(SizeRange.getBegin(), diag::note_memsize_comparison_cast_silence)
+      << FixItHint::CreateInsertion(SizeRange.getBegin(), "(size_t)(")
+      << FixItHint::CreateInsertion(S.getLocForEndOfToken(SizeRange.getEnd()),
+                                    ")");
+
+  return true;
+}
+
+/// Determine whether the given type is or contains a dynamic class type
+/// (e.g., whether it has a vtable).
+static const CXXRecordDecl *getContainedDynamicClass(QualType T,
+                                                     bool &IsContained) {
+  // Look through array types while ignoring qualifiers.
+  const Type *Ty = T->getBaseElementTypeUnsafe();
+  IsContained = false;
+
+  const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+  RD = RD ? RD->getDefinition() : nullptr;
+  if (!RD || RD->isInvalidDecl())
+    return nullptr;
+
+  if (RD->isDynamicClass())
+    return RD;
+
+  // Check all the fields.  If any bases were dynamic, the class is dynamic.
+  // It's impossible for a class to transitively contain itself by value, so
+  // infinite recursion is impossible.
+  for (auto *FD : RD->fields()) {
+    bool SubContained;
+    if (const CXXRecordDecl *ContainedRD =
+            getContainedDynamicClass(FD->getType(), SubContained)) {
+      IsContained = true;
+      return ContainedRD;
+    }
+  }
+
+  return nullptr;
+}
+
+static const UnaryExprOrTypeTraitExpr *getAsSizeOfExpr(const Expr *E) {
+  if (const auto *Unary = dyn_cast<UnaryExprOrTypeTraitExpr>(E))
+    if (Unary->getKind() == UETT_SizeOf)
+      return Unary;
+  return nullptr;
+}
+
+/// If E is a sizeof expression, returns its argument expression,
+/// otherwise returns NULL.
+static const Expr *getSizeOfExprArg(const Expr *E) {
+  if (const UnaryExprOrTypeTraitExpr *SizeOf = getAsSizeOfExpr(E))
+    if (!SizeOf->isArgumentType())
+      return SizeOf->getArgumentExpr()->IgnoreParenImpCasts();
+  return nullptr;
+}
+
+/// If E is a sizeof expression, returns its argument type.
+static QualType getSizeOfArgType(const Expr *E) {
+  if (const UnaryExprOrTypeTraitExpr *SizeOf = getAsSizeOfExpr(E))
+    return SizeOf->getTypeOfArgument();
+  return QualType();
+}
+
+namespace {
+
+struct SearchNonTrivialToInitializeField
+    : DefaultInitializedTypeVisitor<SearchNonTrivialToInitializeField> {
+  using Super =
+      DefaultInitializedTypeVisitor<SearchNonTrivialToInitializeField>;
+
+  SearchNonTrivialToInitializeField(const Expr *E, Sema &S) : E(E), S(S) {}
+
+  void visitWithKind(QualType::PrimitiveDefaultInitializeKind PDIK, QualType FT,
+                     SourceLocation SL) {
+    if (const auto *AT = asDerived().getContext().getAsArrayType(FT)) {
+      asDerived().visitArray(PDIK, AT, SL);
+      return;
+    }
+
+    Super::visitWithKind(PDIK, FT, SL);
+  }
+
+  void visitARCStrong(QualType FT, SourceLocation SL) {
+    S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 1);
+  }
+  void visitARCWeak(QualType FT, SourceLocation SL) {
+    S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 1);
+  }
+  void visitStruct(QualType FT, SourceLocation SL) {
+    for (const FieldDecl *FD : FT->castAsRecordDecl()->fields())
+      visit(FD->getType(), FD->getLocation());
+  }
+  void visitArray(QualType::PrimitiveDefaultInitializeKind PDIK,
+                  const ArrayType *AT, SourceLocation SL) {
+    visit(getContext().getBaseElementType(AT), SL);
+  }
+  void visitTrivial(QualType FT, SourceLocation SL) {}
+
+  static void diag(QualType RT, const Expr *E, Sema &S) {
+    SearchNonTrivialToInitializeField(E, S).visitStruct(RT, SourceLocation());
+  }
+
+  ASTContext &getContext() { return S.getASTContext(); }
+
+  const Expr *E;
+  Sema &S;
+};
+
+struct SearchNonTrivialToCopyField
+    : CopiedTypeVisitor<SearchNonTrivialToCopyField, false> {
+  using Super = CopiedTypeVisitor<SearchNonTrivialToCopyField, false>;
+
+  SearchNonTrivialToCopyField(const Expr *E, Sema &S) : E(E), S(S) {}
+
+  void visitWithKind(QualType::PrimitiveCopyKind PCK, QualType FT,
+                     SourceLocation SL) {
+    if (const auto *AT = asDerived().getContext().getAsArrayType(FT)) {
+      asDerived().visitArray(PCK, AT, SL);
+      return;
+    }
+
+    Super::visitWithKind(PCK, FT, SL);
+  }
+
+  void visitARCStrong(QualType FT, SourceLocation SL) {
+    S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0);
+  }
+  void visitARCWeak(QualType FT, SourceLocation SL) {
+    S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0);
+  }
+  void visitPtrAuth(QualType FT, SourceLocation SL) {
+    S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0);
+  }
+  void visitStruct(QualType FT, SourceLocation SL) {
+    for (const FieldDecl *FD : FT->castAsRecordDecl()->fields())
+      visit(FD->getType(), FD->getLocation());
+  }
+  void visitArray(QualType::PrimitiveCopyKind PCK, const ArrayType *AT,
+                  SourceLocation SL) {
+    visit(getContext().getBaseElementType(AT), SL);
+  }
+  void preVisit(QualType::PrimitiveCopyKind PCK, QualType FT,
+                SourceLocation SL) {}
+  void visitTrivial(QualType FT, SourceLocation SL) {}
+  void visitVolatileTrivial(QualType FT, SourceLocation SL) {}
+
+  static void diag(QualType RT, const Expr *E, Sema &S) {
+    SearchNonTrivialToCopyField(E, S).visitStruct(RT, SourceLocation());
+  }
+
+  ASTContext &getContext() { return S.getASTContext(); }
+
+  const Expr *E;
+  Sema &S;
+};
+
+}
+
+/// Detect if \c SizeofExpr is likely to calculate the sizeof an object.
+static bool doesExprLikelyComputeSize(const Expr *SizeofExpr) {
+  SizeofExpr = SizeofExpr->IgnoreParenImpCasts();
+
+  if (const auto *BO = dyn_cast<BinaryOperator>(SizeofExpr)) {
+    if (BO->getOpcode() != BO_Mul && BO->getOpcode() != BO_Add)
+      return false;
+
+    return doesExprLikelyComputeSize(BO->getLHS()) ||
+           doesExprLikelyComputeSize(BO->getRHS());
+  }
+
+  return getAsSizeOfExpr(SizeofExpr) != nullptr;
+}
+
+/// Check if the ArgLoc originated from a macro passed to the call at CallLoc.
+///
+/// \code
+///   #define MACRO 0
+///   foo(MACRO);
+///   foo(0);
+/// \endcode
+///
+/// This should return true for the first call to foo, but not for the second
+/// (regardless of whether foo is a macro or function).
+static bool isArgumentExpandedFromMacro(SourceManager &SM,
+                                        SourceLocation CallLoc,
+                                        SourceLocation ArgLoc) {
+  if (!CallLoc.isMacroID())
+    return SM.getFileID(CallLoc) != SM.getFileID(ArgLoc);
+
+  return SM.getFileID(SM.getImmediateMacroCallerLoc(CallLoc)) !=
+         SM.getFileID(SM.getImmediateMacroCallerLoc(ArgLoc));
+}
+
+/// Diagnose cases like 'memset(buf, sizeof(buf), 0)', which should have the
+/// last two arguments transposed.
+static void CheckMemaccessSize(Sema &S, unsigned BId, const CallExpr *Call) {
+  if (BId != Builtin::BImemset && BId != Builtin::BIbzero)
+    return;
+
+  const Expr *SizeArg =
+    Call->getArg(BId == Builtin::BImemset ? 2 : 1)->IgnoreImpCasts();
+
+  auto isLiteralZero = [](const Expr *E) {
+    return (isa<IntegerLiteral>(E) &&
+            cast<IntegerLiteral>(E)->getValue() == 0) ||
+           (isa<CharacterLiteral>(E) &&
+            cast<CharacterLiteral>(E)->getValue() == 0);
+  };
+
+  // If we're memsetting or bzeroing 0 bytes, then this is likely an error.
+  SourceLocation CallLoc = Call->getRParenLoc();
+  SourceManager &SM = S.getSourceManager();
+  if (isLiteralZero(SizeArg) &&
+      !isArgumentExpandedFromMacro(SM, CallLoc, SizeArg->getExprLoc())) {
+
+    SourceLocation DiagLoc = SizeArg->getExprLoc();
+
+    // Some platforms #define bzero to __builtin_memset. See if this is the
+    // case, and if so, emit a better diagnostic.
+    if (BId == Builtin::BIbzero ||
+        (CallLoc.isMacroID() && Lexer::getImmediateMacroName(
+                                    CallLoc, SM, S.getLangOpts()) == "bzero")) {
+      S.Diag(DiagLoc, diag::warn_suspicious_bzero_size);
+      S.Diag(DiagLoc, diag::note_suspicious_bzero_size_silence);
+    } else if (!isLiteralZero(Call->getArg(1)->IgnoreImpCasts())) {
+      S.Diag(DiagLoc, diag::warn_suspicious_sizeof_memset) << 0;
+      S.Diag(DiagLoc, diag::note_suspicious_sizeof_memset_silence) << 0;
+    }
+    return;
+  }
+
+  // If the second argument to a memset is a sizeof expression and the third
+  // isn't, this is also likely an error. This should catch
+  // 'memset(buf, sizeof(buf), 0xff)'.
+  if (BId == Builtin::BImemset &&
+      doesExprLikelyComputeSize(Call->getArg(1)) &&
+      !doesExprLikelyComputeSize(Call->getArg(2))) {
+    SourceLocation DiagLoc = Call->getArg(1)->getExprLoc();
+    S.Diag(DiagLoc, diag::warn_suspicious_sizeof_memset) << 1;
+    S.Diag(DiagLoc, diag::note_suspicious_sizeof_memset_silence) << 1;
+    return;
+  }
+}
+
+void Sema::CheckMemaccessArguments(const CallExpr *Call,
+                                   unsigned BId,
+                                   IdentifierInfo *FnName) {
+  assert(BId != 0);
+
+  // It is possible to have a non-standard definition of memset.  Validate
+  // we have enough arguments, and if not, abort further checking.
+  unsigned ExpectedNumArgs =
+      (BId == Builtin::BIstrndup || BId == Builtin::BIbzero ? 2 : 3);
+  if (Call->getNumArgs() < ExpectedNumArgs)
+    return;
+
+  unsigned LastArg = (BId == Builtin::BImemset || BId == Builtin::BIbzero ||
+                      BId == Builtin::BIstrndup ? 1 : 2);
+  unsigned LenArg =
+      (BId == Builtin::BIbzero || BId == Builtin::BIstrndup ? 1 : 2);
+  const Expr *LenExpr = Call->getArg(LenArg)->IgnoreParenImpCasts();
+
+  if (CheckMemorySizeofForComparison(*this, LenExpr, FnName,
+                                     Call->getBeginLoc(), Call->getRParenLoc()))
+    return;
+
+  // Catch cases like 'memset(buf, sizeof(buf), 0)'.
+  CheckMemaccessSize(*this, BId, Call);
+
+  // We have special checking when the length is a sizeof expression.
+  QualType SizeOfArgTy = getSizeOfArgType(LenExpr);
+  const Expr *SizeOfArg = getSizeOfExprArg(LenExpr);
+  llvm::FoldingSetNodeID SizeOfArgID;
+
+  // Although widely used, 'bzero' is not a standard function. Be more strict
+  // with the argument types before allowing diagnostics and only allow the
+  // form bzero(ptr, sizeof(...)).
+  QualType FirstArgTy = Call->getArg(0)->IgnoreParenImpCasts()->getType();
+  if (BId == Builtin::BIbzero && !FirstArgTy->getAs<PointerType>())
+    return;
+
+  for (unsigned ArgIdx = 0; ArgIdx != LastArg; ++ArgIdx) {
+    const Expr *Dest = Call->getArg(ArgIdx)->IgnoreParenImpCasts();
+    SourceRange ArgRange = Call->getArg(ArgIdx)->getSourceRange();
+
+    QualType DestTy = Dest->getType();
+    QualType PointeeTy;
+    if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) {
+      PointeeTy = DestPtrTy->getPointeeType();
+
+      // Never warn about void type pointers. This can be used to suppress
+      // false positives.
+      if (PointeeTy->isVoidType())
+        continue;
+
+      // Catch "memset(p, 0, sizeof(p))" -- needs to be sizeof(*p). Do this by
+      // actually comparing the expressions for equality. Because computing the
+      // expression IDs can be expensive, we only do this if the diagnostic is
+      // enabled.
+      if (SizeOfArg &&
+          !Diags.isIgnored(diag::warn_sizeof_pointer_expr_memaccess,
+                           SizeOfArg->getExprLoc())) {
+        // We only compute IDs for expressions if the warning is enabled, and
+        // cache the sizeof arg's ID.
+        if (SizeOfArgID == llvm::FoldingSetNodeID())
+          SizeOfArg->Profile(SizeOfArgID, Context, true);
+        llvm::FoldingSetNodeID DestID;
+        Dest->Profile(DestID, Context, true);
+        if (DestID == SizeOfArgID) {
+          // TODO: For strncpy() and friends, this could suggest sizeof(dst)
+          //       over sizeof(src) as well.
+          unsigned ActionIdx = 0; // Default is to suggest dereferencing.
+          StringRef ReadableName = FnName->getName();
+
+          if (const UnaryOperator *UnaryOp = dyn_cast<UnaryOperator>(Dest))
+            if (UnaryOp->getOpcode() == UO_AddrOf)
+              ActionIdx = 1; // If its an address-of operator, just remove it.
+          if (!PointeeTy->isIncompleteType() &&
+              (Context.getTypeSize(PointeeTy) == Context.getCharWidth()))
+            ActionIdx = 2; // If the pointee's size is sizeof(char),
+                           // suggest an explicit length.
+
+          // If the function is defined as a builtin macro, do not show macro
+          // expansion.
+          SourceLocation SL = SizeOfArg->getExprLoc();
+          SourceRange DSR = Dest->getSourceRange();
+          SourceRange SSR = SizeOfArg->getSourceRange();
+          SourceManager &SM = getSourceManager();
+
+          if (SM.isMacroArgExpansion(SL)) {
+            ReadableName = Lexer::getImmediateMacroName(SL, SM, LangOpts);
+            SL = SM.getSpellingLoc(SL);
+            DSR = SourceRange(SM.getSpellingLoc(DSR.getBegin()),
+                             SM.getSpellingLoc(DSR.getEnd()));
+            SSR = SourceRange(SM.getSpellingLoc(SSR.getBegin()),
+                             SM.getSpellingLoc(SSR.getEnd()));
+          }
+
+          DiagRuntimeBehavior(SL, SizeOfArg,
+                              PDiag(diag::warn_sizeof_pointer_expr_memaccess)
+                                << ReadableName
+                                << PointeeTy
+                                << DestTy
+                                << DSR
+                                << SSR);
+          DiagRuntimeBehavior(SL, SizeOfArg,
+                         PDiag(diag::warn_sizeof_pointer_expr_memaccess_note)
+                                << ActionIdx
+                                << SSR);
+
+          break;
+        }
+      }
+
+      // Also check for cases where the sizeof argument is the exact same
+      // type as the memory argument, and where it points to a user-defined
+      // record type.
+      if (SizeOfArgTy != QualType()) {
+        if (PointeeTy->isRecordType() &&
+            Context.typesAreCompatible(SizeOfArgTy, DestTy)) {
+          DiagRuntimeBehavior(LenExpr->getExprLoc(), Dest,
+                              PDiag(diag::warn_sizeof_pointer_type_memaccess)
+                                << FnName << SizeOfArgTy << ArgIdx
+                                << PointeeTy << Dest->getSourceRange()
+                                << LenExpr->getSourceRange());
+          break;
+        }
+      }
+    } else if (DestTy->isArrayType()) {
+      PointeeTy = DestTy;
+    }
+
+    if (PointeeTy == QualType())
+      continue;
+
+    // Always complain about dynamic classes.
+    bool IsContained;
+    if (const CXXRecordDecl *ContainedRD =
+            getContainedDynamicClass(PointeeTy, IsContained)) {
+
+      unsigned OperationType = 0;
+      const bool IsCmp = BId == Builtin::BImemcmp || BId == Builtin::BIbcmp;
+      // "overwritten" if we're warning about the destination for any call
+      // but memcmp; otherwise a verb appropriate to the call.
+      if (ArgIdx != 0 || IsCmp) {
+        if (BId == Builtin::BImemcpy)
+          OperationType = 1;
+        else if(BId == Builtin::BImemmove)
+          OperationType = 2;
+        else if (IsCmp)
+          OperationType = 3;
+      }
+
+      DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
+                          PDiag(diag::warn_dyn_class_memaccess)
+                              << (IsCmp ? ArgIdx + 2 : ArgIdx) << FnName
+                              << IsContained << ContainedRD << OperationType
+                              << Call->getCallee()->getSourceRange());
+    } else if (PointeeTy.hasNonTrivialObjCLifetime() &&
+             BId != Builtin::BImemset)
+      DiagRuntimeBehavior(
+        Dest->getExprLoc(), Dest,
+        PDiag(diag::warn_arc_object_memaccess)
+          << ArgIdx << FnName << PointeeTy
+          << Call->getCallee()->getSourceRange());
+    else if (const auto *RD = PointeeTy->getAsRecordDecl()) {
+
+      // FIXME: Do not consider incomplete types even though they may be
+      // completed later. GCC does not diagnose such code, but we may want to
+      // consider diagnosing it in the future, perhaps under a different, but
+      // related, diagnostic group.
+      bool NonTriviallyCopyableCXXRecord =
+          getLangOpts().CPlusPlus && RD->isCompleteDefinition() &&
+          !PointeeTy.isTriviallyCopyableType(Context);
+
+      if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) &&
+          RD->isNonTrivialToPrimitiveDefaultInitialize()) {
+        DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
+                            PDiag(diag::warn_cstruct_memaccess)
+                                << ArgIdx << FnName << PointeeTy << 0);
+        SearchNonTrivialToInitializeField::diag(PointeeTy, Dest, *this);
+      } else if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) &&
+                 NonTriviallyCopyableCXXRecord && ArgIdx == 0) {
+        // FIXME: Limiting this warning to dest argument until we decide
+        // whether it's valid for source argument too.
+        DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
+                            PDiag(diag::warn_cxxstruct_memaccess)
+                                << FnName << PointeeTy);
+      } else if ((BId == Builtin::BImemcpy || BId == Builtin::BImemmove) &&
+                 RD->isNonTrivialToPrimitiveCopy()) {
+        DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
+                            PDiag(diag::warn_cstruct_memaccess)
+                                << ArgIdx << FnName << PointeeTy << 1);
+        SearchNonTrivialToCopyField::diag(PointeeTy, Dest, *this);
+      } else if ((BId == Builtin::BImemcpy || BId == Builtin::BImemmove) &&
+                 NonTriviallyCopyableCXXRecord && ArgIdx == 0) {
+        // FIXME: Limiting this warning to dest argument until we decide
+        // whether it's valid for source argument too.
+        DiagRuntimeBehavior(Dest->getExprLoc(), Dest,
+                            PDiag(diag::warn_cxxstruct_memaccess)
+                                << FnName << PointeeTy);
+      } else {
+        continue;
+      }
+    } else
+      continue;
+
+    DiagRuntimeBehavior(
+      Dest->getExprLoc(), Dest,
+      PDiag(diag::note_bad_memaccess_silence)
+        << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)"));
+    break;
+  }
+}
+
+// A little helper routine: ignore addition and subtraction of integer literals.
+// This intentionally does not ignore all integer constant expressions because
+// we don't want to remove sizeof().
+static const Expr *ignoreLiteralAdditions(const Expr *Ex, ASTContext &Ctx) {
+  Ex = Ex->IgnoreParenCasts();
+
+  while (true) {
+    const BinaryOperator * BO = dyn_cast<BinaryOperator>(Ex);
+    if (!BO || !BO->isAdditiveOp())
+      break;
+
+    const Expr *RHS = BO->getRHS()->IgnoreParenCasts();
+    const Expr *LHS = BO->getLHS()->IgnoreParenCasts();
+
+    if (isa<IntegerLiteral>(RHS))
+      Ex = LHS;
+    else if (isa<IntegerLiteral>(LHS))
+      Ex = RHS;
+    else
+      break;
+  }
+
+  return Ex;
+}
+
+static bool isConstantSizeArrayWithMoreThanOneElement(QualType Ty,
+                                                      ASTContext &Context) {
+  // Only handle constant-sized or VLAs, but not flexible members.
+  if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(Ty)) {
+    // Only issue the FIXIT for arrays of size > 1.
+    if (CAT->getZExtSize() <= 1)
+      return false;
+  } else if (!Ty->isVariableArrayType()) {
+    return false;
+  }
+  return true;
+}
+
+void Sema::CheckStrlcpycatArguments(const CallExpr *Call,
+                                    IdentifierInfo *FnName) {
+
+  // Don't crash if the user has the wrong number of arguments
+  unsigned NumArgs = Call->getNumArgs();
+  if ((NumArgs != 3) && (NumArgs != 4))
+    return;
+
+  const Expr *SrcArg = ignoreLiteralAdditions(Call->getArg(1), Context);
+  const Expr *SizeArg = ignoreLiteralAdditions(Call->getArg(2), Context);
+  const Expr *CompareWithSrc = nullptr;
+
+  if (CheckMemorySizeofForComparison(*this, SizeArg, FnName,
+                                     Call->getBeginLoc(), Call->getRParenLoc()))
+    return;
+
+  // Look for 'strlcpy(dst, x, sizeof(x))'
+  if (const Expr *Ex = getSizeOfExprArg(SizeArg))
+    CompareWithSrc = Ex;
+  else {
+    // Look for 'strlcpy(dst, x, strlen(x))'
+    if (const CallExpr *SizeCall = dyn_cast<CallExpr>(SizeArg)) {
+      if (SizeCall->getBuiltinCallee() == Builtin::BIstrlen &&
+          SizeCall->getNumArgs() == 1)
+        CompareWithSrc = ignoreLiteralAdditions(SizeCall->getArg(0), Context);
+    }
+  }
+
+  if (!CompareWithSrc)
+    return;
+
+  // Determine if the argument to sizeof/strlen is equal to the source
+  // argument.  In principle there's all kinds of things you could do
+  // here, for instance creating an == expression and evaluating it with
+  // EvaluateAsBooleanCondition, but this uses a more direct technique:
+  const DeclRefExpr *SrcArgDRE = dyn_cast<DeclRefExpr>(SrcArg);
+  if (!SrcArgDRE)
+    return;
+
+  const DeclRefExpr *CompareWithSrcDRE = dyn_cast<DeclRefExpr>(CompareWithSrc);
+  if (!CompareWithSrcDRE ||
+      SrcArgDRE->getDecl() != CompareWithSrcDRE->getDecl())
+    return;
+
+  const Expr *OriginalSizeArg = Call->getArg(2);
+  Diag(CompareWithSrcDRE->getBeginLoc(), diag::warn_strlcpycat_wrong_size)
+      << OriginalSizeArg->getSourceRange() << FnName;
+
+  // Output a FIXIT hint if the destination is an array (rather than a
+  // pointer to an array).  This could be enhanced to handle some
+  // pointers if we know the actual size, like if DstArg is 'array+2'
+  // we could say 'sizeof(array)-2'.
+  const Expr *DstArg = Call->getArg(0)->IgnoreParenImpCasts();
+  if (!isConstantSizeArrayWithMoreThanOneElement(DstArg->getType(), Context))
+    return;
+
+  SmallString<128> sizeString;
+  llvm::raw_svector_ostream OS(sizeString);
+  OS << "sizeof(";
+  DstArg->printPretty(OS, nullptr, getPrintingPolicy());
+  OS << ")";
+
+  Diag(OriginalSizeArg->getBeginLoc(), diag::note_strlcpycat_wrong_size)
+      << FixItHint::CreateReplacement(OriginalSizeArg->getSourceRange(),
+                                      OS.str());
+}
+
+/// Check if two expressions refer to the same declaration.
+static bool referToTheSameDecl(const Expr *E1, const Expr *E2) {
+  if (const DeclRefExpr *D1 = dyn_cast_or_null<DeclRefExpr>(E1))
+    if (const DeclRefExpr *D2 = dyn_cast_or_null<DeclRefExpr>(E2))
+      return D1->getDecl() == D2->getDecl();
+  return false;
+}
+
+static const Expr *getStrlenExprArg(const Expr *E) {
+  if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
+    const FunctionDecl *FD = CE->getDirectCallee();
+    if (!FD || FD->getMemoryFunctionKind() != Builtin::BIstrlen)
+      return nullptr;
+    return CE->getArg(0)->IgnoreParenCasts();
+  }
+  return nullptr;
+}
+
+void Sema::CheckStrncatArguments(const CallExpr *CE,
+                                 const IdentifierInfo *FnName) {
+  // Don't crash if the user has the wrong number of arguments.
+  if (CE->getNumArgs() < 3)
+    return;
+  const Expr *DstArg = CE->getArg(0)->IgnoreParenCasts();
+  const Expr *SrcArg = CE->getArg(1)->IgnoreParenCasts();
+  const Expr *LenArg = CE->getArg(2)->IgnoreParenCasts();
+
+  if (CheckMemorySizeofForComparison(*this, LenArg, FnName, CE->getBeginLoc(),
+                                     CE->getRParenLoc()))
+    return;
+
+  // Identify common expressions, which are wrongly used as the size argument
+  // to strncat and may lead to buffer overflows.
+  unsigned PatternType = 0;
+  if (const Expr *SizeOfArg = getSizeOfExprArg(LenArg)) {
+    // - sizeof(dst)
+    if (referToTheSameDecl(SizeOfArg, DstArg))
+      PatternType = 1;
+    // - sizeof(src)
+    else if (referToTheSameDecl(SizeOfArg, SrcArg))
+      PatternType = 2;
+  } else if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(LenArg)) {
+    if (BE->getOpcode() == BO_Sub) {
+      const Expr *L = BE->getLHS()->IgnoreParenCasts();
+      const Expr *R = BE->getRHS()->IgnoreParenCasts();
+      // - sizeof(dst) - strlen(dst)
+      if (referToTheSameDecl(DstArg, getSizeOfExprArg(L)) &&
+          referToTheSameDecl(DstArg, getStrlenExprArg(R)))
+        PatternType = 1;
+      // - sizeof(src) - (anything)
+      else if (referToTheSameDecl(SrcArg, getSizeOfExprArg(L)))
+        PatternType = 2;
+    }
+  }
+
+  if (PatternType == 0)
+    return;
+
+  // Generate the diagnostic.
+  SourceLocation SL = LenArg->getBeginLoc();
+  SourceRange SR = LenArg->getSourceRange();
+  SourceManager &SM = getSourceManager();
+
+  // If the function is defined as a builtin macro, do not show macro expansion.
+  if (SM.isMacroArgExpansion(SL)) {
+    SL = SM.getSpellingLoc(SL);
+    SR = SourceRange(SM.getSpellingLoc(SR.getBegin()),
+                     SM.getSpellingLoc(SR.getEnd()));
+  }
+
+  // Check if the destination is an array (rather than a pointer to an array).
+  QualType DstTy = DstArg->getType();
+  bool isKnownSizeArray = isConstantSizeArrayWithMoreThanOneElement(DstTy,
+                                                                    Context);
+  if (!isKnownSizeArray) {
+    if (PatternType == 1)
+      Diag(SL, diag::warn_strncat_wrong_size) << SR;
+    else
+      Diag(SL, diag::warn_strncat_src_size) << SR;
+    return;
+  }
+
+  if (PatternType == 1)
+    Diag(SL, diag::warn_strncat_large_size) << SR;
+  else
+    Diag(SL, diag::warn_strncat_src_size) << SR;
+
+  SmallString<128> sizeString;
+  llvm::raw_svector_ostream OS(sizeString);
+  OS << "sizeof(";
+  DstArg->printPretty(OS, nullptr, getPrintingPolicy());
+  OS << ") - ";
+  OS << "strlen(";
+  DstArg->printPretty(OS, nullptr, getPrintingPolicy());
+  OS << ") - 1";
+
+  Diag(SL, diag::note_strncat_wrong_size)
+    << FixItHint::CreateReplacement(SR, OS.str());
+}
+
+namespace {
+void CheckFreeArgumentsOnLvalue(Sema &S, const std::string &CalleeName,
+                                const UnaryOperator *UnaryExpr, const Decl *D) {
+  if (isa<FieldDecl, FunctionDecl, VarDecl>(D)) {
+    S.Diag(UnaryExpr->getBeginLoc(), diag::warn_free_nonheap_object)
+        << CalleeName << 0 /*object: */ << cast<NamedDecl>(D);
+    return;
+  }
+}
+
+void CheckFreeArgumentsAddressof(Sema &S, const std::string &CalleeName,
+                                 const UnaryOperator *UnaryExpr) {
+  if (const auto *Lvalue = dyn_cast<DeclRefExpr>(UnaryExpr->getSubExpr())) {
+    const Decl *D = Lvalue->getDecl();
+    if (const auto *DD = dyn_cast<DeclaratorDecl>(D)) {
+      if (!DD->getType()->isReferenceType())
+        return CheckFreeArgumentsOnLvalue(S, CalleeName, UnaryExpr, D);
+    }
+  }
+
+  if (const auto *Lvalue = dyn_cast<MemberExpr>(UnaryExpr->getSubExpr()))
+    return CheckFreeArgumentsOnLvalue(S, CalleeName, UnaryExpr,
+                                      Lvalue->getMemberDecl());
+}
+
+void CheckFreeArgumentsPlus(Sema &S, const std::string &CalleeName,
+                            const UnaryOperator *UnaryExpr) {
+  const auto *Lambda = dyn_cast<LambdaExpr>(
+      UnaryExpr->getSubExpr()->IgnoreImplicitAsWritten()->IgnoreParens());
+  if (!Lambda)
+    return;
+
+  S.Diag(Lambda->getBeginLoc(), diag::warn_free_nonheap_object)
+      << CalleeName << 2 /*object: lambda expression*/;
+}
+
+void CheckFreeArgumentsStackArray(Sema &S, const std::string &CalleeName,
+                                  const DeclRefExpr *Lvalue) {
+  const auto *Var = dyn_cast<VarDecl>(Lvalue->getDecl());
+  if (Var == nullptr)
+    return;
+
+  S.Diag(Lvalue->getBeginLoc(), diag::warn_free_nonheap_object)
+      << CalleeName << 0 /*object: */ << Var;
+}
+
+void CheckFreeArgumentsCast(Sema &S, const std::string &CalleeName,
+                            const CastExpr *Cast) {
+  SmallString<128> SizeString;
+  llvm::raw_svector_ostream OS(SizeString);
+
+  clang::CastKind Kind = Cast->getCastKind();
+  if (Kind == clang::CK_BitCast &&
+      !Cast->getSubExpr()->getType()->isFunctionPointerType())
+    return;
+  if (Kind == clang::CK_IntegralToPointer &&
+      !isa<IntegerLiteral>(
+          Cast->getSubExpr()->IgnoreParenImpCasts()->IgnoreParens()))
+    return;
+
+  switch (Cast->getCastKind()) {
+  case clang::CK_BitCast:
+  case clang::CK_IntegralToPointer:
+  case clang::CK_FunctionToPointerDecay:
+    OS << '\'';
+    Cast->printPretty(OS, nullptr, S.getPrintingPolicy());
+    OS << '\'';
+    break;
+  default:
+    return;
+  }
+
+  S.Diag(Cast->getBeginLoc(), diag::warn_free_nonheap_object)
+      << CalleeName << 0 /*object: */ << OS.str();
+}
+} // namespace
+
+void Sema::CheckFreeArguments(const CallExpr *E) {
+  const std::string CalleeName =
+      cast<FunctionDecl>(E->getCalleeDecl())->getQualifiedNameAsString();
+
+  { // Prefer something that doesn't involve a cast to make things simpler.
+    const Expr *Arg = E->getArg(0)->IgnoreParenCasts();
+    if (const auto *UnaryExpr = dyn_cast<UnaryOperator>(Arg))
+      switch (UnaryExpr->getOpcode()) {
+      case UnaryOperator::Opcode::UO_AddrOf:
+        return CheckFreeArgumentsAddressof(*this, CalleeName, UnaryExpr);
+      case UnaryOperator::Opcode::UO_Plus:
+        return CheckFreeArgumentsPlus(*this, CalleeName, UnaryExpr);
+      default:
+        break;
+      }
+
+    if (const auto *Lvalue = dyn_cast<DeclRefExpr>(Arg))
+      if (Lvalue->getType()->isArrayType())
+        return CheckFreeArgumentsStackArray(*this, CalleeName, Lvalue);
+
+    if (const auto *Label = dyn_cast<AddrLabelExpr>(Arg)) {
+      Diag(Label->getBeginLoc(), diag::warn_free_nonheap_object)
+          << CalleeName << 0 /*object: */ << Label->getLabel()->getIdentifier();
+      return;
+    }
+
+    if (isa<BlockExpr>(Arg)) {
+      Diag(Arg->getBeginLoc(), diag::warn_free_nonheap_object)
+          << CalleeName << 1 /*object: block*/;
+      return;
+    }
+  }
+  // Maybe the cast was important, check after the other cases.
+  if (const auto *Cast = dyn_cast<CastExpr>(E->getArg(0)))
+    return CheckFreeArgumentsCast(*this, CalleeName, Cast);
+}
+
+void
+Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType,
+                         SourceLocation ReturnLoc,
+                         bool isObjCMethod,
+                         const AttrVec *Attrs,
+                         const FunctionDecl *FD) {
+  // Check if the return value is null but should not be.
+  if (((Attrs && hasSpecificAttr<ReturnsNonNullAttr>(*Attrs)) ||
+       (!isObjCMethod && isNonNullType(lhsType))) &&
+      CheckNonNullExpr(*this, RetValExp))
+    Diag(ReturnLoc, diag::warn_null_ret)
+      << (isObjCMethod ? 1 : 0) << RetValExp->getSourceRange();
+
+  // C++11 [basic.stc.dynamic.allocation]p4:
+  //   If an allocation function declared with a non-throwing
+  //   exception-specification fails to allocate storage, it shall return
+  //   a null pointer. Any other allocation function that fails to allocate
+  //   storage shall indicate failure only by throwing an exception [...]
+  if (FD) {
+    OverloadedOperatorKind Op = FD->getOverloadedOperator();
+    if (Op == OO_New || Op == OO_Array_New) {
+      const FunctionProtoType *Proto
+        = FD->getType()->castAs<FunctionProtoType>();
+      if (!Proto->isNothrow(/*ResultIfDependent*/true) &&
+          CheckNonNullExpr(*this, RetValExp))
+        Diag(ReturnLoc, diag::warn_operator_new_returns_null)
+          << FD << getLangOpts().CPlusPlus11;
+    }
+  }
+
+  if (RetValExp && RetValExp->getType()->isWebAssemblyTableType()) {
+    Diag(ReturnLoc, diag::err_wasm_table_art) << 1;
+  }
+
+  // PPC MMA non-pointer types are not allowed as return type. Checking the type
+  // here prevent the user from using a PPC MMA type as trailing return type.
+  if (Context.getTargetInfo().getTriple().isPPC64())
+    PPC().CheckPPCMMAType(RetValExp->getType(), ReturnLoc);
+}
+
+void Sema::CheckFloatComparison(SourceLocation Loc, const Expr *LHS,
+                                const Expr *RHS, BinaryOperatorKind Opcode) {
+  if (!BinaryOperator::isEqualityOp(Opcode))
+    return;
+
+  // Match and capture subexpressions such as "(float) X == 0.1".
+  const FloatingLiteral *FPLiteral;
+  const CastExpr *FPCast;
+  auto getCastAndLiteral = [&FPLiteral, &FPCast](const Expr *L, const Expr *R) {
+    FPLiteral = dyn_cast<FloatingLiteral>(L->IgnoreParens());
+    FPCast = dyn_cast<CastExpr>(R->IgnoreParens());
+    return FPLiteral && FPCast;
+  };
+
+  if (getCastAndLiteral(LHS, RHS) || getCastAndLiteral(RHS, LHS)) {
+    auto *SourceTy = FPCast->getSubExpr()->getType()->getAs<BuiltinType>();
+    auto *TargetTy = FPLiteral->getType()->getAs<BuiltinType>();
+    if (SourceTy && TargetTy && SourceTy->isFloatingPoint() &&
+        TargetTy->isFloatingPoint()) {
+      bool Lossy;
+      llvm::APFloat TargetC = FPLiteral->getValue();
+      TargetC.convert(Context.getFloatTypeSemantics(QualType(SourceTy, 0)),
+                      llvm::APFloat::rmNearestTiesToEven, &Lossy);
+      if (Lossy) {
+        // If the literal cannot be represented in the source type, then a
+        // check for == is always false and check for != is always true.
+        Diag(Loc, diag::warn_float_compare_literal)
+            << (Opcode == BO_EQ) << QualType(SourceTy, 0)
+            << LHS->getSourceRange() << RHS->getSourceRange();
+        return;
+      }
+    }
+  }
+
+  // Match a more general floating-point equality comparison (-Wfloat-equal).
+  const Expr *LeftExprSansParen = LHS->IgnoreParenImpCasts();
+  const Expr *RightExprSansParen = RHS->IgnoreParenImpCasts();
+
+  // Special case: check for x == x (which is OK).
+  // Do not emit warnings for such cases.
+  if (const auto *DRL = dyn_cast<DeclRefExpr>(LeftExprSansParen))
+    if (const auto *DRR = dyn_cast<DeclRefExpr>(RightExprSansParen))
+      if (DRL->getDecl() == DRR->getDecl())
+        return;
+
+  // Special case: check for comparisons against literals that can be exactly
+  //  represented by APFloat.  In such cases, do not emit a warning.  This
+  //  is a heuristic: often comparison against such literals are used to
+  //  detect if a value in a variable has not changed.  This clearly can
+  //  lead to false negatives.
+  if (const auto *FLL = dyn_cast<FloatingLiteral>(LeftExprSansParen)) {
+    if (FLL->isExact())
+      return;
+  } else if (const auto *FLR = dyn_cast<FloatingLiteral>(RightExprSansParen))
+    if (FLR->isExact())
+      return;
+
+  // Check for comparisons with builtin types.
+  if (const auto *CL = dyn_cast<CallExpr>(LeftExprSansParen);
+      CL && CL->getBuiltinCallee())
+    return;
+
+  if (const auto *CR = dyn_cast<CallExpr>(RightExprSansParen);
+      CR && CR->getBuiltinCallee())
+    return;
+
+  // Emit the diagnostic.
+  Diag(Loc, diag::warn_floatingpoint_eq)
+    << LHS->getSourceRange() << RHS->getSourceRange();
+}
+
+//===--- CHECK: Integer mixed-sign comparisons (-Wsign-compare) --------===//
+//===--- CHECK: Lossy implicit conversions (-Wconversion) --------------===//
+
+namespace {
+
+/// Structure recording the 'active' range of an integer-valued
+/// expression.
+struct IntRange {
+  /// The number of bits active in the int. Note that this includes exactly one
+  /// sign bit if !NonNegative.
+  unsigned Width;
+
+  /// True if the int is known not to have negative values. If so, all leading
+  /// bits before Width are known zero, otherwise they are known to be the
+  /// same as the MSB within Width.
+  bool NonNegative;
+
+  IntRange(unsigned Width, bool NonNegative)
+      : Width(Width), NonNegative(NonNegative) {}
+
+  /// Number of bits excluding the sign bit.
+  unsigned valueBits() const {
+    return NonNegative ? Width : Width - 1;
+  }
+
+  /// Returns the range of the bool type.
+  static IntRange forBoolType() {
+    return IntRange(1, true);
+  }
+
+  /// Returns the range of an opaque value of the given integral type.
+  static IntRange forValueOfType(ASTContext &C, QualType T) {
+    return forValueOfCanonicalType(C,
+                          T->getCanonicalTypeInternal().getTypePtr());
+  }
+
+  /// Returns the range of an opaque value of a canonical integral type.
+  static IntRange forValueOfCanonicalType(ASTContext &C, const Type *T) {
+    assert(T->isCanonicalUnqualified());
+
+    if (const auto *VT = dyn_cast<VectorType>(T))
+      T = VT->getElementType().getTypePtr();
+    if (const auto *CT = dyn_cast<ComplexType>(T))
+      T = CT->getElementType().getTypePtr();
+    if (const auto *AT = dyn_cast<AtomicType>(T))
+      T = AT->getValueType().getTypePtr();
+
+    if (!C.getLangOpts().CPlusPlus) {
+      // For enum types in C code, use the underlying datatype.
+      if (const auto *ED = T->getAsEnumDecl())
+        T = ED->getIntegerType().getDesugaredType(C).getTypePtr();
+    } else if (auto *Enum = T->getAsEnumDecl()) {
+      // For enum types in C++, use the known bit width of the enumerators.
+      // In C++11, enums can have a fixed underlying type. Use this type to
+      // compute the range.
+      if (Enum->isFixed()) {
+        return IntRange(C.getIntWidth(QualType(T, 0)),
+                        !Enum->getIntegerType()->isSignedIntegerType());
+      }
+
+      unsigned NumPositive = Enum->getNumPositiveBits();
+      unsigned NumNegative = Enum->getNumNegativeBits();
+
+      if (NumNegative == 0)
+        return IntRange(NumPositive, true/*NonNegative*/);
+      else
+        return IntRange(std::max(NumPositive + 1, NumNegative),
+                        false/*NonNegative*/);
+    }
+
+    if (const auto *EIT = dyn_cast<BitIntType>(T))
+      return IntRange(EIT->getNumBits(), EIT->isUnsigned());
+
+    const BuiltinType *BT = cast<BuiltinType>(T);
+    assert(BT->isInteger());
+
+    return IntRange(C.getIntWidth(QualType(T, 0)), BT->isUnsignedInteger());
+  }
+
+  /// Returns the "target" range of a canonical integral type, i.e.
+  /// the range of values expressible in the type.
+  ///
+  /// This matches forValueOfCanonicalType except that enums have the
+  /// full range of their type, not the range of their enumerators.
+  static IntRange forTargetOfCanonicalType(ASTContext &C, const Type *T) {
+    assert(T->isCanonicalUnqualified());
+
+    if (const VectorType *VT = dyn_cast<VectorType>(T))
+      T = VT->getElementType().getTypePtr();
+    if (const ComplexType *CT = dyn_cast<ComplexType>(T))
+      T = CT->getElementType().getTypePtr();
+    if (const AtomicType *AT = dyn_cast<AtomicType>(T))
+      T = AT->getValueType().getTypePtr();
+    if (const auto *ED = T->getAsEnumDecl())
+      T = C.getCanonicalType(ED->getIntegerType()).getTypePtr();
+
+    if (const auto *EIT = dyn_cast<BitIntType>(T))
+      return IntRange(EIT->getNumBits(), EIT->isUnsigned());
+
+    const BuiltinType *BT = cast<BuiltinType>(T);
+    assert(BT->isInteger());
+
+    return IntRange(C.getIntWidth(QualType(T, 0)), BT->isUnsignedInteger());
+  }
+
+  /// Returns the supremum of two ranges: i.e. their conservative merge.
+  static IntRange join(IntRange L, IntRange R) {
+    bool Unsigned = L.NonNegative && R.NonNegative;
+    return IntRange(std::max(L.valueBits(), R.valueBits()) + !Unsigned,
+                    L.NonNegative && R.NonNegative);
+  }
+
+  /// Return the range of a bitwise-AND of the two ranges.
+  static IntRange bit_and(IntRange L, IntRange R) {
+    unsigned Bits = std::max(L.Width, R.Width);
+    bool NonNegative = false;
+    if (L.NonNegative) {
+      Bits = std::min(Bits, L.Width);
+      NonNegative = true;
+    }
+    if (R.NonNegative) {
+      Bits = std::min(Bits, R.Width);
+      NonNegative = true;
+    }
+    return IntRange(Bits, NonNegative);
+  }
+
+  /// Return the range of a sum of the two ranges.
+  static IntRange sum(IntRange L, IntRange R) {
+    bool Unsigned = L.NonNegative && R.NonNegative;
+    return IntRange(std::max(L.valueBits(), R.valueBits()) + 1 + !Unsigned,
+                    Unsigned);
+  }
+
+  /// Return the range of a difference of the two ranges.
+  static IntRange difference(IntRange L, IntRange R) {
+    // We need a 1-bit-wider range if:
+    //   1) LHS can be negative: least value can be reduced.
+    //   2) RHS can be negative: greatest value can be increased.
+    bool CanWiden = !L.NonNegative || !R.NonNegative;
+    bool Unsigned = L.NonNegative && R.Width == 0;
+    return IntRange(std::max(L.valueBits(), R.valueBits()) + CanWiden +
+                        !Unsigned,
+                    Unsigned);
+  }
+
+  /// Return the range of a product of the two ranges.
+  static IntRange product(IntRange L, IntRange R) {
+    // If both LHS and RHS can be negative, we can form
+    //   -2^L * -2^R = 2^(L + R)
+    // which requires L + R + 1 value bits to represent.
+    bool CanWiden = !L.NonNegative && !R.NonNegative;
+    bool Unsigned = L.NonNegative && R.NonNegative;
+    return IntRange(L.valueBits() + R.valueBits() + CanWiden + !Unsigned,
+                    Unsigned);
+  }
+
+  /// Return the range of a remainder operation between the two ranges.
+  static IntRange rem(IntRange L, IntRange R) {
+    // The result of a remainder can't be larger than the result of
+    // either side. The sign of the result is the sign of the LHS.
+    bool Unsigned = L.NonNegative;
+    return IntRange(std::min(L.valueBits(), R.valueBits()) + !Unsigned,
+                    Unsigned);
+  }
+};
+
+} // namespace
+
+static IntRange GetValueRange(llvm::APSInt &value, unsigned MaxWidth) {
+  if (value.isSigned() && value.isNegative())
+    return IntRange(value.getSignificantBits(), false);
+
+  if (value.getBitWidth() > MaxWidth)
+    value = value.trunc(MaxWidth);
+
+  // isNonNegative() just checks the sign bit without considering
+  // signedness.
+  return IntRange(value.getActiveBits(), true);
+}
+
+static IntRange GetValueRange(APValue &result, QualType Ty, unsigned MaxWidth) {
+  if (result.isInt())
+    return GetValueRange(result.getInt(), MaxWidth);
+
+  if (result.isVector()) {
+    IntRange R = GetValueRange(result.getVectorElt(0), Ty, MaxWidth);
+    for (unsigned i = 1, e = result.getVectorLength(); i != e; ++i) {
+      IntRange El = GetValueRange(result.getVectorElt(i), Ty, MaxWidth);
+      R = IntRange::join(R, El);
+    }
+    return R;
+  }
+
+  if (result.isComplexInt()) {
+    IntRange R = GetValueRange(result.getComplexIntReal(), MaxWidth);
+    IntRange I = GetValueRange(result.getComplexIntImag(), MaxWidth);
+    return IntRange::join(R, I);
+  }
+
+  // This can happen with lossless casts to intptr_t of "based" lvalues.
+  // Assume it might use arbitrary bits.
+  // FIXME: The only reason we need to pass the type in here is to get
+  // the sign right on this one case.  It would be nice if APValue
+  // preserved this.
+  assert(result.isLValue() || result.isAddrLabelDiff());
+  return IntRange(MaxWidth, Ty->isUnsignedIntegerOrEnumerationType());
+}
+
+static QualType GetExprType(const Expr *E) {
+  QualType Ty = E->getType();
+  if (const auto *AtomicRHS = Ty->getAs<AtomicType>())
+    Ty = AtomicRHS->getValueType();
+  return Ty;
+}
+
+/// Attempts to estimate an approximate range for the given integer expression.
+/// Returns a range if successful, otherwise it returns \c std::nullopt if a
+/// reliable estimation cannot be determined.
+///
+/// \param MaxWidth The width to which the value will be truncated.
+/// \param InConstantContext If \c true, interpret the expression within a
+///        constant context.
+/// \param Approximate If \c true, provide a likely range of values by assuming
+///        that arithmetic on narrower types remains within those types.
+///        If \c false, return a range that includes all possible values
+///        resulting from the expression.
+/// \returns A range of values that the expression might take, or
+///          std::nullopt if a reliable estimation cannot be determined.
+static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E,
+                                               unsigned MaxWidth,
+                                               bool InConstantContext,
+                                               bool Approximate) {
+  E = E->IgnoreParens();
+
+  // Try a full evaluation first.
+  Expr::EvalResult result;
+  if (E->EvaluateAsRValue(result, C, InConstantContext))
+    return GetValueRange(result.Val, GetExprType(E), MaxWidth);
+
+  // I think we only want to look through implicit casts here; if the
+  // user has an explicit widening cast, we should treat the value as
+  // being of the new, wider type.
+  if (const auto *CE = dyn_cast<ImplicitCastExpr>(E)) {
+    if (CE->getCastKind() == CK_NoOp || CE->getCastKind() == CK_LValueToRValue)
+      return TryGetExprRange(C, CE->getSubExpr(), MaxWidth, InConstantContext,
+                             Approximate);
+
+    IntRange OutputTypeRange = IntRange::forValueOfType(C, GetExprType(CE));
+
+    bool isIntegerCast = CE->getCastKind() == CK_IntegralCast ||
+                         CE->getCastKind() == CK_BooleanToSignedIntegral;
+
+    // Assume that non-integer casts can span the full range of the type.
+    if (!isIntegerCast)
+      return OutputTypeRange;
+
+    std::optional<IntRange> SubRange = TryGetExprRange(
+        C, CE->getSubExpr(), std::min(MaxWidth, OutputTypeRange.Width),
+        InConstantContext, Approximate);
+    if (!SubRange)
+      return std::nullopt;
+
+    // Bail out if the subexpr's range is as wide as the cast type.
+    if (SubRange->Width >= OutputTypeRange.Width)
+      return OutputTypeRange;
+
+    // Otherwise, we take the smaller width, and we're non-negative if
+    // either the output type or the subexpr is.
+    return IntRange(SubRange->Width,
+                    SubRange->NonNegative || OutputTypeRange.NonNegative);
+  }
+
+  if (const auto *CO = dyn_cast<ConditionalOperator>(E)) {
+    // If we can fold the condition, just take that operand.
+    bool CondResult;
+    if (CO->getCond()->EvaluateAsBooleanCondition(CondResult, C))
+      return TryGetExprRange(
+          C, CondResult ? CO->getTrueExpr() : CO->getFalseExpr(), MaxWidth,
+          InConstantContext, Approximate);
+
+    // Otherwise, conservatively merge.
+    // TryGetExprRange requires an integer expression, but a throw expression
+    // results in a void type.
+    Expr *TrueExpr = CO->getTrueExpr();
+    if (TrueExpr->getType()->isVoidType())
+      return std::nullopt;
+
+    std::optional<IntRange> L =
+        TryGetExprRange(C, TrueExpr, MaxWidth, InConstantContext, Approximate);
+    if (!L)
+      return std::nullopt;
+
+    Expr *FalseExpr = CO->getFalseExpr();
+    if (FalseExpr->getType()->isVoidType())
+      return std::nullopt;
+
+    std::optional<IntRange> R =
+        TryGetExprRange(C, FalseExpr, MaxWidth, InConstantContext, Approximate);
+    if (!R)
+      return std::nullopt;
+
+    return IntRange::join(*L, *R);
+  }
+
+  if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
+    IntRange (*Combine)(IntRange, IntRange) = IntRange::join;
+
+    switch (BO->getOpcode()) {
+    case BO_Cmp:
+      llvm_unreachable("builtin <=> should have class type");
+
+    // Boolean-valued operations are single-bit and positive.
+    case BO_LAnd:
+    case BO_LOr:
+    case BO_LT:
+    case BO_GT:
+    case BO_LE:
+    case BO_GE:
+    case BO_EQ:
+    case BO_NE:
+      return IntRange::forBoolType();
+
+    // The type of the assignments is the type of the LHS, so the RHS
+    // is not necessarily the same type.
+    case BO_MulAssign:
+    case BO_DivAssign:
+    case BO_RemAssign:
+    case BO_AddAssign:
+    case BO_SubAssign:
+    case BO_XorAssign:
+    case BO_OrAssign:
+      // TODO: bitfields?
+      return IntRange::forValueOfType(C, GetExprType(E));
+
+    // Simple assignments just pass through the RHS, which will have
+    // been coerced to the LHS type.
+    case BO_Assign:
+      // TODO: bitfields?
+      return TryGetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext,
+                             Approximate);
+
+    // Operations with opaque sources are black-listed.
+    case BO_PtrMemD:
+    case BO_PtrMemI:
+      return IntRange::forValueOfType(C, GetExprType(E));
+
+    // Bitwise-and uses the *infinum* of the two source ranges.
+    case BO_And:
+    case BO_AndAssign:
+      Combine = IntRange::bit_and;
+      break;
+
+    // Left shift gets black-listed based on a judgement call.
+    case BO_Shl:
+      // ...except that we want to treat '1 << (blah)' as logically
+      // positive.  It's an important idiom.
+      if (IntegerLiteral *I
+            = dyn_cast<IntegerLiteral>(BO->getLHS()->IgnoreParenCasts())) {
+        if (I->getValue() == 1) {
+          IntRange R = IntRange::forValueOfType(C, GetExprType(E));
+          return IntRange(R.Width, /*NonNegative*/ true);
+        }
+      }
+      [[fallthrough]];
+
+    case BO_ShlAssign:
+      return IntRange::forValueOfType(C, GetExprType(E));
+
+    // Right shift by a constant can narrow its left argument.
+    case BO_Shr:
+    case BO_ShrAssign: {
+      std::optional<IntRange> L = TryGetExprRange(
+          C, BO->getLHS(), MaxWidth, InConstantContext, Approximate);
+      if (!L)
+        return std::nullopt;
+
+      // If the shift amount is a positive constant, drop the width by
+      // that much.
+      if (std::optional<llvm::APSInt> shift =
+              BO->getRHS()->getIntegerConstantExpr(C)) {
+        if (shift->isNonNegative()) {
+          if (shift->uge(L->Width))
+            L->Width = (L->NonNegative ? 0 : 1);
+          else
+            L->Width -= shift->getZExtValue();
+        }
+      }
+
+      return L;
+    }
+
+    // Comma acts as its right operand.
+    case BO_Comma:
+      return TryGetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext,
+                             Approximate);
+
+    case BO_Add:
+      if (!Approximate)
+        Combine = IntRange::sum;
+      break;
+
+    case BO_Sub:
+      if (BO->getLHS()->getType()->isPointerType())
+        return IntRange::forValueOfType(C, GetExprType(E));
+      if (!Approximate)
+        Combine = IntRange::difference;
+      break;
+
+    case BO_Mul:
+      if (!Approximate)
+        Combine = IntRange::product;
+      break;
+
+    // The width of a division result is mostly determined by the size
+    // of the LHS.
+    case BO_Div: {
+      // Don't 'pre-truncate' the operands.
+      unsigned opWidth = C.getIntWidth(GetExprType(E));
+      std::optional<IntRange> L = TryGetExprRange(
+          C, BO->getLHS(), opWidth, InConstantContext, Approximate);
+      if (!L)
+        return std::nullopt;
+
+      // If the divisor is constant, use that.
+      if (std::optional<llvm::APSInt> divisor =
+              BO->getRHS()->getIntegerConstantExpr(C)) {
+        unsigned log2 = divisor->logBase2(); // floor(log_2(divisor))
+        if (log2 >= L->Width)
+          L->Width = (L->NonNegative ? 0 : 1);
+        else
+          L->Width = std::min(L->Width - log2, MaxWidth);
+        return L;
+      }
+
+      // Otherwise, just use the LHS's width.
+      // FIXME: This is wrong if the LHS could be its minimal value and the RHS
+      // could be -1.
+      std::optional<IntRange> R = TryGetExprRange(
+          C, BO->getRHS(), opWidth, InConstantContext, Approximate);
+      if (!R)
+        return std::nullopt;
+
+      return IntRange(L->Width, L->NonNegative && R->NonNegative);
+    }
+
+    case BO_Rem:
+      Combine = IntRange::rem;
+      break;
+
+    // The default behavior is okay for these.
+    case BO_Xor:
+    case BO_Or:
+      break;
+    }
+
+    // Combine the two ranges, but limit the result to the type in which we
+    // performed the computation.
+    QualType T = GetExprType(E);
+    unsigned opWidth = C.getIntWidth(T);
+    std::optional<IntRange> L = TryGetExprRange(C, BO->getLHS(), opWidth,
+                                                InConstantContext, Approximate);
+    if (!L)
+      return std::nullopt;
+
+    std::optional<IntRange> R = TryGetExprRange(C, BO->getRHS(), opWidth,
+                                                InConstantContext, Approximate);
+    if (!R)
+      return std::nullopt;
+
+    IntRange C = Combine(*L, *R);
+    C.NonNegative |= T->isUnsignedIntegerOrEnumerationType();
+    C.Width = std::min(C.Width, MaxWidth);
+    return C;
+  }
+
+  if (const auto *UO = dyn_cast<UnaryOperator>(E)) {
+    switch (UO->getOpcode()) {
+    // Boolean-valued operations are white-listed.
+    case UO_LNot:
+      return IntRange::forBoolType();
+
+    // Operations with opaque sources are black-listed.
+    case UO_Deref:
+    case UO_AddrOf: // should be impossible
+      return IntRange::forValueOfType(C, GetExprType(E));
+
+    case UO_Minus: {
+      if (E->getType()->isUnsignedIntegerType()) {
+        return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext,
+                               Approximate);
+      }
+
+      std::optional<IntRange> SubRange = TryGetExprRange(
+          C, UO->getSubExpr(), MaxWidth, InConstantContext, Approximate);
+
+      if (!SubRange)
+        return std::nullopt;
+
+      // If the range was previously non-negative, we need an extra bit for the
+      // sign bit. Otherwise, we need an extra bit because the negation of the
+      // most-negative value is one bit wider than that value.
+      return IntRange(std::min(SubRange->Width + 1, MaxWidth), false);
+    }
+
+    case UO_Not: {
+      if (E->getType()->isUnsignedIntegerType()) {
+        return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext,
+                               Approximate);
+      }
+
+      std::optional<IntRange> SubRange = TryGetExprRange(
+          C, UO->getSubExpr(), MaxWidth, InConstantContext, Approximate);
+
+      if (!SubRange)
+        return std::nullopt;
+
+      // The width increments by 1 if the sub-expression cannot be negative
+      // since it now can be.
+      return IntRange(
+          std::min(SubRange->Width + (int)SubRange->NonNegative, MaxWidth),
+          false);
+    }
+
+    default:
+      return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext,
+                             Approximate);
+    }
+  }
+
+  if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E))
+    return TryGetExprRange(C, OVE->getSourceExpr(), MaxWidth, InConstantContext,
+                           Approximate);
+
+  if (const auto *BitField = E->getSourceBitField())
+    return IntRange(BitField->getBitWidthValue(),
+                    BitField->getType()->isUnsignedIntegerOrEnumerationType());
+
+  if (GetExprType(E)->isVoidType())
+    return std::nullopt;
+
+  return IntRange::forValueOfType(C, GetExprType(E));
+}
+
+static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E,
+                                               bool InConstantContext,
+                                               bool Approximate) {
+  return TryGetExprRange(C, E, C.getIntWidth(GetExprType(E)), InConstantContext,
+                         Approximate);
+}
+
+/// Checks whether the given value, which currently has the given
+/// source semantics, has the same value when coerced through the
+/// target semantics.
+static bool IsSameFloatAfterCast(const llvm::APFloat &value,
+                                 const llvm::fltSemantics &Src,
+                                 const llvm::fltSemantics &Tgt) {
+  llvm::APFloat truncated = value;
+
+  bool ignored;
+  truncated.convert(Src, llvm::APFloat::rmNearestTiesToEven, &ignored);
+  truncated.convert(Tgt, llvm::APFloat::rmNearestTiesToEven, &ignored);
+
+  return truncated.bitwiseIsEqual(value);
+}
+
+/// Checks whether the given value, which currently has the given
+/// source semantics, has the same value when coerced through the
+/// target semantics.
+///
+/// The value might be a vector of floats (or a complex number).
+static bool IsSameFloatAfterCast(const APValue &value,
+                                 const llvm::fltSemantics &Src,
+                                 const llvm::fltSemantics &Tgt) {
+  if (value.isFloat())
+    return IsSameFloatAfterCast(value.getFloat(), Src, Tgt);
+
+  if (value.isVector()) {
+    for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i)
+      if (!IsSameFloatAfterCast(value.getVectorElt(i), Src, Tgt))
+        return false;
+    return true;
+  }
+
+  assert(value.isComplexFloat());
+  return (IsSameFloatAfterCast(value.getComplexFloatReal(), Src, Tgt) &&
+          IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt));
+}
+
+static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC,
+                                       bool IsListInit = false);
+
+static bool IsEnumConstOrFromMacro(Sema &S, const Expr *E) {
+  // Suppress cases where we are comparing against an enum constant.
+  if (const auto *DR = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
+    if (isa<EnumConstantDecl>(DR->getDecl()))
+      return true;
+
+  // Suppress cases where the value is expanded from a macro, unless that macro
+  // is how a language represents a boolean literal. This is the case in both C
+  // and Objective-C.
+  SourceLocation BeginLoc = E->getBeginLoc();
+  if (BeginLoc.isMacroID()) {
+    StringRef MacroName = Lexer::getImmediateMacroName(
+        BeginLoc, S.getSourceManager(), S.getLangOpts());
+    return MacroName != "YES" && MacroName != "NO" &&
+           MacroName != "true" && MacroName != "false";
+  }
+
+  return false;
+}
+
+static bool isKnownToHaveUnsignedValue(const Expr *E) {
+  return E->getType()->isIntegerType() &&
+         (!E->getType()->isSignedIntegerType() ||
+          !E->IgnoreParenImpCasts()->getType()->isSignedIntegerType());
+}
+
+namespace {
+/// The promoted range of values of a type. In general this has the
+/// following structure:
+///
+///     |-----------| . . . |-----------|
+///     ^           ^       ^           ^
+///    Min       HoleMin  HoleMax      Max
+///
+/// ... where there is only a hole if a signed type is promoted to unsigned
+/// (in which case Min and Max are the smallest and largest representable
+/// values).
+struct PromotedRange {
+  // Min, or HoleMax if there is a hole.
+  llvm::APSInt PromotedMin;
+  // Max, or HoleMin if there is a hole.
+  llvm::APSInt PromotedMax;
+
+  PromotedRange(IntRange R, unsigned BitWidth, bool Unsigned) {
+    if (R.Width == 0)
+      PromotedMin = PromotedMax = llvm::APSInt(BitWidth, Unsigned);
+    else if (R.Width >= BitWidth && !Unsigned) {
+      // Promotion made the type *narrower*. This happens when promoting
+      // a < 32-bit unsigned / <= 32-bit signed bit-field to 'signed int'.
+      // Treat all values of 'signed int' as being in range for now.
+      PromotedMin = llvm::APSInt::getMinValue(BitWidth, Unsigned);
+      PromotedMax = llvm::APSInt::getMaxValue(BitWidth, Unsigned);
+    } else {
+      PromotedMin = llvm::APSInt::getMinValue(R.Width, R.NonNegative)
+                        .extOrTrunc(BitWidth);
+      PromotedMin.setIsUnsigned(Unsigned);
+
+      PromotedMax = llvm::APSInt::getMaxValue(R.Width, R.NonNegative)
+                        .extOrTrunc(BitWidth);
+      PromotedMax.setIsUnsigned(Unsigned);
+    }
+  }
+
+  // Determine whether this range is contiguous (has no hole).
+  bool isContiguous() const { return PromotedMin <= PromotedMax; }
+
+  // Where a constant value is within the range.
+  enum ComparisonResult {
+    LT = 0x1,
+    LE = 0x2,
+    GT = 0x4,
+    GE = 0x8,
+    EQ = 0x10,
+    NE = 0x20,
+    InRangeFlag = 0x40,
+
+    Less = LE | LT | NE,
+    Min = LE | InRangeFlag,
+    InRange = InRangeFlag,
+    Max = GE | InRangeFlag,
+    Greater = GE | GT | NE,
+
+    OnlyValue = LE | GE | EQ | InRangeFlag,
+    InHole = NE
+  };
+
+  ComparisonResult compare(const llvm::APSInt &Value) const {
+    assert(Value.getBitWidth() == PromotedMin.getBitWidth() &&
+           Value.isUnsigned() == PromotedMin.isUnsigned());
+    if (!isContiguous()) {
+      assert(Value.isUnsigned() && "discontiguous range for signed compare");
+      if (Value.isMinValue()) return Min;
+      if (Value.isMaxValue()) return Max;
+      if (Value >= PromotedMin) return InRange;
+      if (Value <= PromotedMax) return InRange;
+      return InHole;
+    }
+
+    switch (llvm::APSInt::compareValues(Value, PromotedMin)) {
+    case -1: return Less;
+    case 0: return PromotedMin == PromotedMax ? OnlyValue : Min;
+    case 1:
+      switch (llvm::APSInt::compareValues(Value, PromotedMax)) {
+      case -1: return InRange;
+      case 0: return Max;
+      case 1: return Greater;
+      }
+    }
+
+    llvm_unreachable("impossible compare result");
+  }
+
+  static std::optional<StringRef>
+  constantValue(BinaryOperatorKind Op, ComparisonResult R, bool ConstantOnRHS) {
+    if (Op == BO_Cmp) {
+      ComparisonResult LTFlag = LT, GTFlag = GT;
+      if (ConstantOnRHS) std::swap(LTFlag, GTFlag);
+
+      if (R & EQ) return StringRef("'std::strong_ordering::equal'");
+      if (R & LTFlag) return StringRef("'std::strong_ordering::less'");
+      if (R & GTFlag) return StringRef("'std::strong_ordering::greater'");
+      return std::nullopt;
+    }
+
+    ComparisonResult TrueFlag, FalseFlag;
+    if (Op == BO_EQ) {
+      TrueFlag = EQ;
+      FalseFlag = NE;
+    } else if (Op == BO_NE) {
+      TrueFlag = NE;
+      FalseFlag = EQ;
+    } else {
+      if ((Op == BO_LT || Op == BO_GE) ^ ConstantOnRHS) {
+        TrueFlag = LT;
+        FalseFlag = GE;
+      } else {
+        TrueFlag = GT;
+        FalseFlag = LE;
+      }
+      if (Op == BO_GE || Op == BO_LE)
+        std::swap(TrueFlag, FalseFlag);
+    }
+    if (R & TrueFlag)
+      return StringRef("true");
+    if (R & FalseFlag)
+      return StringRef("false");
+    return std::nullopt;
+  }
+};
+}
+
+static bool HasEnumType(const Expr *E) {
+  // Strip off implicit integral promotions.
+  while (const auto *ICE = dyn_cast<ImplicitCastExpr>(E)) {
+    if (ICE->getCastKind() != CK_IntegralCast &&
+        ICE->getCastKind() != CK_NoOp)
+      break;
+    E = ICE->getSubExpr();
+  }
+
+  return E->getType()->isEnumeralType();
+}
+
+static int classifyConstantValue(Expr *Constant) {
+  // The values of this enumeration are used in the diagnostics
+  // diag::warn_out_of_range_compare and diag::warn_tautological_bool_compare.
+  enum ConstantValueKind {
+    Miscellaneous = 0,
+    LiteralTrue,
+    LiteralFalse
+  };
+  if (auto *BL = dyn_cast<CXXBoolLiteralExpr>(Constant))
+    return BL->getValue() ? ConstantValueKind::LiteralTrue
+                          : ConstantValueKind::LiteralFalse;
+  return ConstantValueKind::Miscellaneous;
+}
+
+static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E,
+                                        Expr *Constant, Expr *Other,
+                                        const llvm::APSInt &Value,
+                                        bool RhsConstant) {
+  if (S.inTemplateInstantiation())
+    return false;
+
+  Expr *OriginalOther = Other;
+
+  Constant = Constant->IgnoreParenImpCasts();
+  Other = Other->IgnoreParenImpCasts();
+
+  // Suppress warnings on tautological comparisons between values of the same
+  // enumeration type. There are only two ways we could warn on this:
+  //  - If the constant is outside the range of representable values of
+  //    the enumeration. In such a case, we should warn about the cast
+  //    to enumeration type, not about the comparison.
+  //  - If the constant is the maximum / minimum in-range value. For an
+  //    enumeratin type, such comparisons can be meaningful and useful.
+  if (Constant->getType()->isEnumeralType() &&
+      S.Context.hasSameUnqualifiedType(Constant->getType(), Other->getType()))
+    return false;
+
+  std::optional<IntRange> OtherValueRange = TryGetExprRange(
+      S.Context, Other, S.isConstantEvaluatedContext(), /*Approximate=*/false);
+  if (!OtherValueRange)
+    return false;
+
+  QualType OtherT = Other->getType();
+  if (const auto *AT = OtherT->getAs<AtomicType>())
+    OtherT = AT->getValueType();
+  IntRange OtherTypeRange = IntRange::forValueOfType(S.Context, OtherT);
+
+  // Special case for ObjC BOOL on targets where its a typedef for a signed char
+  // (Namely, macOS). FIXME: IntRange::forValueOfType should do this.
+  bool IsObjCSignedCharBool = S.getLangOpts().ObjC &&
+                              S.ObjC().NSAPIObj->isObjCBOOLType(OtherT) &&
+                              OtherT->isSpecificBuiltinType(BuiltinType::SChar);
+
+  // Whether we're treating Other as being a bool because of the form of
+  // expression despite it having another type (typically 'int' in C).
+  bool OtherIsBooleanDespiteType =
+      !OtherT->isBooleanType() && Other->isKnownToHaveBooleanValue();
+  if (OtherIsBooleanDespiteType || IsObjCSignedCharBool)
+    OtherTypeRange = *OtherValueRange = IntRange::forBoolType();
+
+  // Check if all values in the range of possible values of this expression
+  // lead to the same comparison outcome.
+  PromotedRange OtherPromotedValueRange(*OtherValueRange, Value.getBitWidth(),
+                                        Value.isUnsigned());
+  auto Cmp = OtherPromotedValueRange.compare(Value);
+  auto Result = PromotedRange::constantValue(E->getOpcode(), Cmp, RhsConstant);
+  if (!Result)
+    return false;
+
+  // Also consider the range determined by the type alone. This allows us to
+  // classify the warning under the proper diagnostic group.
+  bool TautologicalTypeCompare = false;
+  {
+    PromotedRange OtherPromotedTypeRange(OtherTypeRange, Value.getBitWidth(),
+                                         Value.isUnsigned());
+    auto TypeCmp = OtherPromotedTypeRange.compare(Value);
+    if (auto TypeResult = PromotedRange::constantValue(E->getOpcode(), TypeCmp,
+                                                       RhsConstant)) {
+      TautologicalTypeCompare = true;
+      Cmp = TypeCmp;
+      Result = TypeResult;
+    }
+  }
+
+  // Don't warn if the non-constant operand actually always evaluates to the
+  // same value.
+  if (!TautologicalTypeCompare && OtherValueRange->Width == 0)
+    return false;
+
+  // Suppress the diagnostic for an in-range comparison if the constant comes
+  // from a macro or enumerator. We don't want to diagnose
+  //
+  //   some_long_value <= INT_MAX
+  //
+  // when sizeof(int) == sizeof(long).
+  bool InRange = Cmp & PromotedRange::InRangeFlag;
+  if (InRange && IsEnumConstOrFromMacro(S, Constant))
+    return false;
+
+  // A comparison of an unsigned bit-field against 0 is really a type problem,
+  // even though at the type level the bit-field might promote to 'signed int'.
+  if (Other->refersToBitField() && InRange && Value == 0 &&
+      Other->getType()->isUnsignedIntegerOrEnumerationType())
+    TautologicalTypeCompare = true;
+
+  // If this is a comparison to an enum constant, include that
+  // constant in the diagnostic.
+  const EnumConstantDecl *ED = nullptr;
+  if (const auto *DR = dyn_cast<DeclRefExpr>(Constant))
+    ED = dyn_cast<EnumConstantDecl>(DR->getDecl());
+
+  // Should be enough for uint128 (39 decimal digits)
+  SmallString<64> PrettySourceValue;
+  llvm::raw_svector_ostream OS(PrettySourceValue);
+  if (ED) {
+    OS << '\'' << *ED << "' (" << Value << ")";
+  } else if (auto *BL = dyn_cast<ObjCBoolLiteralExpr>(
+               Constant->IgnoreParenImpCasts())) {
+    OS << (BL->getValue() ? "YES" : "NO");
+  } else {
+    OS << Value;
+  }
+
+  if (!TautologicalTypeCompare) {
+    S.Diag(E->getOperatorLoc(), diag::warn_tautological_compare_value_range)
+        << RhsConstant << OtherValueRange->Width << OtherValueRange->NonNegative
+        << E->getOpcodeStr() << OS.str() << *Result
+        << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+    return true;
+  }
+
+  if (IsObjCSignedCharBool) {
+    S.DiagRuntimeBehavior(E->getOperatorLoc(), E,
+                          S.PDiag(diag::warn_tautological_compare_objc_bool)
+                              << OS.str() << *Result);
+    return true;
+  }
+
+  // FIXME: We use a somewhat different formatting for the in-range cases and
+  // cases involving boolean values for historical reasons. We should pick a
+  // consistent way of presenting these diagnostics.
+  if (!InRange || Other->isKnownToHaveBooleanValue()) {
+
+    S.DiagRuntimeBehavior(
+        E->getOperatorLoc(), E,
+        S.PDiag(!InRange ? diag::warn_out_of_range_compare
+                         : diag::warn_tautological_bool_compare)
+            << OS.str() << classifyConstantValue(Constant) << OtherT
+            << OtherIsBooleanDespiteType << *Result
+            << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange());
+  } else {
+    bool IsCharTy = OtherT.withoutLocalFastQualifiers() == S.Context.CharTy;
+    unsigned Diag =
+        (isKnownToHaveUnsignedValue(OriginalOther) && Value == 0)
+            ? (HasEnumType(OriginalOther)
+                   ? diag::warn_unsigned_enum_always_true_comparison
+                   : IsCharTy ? diag::warn_unsigned_char_always_true_comparison
+                              : diag::warn_unsigned_always_true_comparison)
+            : diag::warn_tautological_constant_compare;
+
+    S.Diag(E->getOperatorLoc(), Diag)
+        << RhsConstant << OtherT << E->getOpcodeStr() << OS.str() << *Result
+        << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+  }
+
+  return true;
+}
+
+/// Analyze the operands of the given comparison.  Implements the
+/// fallback case from AnalyzeComparison.
+static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
+  AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc());
+  AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc());
+}
+
+/// Implements -Wsign-compare.
+///
+/// \param E the binary operator to check for warnings
+static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
+  // The type the comparison is being performed in.
+  QualType T = E->getLHS()->getType();
+
+  // Only analyze comparison operators where both sides have been converted to
+  // the same type.
+  if (!S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType()))
+    return AnalyzeImpConvsInComparison(S, E);
+
+  // Don't analyze value-dependent comparisons directly.
+  if (E->isValueDependent())
+    return AnalyzeImpConvsInComparison(S, E);
+
+  Expr *LHS = E->getLHS();
+  Expr *RHS = E->getRHS();
+
+  if (T->isIntegralType(S.Context)) {
+    std::optional<llvm::APSInt> RHSValue =
+        RHS->getIntegerConstantExpr(S.Context);
+    std::optional<llvm::APSInt> LHSValue =
+        LHS->getIntegerConstantExpr(S.Context);
+
+    // We don't care about expressions whose result is a constant.
+    if (RHSValue && LHSValue)
+      return AnalyzeImpConvsInComparison(S, E);
+
+    // We only care about expressions where just one side is literal
+    if ((bool)RHSValue ^ (bool)LHSValue) {
+      // Is the constant on the RHS or LHS?
+      const bool RhsConstant = (bool)RHSValue;
+      Expr *Const = RhsConstant ? RHS : LHS;
+      Expr *Other = RhsConstant ? LHS : RHS;
+      const llvm::APSInt &Value = RhsConstant ? *RHSValue : *LHSValue;
+
+      // Check whether an integer constant comparison results in a value
+      // of 'true' or 'false'.
+      if (CheckTautologicalComparison(S, E, Const, Other, Value, RhsConstant))
+        return AnalyzeImpConvsInComparison(S, E);
+    }
+  }
+
+  if (!T->hasUnsignedIntegerRepresentation()) {
+    // We don't do anything special if this isn't an unsigned integral
+    // comparison:  we're only interested in integral comparisons, and
+    // signed comparisons only happen in cases we don't care to warn about.
+    return AnalyzeImpConvsInComparison(S, E);
+  }
+
+  LHS = LHS->IgnoreParenImpCasts();
+  RHS = RHS->IgnoreParenImpCasts();
+
+  if (!S.getLangOpts().CPlusPlus) {
+    // Avoid warning about comparison of integers with different signs when
+    // RHS/LHS has a `typeof(E)` type whose sign is different from the sign of
+    // the type of `E`.
+    if (const auto *TET = dyn_cast<TypeOfExprType>(LHS->getType()))
+      LHS = TET->getUnderlyingExpr()->IgnoreParenImpCasts();
+    if (const auto *TET = dyn_cast<TypeOfExprType>(RHS->getType()))
+      RHS = TET->getUnderlyingExpr()->IgnoreParenImpCasts();
+  }
+
+  // Check to see if one of the (unmodified) operands is of different
+  // signedness.
+  Expr *signedOperand, *unsignedOperand;
+  if (LHS->getType()->hasSignedIntegerRepresentation()) {
+    assert(!RHS->getType()->hasSignedIntegerRepresentation() &&
+           "unsigned comparison between two signed integer expressions?");
+    signedOperand = LHS;
+    unsignedOperand = RHS;
+  } else if (RHS->getType()->hasSignedIntegerRepresentation()) {
+    signedOperand = RHS;
+    unsignedOperand = LHS;
+  } else {
+    return AnalyzeImpConvsInComparison(S, E);
+  }
+
+  // Otherwise, calculate the effective range of the signed operand.
+  std::optional<IntRange> signedRange =
+      TryGetExprRange(S.Context, signedOperand, S.isConstantEvaluatedContext(),
+                      /*Approximate=*/true);
+  if (!signedRange)
+    return;
+
+  // Go ahead and analyze implicit conversions in the operands.  Note
+  // that we skip the implicit conversions on both sides.
+  AnalyzeImplicitConversions(S, LHS, E->getOperatorLoc());
+  AnalyzeImplicitConversions(S, RHS, E->getOperatorLoc());
+
+  // If the signed range is non-negative, -Wsign-compare won't fire.
+  if (signedRange->NonNegative)
+    return;
+
+  // For (in)equality comparisons, if the unsigned operand is a
+  // constant which cannot collide with a overflowed signed operand,
+  // then reinterpreting the signed operand as unsigned will not
+  // change the result of the comparison.
+  if (E->isEqualityOp()) {
+    unsigned comparisonWidth = S.Context.getIntWidth(T);
+    std::optional<IntRange> unsignedRange = TryGetExprRange(
+        S.Context, unsignedOperand, S.isConstantEvaluatedContext(),
+        /*Approximate=*/true);
+    if (!unsignedRange)
+      return;
+
+    // We should never be unable to prove that the unsigned operand is
+    // non-negative.
+    assert(unsignedRange->NonNegative && "unsigned range includes negative?");
+
+    if (unsignedRange->Width < comparisonWidth)
+      return;
+  }
+
+  S.DiagRuntimeBehavior(E->getOperatorLoc(), E,
+                        S.PDiag(diag::warn_mixed_sign_comparison)
+                            << LHS->getType() << RHS->getType()
+                            << LHS->getSourceRange() << RHS->getSourceRange());
+}
+
+/// Analyzes an attempt to assign the given value to a bitfield.
+///
+/// Returns true if there was something fishy about the attempt.
+static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
+                                      SourceLocation InitLoc) {
+  assert(Bitfield->isBitField());
+  if (Bitfield->isInvalidDecl())
+    return false;
+
+  // White-list bool bitfields.
+  QualType BitfieldType = Bitfield->getType();
+  if (BitfieldType->isBooleanType())
+     return false;
+
+  if (auto *BitfieldEnumDecl = BitfieldType->getAsEnumDecl()) {
+    // If the underlying enum type was not explicitly specified as an unsigned
+    // type and the enum contain only positive values, MSVC++ will cause an
+    // inconsistency by storing this as a signed type.
+    if (S.getLangOpts().CPlusPlus11 &&
+        !BitfieldEnumDecl->getIntegerTypeSourceInfo() &&
+        BitfieldEnumDecl->getNumPositiveBits() > 0 &&
+        BitfieldEnumDecl->getNumNegativeBits() == 0) {
+      S.Diag(InitLoc, diag::warn_no_underlying_type_specified_for_enum_bitfield)
+          << BitfieldEnumDecl;
+    }
+  }
+
+  // Ignore value- or type-dependent expressions.
+  if (Bitfield->getBitWidth()->isValueDependent() ||
+      Bitfield->getBitWidth()->isTypeDependent() ||
+      Init->isValueDependent() ||
+      Init->isTypeDependent())
+    return false;
+
+  Expr *OriginalInit = Init->IgnoreParenImpCasts();
+  unsigned FieldWidth = Bitfield->getBitWidthValue();
+
+  Expr::EvalResult Result;
+  if (!OriginalInit->EvaluateAsInt(Result, S.Context,
+                                   Expr::SE_AllowSideEffects)) {
+    // The RHS is not constant.  If the RHS has an enum type, make sure the
+    // bitfield is wide enough to hold all the values of the enum without
+    // truncation.
+    const auto *ED = OriginalInit->getType()->getAsEnumDecl();
+    const PreferredTypeAttr *PTAttr = nullptr;
+    if (!ED) {
+      PTAttr = Bitfield->getAttr<PreferredTypeAttr>();
+      if (PTAttr)
+        ED = PTAttr->getType()->getAsEnumDecl();
+    }
+    if (ED) {
+      bool SignedBitfield = BitfieldType->isSignedIntegerOrEnumerationType();
+
+      // Enum types are implicitly signed on Windows, so check if there are any
+      // negative enumerators to see if the enum was intended to be signed or
+      // not.
+      bool SignedEnum = ED->getNumNegativeBits() > 0;
+
+      // Check for surprising sign changes when assigning enum values to a
+      // bitfield of different signedness.  If the bitfield is signed and we
+      // have exactly the right number of bits to store this unsigned enum,
+      // suggest changing the enum to an unsigned type. This typically happens
+      // on Windows where unfixed enums always use an underlying type of 'int'.
+      unsigned DiagID = 0;
+      if (SignedEnum && !SignedBitfield) {
+        DiagID =
+            PTAttr == nullptr
+                ? diag::warn_unsigned_bitfield_assigned_signed_enum
+                : diag::
+                      warn_preferred_type_unsigned_bitfield_assigned_signed_enum;
+      } else if (SignedBitfield && !SignedEnum &&
+                 ED->getNumPositiveBits() == FieldWidth) {
+        DiagID =
+            PTAttr == nullptr
+                ? diag::warn_signed_bitfield_enum_conversion
+                : diag::warn_preferred_type_signed_bitfield_enum_conversion;
+      }
+      if (DiagID) {
+        S.Diag(InitLoc, DiagID) << Bitfield << ED;
+        TypeSourceInfo *TSI = Bitfield->getTypeSourceInfo();
+        SourceRange TypeRange =
+            TSI ? TSI->getTypeLoc().getSourceRange() : SourceRange();
+        S.Diag(Bitfield->getTypeSpecStartLoc(), diag::note_change_bitfield_sign)
+            << SignedEnum << TypeRange;
+        if (PTAttr)
+          S.Diag(PTAttr->getLocation(), diag::note_bitfield_preferred_type)
+              << ED;
+      }
+
+      // Compute the required bitwidth. If the enum has negative values, we need
+      // one more bit than the normal number of positive bits to represent the
+      // sign bit.
+      unsigned BitsNeeded = SignedEnum ? std::max(ED->getNumPositiveBits() + 1,
+                                                  ED->getNumNegativeBits())
+                                       : ED->getNumPositiveBits();
+
+      // Check the bitwidth.
+      if (BitsNeeded > FieldWidth) {
+        Expr *WidthExpr = Bitfield->getBitWidth();
+        auto DiagID =
+            PTAttr == nullptr
+                ? diag::warn_bitfield_too_small_for_enum
+                : diag::warn_preferred_type_bitfield_too_small_for_enum;
+        S.Diag(InitLoc, DiagID) << Bitfield << ED;
+        S.Diag(WidthExpr->getExprLoc(), diag::note_widen_bitfield)
+            << BitsNeeded << ED << WidthExpr->getSourceRange();
+        if (PTAttr)
+          S.Diag(PTAttr->getLocation(), diag::note_bitfield_preferred_type)
+              << ED;
+      }
+    }
+
+    return false;
+  }
+
+  llvm::APSInt Value = Result.Val.getInt();
+
+  unsigned OriginalWidth = Value.getBitWidth();
+
+  // In C, the macro 'true' from stdbool.h will evaluate to '1'; To reduce
+  // false positives where the user is demonstrating they intend to use the
+  // bit-field as a Boolean, check to see if the value is 1 and we're assigning
+  // to a one-bit bit-field to see if the value came from a macro named 'true'.
+  bool OneAssignedToOneBitBitfield = FieldWidth == 1 && Value == 1;
+  if (OneAssignedToOneBitBitfield && !S.LangOpts.CPlusPlus) {
+    SourceLocation MaybeMacroLoc = OriginalInit->getBeginLoc();
+    if (S.SourceMgr.isInSystemMacro(MaybeMacroLoc) &&
+        S.findMacroSpelling(MaybeMacroLoc, "true"))
+      return false;
+  }
+
+  if (!Value.isSigned() || Value.isNegative())
+    if (UnaryOperator *UO = dyn_cast<UnaryOperator>(OriginalInit))
+      if (UO->getOpcode() == UO_Minus || UO->getOpcode() == UO_Not)
+        OriginalWidth = Value.getSignificantBits();
+
+  if (OriginalWidth <= FieldWidth)
+    return false;
+
+  // Compute the value which the bitfield will contain.
+  llvm::APSInt TruncatedValue = Value.trunc(FieldWidth);
+  TruncatedValue.setIsSigned(BitfieldType->isSignedIntegerType());
+
+  // Check whether the stored value is equal to the original value.
+  TruncatedValue = TruncatedValue.extend(OriginalWidth);
+  if (llvm::APSInt::isSameValue(Value, TruncatedValue))
+    return false;
+
+  std::string PrettyValue = toString(Value, 10);
+  std::string PrettyTrunc = toString(TruncatedValue, 10);
+
+  S.Diag(InitLoc, OneAssignedToOneBitBitfield
+                      ? diag::warn_impcast_single_bit_bitield_precision_constant
+                      : diag::warn_impcast_bitfield_precision_constant)
+      << PrettyValue << PrettyTrunc << OriginalInit->getType()
+      << Init->getSourceRange();
+
+  return true;
+}
+
+/// Analyze the given simple or compound assignment for warning-worthy
+/// operations.
+static void AnalyzeAssignment(Sema &S, BinaryOperator *E) {
+  // Just recurse on the LHS.
+  AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc());
+
+  // We want to recurse on the RHS as normal unless we're assigning to
+  // a bitfield.
+  if (FieldDecl *Bitfield = E->getLHS()->getSourceBitField()) {
+    if (AnalyzeBitFieldAssignment(S, Bitfield, E->getRHS(),
+                                  E->getOperatorLoc())) {
+      // Recurse, ignoring any implicit conversions on the RHS.
+      return AnalyzeImplicitConversions(S, E->getRHS()->IgnoreParenImpCasts(),
+                                        E->getOperatorLoc());
+    }
+  }
+
+  AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc());
+
+  // Diagnose implicitly sequentially-consistent atomic assignment.
+  if (E->getLHS()->getType()->isAtomicType())
+    S.Diag(E->getRHS()->getBeginLoc(), diag::warn_atomic_implicit_seq_cst);
+}
+
+/// Diagnose an implicit cast;  purely a helper for CheckImplicitConversion.
+static void DiagnoseImpCast(Sema &S, const Expr *E, QualType SourceType,
+                            QualType T, SourceLocation CContext, unsigned diag,
+                            bool PruneControlFlow = false) {
+  // For languages like HLSL and OpenCL, implicit conversion diagnostics listing
+  // address space annotations isn't really useful. The warnings aren't because
+  // you're converting a `private int` to `unsigned int`, it is because you're
+  // conerting `int` to `unsigned int`.
+  if (SourceType.hasAddressSpace())
+    SourceType = S.getASTContext().removeAddrSpaceQualType(SourceType);
+  if (T.hasAddressSpace())
+    T = S.getASTContext().removeAddrSpaceQualType(T);
+  if (PruneControlFlow) {
+    S.DiagRuntimeBehavior(E->getExprLoc(), E,
+                          S.PDiag(diag)
+                              << SourceType << T << E->getSourceRange()
+                              << SourceRange(CContext));
+    return;
+  }
+  S.Diag(E->getExprLoc(), diag)
+    << SourceType << T << E->getSourceRange() << SourceRange(CContext);
+}
+
+/// Diagnose an implicit cast;  purely a helper for CheckImplicitConversion.
+static void DiagnoseImpCast(Sema &S, const Expr *E, QualType T,
+                            SourceLocation CContext, unsigned diag,
+                            bool PruneControlFlow = false) {
+  DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, PruneControlFlow);
+}
+
+/// Diagnose an implicit cast from a floating point value to an integer value.
+static void DiagnoseFloatingImpCast(Sema &S, const Expr *E, QualType T,
+                                    SourceLocation CContext) {
+  bool IsBool = T->isSpecificBuiltinType(BuiltinType::Bool);
+  bool PruneWarnings = S.inTemplateInstantiation();
+
+  const Expr *InnerE = E->IgnoreParenImpCasts();
+  // We also want to warn on, e.g., "int i = -1.234"
+  if (const auto *UOp = dyn_cast<UnaryOperator>(InnerE))
+    if (UOp->getOpcode() == UO_Minus || UOp->getOpcode() == UO_Plus)
+      InnerE = UOp->getSubExpr()->IgnoreParenImpCasts();
+
+  bool IsLiteral = isa<FloatingLiteral>(E) || isa<FloatingLiteral>(InnerE);
+
+  llvm::APFloat Value(0.0);
+  bool IsConstant =
+    E->EvaluateAsFloat(Value, S.Context, Expr::SE_AllowSideEffects);
+  if (!IsConstant) {
+    if (S.ObjC().isSignedCharBool(T)) {
+      return S.ObjC().adornBoolConversionDiagWithTernaryFixit(
+          E, S.Diag(CContext, diag::warn_impcast_float_to_objc_signed_char_bool)
+                 << E->getType());
+    }
+
+    return DiagnoseImpCast(S, E, T, CContext,
+                           diag::warn_impcast_float_integer, PruneWarnings);
+  }
+
+  bool isExact = false;
+
+  llvm::APSInt IntegerValue(S.Context.getIntWidth(T),
+                            T->hasUnsignedIntegerRepresentation());
+  llvm::APFloat::opStatus Result = Value.convertToInteger(
+      IntegerValue, llvm::APFloat::rmTowardZero, &isExact);
+
+  // FIXME: Force the precision of the source value down so we don't print
+  // digits which are usually useless (we don't really care here if we
+  // truncate a digit by accident in edge cases).  Ideally, APFloat::toString
+  // would automatically print the shortest representation, but it's a bit
+  // tricky to implement.
+  SmallString<16> PrettySourceValue;
+  unsigned precision = llvm::APFloat::semanticsPrecision(Value.getSemantics());
+  precision = (precision * 59 + 195) / 196;
+  Value.toString(PrettySourceValue, precision);
+
+  if (S.ObjC().isSignedCharBool(T) && IntegerValue != 0 && IntegerValue != 1) {
+    return S.ObjC().adornBoolConversionDiagWithTernaryFixit(
+        E, S.Diag(CContext, diag::warn_impcast_constant_value_to_objc_bool)
+               << PrettySourceValue);
+  }
+
+  if (Result == llvm::APFloat::opOK && isExact) {
+    if (IsLiteral) return;
+    return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer,
+                           PruneWarnings);
+  }
+
+  // Conversion of a floating-point value to a non-bool integer where the
+  // integral part cannot be represented by the integer type is undefined.
+  if (!IsBool && Result == llvm::APFloat::opInvalidOp)
+    return DiagnoseImpCast(
+        S, E, T, CContext,
+        IsLiteral ? diag::warn_impcast_literal_float_to_integer_out_of_range
+                  : diag::warn_impcast_float_to_integer_out_of_range,
+        PruneWarnings);
+
+  unsigned DiagID = 0;
+  if (IsLiteral) {
+    // Warn on floating point literal to integer.
+    DiagID = diag::warn_impcast_literal_float_to_integer;
+  } else if (IntegerValue == 0) {
+    if (Value.isZero()) {  // Skip -0.0 to 0 conversion.
+      return DiagnoseImpCast(S, E, T, CContext,
+                             diag::warn_impcast_float_integer, PruneWarnings);
+    }
+    // Warn on non-zero to zero conversion.
+    DiagID = diag::warn_impcast_float_to_integer_zero;
+  } else {
+    if (IntegerValue.isUnsigned()) {
+      if (!IntegerValue.isMaxValue()) {
+        return DiagnoseImpCast(S, E, T, CContext,
+                               diag::warn_impcast_float_integer, PruneWarnings);
+      }
+    } else {  // IntegerValue.isSigned()
+      if (!IntegerValue.isMaxSignedValue() &&
+          !IntegerValue.isMinSignedValue()) {
+        return DiagnoseImpCast(S, E, T, CContext,
+                               diag::warn_impcast_float_integer, PruneWarnings);
+      }
+    }
+    // Warn on evaluatable floating point expression to integer conversion.
+    DiagID = diag::warn_impcast_float_to_integer;
+  }
+
+  SmallString<16> PrettyTargetValue;
+  if (IsBool)
+    PrettyTargetValue = Value.isZero() ? "false" : "true";
+  else
+    IntegerValue.toString(PrettyTargetValue);
+
+  if (PruneWarnings) {
+    S.DiagRuntimeBehavior(E->getExprLoc(), E,
+                          S.PDiag(DiagID)
+                              << E->getType() << T.getUnqualifiedType()
+                              << PrettySourceValue << PrettyTargetValue
+                              << E->getSourceRange() << SourceRange(CContext));
+  } else {
+    S.Diag(E->getExprLoc(), DiagID)
+        << E->getType() << T.getUnqualifiedType() << PrettySourceValue
+        << PrettyTargetValue << E->getSourceRange() << SourceRange(CContext);
+  }
+}
+
+/// Analyze the given compound assignment for the possible losing of
+/// floating-point precision.
+static void AnalyzeCompoundAssignment(Sema &S, BinaryOperator *E) {
+  assert(isa<CompoundAssignOperator>(E) &&
+         "Must be compound assignment operation");
+  // Recurse on the LHS and RHS in here
+  AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc());
+  AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc());
+
+  if (E->getLHS()->getType()->isAtomicType())
+    S.Diag(E->getOperatorLoc(), diag::warn_atomic_implicit_seq_cst);
+
+  // Now check the outermost expression
+  const auto *ResultBT = E->getLHS()->getType()->getAs<BuiltinType>();
+  const auto *RBT = cast<CompoundAssignOperator>(E)
+                        ->getComputationResultType()
+                        ->getAs<BuiltinType>();
+
+  // The below checks assume source is floating point.
+  if (!ResultBT || !RBT || !RBT->isFloatingPoint()) return;
+
+  // If source is floating point but target is an integer.
+  if (ResultBT->isInteger())
+    return DiagnoseImpCast(S, E, E->getRHS()->getType(), E->getLHS()->getType(),
+                           E->getExprLoc(), diag::warn_impcast_float_integer);
+
+  if (!ResultBT->isFloatingPoint())
+    return;
+
+  // If both source and target are floating points, warn about losing precision.
+  int Order = S.getASTContext().getFloatingTypeSemanticOrder(
+      QualType(ResultBT, 0), QualType(RBT, 0));
+  if (Order < 0 && !S.SourceMgr.isInSystemMacro(E->getOperatorLoc()))
+    // warn about dropping FP rank.
+    DiagnoseImpCast(S, E->getRHS(), E->getLHS()->getType(), E->getOperatorLoc(),
+                    diag::warn_impcast_float_result_precision);
+}
+
+static std::string PrettyPrintInRange(const llvm::APSInt &Value,
+                                      IntRange Range) {
+  if (!Range.Width) return "0";
+
+  llvm::APSInt ValueInRange = Value;
+  ValueInRange.setIsSigned(!Range.NonNegative);
+  ValueInRange = ValueInRange.trunc(Range.Width);
+  return toString(ValueInRange, 10);
+}
+
+static bool IsImplicitBoolFloatConversion(Sema &S, const Expr *Ex,
+                                          bool ToBool) {
+  if (!isa<ImplicitCastExpr>(Ex))
+    return false;
+
+  const Expr *InnerE = Ex->IgnoreParenImpCasts();
+  const Type *Target = S.Context.getCanonicalType(Ex->getType()).getTypePtr();
+  const Type *Source =
+    S.Context.getCanonicalType(InnerE->getType()).getTypePtr();
+  if (Target->isDependentType())
+    return false;
+
+  const auto *FloatCandidateBT =
+      dyn_cast<BuiltinType>(ToBool ? Source : Target);
+  const Type *BoolCandidateType = ToBool ? Target : Source;
+
+  return (BoolCandidateType->isSpecificBuiltinType(BuiltinType::Bool) &&
+          FloatCandidateBT && (FloatCandidateBT->isFloatingPoint()));
+}
+
+static void CheckImplicitArgumentConversions(Sema &S, const CallExpr *TheCall,
+                                             SourceLocation CC) {
+  for (unsigned I = 0, N = TheCall->getNumArgs(); I < N; ++I) {
+    const Expr *CurrA = TheCall->getArg(I);
+    if (!IsImplicitBoolFloatConversion(S, CurrA, true))
+      continue;
+
+    bool IsSwapped = ((I > 0) && IsImplicitBoolFloatConversion(
+                                     S, TheCall->getArg(I - 1), false));
+    IsSwapped |= ((I < (N - 1)) && IsImplicitBoolFloatConversion(
+                                       S, TheCall->getArg(I + 1), false));
+    if (IsSwapped) {
+      // Warn on this floating-point to bool conversion.
+      DiagnoseImpCast(S, CurrA->IgnoreParenImpCasts(),
+                      CurrA->getType(), CC,
+                      diag::warn_impcast_floating_point_to_bool);
+    }
+  }
+}
+
+static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T,
+                                   SourceLocation CC) {
+  // Don't warn on functions which have return type nullptr_t.
+  if (isa<CallExpr>(E))
+    return;
+
+  // Check for NULL (GNUNull) or nullptr (CXX11_nullptr).
+  const Expr *NewE = E->IgnoreParenImpCasts();
+  bool IsGNUNullExpr = isa<GNUNullExpr>(NewE);
+  bool HasNullPtrType = NewE->getType()->isNullPtrType();
+  if (!IsGNUNullExpr && !HasNullPtrType)
+    return;
+
+  // Return if target type is a safe conversion.
+  if (T->isAnyPointerType() || T->isBlockPointerType() ||
+      T->isMemberPointerType() || !T->isScalarType() || T->isNullPtrType())
+    return;
+
+  if (S.Diags.isIgnored(diag::warn_impcast_null_pointer_to_integer,
+                        E->getExprLoc()))
+    return;
+
+  SourceLocation Loc = E->getSourceRange().getBegin();
+
+  // Venture through the macro stacks to get to the source of macro arguments.
+  // The new location is a better location than the complete location that was
+  // passed in.
+  Loc = S.SourceMgr.getTopMacroCallerLoc(Loc);
+  CC = S.SourceMgr.getTopMacroCallerLoc(CC);
+
+  // __null is usually wrapped in a macro.  Go up a macro if that is the case.
+  if (IsGNUNullExpr && Loc.isMacroID()) {
+    StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics(
+        Loc, S.SourceMgr, S.getLangOpts());
+    if (MacroName == "NULL")
+      Loc = S.SourceMgr.getImmediateExpansionRange(Loc).getBegin();
+  }
+
+  // Only warn if the null and context location are in the same macro expansion.
+  if (S.SourceMgr.getFileID(Loc) != S.SourceMgr.getFileID(CC))
+    return;
+
+  S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer)
+      << HasNullPtrType << T << SourceRange(CC)
+      << FixItHint::CreateReplacement(Loc,
+                                      S.getFixItZeroLiteralForType(T, Loc));
+}
+
+// Helper function to filter out cases for constant width constant conversion.
+// Don't warn on char array initialization or for non-decimal values.
+static bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T,
+                                          SourceLocation CC) {
+  // If initializing from a constant, and the constant starts with '0',
+  // then it is a binary, octal, or hexadecimal.  Allow these constants
+  // to fill all the bits, even if there is a sign change.
+  if (auto *IntLit = dyn_cast<IntegerLiteral>(E->IgnoreParenImpCasts())) {
+    const char FirstLiteralCharacter =
+        S.getSourceManager().getCharacterData(IntLit->getBeginLoc())[0];
+    if (FirstLiteralCharacter == '0')
+      return false;
+  }
+
+  // If the CC location points to a '{', and the type is char, then assume
+  // assume it is an array initialization.
+  if (CC.isValid() && T->isCharType()) {
+    const char FirstContextCharacter =
+        S.getSourceManager().getCharacterData(CC)[0];
+    if (FirstContextCharacter == '{')
+      return false;
+  }
+
+  return true;
+}
+
+static const IntegerLiteral *getIntegerLiteral(Expr *E) {
+  const auto *IL = dyn_cast<IntegerLiteral>(E);
+  if (!IL) {
+    if (auto *UO = dyn_cast<UnaryOperator>(E)) {
+      if (UO->getOpcode() == UO_Minus)
+        return dyn_cast<IntegerLiteral>(UO->getSubExpr());
+    }
+  }
+
+  return IL;
+}
+
+static void DiagnoseIntInBoolContext(Sema &S, Expr *E) {
+  E = E->IgnoreParenImpCasts();
+  SourceLocation ExprLoc = E->getExprLoc();
+
+  if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
+    BinaryOperator::Opcode Opc = BO->getOpcode();
+    Expr::EvalResult Result;
+    // Do not diagnose unsigned shifts.
+    if (Opc == BO_Shl) {
+      const auto *LHS = getIntegerLiteral(BO->getLHS());
+      const auto *RHS = getIntegerLiteral(BO->getRHS());
+      if (LHS && LHS->getValue() == 0)
+        S.Diag(ExprLoc, diag::warn_left_shift_always) << 0;
+      else if (!E->isValueDependent() && LHS && RHS &&
+               RHS->getValue().isNonNegative() &&
+               E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects))
+        S.Diag(ExprLoc, diag::warn_left_shift_always)
+            << (Result.Val.getInt() != 0);
+      else if (E->getType()->isSignedIntegerType())
+        S.Diag(ExprLoc, diag::warn_left_shift_in_bool_context)
+            << FixItHint::CreateInsertion(E->getBeginLoc(), "(")
+            << FixItHint::CreateInsertion(S.getLocForEndOfToken(E->getEndLoc()),
+                                          ") != 0");
+    }
+  }
+
+  if (const auto *CO = dyn_cast<ConditionalOperator>(E)) {
+    const auto *LHS = getIntegerLiteral(CO->getTrueExpr());
+    const auto *RHS = getIntegerLiteral(CO->getFalseExpr());
+    if (!LHS || !RHS)
+      return;
+    if ((LHS->getValue() == 0 || LHS->getValue() == 1) &&
+        (RHS->getValue() == 0 || RHS->getValue() == 1))
+      // Do not diagnose common idioms.
+      return;
+    if (LHS->getValue() != 0 && RHS->getValue() != 0)
+      S.Diag(ExprLoc, diag::warn_integer_constants_in_conditional_always_true);
+  }
+}
+
+static void DiagnoseMixedUnicodeImplicitConversion(Sema &S, const Type *Source,
+                                                   const Type *Target, Expr *E,
+                                                   QualType T,
+                                                   SourceLocation CC) {
+  assert(Source->isUnicodeCharacterType() && Target->isUnicodeCharacterType() &&
+         Source != Target);
+
+  // Lone surrogates have a distinct representation in UTF-32.
+  // Converting between UTF-16 and UTF-32 codepoints seems very widespread,
+  // so don't warn on such conversion.
+  if (Source->isChar16Type() && Target->isChar32Type())
+    return;
+
+  Expr::EvalResult Result;
+  if (E->EvaluateAsInt(Result, S.getASTContext(), Expr::SE_AllowSideEffects,
+                       S.isConstantEvaluatedContext())) {
+    llvm::APSInt Value(32);
+    Value = Result.Val.getInt();
+    bool IsASCII = Value <= 0x7F;
+    bool IsBMP = Value <= 0xDFFF || (Value >= 0xE000 && Value <= 0xFFFF);
+    bool ConversionPreservesSemantics =
+        IsASCII || (!Source->isChar8Type() && !Target->isChar8Type() && IsBMP);
+
+    if (!ConversionPreservesSemantics) {
+      auto IsSingleCodeUnitCP = [](const QualType &T,
+                                   const llvm::APSInt &Value) {
+        if (T->isChar8Type())
+          return llvm::IsSingleCodeUnitUTF8Codepoint(Value.getExtValue());
+        if (T->isChar16Type())
+          return llvm::IsSingleCodeUnitUTF16Codepoint(Value.getExtValue());
+        assert(T->isChar32Type());
+        return llvm::IsSingleCodeUnitUTF32Codepoint(Value.getExtValue());
+      };
+
+      S.Diag(CC, diag::warn_impcast_unicode_char_type_constant)
+          << E->getType() << T
+          << IsSingleCodeUnitCP(E->getType().getUnqualifiedType(), Value)
+          << FormatUTFCodeUnitAsCodepoint(Value.getExtValue(), E->getType());
+    }
+  } else {
+    bool LosesPrecision = S.getASTContext().getIntWidth(E->getType()) >
+                          S.getASTContext().getIntWidth(T);
+    DiagnoseImpCast(S, E, T, CC,
+                    LosesPrecision ? diag::warn_impcast_unicode_precision
+                                   : diag::warn_impcast_unicode_char_type);
+  }
+}
+
+bool Sema::DiscardingCFIUncheckedCallee(QualType From, QualType To) const {
+  From = Context.getCanonicalType(From);
+  To = Context.getCanonicalType(To);
+  QualType MaybePointee = From->getPointeeType();
+  if (!MaybePointee.isNull() && MaybePointee->getAs<FunctionType>())
+    From = MaybePointee;
+  MaybePointee = To->getPointeeType();
+  if (!MaybePointee.isNull() && MaybePointee->getAs<FunctionType>())
+    To = MaybePointee;
+
+  if (const auto *FromFn = From->getAs<FunctionType>()) {
+    if (const auto *ToFn = To->getAs<FunctionType>()) {
+      if (FromFn->getCFIUncheckedCalleeAttr() &&
+          !ToFn->getCFIUncheckedCalleeAttr())
+        return true;
+    }
+  }
+  return false;
+}
+
+void Sema::CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC,
+                                   bool *ICContext, bool IsListInit) {
+  if (E->isTypeDependent() || E->isValueDependent()) return;
+
+  const Type *Source = Context.getCanonicalType(E->getType()).getTypePtr();
+  const Type *Target = Context.getCanonicalType(T).getTypePtr();
+  if (Source == Target) return;
+  if (Target->isDependentType()) return;
+
+  // If the conversion context location is invalid don't complain. We also
+  // don't want to emit a warning if the issue occurs from the expansion of
+  // a system macro. The problem is that 'getSpellingLoc()' is slow, so we
+  // delay this check as long as possible. Once we detect we are in that
+  // scenario, we just return.
+  if (CC.isInvalid())
+    return;
+
+  if (Source->isAtomicType())
+    Diag(E->getExprLoc(), diag::warn_atomic_implicit_seq_cst);
+
+  // Diagnose implicit casts to bool.
+  if (Target->isSpecificBuiltinType(BuiltinType::Bool)) {
+    if (isa<StringLiteral>(E))
+      // Warn on string literal to bool.  Checks for string literals in logical
+      // and expressions, for instance, assert(0 && "error here"), are
+      // prevented by a check in AnalyzeImplicitConversions().
+      return DiagnoseImpCast(*this, E, T, CC,
+                             diag::warn_impcast_string_literal_to_bool);
+    if (isa<ObjCStringLiteral>(E) || isa<ObjCArrayLiteral>(E) ||
+        isa<ObjCDictionaryLiteral>(E) || isa<ObjCBoxedExpr>(E)) {
+      // This covers the literal expressions that evaluate to Objective-C
+      // objects.
+      return DiagnoseImpCast(*this, E, T, CC,
+                             diag::warn_impcast_objective_c_literal_to_bool);
+    }
+    if (Source->isPointerType() || Source->canDecayToPointerType()) {
+      // Warn on pointer to bool conversion that is always true.
+      DiagnoseAlwaysNonNullPointer(E, Expr::NPCK_NotNull, /*IsEqual*/ false,
+                                   SourceRange(CC));
+    }
+  }
+
+  // If the we're converting a constant to an ObjC BOOL on a platform where BOOL
+  // is a typedef for signed char (macOS), then that constant value has to be 1
+  // or 0.
+  if (ObjC().isSignedCharBool(T) && Source->isIntegralType(Context)) {
+    Expr::EvalResult Result;
+    if (E->EvaluateAsInt(Result, getASTContext(), Expr::SE_AllowSideEffects)) {
+      if (Result.Val.getInt() != 1 && Result.Val.getInt() != 0) {
+        ObjC().adornBoolConversionDiagWithTernaryFixit(
+            E, Diag(CC, diag::warn_impcast_constant_value_to_objc_bool)
+                   << toString(Result.Val.getInt(), 10));
+      }
+      return;
+    }
+  }
+
+  // Check implicit casts from Objective-C collection literals to specialized
+  // collection types, e.g., NSArray<NSString *> *.
+  if (auto *ArrayLiteral = dyn_cast<ObjCArrayLiteral>(E))
+    ObjC().checkArrayLiteral(QualType(Target, 0), ArrayLiteral);
+  else if (auto *DictionaryLiteral = dyn_cast<ObjCDictionaryLiteral>(E))
+    ObjC().checkDictionaryLiteral(QualType(Target, 0), DictionaryLiteral);
+
+  // Strip vector types.
+  if (isa<VectorType>(Source)) {
+    if (Target->isSveVLSBuiltinType() &&
+        (ARM().areCompatibleSveTypes(QualType(Target, 0),
+                                     QualType(Source, 0)) ||
+         ARM().areLaxCompatibleSveTypes(QualType(Target, 0),
+                                        QualType(Source, 0))))
+      return;
+
+    if (Target->isRVVVLSBuiltinType() &&
+        (Context.areCompatibleRVVTypes(QualType(Target, 0),
+                                       QualType(Source, 0)) ||
+         Context.areLaxCompatibleRVVTypes(QualType(Target, 0),
+                                          QualType(Source, 0))))
+      return;
+
+    if (!isa<VectorType>(Target)) {
+      if (SourceMgr.isInSystemMacro(CC))
+        return;
+      return DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_vector_scalar);
+    }
+    if (getLangOpts().HLSL &&
+        Target->castAs<VectorType>()->getNumElements() <
+            Source->castAs<VectorType>()->getNumElements()) {
+      // Diagnose vector truncation but don't return. We may also want to
+      // diagnose an element conversion.
+      DiagnoseImpCast(*this, E, T, CC,
+                      diag::warn_hlsl_impcast_vector_truncation);
+    }
+
+    // If the vector cast is cast between two vectors of the same size, it is
+    // a bitcast, not a conversion, except under HLSL where it is a conversion.
+    if (!getLangOpts().HLSL &&
+        Context.getTypeSize(Source) == Context.getTypeSize(Target))
+      return;
+
+    Source = cast<VectorType>(Source)->getElementType().getTypePtr();
+    Target = cast<VectorType>(Target)->getElementType().getTypePtr();
+  }
+  if (const auto *VecTy = dyn_cast<VectorType>(Target))
+    Target = VecTy->getElementType().getTypePtr();
+
+  if (isa<ConstantMatrixType>(Source)) {
+    if (Target->isScalarType())
+      return DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_matrix_scalar);
+
+    if (getLangOpts().HLSL &&
+        Target->castAs<ConstantMatrixType>()->getNumElementsFlattened() <
+            Source->castAs<ConstantMatrixType>()->getNumElementsFlattened()) {
+      // Diagnose Matrix truncation but don't return. We may also want to
+      // diagnose an element conversion.
+      DiagnoseImpCast(*this, E, T, CC,
+                      diag::warn_hlsl_impcast_matrix_truncation);
+    }
+  }
+  // Strip complex types.
+  if (isa<ComplexType>(Source)) {
+    if (!isa<ComplexType>(Target)) {
+      if (SourceMgr.isInSystemMacro(CC) || Target->isBooleanType())
+        return;
+
+      return DiagnoseImpCast(*this, E, T, CC,
+                             getLangOpts().CPlusPlus
+                                 ? diag::err_impcast_complex_scalar
+                                 : diag::warn_impcast_complex_scalar);
+    }
+
+    Source = cast<ComplexType>(Source)->getElementType().getTypePtr();
+    Target = cast<ComplexType>(Target)->getElementType().getTypePtr();
+  }
+
+  const BuiltinType *SourceBT = dyn_cast<BuiltinType>(Source);
+  const BuiltinType *TargetBT = dyn_cast<BuiltinType>(Target);
+
+  // Strip SVE vector types
+  if (SourceBT && SourceBT->isSveVLSBuiltinType()) {
+    // Need the original target type for vector type checks
+    const Type *OriginalTarget = Context.getCanonicalType(T).getTypePtr();
+    // Handle conversion from scalable to fixed when msve-vector-bits is
+    // specified
+    if (ARM().areCompatibleSveTypes(QualType(OriginalTarget, 0),
+                                    QualType(Source, 0)) ||
+        ARM().areLaxCompatibleSveTypes(QualType(OriginalTarget, 0),
+                                       QualType(Source, 0)))
+      return;
+
+    // If the vector cast is cast between two vectors of the same size, it is
+    // a bitcast, not a conversion.
+    if (Context.getTypeSize(Source) == Context.getTypeSize(Target))
+      return;
+
+    Source = SourceBT->getSveEltType(Context).getTypePtr();
+  }
+
+  if (TargetBT && TargetBT->isSveVLSBuiltinType())
+    Target = TargetBT->getSveEltType(Context).getTypePtr();
+
+  // If the source is floating point...
+  if (SourceBT && SourceBT->isFloatingPoint()) {
+    // ...and the target is floating point...
+    if (TargetBT && TargetBT->isFloatingPoint()) {
+      // ...then warn if we're dropping FP rank.
+
+      int Order = getASTContext().getFloatingTypeSemanticOrder(
+          QualType(SourceBT, 0), QualType(TargetBT, 0));
+      if (Order > 0) {
+        // Don't warn about float constants that are precisely
+        // representable in the target type.
+        Expr::EvalResult result;
+        if (E->EvaluateAsRValue(result, Context)) {
+          // Value might be a float, a float vector, or a float complex.
+          if (IsSameFloatAfterCast(
+                  result.Val,
+                  Context.getFloatTypeSemantics(QualType(TargetBT, 0)),
+                  Context.getFloatTypeSemantics(QualType(SourceBT, 0))))
+            return;
+        }
+
+        if (SourceMgr.isInSystemMacro(CC))
+          return;
+
+        DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_float_precision);
+      }
+      // ... or possibly if we're increasing rank, too
+      else if (Order < 0) {
+        if (SourceMgr.isInSystemMacro(CC))
+          return;
+
+        DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_double_promotion);
+      }
+      return;
+    }
+
+    // If the target is integral, always warn.
+    if (TargetBT && TargetBT->isInteger()) {
+      if (SourceMgr.isInSystemMacro(CC))
+        return;
+
+      DiagnoseFloatingImpCast(*this, E, T, CC);
+    }
+
+    // Detect the case where a call result is converted from floating-point to
+    // to bool, and the final argument to the call is converted from bool, to
+    // discover this typo:
+    //
+    //    bool b = fabs(x < 1.0);  // should be "bool b = fabs(x) < 1.0;"
+    //
+    // FIXME: This is an incredibly special case; is there some more general
+    // way to detect this class of misplaced-parentheses bug?
+    if (Target->isBooleanType() && isa<CallExpr>(E)) {
+      // Check last argument of function call to see if it is an
+      // implicit cast from a type matching the type the result
+      // is being cast to.
+      CallExpr *CEx = cast<CallExpr>(E);
+      if (unsigned NumArgs = CEx->getNumArgs()) {
+        Expr *LastA = CEx->getArg(NumArgs - 1);
+        Expr *InnerE = LastA->IgnoreParenImpCasts();
+        if (isa<ImplicitCastExpr>(LastA) &&
+            InnerE->getType()->isBooleanType()) {
+          // Warn on this floating-point to bool conversion
+          DiagnoseImpCast(*this, E, T, CC,
+                          diag::warn_impcast_floating_point_to_bool);
+        }
+      }
+    }
+    return;
+  }
+
+  // Valid casts involving fixed point types should be accounted for here.
+  if (Source->isFixedPointType()) {
+    if (Target->isUnsaturatedFixedPointType()) {
+      Expr::EvalResult Result;
+      if (E->EvaluateAsFixedPoint(Result, Context, Expr::SE_AllowSideEffects,
+                                  isConstantEvaluatedContext())) {
+        llvm::APFixedPoint Value = Result.Val.getFixedPoint();
+        llvm::APFixedPoint MaxVal = Context.getFixedPointMax(T);
+        llvm::APFixedPoint MinVal = Context.getFixedPointMin(T);
+        if (Value > MaxVal || Value < MinVal) {
+          DiagRuntimeBehavior(E->getExprLoc(), E,
+                              PDiag(diag::warn_impcast_fixed_point_range)
+                                  << Value.toString() << T
+                                  << E->getSourceRange()
+                                  << clang::SourceRange(CC));
+          return;
+        }
+      }
+    } else if (Target->isIntegerType()) {
+      Expr::EvalResult Result;
+      if (!isConstantEvaluatedContext() &&
+          E->EvaluateAsFixedPoint(Result, Context, Expr::SE_AllowSideEffects)) {
+        llvm::APFixedPoint FXResult = Result.Val.getFixedPoint();
+
+        bool Overflowed;
+        llvm::APSInt IntResult = FXResult.convertToInt(
+            Context.getIntWidth(T), Target->isSignedIntegerOrEnumerationType(),
+            &Overflowed);
+
+        if (Overflowed) {
+          DiagRuntimeBehavior(E->getExprLoc(), E,
+                              PDiag(diag::warn_impcast_fixed_point_range)
+                                  << FXResult.toString() << T
+                                  << E->getSourceRange()
+                                  << clang::SourceRange(CC));
+          return;
+        }
+      }
+    }
+  } else if (Target->isUnsaturatedFixedPointType()) {
+    if (Source->isIntegerType()) {
+      Expr::EvalResult Result;
+      if (!isConstantEvaluatedContext() &&
+          E->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects)) {
+        llvm::APSInt Value = Result.Val.getInt();
+
+        bool Overflowed;
+        llvm::APFixedPoint IntResult = llvm::APFixedPoint::getFromIntValue(
+            Value, Context.getFixedPointSemantics(T), &Overflowed);
+
+        if (Overflowed) {
+          DiagRuntimeBehavior(E->getExprLoc(), E,
+                              PDiag(diag::warn_impcast_fixed_point_range)
+                                  << toString(Value, /*Radix=*/10) << T
+                                  << E->getSourceRange()
+                                  << clang::SourceRange(CC));
+          return;
+        }
+      }
+    }
+  }
+
+  // If we are casting an integer type to a floating point type without
+  // initialization-list syntax, we might lose accuracy if the floating
+  // point type has a narrower significand than the integer type.
+  if (SourceBT && TargetBT && SourceBT->isIntegerType() &&
+      TargetBT->isFloatingType() && !IsListInit) {
+    // Determine the number of precision bits in the source integer type.
+    std::optional<IntRange> SourceRange =
+        TryGetExprRange(Context, E, isConstantEvaluatedContext(),
+                        /*Approximate=*/true);
+    if (!SourceRange)
+      return;
+    unsigned int SourcePrecision = SourceRange->Width;
+
+    // Determine the number of precision bits in the
+    // target floating point type.
+    unsigned int TargetPrecision = llvm::APFloatBase::semanticsPrecision(
+        Context.getFloatTypeSemantics(QualType(TargetBT, 0)));
+
+    if (SourcePrecision > 0 && TargetPrecision > 0 &&
+        SourcePrecision > TargetPrecision) {
+
+      if (std::optional<llvm::APSInt> SourceInt =
+              E->getIntegerConstantExpr(Context)) {
+        // If the source integer is a constant, convert it to the target
+        // floating point type. Issue a warning if the value changes
+        // during the whole conversion.
+        llvm::APFloat TargetFloatValue(
+            Context.getFloatTypeSemantics(QualType(TargetBT, 0)));
+        llvm::APFloat::opStatus ConversionStatus =
+            TargetFloatValue.convertFromAPInt(
+                *SourceInt, SourceBT->isSignedInteger(),
+                llvm::APFloat::rmNearestTiesToEven);
+
+        if (ConversionStatus != llvm::APFloat::opOK) {
+          SmallString<32> PrettySourceValue;
+          SourceInt->toString(PrettySourceValue, 10);
+          SmallString<32> PrettyTargetValue;
+          TargetFloatValue.toString(PrettyTargetValue, TargetPrecision);
+
+          DiagRuntimeBehavior(
+              E->getExprLoc(), E,
+              PDiag(diag::warn_impcast_integer_float_precision_constant)
+                  << PrettySourceValue << PrettyTargetValue << E->getType() << T
+                  << E->getSourceRange() << clang::SourceRange(CC));
+        }
+      } else {
+        // Otherwise, the implicit conversion may lose precision.
+        DiagnoseImpCast(*this, E, T, CC,
+                        diag::warn_impcast_integer_float_precision);
+      }
+    }
+  }
+
+  DiagnoseNullConversion(*this, E, T, CC);
+
+  DiscardMisalignedMemberAddress(Target, E);
+
+  if (Source->isUnicodeCharacterType() && Target->isUnicodeCharacterType()) {
+    DiagnoseMixedUnicodeImplicitConversion(*this, Source, Target, E, T, CC);
+    return;
+  }
+
+  if (Target->isBooleanType())
+    DiagnoseIntInBoolContext(*this, E);
+
+  if (DiscardingCFIUncheckedCallee(QualType(Source, 0), QualType(Target, 0))) {
+    Diag(CC, diag::warn_cast_discards_cfi_unchecked_callee)
+        << QualType(Source, 0) << QualType(Target, 0);
+  }
+
+  if (!Source->isIntegerType() || !Target->isIntegerType())
+    return;
+
+  // TODO: remove this early return once the false positives for constant->bool
+  // in templates, macros, etc, are reduced or removed.
+  if (Target->isSpecificBuiltinType(BuiltinType::Bool))
+    return;
+
+  if (ObjC().isSignedCharBool(T) && !Source->isCharType() &&
+      !E->isKnownToHaveBooleanValue(/*Semantic=*/false)) {
+    return ObjC().adornBoolConversionDiagWithTernaryFixit(
+        E, Diag(CC, diag::warn_impcast_int_to_objc_signed_char_bool)
+               << E->getType());
+  }
+  std::optional<IntRange> LikelySourceRange = TryGetExprRange(
+      Context, E, isConstantEvaluatedContext(), /*Approximate=*/true);
+  if (!LikelySourceRange)
+    return;
+
+  IntRange SourceTypeRange =
+      IntRange::forTargetOfCanonicalType(Context, Source);
+  IntRange TargetRange = IntRange::forTargetOfCanonicalType(Context, Target);
+
+  if (LikelySourceRange->Width > TargetRange.Width) {
+    // If the source is a constant, use a default-on diagnostic.
+    // TODO: this should happen for bitfield stores, too.
+    Expr::EvalResult Result;
+    if (E->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects,
+                         isConstantEvaluatedContext())) {
+      llvm::APSInt Value(32);
+      Value = Result.Val.getInt();
+
+      if (SourceMgr.isInSystemMacro(CC))
+        return;
+
+      std::string PrettySourceValue = toString(Value, 10);
+      std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange);
+
+      DiagRuntimeBehavior(E->getExprLoc(), E,
+                          PDiag(diag::warn_impcast_integer_precision_constant)
+                              << PrettySourceValue << PrettyTargetValue
+                              << E->getType() << T << E->getSourceRange()
+                              << SourceRange(CC));
+      return;
+    }
+
+    // People want to build with -Wshorten-64-to-32 and not -Wconversion.
+    if (SourceMgr.isInSystemMacro(CC))
+      return;
+
+    if (const auto *UO = dyn_cast<UnaryOperator>(E)) {
+      if (UO->getOpcode() == UO_Minus)
+        return DiagnoseImpCast(
+            *this, E, T, CC, diag::warn_impcast_integer_precision_on_negation);
+    }
+
+    if (TargetRange.Width == 32 && Context.getIntWidth(E->getType()) == 64)
+      return DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_integer_64_32,
+                             /* pruneControlFlow */ true);
+    return DiagnoseImpCast(*this, E, T, CC,
+                           diag::warn_impcast_integer_precision);
+  }
+
+  if (TargetRange.Width > SourceTypeRange.Width) {
+    if (auto *UO = dyn_cast<UnaryOperator>(E))
+      if (UO->getOpcode() == UO_Minus)
+        if (Source->isUnsignedIntegerType()) {
+          if (Target->isUnsignedIntegerType())
+            return DiagnoseImpCast(*this, E, T, CC,
+                                   diag::warn_impcast_high_order_zero_bits);
+          if (Target->isSignedIntegerType())
+            return DiagnoseImpCast(*this, E, T, CC,
+                                   diag::warn_impcast_nonnegative_result);
+        }
+  }
+
+  if (TargetRange.Width == LikelySourceRange->Width &&
+      !TargetRange.NonNegative && LikelySourceRange->NonNegative &&
+      Source->isSignedIntegerType()) {
+    // Warn when doing a signed to signed conversion, warn if the positive
+    // source value is exactly the width of the target type, which will
+    // cause a negative value to be stored.
+
+    Expr::EvalResult Result;
+    if (E->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects) &&
+        !SourceMgr.isInSystemMacro(CC)) {
+      llvm::APSInt Value = Result.Val.getInt();
+      if (isSameWidthConstantConversion(*this, E, T, CC)) {
+        std::string PrettySourceValue = toString(Value, 10);
+        std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange);
+
+        Diag(E->getExprLoc(),
+             PDiag(diag::warn_impcast_integer_precision_constant)
+                 << PrettySourceValue << PrettyTargetValue << E->getType() << T
+                 << E->getSourceRange() << SourceRange(CC));
+        return;
+      }
+    }
+
+    // Fall through for non-constants to give a sign conversion warning.
+  }
+
+  if ((!isa<EnumType>(Target) || !isa<EnumType>(Source)) &&
+      ((TargetRange.NonNegative && !LikelySourceRange->NonNegative) ||
+       (!TargetRange.NonNegative && LikelySourceRange->NonNegative &&
+        LikelySourceRange->Width == TargetRange.Width))) {
+    if (SourceMgr.isInSystemMacro(CC))
+      return;
+
+    if (SourceBT && SourceBT->isInteger() && TargetBT &&
+        TargetBT->isInteger() &&
+        Source->isSignedIntegerType() == Target->isSignedIntegerType()) {
+      return;
+    }
+
+    unsigned DiagID = diag::warn_impcast_integer_sign;
+
+    // Traditionally, gcc has warned about this under -Wsign-compare.
+    // We also want to warn about it in -Wconversion.
+    // So if -Wconversion is off, use a completely identical diagnostic
+    // in the sign-compare group.
+    // The conditional-checking code will
+    if (ICContext) {
+      DiagID = diag::warn_impcast_integer_sign_conditional;
+      *ICContext = true;
+    }
+
+    DiagnoseImpCast(*this, E, T, CC, DiagID);
+  }
+
+  // If we're implicitly converting from an integer into an enumeration, that
+  // is valid in C but invalid in C++.
+  QualType SourceType = E->getEnumCoercedType(Context);
+  const BuiltinType *CoercedSourceBT = SourceType->getAs<BuiltinType>();
+  if (CoercedSourceBT && CoercedSourceBT->isInteger() && isa<EnumType>(Target))
+    return DiagnoseImpCast(*this, E, T, CC, diag::warn_impcast_int_to_enum);
+
+  // Diagnose conversions between different enumeration types.
+  // In C, we pretend that the type of an EnumConstantDecl is its enumeration
+  // type, to give us better diagnostics.
+  Source = Context.getCanonicalType(SourceType).getTypePtr();
+
+  if (const EnumType *SourceEnum = Source->getAsCanonical<EnumType>())
+    if (const EnumType *TargetEnum = Target->getAsCanonical<EnumType>())
+      if (SourceEnum->getDecl()->hasNameForLinkage() &&
+          TargetEnum->getDecl()->hasNameForLinkage() &&
+          SourceEnum != TargetEnum) {
+        if (SourceMgr.isInSystemMacro(CC))
+          return;
+
+        return DiagnoseImpCast(*this, E, SourceType, T, CC,
+                               diag::warn_impcast_different_enum_types);
+      }
+}
+
+static void CheckConditionalOperator(Sema &S, AbstractConditionalOperator *E,
+                                     SourceLocation CC, QualType T);
+
+static void CheckConditionalOperand(Sema &S, Expr *E, QualType T,
+                                    SourceLocation CC, bool &ICContext) {
+  E = E->IgnoreParenImpCasts();
+  // Diagnose incomplete type for second or third operand in C.
+  if (!S.getLangOpts().CPlusPlus && E->getType()->isRecordType())
+    S.RequireCompleteExprType(E, diag::err_incomplete_type);
+
+  if (auto *CO = dyn_cast<AbstractConditionalOperator>(E))
+    return CheckConditionalOperator(S, CO, CC, T);
+
+  AnalyzeImplicitConversions(S, E, CC);
+  if (E->getType() != T)
+    return S.CheckImplicitConversion(E, T, CC, &ICContext);
+}
+
+static void CheckConditionalOperator(Sema &S, AbstractConditionalOperator *E,
+                                     SourceLocation CC, QualType T) {
+  AnalyzeImplicitConversions(S, E->getCond(), E->getQuestionLoc());
+
+  Expr *TrueExpr = E->getTrueExpr();
+  if (auto *BCO = dyn_cast<BinaryConditionalOperator>(E))
+    TrueExpr = BCO->getCommon();
+
+  bool Suspicious = false;
+  CheckConditionalOperand(S, TrueExpr, T, CC, Suspicious);
+  CheckConditionalOperand(S, E->getFalseExpr(), T, CC, Suspicious);
+
+  if (T->isBooleanType())
+    DiagnoseIntInBoolContext(S, E);
+
+  // If -Wconversion would have warned about either of the candidates
+  // for a signedness conversion to the context type...
+  if (!Suspicious) return;
+
+  // ...but it's currently ignored...
+  if (!S.Diags.isIgnored(diag::warn_impcast_integer_sign_conditional, CC))
+    return;
+
+  // ...then check whether it would have warned about either of the
+  // candidates for a signedness conversion to the condition type.
+  if (E->getType() == T) return;
+
+  Suspicious = false;
+  S.CheckImplicitConversion(TrueExpr->IgnoreParenImpCasts(), E->getType(), CC,
+                            &Suspicious);
+  if (!Suspicious)
+    S.CheckImplicitConversion(E->getFalseExpr()->IgnoreParenImpCasts(),
+                              E->getType(), CC, &Suspicious);
+}
+
+/// Check conversion of given expression to boolean.
+/// Input argument E is a logical expression.
+static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) {
+  // Run the bool-like conversion checks only for C since there bools are
+  // still not used as the return type from "boolean" operators or as the input
+  // type for conditional operators.
+  if (S.getLangOpts().CPlusPlus)
+    return;
+  if (E->IgnoreParenImpCasts()->getType()->isAtomicType())
+    return;
+  S.CheckImplicitConversion(E->IgnoreParenImpCasts(), S.Context.BoolTy, CC);
+}
+
+namespace {
+struct AnalyzeImplicitConversionsWorkItem {
+  Expr *E;
+  SourceLocation CC;
+  bool IsListInit;
+};
+}
+
+static void CheckCommaOperand(
+    Sema &S, Expr *E, QualType T, SourceLocation CC,
+    bool ExtraCheckForImplicitConversion,
+    llvm::SmallVectorImpl<AnalyzeImplicitConversionsWorkItem> &WorkList) {
+  E = E->IgnoreParenImpCasts();
+  WorkList.push_back({E, CC, false});
+
+  if (ExtraCheckForImplicitConversion && E->getType() != T)
+    S.CheckImplicitConversion(E, T, CC);
+}
+
+/// Data recursive variant of AnalyzeImplicitConversions. Subexpressions
+/// that should be visited are added to WorkList.
+static void AnalyzeImplicitConversions(
+    Sema &S, AnalyzeImplicitConversionsWorkItem Item,
+    llvm::SmallVectorImpl<AnalyzeImplicitConversionsWorkItem> &WorkList) {
+  Expr *OrigE = Item.E;
+  SourceLocation CC = Item.CC;
+
+  QualType T = OrigE->getType();
+  Expr *E = OrigE->IgnoreParenImpCasts();
+
+  // Propagate whether we are in a C++ list initialization expression.
+  // If so, we do not issue warnings for implicit int-float conversion
+  // precision loss, because C++11 narrowing already handles it.
+  //
+  // HLSL's initialization lists are special, so they shouldn't observe the C++
+  // behavior here.
+  bool IsListInit =
+      Item.IsListInit || (isa<InitListExpr>(OrigE) &&
+                          S.getLangOpts().CPlusPlus && !S.getLangOpts().HLSL);
+
+  if (E->isTypeDependent() || E->isValueDependent())
+    return;
+
+  Expr *SourceExpr = E;
+  // Examine, but don't traverse into the source expression of an
+  // OpaqueValueExpr, since it may have multiple parents and we don't want to
+  // emit duplicate diagnostics. Its fine to examine the form or attempt to
+  // evaluate it in the context of checking the specific conversion to T though.
+  if (auto *OVE = dyn_cast<OpaqueValueExpr>(E))
+    if (auto *Src = OVE->getSourceExpr())
+      SourceExpr = Src;
+
+  if (const auto *UO = dyn_cast<UnaryOperator>(SourceExpr))
+    if (UO->getOpcode() == UO_Not &&
+        UO->getSubExpr()->isKnownToHaveBooleanValue())
+      S.Diag(UO->getBeginLoc(), diag::warn_bitwise_negation_bool)
+          << OrigE->getSourceRange() << T->isBooleanType()
+          << FixItHint::CreateReplacement(UO->getBeginLoc(), "!");
+
+  if (auto *BO = dyn_cast<BinaryOperator>(SourceExpr)) {
+    if ((BO->getOpcode() == BO_And || BO->getOpcode() == BO_Or) &&
+        BO->getLHS()->isKnownToHaveBooleanValue() &&
+        BO->getRHS()->isKnownToHaveBooleanValue() &&
+        BO->getLHS()->HasSideEffects(S.Context) &&
+        BO->getRHS()->HasSideEffects(S.Context)) {
+      SourceManager &SM = S.getSourceManager();
+      const LangOptions &LO = S.getLangOpts();
+      SourceLocation BLoc = BO->getOperatorLoc();
+      SourceLocation ELoc = Lexer::getLocForEndOfToken(BLoc, 0, SM, LO);
+      StringRef SR = clang::Lexer::getSourceText(
+          clang::CharSourceRange::getTokenRange(BLoc, ELoc), SM, LO);
+      // To reduce false positives, only issue the diagnostic if the operator
+      // is explicitly spelled as a punctuator. This suppresses the diagnostic
+      // when using 'bitand' or 'bitor' either as keywords in C++ or as macros
+      // in C, along with other macro spellings the user might invent.
+      if (SR.str() == "&" || SR.str() == "|") {
+
+        S.Diag(BO->getBeginLoc(), diag::warn_bitwise_instead_of_logical)
+            << (BO->getOpcode() == BO_And ? "&" : "|")
+            << OrigE->getSourceRange()
+            << FixItHint::CreateReplacement(
+                   BO->getOperatorLoc(),
+                   (BO->getOpcode() == BO_And ? "&&" : "||"));
+        S.Diag(BO->getBeginLoc(), diag::note_cast_operand_to_int);
+      }
+    } else if (BO->isCommaOp() && !S.getLangOpts().CPlusPlus) {
+      /// Analyze the given comma operator. The basic idea behind the analysis
+      /// is to analyze the left and right operands slightly differently. The
+      /// left operand needs to check whether the operand itself has an implicit
+      /// conversion, but not whether the left operand induces an implicit
+      /// conversion for the entire comma expression itself. This is similar to
+      /// how CheckConditionalOperand behaves; it's as-if the correct operand
+      /// were directly used for the implicit conversion check.
+      CheckCommaOperand(S, BO->getLHS(), T, BO->getOperatorLoc(),
+                        /*ExtraCheckForImplicitConversion=*/false, WorkList);
+      CheckCommaOperand(S, BO->getRHS(), T, BO->getOperatorLoc(),
+                        /*ExtraCheckForImplicitConversion=*/true, WorkList);
+      return;
+    }
+  }
+
+  // For conditional operators, we analyze the arguments as if they
+  // were being fed directly into the output.
+  if (auto *CO = dyn_cast<AbstractConditionalOperator>(SourceExpr)) {
+    CheckConditionalOperator(S, CO, CC, T);
+    return;
+  }
+
+  // Check implicit argument conversions for function calls.
+  if (const auto *Call = dyn_cast<CallExpr>(SourceExpr))
+    CheckImplicitArgumentConversions(S, Call, CC);
+
+  // Go ahead and check any implicit conversions we might have skipped.
+  // The non-canonical typecheck is just an optimization;
+  // CheckImplicitConversion will filter out dead implicit conversions.
+  if (SourceExpr->getType() != T)
+    S.CheckImplicitConversion(SourceExpr, T, CC, nullptr, IsListInit);
+
+  // Now continue drilling into this expression.
+
+  if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) {
+    // The bound subexpressions in a PseudoObjectExpr are not reachable
+    // as transitive children.
+    // FIXME: Use a more uniform representation for this.
+    for (auto *SE : POE->semantics())
+      if (auto *OVE = dyn_cast<OpaqueValueExpr>(SE))
+        WorkList.push_back({OVE->getSourceExpr(), CC, IsListInit});
+  }
+
+  // Skip past explicit casts.
+  if (auto *CE = dyn_cast<ExplicitCastExpr>(E)) {
+    E = CE->getSubExpr();
+    // In the special case of a C++ function-style cast with braces,
+    // CXXFunctionalCastExpr has an InitListExpr as direct child with a single
+    // initializer. This InitListExpr basically belongs to the cast itself, so
+    // we skip it too. Specifically this is needed to silence -Wdouble-promotion
+    if (isa<CXXFunctionalCastExpr>(CE)) {
+      if (auto *InitListE = dyn_cast<InitListExpr>(E)) {
+        if (InitListE->getNumInits() == 1) {
+          E = InitListE->getInit(0);
+        }
+      }
+    }
+    E = E->IgnoreParenImpCasts();
+    if (!CE->getType()->isVoidType() && E->getType()->isAtomicType())
+      S.Diag(E->getBeginLoc(), diag::warn_atomic_implicit_seq_cst);
+    WorkList.push_back({E, CC, IsListInit});
+    return;
+  }
+
+  if (auto *OutArgE = dyn_cast<HLSLOutArgExpr>(E)) {
+    WorkList.push_back({OutArgE->getArgLValue(), CC, IsListInit});
+    // The base expression is only used to initialize the parameter for
+    // arguments to `inout` parameters, so we only traverse down the base
+    // expression for `inout` cases.
+    if (OutArgE->isInOut())
+      WorkList.push_back(
+          {OutArgE->getCastedTemporary()->getSourceExpr(), CC, IsListInit});
+    WorkList.push_back({OutArgE->getWritebackCast(), CC, IsListInit});
+    return;
+  }
+
+  if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+    // Do a somewhat different check with comparison operators.
+    if (BO->isComparisonOp())
+      return AnalyzeComparison(S, BO);
+
+    // And with simple assignments.
+    if (BO->getOpcode() == BO_Assign)
+      return AnalyzeAssignment(S, BO);
+    // And with compound assignments.
+    if (BO->isAssignmentOp())
+      return AnalyzeCompoundAssignment(S, BO);
+  }
+
+  // These break the otherwise-useful invariant below.  Fortunately,
+  // we don't really need to recurse into them, because any internal
+  // expressions should have been analyzed already when they were
+  // built into statements.
+  if (isa<StmtExpr>(E)) return;
+
+  // Don't descend into unevaluated contexts.
+  if (isa<UnaryExprOrTypeTraitExpr>(E)) return;
+
+  // Now just recurse over the expression's children.
+  CC = E->getExprLoc();
+  BinaryOperator *BO = dyn_cast<BinaryOperator>(E);
+  bool IsLogicalAndOperator = BO && BO->getOpcode() == BO_LAnd;
+  for (Stmt *SubStmt : E->children()) {
+    Expr *ChildExpr = dyn_cast_or_null<Expr>(SubStmt);
+    if (!ChildExpr)
+      continue;
+
+    if (auto *CSE = dyn_cast<CoroutineSuspendExpr>(E))
+      if (ChildExpr == CSE->getOperand())
+        // Do not recurse over a CoroutineSuspendExpr's operand.
+        // The operand is also a subexpression of getCommonExpr(), and
+        // recursing into it directly would produce duplicate diagnostics.
+        continue;
+
+    if (IsLogicalAndOperator &&
+        isa<StringLiteral>(ChildExpr->IgnoreParenImpCasts()))
+      // Ignore checking string literals that are in logical and operators.
+      // This is a common pattern for asserts.
+      continue;
+    WorkList.push_back({ChildExpr, CC, IsListInit});
+  }
+
+  if (BO && BO->isLogicalOp()) {
+    Expr *SubExpr = BO->getLHS()->IgnoreParenImpCasts();
+    if (!IsLogicalAndOperator || !isa<StringLiteral>(SubExpr))
+      ::CheckBoolLikeConversion(S, SubExpr, BO->getExprLoc());
+
+    SubExpr = BO->getRHS()->IgnoreParenImpCasts();
+    if (!IsLogicalAndOperator || !isa<StringLiteral>(SubExpr))
+      ::CheckBoolLikeConversion(S, SubExpr, BO->getExprLoc());
+  }
+
+  if (const UnaryOperator *U = dyn_cast<UnaryOperator>(E)) {
+    if (U->getOpcode() == UO_LNot) {
+      ::CheckBoolLikeConversion(S, U->getSubExpr(), CC);
+    } else if (U->getOpcode() != UO_AddrOf) {
+      if (U->getSubExpr()->getType()->isAtomicType())
+        S.Diag(U->getSubExpr()->getBeginLoc(),
+               diag::warn_atomic_implicit_seq_cst);
+    }
+  }
+}
+
+/// AnalyzeImplicitConversions - Find and report any interesting
+/// implicit conversions in the given expression.  There are a couple
+/// of competing diagnostics here, -Wconversion and -Wsign-compare.
+static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC,
+                                       bool IsListInit/*= false*/) {
+  llvm::SmallVector<AnalyzeImplicitConversionsWorkItem, 16> WorkList;
+  WorkList.push_back({OrigE, CC, IsListInit});
+  while (!WorkList.empty())
+    AnalyzeImplicitConversions(S, WorkList.pop_back_val(), WorkList);
+}
+
+// Helper function for Sema::DiagnoseAlwaysNonNullPointer.
+// Returns true when emitting a warning about taking the address of a reference.
+static bool CheckForReference(Sema &SemaRef, const Expr *E,
+                              const PartialDiagnostic &PD) {
+  E = E->IgnoreParenImpCasts();
+
+  const FunctionDecl *FD = nullptr;
+
+  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+    if (!DRE->getDecl()->getType()->isReferenceType())
+      return false;
+  } else if (const MemberExpr *M = dyn_cast<MemberExpr>(E)) {
+    if (!M->getMemberDecl()->getType()->isReferenceType())
+      return false;
+  } else if (const CallExpr *Call = dyn_cast<CallExpr>(E)) {
+    if (!Call->getCallReturnType(SemaRef.Context)->isReferenceType())
+      return false;
+    FD = Call->getDirectCallee();
+  } else {
+    return false;
+  }
+
+  SemaRef.Diag(E->getExprLoc(), PD);
+
+  // If possible, point to location of function.
+  if (FD) {
+    SemaRef.Diag(FD->getLocation(), diag::note_reference_is_return_value) << FD;
+  }
+
+  return true;
+}
+
+// Returns true if the SourceLocation is expanded from any macro body.
+// Returns false if the SourceLocation is invalid, is from not in a macro
+// expansion, or is from expanded from a top-level macro argument.
+static bool IsInAnyMacroBody(const SourceManager &SM, SourceLocation Loc) {
+  if (Loc.isInvalid())
+    return false;
+
+  while (Loc.isMacroID()) {
+    if (SM.isMacroBodyExpansion(Loc))
+      return true;
+    Loc = SM.getImmediateMacroCallerLoc(Loc);
+  }
+
+  return false;
+}
+
+void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
+                                        Expr::NullPointerConstantKind NullKind,
+                                        bool IsEqual, SourceRange Range) {
+  if (!E)
+    return;
+
+  // Don't warn inside macros.
+  if (E->getExprLoc().isMacroID()) {
+    const SourceManager &SM = getSourceManager();
+    if (IsInAnyMacroBody(SM, E->getExprLoc()) ||
+        IsInAnyMacroBody(SM, Range.getBegin()))
+      return;
+  }
+  E = E->IgnoreImpCasts();
+
+  const bool IsCompare = NullKind != Expr::NPCK_NotNull;
+
+  if (isa<CXXThisExpr>(E)) {
+    unsigned DiagID = IsCompare ? diag::warn_this_null_compare
+                                : diag::warn_this_bool_conversion;
+    Diag(E->getExprLoc(), DiagID) << E->getSourceRange() << Range << IsEqual;
+    return;
+  }
+
+  bool IsAddressOf = false;
+
+  if (auto *UO = dyn_cast<UnaryOperator>(E->IgnoreParens())) {
+    if (UO->getOpcode() != UO_AddrOf)
+      return;
+    IsAddressOf = true;
+    E = UO->getSubExpr();
+  }
+
+  if (IsAddressOf) {
+    unsigned DiagID = IsCompare
+                          ? diag::warn_address_of_reference_null_compare
+                          : diag::warn_address_of_reference_bool_conversion;
+    PartialDiagnostic PD = PDiag(DiagID) << E->getSourceRange() << Range
+                                         << IsEqual;
+    if (CheckForReference(*this, E, PD)) {
+      return;
+    }
+  }
+
+  auto ComplainAboutNonnullParamOrCall = [&](const Attr *NonnullAttr) {
+    bool IsParam = isa<NonNullAttr>(NonnullAttr);
+    std::string Str;
+    llvm::raw_string_ostream S(Str);
+    E->printPretty(S, nullptr, getPrintingPolicy());
+    unsigned DiagID = IsCompare ? diag::warn_nonnull_expr_compare
+                                : diag::warn_cast_nonnull_to_bool;
+    Diag(E->getExprLoc(), DiagID) << IsParam << S.str()
+      << E->getSourceRange() << Range << IsEqual;
+    Diag(NonnullAttr->getLocation(), diag::note_declared_nonnull) << IsParam;
+  };
+
+  // If we have a CallExpr that is tagged with returns_nonnull, we can complain.
+  if (auto *Call = dyn_cast<CallExpr>(E->IgnoreParenImpCasts())) {
+    if (auto *Callee = Call->getDirectCallee()) {
+      if (const Attr *A = Callee->getAttr<ReturnsNonNullAttr>()) {
+        ComplainAboutNonnullParamOrCall(A);
+        return;
+      }
+    }
+  }
+
+  // Complain if we are converting a lambda expression to a boolean value
+  // outside of instantiation.
+  if (!inTemplateInstantiation()) {
+    if (const auto *MCallExpr = dyn_cast<CXXMemberCallExpr>(E)) {
+      if (const auto *MRecordDecl = MCallExpr->getRecordDecl();
+          MRecordDecl && MRecordDecl->isLambda()) {
+        Diag(E->getExprLoc(), diag::warn_impcast_pointer_to_bool)
+            << /*LambdaPointerConversionOperatorType=*/3
+            << MRecordDecl->getSourceRange() << Range << IsEqual;
+        return;
+      }
+    }
+  }
+
+  // Expect to find a single Decl.  Skip anything more complicated.
+  ValueDecl *D = nullptr;
+  if (DeclRefExpr *R = dyn_cast<DeclRefExpr>(E)) {
+    D = R->getDecl();
+  } else if (MemberExpr *M = dyn_cast<MemberExpr>(E)) {
+    D = M->getMemberDecl();
+  }
+
+  // Weak Decls can be null.
+  if (!D || D->isWeak())
+    return;
+
+  // Check for parameter decl with nonnull attribute
+  if (const auto* PV = dyn_cast<ParmVarDecl>(D)) {
+    if (getCurFunction() &&
+        !getCurFunction()->ModifiedNonNullParams.count(PV)) {
+      if (const Attr *A = PV->getAttr<NonNullAttr>()) {
+        ComplainAboutNonnullParamOrCall(A);
+        return;
+      }
+
+      if (const auto *FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) {
+        // Skip function template not specialized yet.
+        if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
+          return;
+        auto ParamIter = llvm::find(FD->parameters(), PV);
+        assert(ParamIter != FD->param_end());
+        unsigned ParamNo = std::distance(FD->param_begin(), ParamIter);
+
+        for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
+          if (!NonNull->args_size()) {
+              ComplainAboutNonnullParamOrCall(NonNull);
+              return;
+          }
+
+          for (const ParamIdx &ArgNo : NonNull->args()) {
+            if (ArgNo.getASTIndex() == ParamNo) {
+              ComplainAboutNonnullParamOrCall(NonNull);
+              return;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  QualType T = D->getType();
+  const bool IsArray = T->isArrayType();
+  const bool IsFunction = T->isFunctionType();
+
+  // Address of function is used to silence the function warning.
+  if (IsAddressOf && IsFunction) {
+    return;
+  }
+
+  // Found nothing.
+  if (!IsAddressOf && !IsFunction && !IsArray)
+    return;
+
+  // Pretty print the expression for the diagnostic.
+  std::string Str;
+  llvm::raw_string_ostream S(Str);
+  E->printPretty(S, nullptr, getPrintingPolicy());
+
+  unsigned DiagID = IsCompare ? diag::warn_null_pointer_compare
+                              : diag::warn_impcast_pointer_to_bool;
+  enum {
+    AddressOf,
+    FunctionPointer,
+    ArrayPointer
+  } DiagType;
+  if (IsAddressOf)
+    DiagType = AddressOf;
+  else if (IsFunction)
+    DiagType = FunctionPointer;
+  else if (IsArray)
+    DiagType = ArrayPointer;
+  else
+    llvm_unreachable("Could not determine diagnostic.");
+  Diag(E->getExprLoc(), DiagID) << DiagType << S.str() << E->getSourceRange()
+                                << Range << IsEqual;
+
+  if (!IsFunction)
+    return;
+
+  // Suggest '&' to silence the function warning.
+  Diag(E->getExprLoc(), diag::note_function_warning_silence)
+      << FixItHint::CreateInsertion(E->getBeginLoc(), "&");
+
+  // Check to see if '()' fixit should be emitted.
+  QualType ReturnType;
+  UnresolvedSet<4> NonTemplateOverloads;
+  tryExprAsCall(*E, ReturnType, NonTemplateOverloads);
+  if (ReturnType.isNull())
+    return;
+
+  if (IsCompare) {
+    // There are two cases here.  If there is null constant, the only suggest
+    // for a pointer return type.  If the null is 0, then suggest if the return
+    // type is a pointer or an integer type.
+    if (!ReturnType->isPointerType()) {
+      if (NullKind == Expr::NPCK_ZeroExpression ||
+          NullKind == Expr::NPCK_ZeroLiteral) {
+        if (!ReturnType->isIntegerType())
+          return;
+      } else {
+        return;
+      }
+    }
+  } else { // !IsCompare
+    // For function to bool, only suggest if the function pointer has bool
+    // return type.
+    if (!ReturnType->isSpecificBuiltinType(BuiltinType::Bool))
+      return;
+  }
+  Diag(E->getExprLoc(), diag::note_function_to_function_call)
+      << FixItHint::CreateInsertion(getLocForEndOfToken(E->getEndLoc()), "()");
+}
+
+void Sema::CheckImplicitConversions(Expr *E, SourceLocation CC) {
+  // Don't diagnose in unevaluated contexts.
+  if (isUnevaluatedContext())
+    return;
+
+  // Don't diagnose for value- or type-dependent expressions.
+  if (E->isTypeDependent() || E->isValueDependent())
+    return;
+
+  // Check for array bounds violations in cases where the check isn't triggered
+  // elsewhere for other Expr types (like BinaryOperators), e.g. when an
+  // ArraySubscriptExpr is on the RHS of a variable initialization.
+  CheckArrayAccess(E);
+
+  // This is not the right CC for (e.g.) a variable initialization.
+  AnalyzeImplicitConversions(*this, E, CC);
+}
+
+void Sema::CheckBoolLikeConversion(Expr *E, SourceLocation CC) {
+  ::CheckBoolLikeConversion(*this, E, CC);
+}
+
+void Sema::CheckForIntOverflow (const Expr *E) {
+  // Use a work list to deal with nested struct initializers.
+  SmallVector<const Expr *, 2> Exprs(1, E);
+
+  do {
+    const Expr *OriginalE = Exprs.pop_back_val();
+    const Expr *E = OriginalE->IgnoreParenCasts();
+
+    if (isa<BinaryOperator, UnaryOperator>(E)) {
+      E->EvaluateForOverflow(Context);
+      continue;
+    }
+
+    if (const auto *InitList = dyn_cast<InitListExpr>(OriginalE))
+      Exprs.append(InitList->inits().begin(), InitList->inits().end());
+    else if (isa<ObjCBoxedExpr>(OriginalE))
+      E->EvaluateForOverflow(Context);
+    else if (const auto *Call = dyn_cast<CallExpr>(E))
+      Exprs.append(Call->arg_begin(), Call->arg_end());
+    else if (const auto *Message = dyn_cast<ObjCMessageExpr>(E))
+      Exprs.append(Message->arg_begin(), Message->arg_end());
+    else if (const auto *Construct = dyn_cast<CXXConstructExpr>(E))
+      Exprs.append(Construct->arg_begin(), Construct->arg_end());
+    else if (const auto *Temporary = dyn_cast<CXXBindTemporaryExpr>(E))
+      Exprs.push_back(Temporary->getSubExpr());
+    else if (const auto *Array = dyn_cast<ArraySubscriptExpr>(E))
+      Exprs.push_back(Array->getIdx());
+    else if (const auto *Compound = dyn_cast<CompoundLiteralExpr>(E))
+      Exprs.push_back(Compound->getInitializer());
+    else if (const auto *New = dyn_cast<CXXNewExpr>(E);
+             New && New->isArray()) {
+      if (auto ArraySize = New->getArraySize())
+        Exprs.push_back(*ArraySize);
+    } else if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(OriginalE))
+      Exprs.push_back(MTE->getSubExpr());
+  } while (!Exprs.empty());
+}
+
+namespace {
+
+/// Visitor for expressions which looks for unsequenced operations on the
+/// same object.
+class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
+  using Base = ConstEvaluatedExprVisitor<SequenceChecker>;
+
+  /// A tree of sequenced regions within an expression. Two regions are
+  /// unsequenced if one is an ancestor or a descendent of the other. When we
+  /// finish processing an expression with sequencing, such as a comma
+  /// expression, we fold its tree nodes into its parent, since they are
+  /// unsequenced with respect to nodes we will visit later.
+  class SequenceTree {
+    struct Value {
+      explicit Value(unsigned Parent) : Parent(Parent), Merged(false) {}
+      unsigned Parent : 31;
+      LLVM_PREFERRED_TYPE(bool)
+      unsigned Merged : 1;
+    };
+    SmallVector<Value, 8> Values;
+
+  public:
+    /// A region within an expression which may be sequenced with respect
+    /// to some other region.
+    class Seq {
+      friend class SequenceTree;
+
+      unsigned Index;
+
+      explicit Seq(unsigned N) : Index(N) {}
+
+    public:
+      Seq() : Index(0) {}
+    };
+
+    SequenceTree() { Values.push_back(Value(0)); }
+    Seq root() const { return Seq(0); }
+
+    /// Create a new sequence of operations, which is an unsequenced
+    /// subset of \p Parent. This sequence of operations is sequenced with
+    /// respect to other children of \p Parent.
+    Seq allocate(Seq Parent) {
+      Values.push_back(Value(Parent.Index));
+      return Seq(Values.size() - 1);
+    }
+
+    /// Merge a sequence of operations into its parent.
+    void merge(Seq S) {
+      Values[S.Index].Merged = true;
+    }
+
+    /// Determine whether two operations are unsequenced. This operation
+    /// is asymmetric: \p Cur should be the more recent sequence, and \p Old
+    /// should have been merged into its parent as appropriate.
+    bool isUnsequenced(Seq Cur, Seq Old) {
+      unsigned C = representative(Cur.Index);
+      unsigned Target = representative(Old.Index);
+      while (C >= Target) {
+        if (C == Target)
+          return true;
+        C = Values[C].Parent;
+      }
+      return false;
+    }
+
+  private:
+    /// Pick a representative for a sequence.
+    unsigned representative(unsigned K) {
+      if (Values[K].Merged)
+        // Perform path compression as we go.
+        return Values[K].Parent = representative(Values[K].Parent);
+      return K;
+    }
+  };
+
+  /// An object for which we can track unsequenced uses.
+  using Object = const ValueDecl *;
+
+  /// Different flavors of object usage which we track. We only track the
+  /// least-sequenced usage of each kind.
+  enum UsageKind {
+    /// A read of an object. Multiple unsequenced reads are OK.
+    UK_Use,
+
+    /// A modification of an object which is sequenced before the value
+    /// computation of the expression, such as ++n in C++.
+    UK_ModAsValue,
+
+    /// A modification of an object which is not sequenced before the value
+    /// computation of the expression, such as n++.
+    UK_ModAsSideEffect,
+
+    UK_Count = UK_ModAsSideEffect + 1
+  };
+
+  enum WarningKind {
+    /// A warning message is one for unsequenced use and modification
+    WK_UseAndMod, 
+
+    /// A warning message is one for multiple unsequenced modification
+    WK_ModAndMod, 
+
+    /// A warning message is one for multiple unsequenced volatile use
+    WK_Volatile_UseAndUse 
+  };
+
+  /// Bundle together a sequencing region and the expression corresponding
+  /// to a specific usage. One Usage is stored for each usage kind in UsageInfo.
+  struct Usage {
+    const Expr *UsageExpr = nullptr;
+    SequenceTree::Seq Seq;
+
+    Usage() = default;
+  };
+
+  struct UsageInfo {
+    Usage Uses[UK_Count];
+
+    /// Have we issued a diagnostic for this object already?
+    bool Diagnosed = false;
+
+    UsageInfo();
+  };
+  using UsageInfoMap = llvm::SmallDenseMap<Object, UsageInfo, 16>;
+
+  Sema &SemaRef;
+
+  /// Sequenced regions within the expression.
+  SequenceTree Tree;
+
+  /// Declaration modifications and references which we have seen.
+  UsageInfoMap UsageMap;
+
+  /// The region we are currently within.
+  SequenceTree::Seq Region;
+
+  /// Filled in with declarations which were modified as a side-effect
+  /// (that is, post-increment operations).
+  SmallVectorImpl<std::pair<Object, Usage>> *ModAsSideEffect = nullptr;
+
+  /// Expressions to check later. We defer checking these to reduce
+  /// stack usage.
+  SmallVectorImpl<const Expr *> &WorkList;
+
+  /// RAII object wrapping the visitation of a sequenced subexpression of an
+  /// expression. At the end of this process, the side-effects of the evaluation
+  /// become sequenced with respect to the value computation of the result, so
+  /// we downgrade any UK_ModAsSideEffect within the evaluation to
+  /// UK_ModAsValue.
+  struct SequencedSubexpression {
+    SequencedSubexpression(SequenceChecker &Self)
+      : Self(Self), OldModAsSideEffect(Self.ModAsSideEffect) {
+      Self.ModAsSideEffect = &ModAsSideEffect;
+    }
+
+    ~SequencedSubexpression() {
+      for (const std::pair<Object, Usage> &M : llvm::reverse(ModAsSideEffect)) {
+        // Add a new usage with usage kind UK_ModAsValue, and then restore
+        // the previous usage with UK_ModAsSideEffect (thus clearing it if
+        // the previous one was empty).
+        UsageInfo &UI = Self.UsageMap[M.first];
+        auto &SideEffectUsage = UI.Uses[UK_ModAsSideEffect];
+        Self.addUsage(M.first, UI, SideEffectUsage.UsageExpr, UK_ModAsValue);
+        SideEffectUsage = M.second;
+      }
+      Self.ModAsSideEffect = OldModAsSideEffect;
+    }
+
+    SequenceChecker &Self;
+    SmallVector<std::pair<Object, Usage>, 4> ModAsSideEffect;
+    SmallVectorImpl<std::pair<Object, Usage>> *OldModAsSideEffect;
+  };
+
+  /// RAII object wrapping the visitation of a subexpression which we might
+  /// choose to evaluate as a constant. If any subexpression is evaluated and
+  /// found to be non-constant, this allows us to suppress the evaluation of
+  /// the outer expression.
+  class EvaluationTracker {
+  public:
+    EvaluationTracker(SequenceChecker &Self)
+        : Self(Self), Prev(Self.EvalTracker) {
+      Self.EvalTracker = this;
+    }
+
+    ~EvaluationTracker() {
+      Self.EvalTracker = Prev;
+      if (Prev)
+        Prev->EvalOK &= EvalOK;
+    }
+
+    bool evaluate(const Expr *E, bool &Result) {
+      if (!EvalOK || E->isValueDependent())
+        return false;
+      EvalOK = E->EvaluateAsBooleanCondition(
+          Result, Self.SemaRef.Context,
+          Self.SemaRef.isConstantEvaluatedContext());
+      return EvalOK;
+    }
+
+  private:
+    SequenceChecker &Self;
+    EvaluationTracker *Prev;
+    bool EvalOK = true;
+  } *EvalTracker = nullptr;
+
+  /// Find the object which is produced by the specified expression,
+  /// if any.
+  Object getObject(const Expr *E, bool Mod) const {
+    E = E->IgnoreParenCasts();
+    if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+      if (Mod && (UO->getOpcode() == UO_PreInc || UO->getOpcode() == UO_PreDec))
+        return getObject(UO->getSubExpr(), Mod);
+    } else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+      if (BO->getOpcode() == BO_Comma)
+        return getObject(BO->getRHS(), Mod);
+      if (Mod && BO->isAssignmentOp())
+        return getObject(BO->getLHS(), Mod);
+    } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+      // FIXME: Check for more interesting cases, like "x.n = ++x.n".
+      if (isa<CXXThisExpr>(ME->getBase()->IgnoreParenCasts()))
+        return ME->getMemberDecl();
+    } else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
+      // FIXME: If this is a reference, map through to its value.
+      return DRE->getDecl();
+    return nullptr;
+  }
+
+  /// Note that an object \p O was modified or used by an expression
+  /// \p UsageExpr with usage kind \p UK. \p UI is the \p UsageInfo for
+  /// the object \p O as obtained via the \p UsageMap.
+  void addUsage(Object O, UsageInfo &UI, const Expr *UsageExpr, UsageKind UK) {
+    // Get the old usage for the given object and usage kind.
+    Usage &U = UI.Uses[UK];
+    if (!U.UsageExpr || !Tree.isUnsequenced(Region, U.Seq)) {
+      // If we have a modification as side effect and are in a sequenced
+      // subexpression, save the old Usage so that we can restore it later
+      // in SequencedSubexpression::~SequencedSubexpression.
+      if (UK == UK_ModAsSideEffect && ModAsSideEffect)
+        ModAsSideEffect->push_back(std::make_pair(O, U));
+      // Then record the new usage with the current sequencing region.
+      U.UsageExpr = UsageExpr;
+      U.Seq = Region;
+    }
+  }
+
+  /// Check whether a modification or use of an object \p O in an expression
+  /// \p UsageExpr conflicts with a prior usage of kind \p OtherKind. \p UI is
+  /// the \p UsageInfo for the object \p O as obtained via the \p UsageMap.
+  /// \p IsModMod is true when we are checking for a mod-mod unsequenced
+  /// usage and false we are checking for a mod-use unsequenced usage.
+  void checkUsage(Object O, UsageInfo &UI, const Expr *UsageExpr,
+                  UsageKind OtherKind, WarningKind WarnKind) {
+    if (UI.Diagnosed)
+      return;
+
+    const Usage &U = UI.Uses[OtherKind];
+    if (!U.UsageExpr || !Tree.isUnsequenced(Region, U.Seq))
+      return;
+
+    const Expr *Mod = U.UsageExpr;
+    const Expr *ModOrUse = UsageExpr;
+    if (OtherKind == UK_Use)
+      std::swap(Mod, ModOrUse);
+
+    unsigned DiagID = 0;
+    switch (WarnKind) {
+    case WK_UseAndMod:
+      DiagID = diag::warn_unsequenced_mod_use;
+      break;
+    case WK_ModAndMod:
+      DiagID = diag::warn_unsequenced_mod_mod;
+      break;
+    case WK_Volatile_UseAndUse:
+      DiagID = diag::warn_unsequenced_use_use_volatile;
+      break;
+    }
+
+    SemaRef.DiagRuntimeBehavior(
+        Mod->getExprLoc(), {Mod, ModOrUse},
+        SemaRef.PDiag(DiagID) << O << SourceRange(ModOrUse->getExprLoc()));
+    UI.Diagnosed = true;
+  }
+
+  // A note on note{Pre, Post}{Use, Mod}:
+  //
+  // (It helps to follow the algorithm with an expression such as
+  //  "((++k)++, k) = k" or "k = (k++, k++)". Both contain unsequenced
+  //  operations before C++17 and both are well-defined in C++17).
+  //
+  // When visiting a node which uses/modify an object we first call notePreUse
+  // or notePreMod before visiting its sub-expression(s). At this point the
+  // children of the current node have not yet been visited and so the eventual
+  // uses/modifications resulting from the children of the current node have not
+  // been recorded yet.
+  //
+  // We then visit the children of the current node. After that notePostUse or
+  // notePostMod is called. These will 1) detect an unsequenced modification
+  // as side effect (as in "k++ + k") and 2) add a new usage with the
+  // appropriate usage kind.
+  //
+  // We also have to be careful that some operation sequences modification as
+  // side effect as well (for example: || or ,). To account for this we wrap
+  // the visitation of such a sub-expression (for example: the LHS of || or ,)
+  // with SequencedSubexpression. SequencedSubexpression is an RAII object
+  // which record usages which are modifications as side effect, and then
+  // downgrade them (or more accurately restore the previous usage which was a
+  // modification as side effect) when exiting the scope of the sequenced
+  // subexpression.
+
+  void notePreUse(Object O, const Expr *UseExpr) {
+    UsageInfo &UI = UsageMap[O];
+    // Uses conflict with other modifications.
+    checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsValue, WK_UseAndMod);
+    // Volatile uses conflict with other uses.
+    if (O->getType().isVolatileQualified())
+      checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_Use, WK_Volatile_UseAndUse);
+  }
+
+  void notePostUse(Object O, const Expr *UseExpr) {
+    UsageInfo &UI = UsageMap[O];
+    checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsSideEffect, WK_UseAndMod);
+    addUsage(O, UI, UseExpr, /*UsageKind=*/UK_Use);
+  }
+
+  void notePreMod(Object O, const Expr *ModExpr) {
+    UsageInfo &UI = UsageMap[O];
+    // Modifications conflict with other modifications and with uses.
+    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsValue, WK_ModAndMod);
+    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_Use, WK_UseAndMod);
+  }
+
+  void notePostMod(Object O, const Expr *ModExpr, UsageKind UK) {
+    UsageInfo &UI = UsageMap[O];
+    checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsSideEffect, WK_ModAndMod);
+    addUsage(O, UI, ModExpr, /*UsageKind=*/UK);
+  }
+
+public:
+  SequenceChecker(Sema &S, const Expr *E,
+                  SmallVectorImpl<const Expr *> &WorkList)
+      : Base(S.Context), SemaRef(S), Region(Tree.root()), WorkList(WorkList) {
+    Visit(E);
+    // Silence a -Wunused-private-field since WorkList is now unused.
+    // TODO: Evaluate if it can be used, and if not remove it.
+    (void)this->WorkList;
+  }
+
+  void VisitStmt(const Stmt *S) {
+    // Skip all statements which aren't expressions for now.
+  }
+
+  void VisitExpr(const Expr *E) {
+    // By default, just recurse to evaluated subexpressions.
+    Base::VisitStmt(E);
+  }
+
+  void VisitCoroutineSuspendExpr(const CoroutineSuspendExpr *CSE) {
+    for (auto *Sub : CSE->children()) {
+      const Expr *ChildExpr = dyn_cast_or_null<Expr>(Sub);
+      if (!ChildExpr)
+        continue;
+
+      if (ChildExpr == CSE->getOperand())
+        // Do not recurse over a CoroutineSuspendExpr's operand.
+        // The operand is also a subexpression of getCommonExpr(), and
+        // recursing into it directly could confuse object management
+        // for the sake of sequence tracking.
+        continue;
+
+      Visit(Sub);
+    }
+  }
+
+  void VisitCastExpr(const CastExpr *E) {
+    Object O = Object();
+    if (E->getCastKind() == CK_LValueToRValue)
+      O = getObject(E->getSubExpr(), false);
+
+    if (O)
+      notePreUse(O, E);
+    VisitExpr(E);
+    if (O)
+      notePostUse(O, E);
+  }
+
+  void VisitSequencedExpressions(const Expr *SequencedBefore,
+                                 const Expr *SequencedAfter) {
+    SequenceTree::Seq BeforeRegion = Tree.allocate(Region);
+    SequenceTree::Seq AfterRegion = Tree.allocate(Region);
+    SequenceTree::Seq OldRegion = Region;
+
+    {
+      SequencedSubexpression SeqBefore(*this);
+      Region = BeforeRegion;
+      Visit(SequencedBefore);
+    }
+
+    Region = AfterRegion;
+    Visit(SequencedAfter);
+
+    Region = OldRegion;
+
+    Tree.merge(BeforeRegion);
+    Tree.merge(AfterRegion);
+  }
+
+  void VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE) {
+    // C++17 [expr.sub]p1:
+    //   The expression E1[E2] is identical (by definition) to *((E1)+(E2)). The
+    //   expression E1 is sequenced before the expression E2.
+    if (SemaRef.getLangOpts().CPlusPlus17)
+      VisitSequencedExpressions(ASE->getLHS(), ASE->getRHS());
+    else {
+      Visit(ASE->getLHS());
+      Visit(ASE->getRHS());
+    }
+  }
+
+  void VisitBinPtrMemD(const BinaryOperator *BO) { VisitBinPtrMem(BO); }
+  void VisitBinPtrMemI(const BinaryOperator *BO) { VisitBinPtrMem(BO); }
+  void VisitBinPtrMem(const BinaryOperator *BO) {
+    // C++17 [expr.mptr.oper]p4:
+    //  Abbreviating pm-expression.*cast-expression as E1.*E2, [...]
+    //  the expression E1 is sequenced before the expression E2.
+    if (SemaRef.getLangOpts().CPlusPlus17)
+      VisitSequencedExpressions(BO->getLHS(), BO->getRHS());
+    else {
+      Visit(BO->getLHS());
+      Visit(BO->getRHS());
+    }
+  }
+
+  void VisitBinShl(const BinaryOperator *BO) { VisitBinShlShr(BO); }
+  void VisitBinShr(const BinaryOperator *BO) { VisitBinShlShr(BO); }
+  void VisitBinShlShr(const BinaryOperator *BO) {
+    // C++17 [expr.shift]p4:
+    //  The expression E1 is sequenced before the expression E2.
+    if (SemaRef.getLangOpts().CPlusPlus17)
+      VisitSequencedExpressions(BO->getLHS(), BO->getRHS());
+    else {
+      Visit(BO->getLHS());
+      Visit(BO->getRHS());
+    }
+  }
+
+  void VisitBinComma(const BinaryOperator *BO) {
+    // C++11 [expr.comma]p1:
+    //   Every value computation and side effect associated with the left
+    //   expression is sequenced before every value computation and side
+    //   effect associated with the right expression.
+    VisitSequencedExpressions(BO->getLHS(), BO->getRHS());
+  }
+
+  void VisitBinAssign(const BinaryOperator *BO) {
+    SequenceTree::Seq RHSRegion;
+    SequenceTree::Seq LHSRegion;
+    if (SemaRef.getLangOpts().CPlusPlus17) {
+      RHSRegion = Tree.allocate(Region);
+      LHSRegion = Tree.allocate(Region);
+    } else {
+      RHSRegion = Region;
+      LHSRegion = Region;
+    }
+    SequenceTree::Seq OldRegion = Region;
+
+    // C++11 [expr.ass]p1:
+    //  [...] the assignment is sequenced after the value computation
+    //  of the right and left operands, [...]
+    //
+    // so check it before inspecting the operands and update the
+    // map afterwards.
+    Object O = getObject(BO->getLHS(), /*Mod=*/true);
+    if (O)
+      notePreMod(O, BO);
+
+    if (SemaRef.getLangOpts().CPlusPlus17) {
+      // C++17 [expr.ass]p1:
+      //  [...] The right operand is sequenced before the left operand. [...]
+      {
+        SequencedSubexpression SeqBefore(*this);
+        Region = RHSRegion;
+        Visit(BO->getRHS());
+      }
+
+      Region = LHSRegion;
+      Visit(BO->getLHS());
+
+      if (O && isa<CompoundAssignOperator>(BO))
+        notePostUse(O, BO);
+
+    } else {
+      // C++11 does not specify any sequencing between the LHS and RHS.
+      Region = LHSRegion;
+      Visit(BO->getLHS());
+
+      if (O && isa<CompoundAssignOperator>(BO))
+        notePostUse(O, BO);
+
+      Region = RHSRegion;
+      Visit(BO->getRHS());
+    }
+
+    // C++11 [expr.ass]p1:
+    //  the assignment is sequenced [...] before the value computation of the
+    //  assignment expression.
+    // C11 6.5.16/3 has no such rule.
+    Region = OldRegion;
+    if (O)
+      notePostMod(O, BO,
+                  SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
+                                                  : UK_ModAsSideEffect);
+    if (SemaRef.getLangOpts().CPlusPlus17) {
+      Tree.merge(RHSRegion);
+      Tree.merge(LHSRegion);
+    }
+  }
+
+  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) {
+    Object O = getObject(UO->getSubExpr(), true);
+    if (!O)
+      return VisitExpr(UO);
+
+    notePreMod(O, UO);
+    Visit(UO->getSubExpr());
+    // C++11 [expr.pre.incr]p1:
+    //   the expression ++x is equivalent to x+=1
+    notePostMod(O, UO,
+                SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
+                                                : UK_ModAsSideEffect);
+  }
+
+  void VisitUnaryPostInc(const UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
+  void VisitUnaryPostDec(const UnaryOperator *UO) { VisitUnaryPostIncDec(UO); }
+  void VisitUnaryPostIncDec(const UnaryOperator *UO) {
+    Object O = getObject(UO->getSubExpr(), true);
+    if (!O)
+      return VisitExpr(UO);
+
+    notePreMod(O, UO);
+    Visit(UO->getSubExpr());
+    notePostMod(O, UO, UK_ModAsSideEffect);
+  }
+
+  void VisitBinLOr(const BinaryOperator *BO) {
+    // C++11 [expr.log.or]p2:
+    //  If the second expression is evaluated, every value computation and
+    //  side effect associated with the first expression is sequenced before
+    //  every value computation and side effect associated with the
+    //  second expression.
+    SequenceTree::Seq LHSRegion = Tree.allocate(Region);
+    SequenceTree::Seq RHSRegion = Tree.allocate(Region);
+    SequenceTree::Seq OldRegion = Region;
+
+    EvaluationTracker Eval(*this);
+    {
+      SequencedSubexpression Sequenced(*this);
+      Region = LHSRegion;
+      Visit(BO->getLHS());
+    }
+
+    // C++11 [expr.log.or]p1:
+    //  [...] the second operand is not evaluated if the first operand
+    //  evaluates to true.
+    bool EvalResult = false;
+    bool EvalOK = Eval.evaluate(BO->getLHS(), EvalResult);
+    bool ShouldVisitRHS = !EvalOK || !EvalResult;
+    if (ShouldVisitRHS) {
+      Region = RHSRegion;
+      Visit(BO->getRHS());
+    }
+
+    Region = OldRegion;
+    Tree.merge(LHSRegion);
+    Tree.merge(RHSRegion);
+  }
+
+  void VisitBinLAnd(const BinaryOperator *BO) {
+    // C++11 [expr.log.and]p2:
+    //  If the second expression is evaluated, every value computation and
+    //  side effect associated with the first expression is sequenced before
+    //  every value computation and side effect associated with the
+    //  second expression.
+    SequenceTree::Seq LHSRegion = Tree.allocate(Region);
+    SequenceTree::Seq RHSRegion = Tree.allocate(Region);
+    SequenceTree::Seq OldRegion = Region;
+
+    EvaluationTracker Eval(*this);
+    {
+      SequencedSubexpression Sequenced(*this);
+      Region = LHSRegion;
+      Visit(BO->getLHS());
+    }
+
+    // C++11 [expr.log.and]p1:
+    //  [...] the second operand is not evaluated if the first operand is false.
+    bool EvalResult = false;
+    bool EvalOK = Eval.evaluate(BO->getLHS(), EvalResult);
+    bool ShouldVisitRHS = !EvalOK || EvalResult;
+    if (ShouldVisitRHS) {
+      Region = RHSRegion;
+      Visit(BO->getRHS());
+    }
+
+    Region = OldRegion;
+    Tree.merge(LHSRegion);
+    Tree.merge(RHSRegion);
+  }
+
+  void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO) {
+    // C++11 [expr.cond]p1:
+    //  [...] Every value computation and side effect associated with the first
+    //  expression is sequenced before every value computation and side effect
+    //  associated with the second or third expression.
+    SequenceTree::Seq ConditionRegion = Tree.allocate(Region);
+
+    // No sequencing is specified between the true and false expression.
+    // However since exactly one of both is going to be evaluated we can
+    // consider them to be sequenced. This is needed to avoid warning on
+    // something like "x ? y+= 1 : y += 2;" in the case where we will visit
+    // both the true and false expressions because we can't evaluate x.
+    // This will still allow us to detect an expression like (pre C++17)
+    // "(x ? y += 1 : y += 2) = y".
+    //
+    // We don't wrap the visitation of the true and false expression with
+    // SequencedSubexpression because we don't want to downgrade modifications
+    // as side effect in the true and false expressions after the visition
+    // is done. (for example in the expression "(x ? y++ : y++) + y" we should
+    // not warn between the two "y++", but we should warn between the "y++"
+    // and the "y".
+    SequenceTree::Seq TrueRegion = Tree.allocate(Region);
+    SequenceTree::Seq FalseRegion = Tree.allocate(Region);
+    SequenceTree::Seq OldRegion = Region;
+
+    EvaluationTracker Eval(*this);
+    {
+      SequencedSubexpression Sequenced(*this);
+      Region = ConditionRegion;
+      Visit(CO->getCond());
+    }
+
+    // C++11 [expr.cond]p1:
+    // [...] The first expression is contextually converted to bool (Clause 4).
+    // It is evaluated and if it is true, the result of the conditional
+    // expression is the value of the second expression, otherwise that of the
+    // third expression. Only one of the second and third expressions is
+    // evaluated. [...]
+    bool EvalResult = false;
+    bool EvalOK = Eval.evaluate(CO->getCond(), EvalResult);
+    bool ShouldVisitTrueExpr = !EvalOK || EvalResult;
+    bool ShouldVisitFalseExpr = !EvalOK || !EvalResult;
+    if (ShouldVisitTrueExpr) {
+      Region = TrueRegion;
+      Visit(CO->getTrueExpr());
+    }
+    if (ShouldVisitFalseExpr) {
+      Region = FalseRegion;
+      Visit(CO->getFalseExpr());
+    }
+
+    Region = OldRegion;
+    Tree.merge(ConditionRegion);
+    Tree.merge(TrueRegion);
+    Tree.merge(FalseRegion);
+  }
+
+  void VisitCallExpr(const CallExpr *CE) {
+    // FIXME: CXXNewExpr and CXXDeleteExpr implicitly call functions.
+
+    if (CE->isUnevaluatedBuiltinCall(Context))
+      return;
+
+    // C++11 [intro.execution]p15:
+    //   When calling a function [...], every value computation and side effect
+    //   associated with any argument expression, or with the postfix expression
+    //   designating the called function, is sequenced before execution of every
+    //   expression or statement in the body of the function [and thus before
+    //   the value computation of its result].
+    SequencedSubexpression Sequenced(*this);
+    SemaRef.runWithSufficientStackSpace(CE->getExprLoc(), [&] {
+      // C++17 [expr.call]p5
+      //   The postfix-expression is sequenced before each expression in the
+      //   expression-list and any default argument. [...]
+      SequenceTree::Seq CalleeRegion;
+      SequenceTree::Seq OtherRegion;
+      if (SemaRef.getLangOpts().CPlusPlus17) {
+        CalleeRegion = Tree.allocate(Region);
+        OtherRegion = Tree.allocate(Region);
+      } else {
+        CalleeRegion = Region;
+        OtherRegion = Region;
+      }
+      SequenceTree::Seq OldRegion = Region;
+
+      // Visit the callee expression first.
+      Region = CalleeRegion;
+      if (SemaRef.getLangOpts().CPlusPlus17) {
+        SequencedSubexpression Sequenced(*this);
+        Visit(CE->getCallee());
+      } else {
+        Visit(CE->getCallee());
+      }
+
+      // Then visit the argument expressions.
+      Region = OtherRegion;
+      for (const Expr *Argument : CE->arguments())
+        Visit(Argument);
+
+      Region = OldRegion;
+      if (SemaRef.getLangOpts().CPlusPlus17) {
+        Tree.merge(CalleeRegion);
+        Tree.merge(OtherRegion);
+      }
+    });
+  }
+
+  void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *CXXOCE) {
+    // C++17 [over.match.oper]p2:
+    //   [...] the operator notation is first transformed to the equivalent
+    //   function-call notation as summarized in Table 12 (where @ denotes one
+    //   of the operators covered in the specified subclause). However, the
+    //   operands are sequenced in the order prescribed for the built-in
+    //   operator (Clause 8).
+    //
+    // From the above only overloaded binary operators and overloaded call
+    // operators have sequencing rules in C++17 that we need to handle
+    // separately.
+    if (!SemaRef.getLangOpts().CPlusPlus17 ||
+        (CXXOCE->getNumArgs() != 2 && CXXOCE->getOperator() != OO_Call))
+      return VisitCallExpr(CXXOCE);
+
+    enum {
+      NoSequencing,
+      LHSBeforeRHS,
+      RHSBeforeLHS,
+      LHSBeforeRest
+    } SequencingKind;
+    switch (CXXOCE->getOperator()) {
+    case OO_Equal:
+    case OO_PlusEqual:
+    case OO_MinusEqual:
+    case OO_StarEqual:
+    case OO_SlashEqual:
+    case OO_PercentEqual:
+    case OO_CaretEqual:
+    case OO_AmpEqual:
+    case OO_PipeEqual:
+    case OO_LessLessEqual:
+    case OO_GreaterGreaterEqual:
+      SequencingKind = RHSBeforeLHS;
+      break;
+
+    case OO_LessLess:
+    case OO_GreaterGreater:
+    case OO_AmpAmp:
+    case OO_PipePipe:
+    case OO_Comma:
+    case OO_ArrowStar:
+    case OO_Subscript:
+      SequencingKind = LHSBeforeRHS;
+      break;
+
+    case OO_Call:
+      SequencingKind = LHSBeforeRest;
+      break;
+
+    default:
+      SequencingKind = NoSequencing;
+      break;
+    }
+
+    if (SequencingKind == NoSequencing)
+      return VisitCallExpr(CXXOCE);
+
+    // This is a call, so all subexpressions are sequenced before the result.
+    SequencedSubexpression Sequenced(*this);
+
+    SemaRef.runWithSufficientStackSpace(CXXOCE->getExprLoc(), [&] {
+      assert(SemaRef.getLangOpts().CPlusPlus17 &&
+             "Should only get there with C++17 and above!");
+      assert((CXXOCE->getNumArgs() == 2 || CXXOCE->getOperator() == OO_Call) &&
+             "Should only get there with an overloaded binary operator"
+             " or an overloaded call operator!");
+
+      if (SequencingKind == LHSBeforeRest) {
+        assert(CXXOCE->getOperator() == OO_Call &&
+               "We should only have an overloaded call operator here!");
+
+        // This is very similar to VisitCallExpr, except that we only have the
+        // C++17 case. The postfix-expression is the first argument of the
+        // CXXOperatorCallExpr. The expressions in the expression-list, if any,
+        // are in the following arguments.
+        //
+        // Note that we intentionally do not visit the callee expression since
+        // it is just a decayed reference to a function.
+        SequenceTree::Seq PostfixExprRegion = Tree.allocate(Region);
+        SequenceTree::Seq ArgsRegion = Tree.allocate(Region);
+        SequenceTree::Seq OldRegion = Region;
+
+        assert(CXXOCE->getNumArgs() >= 1 &&
+               "An overloaded call operator must have at least one argument"
+               " for the postfix-expression!");
+        const Expr *PostfixExpr = CXXOCE->getArgs()[0];
+        llvm::ArrayRef<const Expr *> Args(CXXOCE->getArgs() + 1,
+                                          CXXOCE->getNumArgs() - 1);
+
+        // Visit the postfix-expression first.
+        {
+          Region = PostfixExprRegion;
+          SequencedSubexpression Sequenced(*this);
+          Visit(PostfixExpr);
+        }
+
+        // Then visit the argument expressions.
+        Region = ArgsRegion;
+        for (const Expr *Arg : Args)
+          Visit(Arg);
+
+        Region = OldRegion;
+        Tree.merge(PostfixExprRegion);
+        Tree.merge(ArgsRegion);
+      } else {
+        assert(CXXOCE->getNumArgs() == 2 &&
+               "Should only have two arguments here!");
+        assert((SequencingKind == LHSBeforeRHS ||
+                SequencingKind == RHSBeforeLHS) &&
+               "Unexpected sequencing kind!");
+
+        // We do not visit the callee expression since it is just a decayed
+        // reference to a function.
+        const Expr *E1 = CXXOCE->getArg(0);
+        const Expr *E2 = CXXOCE->getArg(1);
+        if (SequencingKind == RHSBeforeLHS)
+          std::swap(E1, E2);
+
+        return VisitSequencedExpressions(E1, E2);
+      }
+    });
+  }
+
+  void VisitCXXConstructExpr(const CXXConstructExpr *CCE) {
+    // This is a call, so all subexpressions are sequenced before the result.
+    SequencedSubexpression Sequenced(*this);
+
+    if (!CCE->isListInitialization())
+      return VisitExpr(CCE);
+
+    // In C++11, list initializations are sequenced.
+    SequenceExpressionsInOrder(
+        llvm::ArrayRef(CCE->getArgs(), CCE->getNumArgs()));
+  }
+
+  void VisitInitListExpr(const InitListExpr *ILE) {
+    if (!SemaRef.getLangOpts().CPlusPlus11)
+      return VisitExpr(ILE);
+
+    // In C++11, list initializations are sequenced.
+    SequenceExpressionsInOrder(ILE->inits());
+  }
+
+  void VisitCXXParenListInitExpr(const CXXParenListInitExpr *PLIE) {
+    // C++20 parenthesized list initializations are sequenced. See C++20
+    // [decl.init.general]p16.5 and [decl.init.general]p16.6.2.2.
+    SequenceExpressionsInOrder(PLIE->getInitExprs());
+  }
+
+private:
+  void SequenceExpressionsInOrder(ArrayRef<const Expr *> ExpressionList) {
+    SmallVector<SequenceTree::Seq, 32> Elts;
+    SequenceTree::Seq Parent = Region;
+    for (const Expr *E : ExpressionList) {
+      if (!E)
+        continue;
+      Region = Tree.allocate(Parent);
+      Elts.push_back(Region);
+      Visit(E);
+    }
+
+    // Forget that the initializers are sequenced.
+    Region = Parent;
+    for (unsigned I = 0; I < Elts.size(); ++I)
+      Tree.merge(Elts[I]);
+  }
+};
+
+SequenceChecker::UsageInfo::UsageInfo() = default;
+
+} // namespace
+
+void Sema::CheckUnsequencedOperations(const Expr *E) {
+  SmallVector<const Expr *, 8> WorkList;
+  WorkList.push_back(E);
+  while (!WorkList.empty()) {
+    const Expr *Item = WorkList.pop_back_val();
+    SequenceChecker(*this, Item, WorkList);
+  }
+}
+
+void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc,
+                              bool IsConstexpr) {
+  llvm::SaveAndRestore ConstantContext(isConstantEvaluatedOverride,
+                                       IsConstexpr || isa<ConstantExpr>(E));
+  CheckImplicitConversions(E, CheckLoc);
+  if (!E->isInstantiationDependent())
+    CheckUnsequencedOperations(E);
+  if (!IsConstexpr && !E->isValueDependent())
+    CheckForIntOverflow(E);
+}
+
+void Sema::CheckBitFieldInitialization(SourceLocation InitLoc,
+                                       FieldDecl *BitField,
+                                       Expr *Init) {
+  (void) AnalyzeBitFieldAssignment(*this, BitField, Init, InitLoc);
+}
+
+static void diagnoseArrayStarInParamType(Sema &S, QualType PType,
+                                         SourceLocation Loc) {
+  if (!PType->isVariablyModifiedType())
+    return;
+  if (const auto *PointerTy = dyn_cast<PointerType>(PType)) {
+    diagnoseArrayStarInParamType(S, PointerTy->getPointeeType(), Loc);
+    return;
+  }
+  if (const auto *ReferenceTy = dyn_cast<ReferenceType>(PType)) {
+    diagnoseArrayStarInParamType(S, ReferenceTy->getPointeeType(), Loc);
+    return;
+  }
+  if (const auto *ParenTy = dyn_cast<ParenType>(PType)) {
+    diagnoseArrayStarInParamType(S, ParenTy->getInnerType(), Loc);
+    return;
+  }
+
+  const ArrayType *AT = S.Context.getAsArrayType(PType);
+  if (!AT)
+    return;
+
+  if (AT->getSizeModifier() != ArraySizeModifier::Star) {
+    diagnoseArrayStarInParamType(S, AT->getElementType(), Loc);
+    return;
+  }
+
+  S.Diag(Loc, diag::err_array_star_in_function_definition);
+}
+
+bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters,
+                                    bool CheckParameterNames) {
+  bool HasInvalidParm = false;
+  for (ParmVarDecl *Param : Parameters) {
+    assert(Param && "null in a parameter list");
+    // C99 6.7.5.3p4: the parameters in a parameter type list in a
+    // function declarator that is part of a function definition of
+    // that function shall not have incomplete type.
+    //
+    // C++23 [dcl.fct.def.general]/p2
+    // The type of a parameter [...] for a function definition
+    // shall not be a (possibly cv-qualified) class type that is incomplete
+    // or abstract within the function body unless the function is deleted.
+    if (!Param->isInvalidDecl() &&
+        (RequireCompleteType(Param->getLocation(), Param->getType(),
+                             diag::err_typecheck_decl_incomplete_type) ||
+         RequireNonAbstractType(Param->getBeginLoc(), Param->getOriginalType(),
+                                diag::err_abstract_type_in_decl,
+                                AbstractParamType))) {
+      Param->setInvalidDecl();
+      HasInvalidParm = true;
+    }
+
+    // C99 6.9.1p5: If the declarator includes a parameter type list, the
+    // declaration of each parameter shall include an identifier.
+    if (CheckParameterNames && Param->getIdentifier() == nullptr &&
+        !Param->isImplicit() && !getLangOpts().CPlusPlus) {
+      // Diagnose this as an extension in C17 and earlier.
+      if (!getLangOpts().C23)
+        Diag(Param->getLocation(), diag::ext_parameter_name_omitted_c23);
+    }
+
+    // C99 6.7.5.3p12:
+    //   If the function declarator is not part of a definition of that
+    //   function, parameters may have incomplete type and may use the [*]
+    //   notation in their sequences of declarator specifiers to specify
+    //   variable length array types.
+    QualType PType = Param->getOriginalType();
+    // FIXME: This diagnostic should point the '[*]' if source-location
+    // information is added for it.
+    diagnoseArrayStarInParamType(*this, PType, Param->getLocation());
+
+    // If the parameter is a c++ class type and it has to be destructed in the
+    // callee function, declare the destructor so that it can be called by the
+    // callee function. Do not perform any direct access check on the dtor here.
+    if (!Param->isInvalidDecl()) {
+      if (CXXRecordDecl *ClassDecl = Param->getType()->getAsCXXRecordDecl()) {
+        if (!ClassDecl->isInvalidDecl() &&
+            !ClassDecl->hasIrrelevantDestructor() &&
+            !ClassDecl->isDependentContext() &&
+            ClassDecl->isParamDestroyedInCallee()) {
+          CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl);
+          MarkFunctionReferenced(Param->getLocation(), Destructor);
+          DiagnoseUseOfDecl(Destructor, Param->getLocation());
+        }
+      }
+    }
+
+    // Parameters with the pass_object_size attribute only need to be marked
+    // constant at function definitions. Because we lack information about
+    // whether we're on a declaration or definition when we're instantiating the
+    // attribute, we need to check for constness here.
+    if (const auto *Attr = Param->getAttr<PassObjectSizeAttr>())
+      if (!Param->getType().isConstQualified())
+        Diag(Param->getLocation(), diag::err_attribute_pointers_only)
+            << Attr->getSpelling() << 1;
+
+    // Check for parameter names shadowing fields from the class.
+    if (LangOpts.CPlusPlus && !Param->isInvalidDecl()) {
+      // The owning context for the parameter should be the function, but we
+      // want to see if this function's declaration context is a record.
+      DeclContext *DC = Param->getDeclContext();
+      if (DC && DC->isFunctionOrMethod()) {
+        if (auto *RD = dyn_cast<CXXRecordDecl>(DC->getParent()))
+          CheckShadowInheritedFields(Param->getLocation(), Param->getDeclName(),
+                                     RD, /*DeclIsField*/ false);
+      }
+    }
+
+    if (!Param->isInvalidDecl() &&
+        Param->getOriginalType()->isWebAssemblyTableType()) {
+      Param->setInvalidDecl();
+      HasInvalidParm = true;
+      Diag(Param->getLocation(), diag::err_wasm_table_as_function_parameter);
+    }
+  }
+
+  return HasInvalidParm;
+}
+
+std::optional<std::pair<
+    CharUnits, CharUnits>> static getBaseAlignmentAndOffsetFromPtr(const Expr
+                                                                       *E,
+                                                                   ASTContext
+                                                                       &Ctx);
+
+/// Compute the alignment and offset of the base class object given the
+/// derived-to-base cast expression and the alignment and offset of the derived
+/// class object.
+static std::pair<CharUnits, CharUnits>
+getDerivedToBaseAlignmentAndOffset(const CastExpr *CE, QualType DerivedType,
+                                   CharUnits BaseAlignment, CharUnits Offset,
+                                   ASTContext &Ctx) {
+  for (auto PathI = CE->path_begin(), PathE = CE->path_end(); PathI != PathE;
+       ++PathI) {
+    const CXXBaseSpecifier *Base = *PathI;
+    const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl();
+    if (Base->isVirtual()) {
+      // The complete object may have a lower alignment than the non-virtual
+      // alignment of the base, in which case the base may be misaligned. Choose
+      // the smaller of the non-virtual alignment and BaseAlignment, which is a
+      // conservative lower bound of the complete object alignment.
+      CharUnits NonVirtualAlignment =
+          Ctx.getASTRecordLayout(BaseDecl).getNonVirtualAlignment();
+      BaseAlignment = std::min(BaseAlignment, NonVirtualAlignment);
+      Offset = CharUnits::Zero();
+    } else {
+      const ASTRecordLayout &RL =
+          Ctx.getASTRecordLayout(DerivedType->getAsCXXRecordDecl());
+      Offset += RL.getBaseClassOffset(BaseDecl);
+    }
+    DerivedType = Base->getType();
+  }
+
+  return std::make_pair(BaseAlignment, Offset);
+}
+
+/// Compute the alignment and offset of a binary additive operator.
+static std::optional<std::pair<CharUnits, CharUnits>>
+getAlignmentAndOffsetFromBinAddOrSub(const Expr *PtrE, const Expr *IntE,
+                                     bool IsSub, ASTContext &Ctx) {
+  QualType PointeeType = PtrE->getType()->getPointeeType();
+
+  if (!PointeeType->isConstantSizeType())
+    return std::nullopt;
+
+  auto P = getBaseAlignmentAndOffsetFromPtr(PtrE, Ctx);
+
+  if (!P)
+    return std::nullopt;
+
+  CharUnits EltSize = Ctx.getTypeSizeInChars(PointeeType);
+  if (std::optional<llvm::APSInt> IdxRes = IntE->getIntegerConstantExpr(Ctx)) {
+    CharUnits Offset = EltSize * IdxRes->getExtValue();
+    if (IsSub)
+      Offset = -Offset;
+    return std::make_pair(P->first, P->second + Offset);
+  }
+
+  // If the integer expression isn't a constant expression, compute the lower
+  // bound of the alignment using the alignment and offset of the pointer
+  // expression and the element size.
+  return std::make_pair(
+      P->first.alignmentAtOffset(P->second).alignmentAtOffset(EltSize),
+      CharUnits::Zero());
+}
+
+/// This helper function takes an lvalue expression and returns the alignment of
+/// a VarDecl and a constant offset from the VarDecl.
+std::optional<std::pair<
+    CharUnits,
+    CharUnits>> static getBaseAlignmentAndOffsetFromLValue(const Expr *E,
+                                                           ASTContext &Ctx) {
+  E = E->IgnoreParens();
+  switch (E->getStmtClass()) {
+  default:
+    break;
+  case Stmt::CStyleCastExprClass:
+  case Stmt::CXXStaticCastExprClass:
+  case Stmt::ImplicitCastExprClass: {
+    auto *CE = cast<CastExpr>(E);
+    const Expr *From = CE->getSubExpr();
+    switch (CE->getCastKind()) {
+    default:
+      break;
+    case CK_NoOp:
+      return getBaseAlignmentAndOffsetFromLValue(From, Ctx);
+    case CK_UncheckedDerivedToBase:
+    case CK_DerivedToBase: {
+      auto P = getBaseAlignmentAndOffsetFromLValue(From, Ctx);
+      if (!P)
+        break;
+      return getDerivedToBaseAlignmentAndOffset(CE, From->getType(), P->first,
+                                                P->second, Ctx);
+    }
+    }
+    break;
+  }
+  case Stmt::ArraySubscriptExprClass: {
+    auto *ASE = cast<ArraySubscriptExpr>(E);
+    return getAlignmentAndOffsetFromBinAddOrSub(ASE->getBase(), ASE->getIdx(),
+                                                false, Ctx);
+  }
+  case Stmt::DeclRefExprClass: {
+    if (auto *VD = dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl())) {
+      // FIXME: If VD is captured by copy or is an escaping __block variable,
+      // use the alignment of VD's type.
+      if (!VD->getType()->isReferenceType()) {
+        // Dependent alignment cannot be resolved -> bail out.
+        if (VD->hasDependentAlignment())
+          break;
+        return std::make_pair(Ctx.getDeclAlign(VD), CharUnits::Zero());
+      }
+      if (VD->hasInit())
+        return getBaseAlignmentAndOffsetFromLValue(VD->getInit(), Ctx);
+    }
+    break;
+  }
+  case Stmt::MemberExprClass: {
+    auto *ME = cast<MemberExpr>(E);
+    auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
+    if (!FD || FD->getType()->isReferenceType() ||
+        FD->getParent()->isInvalidDecl())
+      break;
+    std::optional<std::pair<CharUnits, CharUnits>> P;
+    if (ME->isArrow())
+      P = getBaseAlignmentAndOffsetFromPtr(ME->getBase(), Ctx);
+    else
+      P = getBaseAlignmentAndOffsetFromLValue(ME->getBase(), Ctx);
+    if (!P)
+      break;
+    const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(FD->getParent());
+    uint64_t Offset = Layout.getFieldOffset(FD->getFieldIndex());
+    return std::make_pair(P->first,
+                          P->second + CharUnits::fromQuantity(Offset));
+  }
+  case Stmt::UnaryOperatorClass: {
+    auto *UO = cast<UnaryOperator>(E);
+    switch (UO->getOpcode()) {
+    default:
+      break;
+    case UO_Deref:
+      return getBaseAlignmentAndOffsetFromPtr(UO->getSubExpr(), Ctx);
+    }
+    break;
+  }
+  case Stmt::BinaryOperatorClass: {
+    auto *BO = cast<BinaryOperator>(E);
+    auto Opcode = BO->getOpcode();
+    switch (Opcode) {
+    default:
+      break;
+    case BO_Comma:
+      return getBaseAlignmentAndOffsetFromLValue(BO->getRHS(), Ctx);
+    }
+    break;
+  }
+  }
+  return std::nullopt;
+}
+
+/// This helper function takes a pointer expression and returns the alignment of
+/// a VarDecl and a constant offset from the VarDecl.
+std::optional<std::pair<
+    CharUnits, CharUnits>> static getBaseAlignmentAndOffsetFromPtr(const Expr
+                                                                       *E,
+                                                                   ASTContext
+                                                                       &Ctx) {
+  E = E->IgnoreParens();
+  switch (E->getStmtClass()) {
+  default:
+    break;
+  case Stmt::CStyleCastExprClass:
+  case Stmt::CXXStaticCastExprClass:
+  case Stmt::ImplicitCastExprClass: {
+    auto *CE = cast<CastExpr>(E);
+    const Expr *From = CE->getSubExpr();
+    switch (CE->getCastKind()) {
+    default:
+      break;
+    case CK_NoOp:
+      return getBaseAlignmentAndOffsetFromPtr(From, Ctx);
+    case CK_ArrayToPointerDecay:
+      return getBaseAlignmentAndOffsetFromLValue(From, Ctx);
+    case CK_UncheckedDerivedToBase:
+    case CK_DerivedToBase: {
+      auto P = getBaseAlignmentAndOffsetFromPtr(From, Ctx);
+      if (!P)
+        break;
+      return getDerivedToBaseAlignmentAndOffset(
+          CE, From->getType()->getPointeeType(), P->first, P->second, Ctx);
+    }
+    }
+    break;
+  }
+  case Stmt::CXXThisExprClass: {
+    auto *RD = E->getType()->getPointeeType()->getAsCXXRecordDecl();
+    CharUnits Alignment = Ctx.getASTRecordLayout(RD).getNonVirtualAlignment();
+    return std::make_pair(Alignment, CharUnits::Zero());
+  }
+  case Stmt::UnaryOperatorClass: {
+    auto *UO = cast<UnaryOperator>(E);
+    if (UO->getOpcode() == UO_AddrOf)
+      return getBaseAlignmentAndOffsetFromLValue(UO->getSubExpr(), Ctx);
+    break;
+  }
+  case Stmt::BinaryOperatorClass: {
+    auto *BO = cast<BinaryOperator>(E);
+    auto Opcode = BO->getOpcode();
+    switch (Opcode) {
+    default:
+      break;
+    case BO_Add:
+    case BO_Sub: {
+      const Expr *LHS = BO->getLHS(), *RHS = BO->getRHS();
+      if (Opcode == BO_Add && !RHS->getType()->isIntegralOrEnumerationType())
+        std::swap(LHS, RHS);
+      return getAlignmentAndOffsetFromBinAddOrSub(LHS, RHS, Opcode == BO_Sub,
+                                                  Ctx);
+    }
+    case BO_Comma:
+      return getBaseAlignmentAndOffsetFromPtr(BO->getRHS(), Ctx);
+    }
+    break;
+  }
+  }
+  return std::nullopt;
+}
+
+static CharUnits getPresumedAlignmentOfPointer(const Expr *E, Sema &S) {
+  // See if we can compute the alignment of a VarDecl and an offset from it.
+  std::optional<std::pair<CharUnits, CharUnits>> P =
+      getBaseAlignmentAndOffsetFromPtr(E, S.Context);
+
+  if (P)
+    return P->first.alignmentAtOffset(P->second);
+
+  // If that failed, return the type's alignment.
+  return S.Context.getTypeAlignInChars(E->getType()->getPointeeType());
+}
+
+void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) {
+  // This is actually a lot of work to potentially be doing on every
+  // cast; don't do it if we're ignoring -Wcast_align (as is the default).
+  if (getDiagnostics().isIgnored(diag::warn_cast_align, TRange.getBegin()))
+    return;
+
+  // Ignore dependent types.
+  if (T->isDependentType() || Op->getType()->isDependentType())
+    return;
+
+  // Require that the destination be a pointer type.
+  const PointerType *DestPtr = T->getAs<PointerType>();
+  if (!DestPtr) return;
+
+  // If the destination has alignment 1, we're done.
+  QualType DestPointee = DestPtr->getPointeeType();
+  if (DestPointee->isIncompleteType()) return;
+  CharUnits DestAlign = Context.getTypeAlignInChars(DestPointee);
+  if (DestAlign.isOne()) return;
+
+  // Require that the source be a pointer type.
+  const PointerType *SrcPtr = Op->getType()->getAs<PointerType>();
+  if (!SrcPtr) return;
+  QualType SrcPointee = SrcPtr->getPointeeType();
+
+  // Explicitly allow casts from cv void*.  We already implicitly
+  // allowed casts to cv void*, since they have alignment 1.
+  // Also allow casts involving incomplete types, which implicitly
+  // includes 'void'.
+  if (SrcPointee->isIncompleteType()) return;
+
+  CharUnits SrcAlign = getPresumedAlignmentOfPointer(Op, *this);
+
+  if (SrcAlign >= DestAlign) return;
+
+  Diag(TRange.getBegin(), diag::warn_cast_align)
+    << Op->getType() << T
+    << static_cast<unsigned>(SrcAlign.getQuantity())
+    << static_cast<unsigned>(DestAlign.getQuantity())
+    << TRange << Op->getSourceRange();
+}
+
+void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
+                            const ArraySubscriptExpr *ASE,
+                            bool AllowOnePastEnd, bool IndexNegated) {
+  // Already diagnosed by the constant evaluator.
+  if (isConstantEvaluatedContext())
+    return;
+
+  IndexExpr = IndexExpr->IgnoreParenImpCasts();
+  if (IndexExpr->isValueDependent())
+    return;
+
+  const Type *EffectiveType =
+      BaseExpr->getType()->getPointeeOrArrayElementType();
+  BaseExpr = BaseExpr->IgnoreParenCasts();
+  const ConstantArrayType *ArrayTy =
+      Context.getAsConstantArrayType(BaseExpr->getType());
+
+  LangOptions::StrictFlexArraysLevelKind
+    StrictFlexArraysLevel = getLangOpts().getStrictFlexArraysLevel();
+
+  const Type *BaseType =
+      ArrayTy == nullptr ? nullptr : ArrayTy->getElementType().getTypePtr();
+  bool IsUnboundedArray =
+      BaseType == nullptr || BaseExpr->isFlexibleArrayMemberLike(
+                                 Context, StrictFlexArraysLevel,
+                                 /*IgnoreTemplateOrMacroSubstitution=*/true);
+  if (EffectiveType->isDependentType() ||
+      (!IsUnboundedArray && BaseType->isDependentType()))
+    return;
+
+  Expr::EvalResult Result;
+  if (!IndexExpr->EvaluateAsInt(Result, Context, Expr::SE_AllowSideEffects))
+    return;
+
+  llvm::APSInt index = Result.Val.getInt();
+  if (IndexNegated) {
+    index.setIsUnsigned(false);
+    index = -index;
+  }
+
+  if (IsUnboundedArray) {
+    if (EffectiveType->isFunctionType())
+      return;
+    if (index.isUnsigned() || !index.isNegative()) {
+      const auto &ASTC = getASTContext();
+      unsigned AddrBits = ASTC.getTargetInfo().getPointerWidth(
+          EffectiveType->getCanonicalTypeInternal().getAddressSpace());
+      if (index.getBitWidth() < AddrBits)
+        index = index.zext(AddrBits);
+      std::optional<CharUnits> ElemCharUnits =
+          ASTC.getTypeSizeInCharsIfKnown(EffectiveType);
+      // PR50741 - If EffectiveType has unknown size (e.g., if it's a void
+      // pointer) bounds-checking isn't meaningful.
+      if (!ElemCharUnits || ElemCharUnits->isZero())
+        return;
+      llvm::APInt ElemBytes(index.getBitWidth(), ElemCharUnits->getQuantity());
+      // If index has more active bits than address space, we already know
+      // we have a bounds violation to warn about.  Otherwise, compute
+      // address of (index + 1)th element, and warn about bounds violation
+      // only if that address exceeds address space.
+      if (index.getActiveBits() <= AddrBits) {
+        bool Overflow;
+        llvm::APInt Product(index);
+        Product += 1;
+        Product = Product.umul_ov(ElemBytes, Overflow);
+        if (!Overflow && Product.getActiveBits() <= AddrBits)
+          return;
+      }
+
+      // Need to compute max possible elements in address space, since that
+      // is included in diag message.
+      llvm::APInt MaxElems = llvm::APInt::getMaxValue(AddrBits);
+      MaxElems = MaxElems.zext(std::max(AddrBits + 1, ElemBytes.getBitWidth()));
+      MaxElems += 1;
+      ElemBytes = ElemBytes.zextOrTrunc(MaxElems.getBitWidth());
+      MaxElems = MaxElems.udiv(ElemBytes);
+
+      unsigned DiagID =
+          ASE ? diag::warn_array_index_exceeds_max_addressable_bounds
+              : diag::warn_ptr_arith_exceeds_max_addressable_bounds;
+
+      // Diag message shows element size in bits and in "bytes" (platform-
+      // dependent CharUnits)
+      DiagRuntimeBehavior(BaseExpr->getBeginLoc(), BaseExpr,
+                          PDiag(DiagID) << index << AddrBits
+                                        << (unsigned)ASTC.toBits(*ElemCharUnits)
+                                        << ElemBytes << MaxElems
+                                        << MaxElems.getZExtValue()
+                                        << IndexExpr->getSourceRange());
+
+      const NamedDecl *ND = nullptr;
+      // Try harder to find a NamedDecl to point at in the note.
+      while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr))
+        BaseExpr = ASE->getBase()->IgnoreParenCasts();
+      if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
+        ND = DRE->getDecl();
+      if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr))
+        ND = ME->getMemberDecl();
+
+      if (ND)
+        DiagRuntimeBehavior(ND->getBeginLoc(), BaseExpr,
+                            PDiag(diag::note_array_declared_here) << ND);
+    }
+    return;
+  }
+
+  if (index.isUnsigned() || !index.isNegative()) {
+    // It is possible that the type of the base expression after
+    // IgnoreParenCasts is incomplete, even though the type of the base
+    // expression before IgnoreParenCasts is complete (see PR39746 for an
+    // example). In this case we have no information about whether the array
+    // access exceeds the array bounds. However we can still diagnose an array
+    // access which precedes the array bounds.
+    if (BaseType->isIncompleteType())
+      return;
+
+    llvm::APInt size = ArrayTy->getSize();
+
+    if (BaseType != EffectiveType) {
+      // Make sure we're comparing apples to apples when comparing index to
+      // size.
+      uint64_t ptrarith_typesize = Context.getTypeSize(EffectiveType);
+      uint64_t array_typesize = Context.getTypeSize(BaseType);
+
+      // Handle ptrarith_typesize being zero, such as when casting to void*.
+      // Use the size in bits (what "getTypeSize()" returns) rather than bytes.
+      if (!ptrarith_typesize)
+        ptrarith_typesize = Context.getCharWidth();
+
+      if (ptrarith_typesize != array_typesize) {
+        // There's a cast to a different size type involved.
+        uint64_t ratio = array_typesize / ptrarith_typesize;
+
+        // TODO: Be smarter about handling cases where array_typesize is not a
+        // multiple of ptrarith_typesize.
+        if (ptrarith_typesize * ratio == array_typesize)
+          size *= llvm::APInt(size.getBitWidth(), ratio);
+      }
+    }
+
+    if (size.getBitWidth() > index.getBitWidth())
+      index = index.zext(size.getBitWidth());
+    else if (size.getBitWidth() < index.getBitWidth())
+      size = size.zext(index.getBitWidth());
+
+    // For array subscripting the index must be less than size, but for pointer
+    // arithmetic also allow the index (offset) to be equal to size since
+    // computing the next address after the end of the array is legal and
+    // commonly done e.g. in C++ iterators and range-based for loops.
+    if (AllowOnePastEnd ? index.ule(size) : index.ult(size))
+      return;
+
+    // Suppress the warning if the subscript expression (as identified by the
+    // ']' location) and the index expression are both from macro expansions
+    // within a system header.
+    if (ASE) {
+      SourceLocation RBracketLoc = SourceMgr.getSpellingLoc(
+          ASE->getRBracketLoc());
+      if (SourceMgr.isInSystemHeader(RBracketLoc)) {
+        SourceLocation IndexLoc =
+            SourceMgr.getSpellingLoc(IndexExpr->getBeginLoc());
+        if (SourceMgr.isWrittenInSameFile(RBracketLoc, IndexLoc))
+          return;
+      }
+    }
+
+    unsigned DiagID = ASE ? diag::warn_array_index_exceeds_bounds
+                          : diag::warn_ptr_arith_exceeds_bounds;
+    unsigned CastMsg = (!ASE || BaseType == EffectiveType) ? 0 : 1;
+    QualType CastMsgTy = ASE ? ASE->getLHS()->getType() : QualType();
+
+    DiagRuntimeBehavior(BaseExpr->getBeginLoc(), BaseExpr,
+                        PDiag(DiagID)
+                            << index << ArrayTy->desugar() << CastMsg
+                            << CastMsgTy << IndexExpr->getSourceRange());
+  } else {
+    unsigned DiagID = diag::warn_array_index_precedes_bounds;
+    if (!ASE) {
+      DiagID = diag::warn_ptr_arith_precedes_bounds;
+      if (index.isNegative()) index = -index;
+    }
+
+    DiagRuntimeBehavior(BaseExpr->getBeginLoc(), BaseExpr,
+                        PDiag(DiagID) << index << IndexExpr->getSourceRange());
+  }
+
+  const NamedDecl *ND = nullptr;
+  // Try harder to find a NamedDecl to point at in the note.
+  while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr))
+    BaseExpr = ASE->getBase()->IgnoreParenCasts();
+  if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr))
+    ND = DRE->getDecl();
+  if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr))
+    ND = ME->getMemberDecl();
+
+  if (ND)
+    DiagRuntimeBehavior(ND->getBeginLoc(), BaseExpr,
+                        PDiag(diag::note_array_declared_here) << ND);
+}
+
+void Sema::CheckArrayAccess(const Expr *expr) {
+  int AllowOnePastEnd = 0;
+  while (expr) {
+    expr = expr->IgnoreParenImpCasts();
+    switch (expr->getStmtClass()) {
+      case Stmt::ArraySubscriptExprClass: {
+        const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(expr);
+        CheckArrayAccess(ASE->getBase(), ASE->getIdx(), ASE,
+                         AllowOnePastEnd > 0);
+        expr = ASE->getBase();
+        break;
+      }
+      case Stmt::MemberExprClass: {
+        expr = cast<MemberExpr>(expr)->getBase();
+        break;
+      }
+      case Stmt::CXXMemberCallExprClass: {
+        expr = cast<CXXMemberCallExpr>(expr)->getImplicitObjectArgument();
+        break;
+      }
+      case Stmt::ArraySectionExprClass: {
+        const ArraySectionExpr *ASE = cast<ArraySectionExpr>(expr);
+        // FIXME: We should probably be checking all of the elements to the
+        // 'length' here as well.
+        if (ASE->getLowerBound())
+          CheckArrayAccess(ASE->getBase(), ASE->getLowerBound(),
+                           /*ASE=*/nullptr, AllowOnePastEnd > 0);
+        return;
+      }
+      case Stmt::UnaryOperatorClass: {
+        // Only unwrap the * and & unary operators
+        const UnaryOperator *UO = cast<UnaryOperator>(expr);
+        expr = UO->getSubExpr();
+        switch (UO->getOpcode()) {
+          case UO_AddrOf:
+            AllowOnePastEnd++;
+            break;
+          case UO_Deref:
+            AllowOnePastEnd--;
+            break;
+          default:
+            return;
+        }
+        break;
+      }
+      case Stmt::ConditionalOperatorClass: {
+        const ConditionalOperator *cond = cast<ConditionalOperator>(expr);
+        if (const Expr *lhs = cond->getLHS())
+          CheckArrayAccess(lhs);
+        if (const Expr *rhs = cond->getRHS())
+          CheckArrayAccess(rhs);
+        return;
+      }
+      case Stmt::CXXOperatorCallExprClass: {
+        const auto *OCE = cast<CXXOperatorCallExpr>(expr);
+        for (const auto *Arg : OCE->arguments())
+          CheckArrayAccess(Arg);
+        return;
+      }
+      default:
+        return;
+    }
+  }
+}
+
+static bool checkUnsafeAssignLiteral(Sema &S, SourceLocation Loc,
+                                     Expr *RHS, bool isProperty) {
+  // Check if RHS is an Objective-C object literal, which also can get
+  // immediately zapped in a weak reference.  Note that we explicitly
+  // allow ObjCStringLiterals, since those are designed to never really die.
+  RHS = RHS->IgnoreParenImpCasts();
+
+  // This enum needs to match with the 'select' in
+  // warn_objc_arc_literal_assign (off-by-1).
+  SemaObjC::ObjCLiteralKind Kind = S.ObjC().CheckLiteralKind(RHS);
+  if (Kind == SemaObjC::LK_String || Kind == SemaObjC::LK_None)
+    return false;
+
+  S.Diag(Loc, diag::warn_arc_literal_assign)
+    << (unsigned) Kind
+    << (isProperty ? 0 : 1)
+    << RHS->getSourceRange();
+
+  return true;
+}
+
+static bool checkUnsafeAssignObject(Sema &S, SourceLocation Loc,
+                                    Qualifiers::ObjCLifetime LT,
+                                    Expr *RHS, bool isProperty) {
+  // Strip off any implicit cast added to get to the one ARC-specific.
+  while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
+    if (cast->getCastKind() == CK_ARCConsumeObject) {
+      S.Diag(Loc, diag::warn_arc_retained_assign)
+        << (LT == Qualifiers::OCL_ExplicitNone)
+        << (isProperty ? 0 : 1)
+        << RHS->getSourceRange();
+      return true;
+    }
+    RHS = cast->getSubExpr();
+  }
+
+  if (LT == Qualifiers::OCL_Weak &&
+      checkUnsafeAssignLiteral(S, Loc, RHS, isProperty))
+    return true;
+
+  return false;
+}
+
+bool Sema::checkUnsafeAssigns(SourceLocation Loc,
+                              QualType LHS, Expr *RHS) {
+  Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime();
+
+  if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone)
+    return false;
+
+  if (checkUnsafeAssignObject(*this, Loc, LT, RHS, false))
+    return true;
+
+  return false;
+}
+
+void Sema::checkUnsafeExprAssigns(SourceLocation Loc,
+                              Expr *LHS, Expr *RHS) {
+  QualType LHSType;
+  // PropertyRef on LHS type need be directly obtained from
+  // its declaration as it has a PseudoType.
+  ObjCPropertyRefExpr *PRE
+    = dyn_cast<ObjCPropertyRefExpr>(LHS->IgnoreParens());
+  if (PRE && !PRE->isImplicitProperty()) {
+    const ObjCPropertyDecl *PD = PRE->getExplicitProperty();
+    if (PD)
+      LHSType = PD->getType();
+  }
+
+  if (LHSType.isNull())
+    LHSType = LHS->getType();
+
+  Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime();
+
+  if (LT == Qualifiers::OCL_Weak) {
+    if (!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc))
+      getCurFunction()->markSafeWeakUse(LHS);
+  }
+
+  if (checkUnsafeAssigns(Loc, LHSType, RHS))
+    return;
+
+  // FIXME. Check for other life times.
+  if (LT != Qualifiers::OCL_None)
+    return;
+
+  if (PRE) {
+    if (PRE->isImplicitProperty())
+      return;
+    const ObjCPropertyDecl *PD = PRE->getExplicitProperty();
+    if (!PD)
+      return;
+
+    unsigned Attributes = PD->getPropertyAttributes();
+    if (Attributes & ObjCPropertyAttribute::kind_assign) {
+      // when 'assign' attribute was not explicitly specified
+      // by user, ignore it and rely on property type itself
+      // for lifetime info.
+      unsigned AsWrittenAttr = PD->getPropertyAttributesAsWritten();
+      if (!(AsWrittenAttr & ObjCPropertyAttribute::kind_assign) &&
+          LHSType->isObjCRetainableType())
+        return;
+
+      while (ImplicitCastExpr *cast = dyn_cast<ImplicitCastExpr>(RHS)) {
+        if (cast->getCastKind() == CK_ARCConsumeObject) {
+          Diag(Loc, diag::warn_arc_retained_property_assign)
+          << RHS->getSourceRange();
+          return;
+        }
+        RHS = cast->getSubExpr();
+      }
+    } else if (Attributes & ObjCPropertyAttribute::kind_weak) {
+      if (checkUnsafeAssignObject(*this, Loc, Qualifiers::OCL_Weak, RHS, true))
+        return;
+    }
+  }
+}
+
+//===--- CHECK: Empty statement body (-Wempty-body) ---------------------===//
+
+static bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr,
+                                        SourceLocation StmtLoc,
+                                        const NullStmt *Body) {
+  // Do not warn if the body is a macro that expands to nothing, e.g:
+  //
+  // #define CALL(x)
+  // if (condition)
+  //   CALL(0);
+  if (Body->hasLeadingEmptyMacro())
+    return false;
+
+  // Get line numbers of statement and body.
+  bool StmtLineInvalid;
+  unsigned StmtLine = SourceMgr.getPresumedLineNumber(StmtLoc,
+                                                      &StmtLineInvalid);
+  if (StmtLineInvalid)
+    return false;
+
+  bool BodyLineInvalid;
+  unsigned BodyLine = SourceMgr.getSpellingLineNumber(Body->getSemiLoc(),
+                                                      &BodyLineInvalid);
+  if (BodyLineInvalid)
+    return false;
+
+  // Warn if null statement and body are on the same line.
+  if (StmtLine != BodyLine)
+    return false;
+
+  return true;
+}
+
+void Sema::DiagnoseEmptyStmtBody(SourceLocation StmtLoc,
+                                 const Stmt *Body,
+                                 unsigned DiagID) {
+  // Since this is a syntactic check, don't emit diagnostic for template
+  // instantiations, this just adds noise.
+  if (CurrentInstantiationScope)
+    return;
+
+  // The body should be a null statement.
+  const NullStmt *NBody = dyn_cast<NullStmt>(Body);
+  if (!NBody)
+    return;
+
+  // Do the usual checks.
+  if (!ShouldDiagnoseEmptyStmtBody(SourceMgr, StmtLoc, NBody))
+    return;
+
+  Diag(NBody->getSemiLoc(), DiagID);
+  Diag(NBody->getSemiLoc(), diag::note_empty_body_on_separate_line);
+}
+
+void Sema::DiagnoseEmptyLoopBody(const Stmt *S,
+                                 const Stmt *PossibleBody) {
+  assert(!CurrentInstantiationScope); // Ensured by caller
+
+  SourceLocation StmtLoc;
+  const Stmt *Body;
+  unsigned DiagID;
+  if (const ForStmt *FS = dyn_cast<ForStmt>(S)) {
+    StmtLoc = FS->getRParenLoc();
+    Body = FS->getBody();
+    DiagID = diag::warn_empty_for_body;
+  } else if (const WhileStmt *WS = dyn_cast<WhileStmt>(S)) {
+    StmtLoc = WS->getRParenLoc();
+    Body = WS->getBody();
+    DiagID = diag::warn_empty_while_body;
+  } else
+    return; // Neither `for' nor `while'.
+
+  // The body should be a null statement.
+  const NullStmt *NBody = dyn_cast<NullStmt>(Body);
+  if (!NBody)
+    return;
+
+  // Skip expensive checks if diagnostic is disabled.
+  if (Diags.isIgnored(DiagID, NBody->getSemiLoc()))
+    return;
+
+  // Do the usual checks.
+  if (!ShouldDiagnoseEmptyStmtBody(SourceMgr, StmtLoc, NBody))
+    return;
+
+  // `for(...);' and `while(...);' are popular idioms, so in order to keep
+  // noise level low, emit diagnostics only if for/while is followed by a
+  // CompoundStmt, e.g.:
+  //    for (int i = 0; i < n; i++);
+  //    {
+  //      a(i);
+  //    }
+  // or if for/while is followed by a statement with more indentation
+  // than for/while itself:
+  //    for (int i = 0; i < n; i++);
+  //      a(i);
+  bool ProbableTypo = isa<CompoundStmt>(PossibleBody);
+  if (!ProbableTypo) {
+    bool BodyColInvalid;
+    unsigned BodyCol = SourceMgr.getPresumedColumnNumber(
+        PossibleBody->getBeginLoc(), &BodyColInvalid);
+    if (BodyColInvalid)
+      return;
+
+    bool StmtColInvalid;
+    unsigned StmtCol =
+        SourceMgr.getPresumedColumnNumber(S->getBeginLoc(), &StmtColInvalid);
+    if (StmtColInvalid)
+      return;
+
+    if (BodyCol > StmtCol)
+      ProbableTypo = true;
+  }
+
+  if (ProbableTypo) {
+    Diag(NBody->getSemiLoc(), DiagID);
+    Diag(NBody->getSemiLoc(), diag::note_empty_body_on_separate_line);
+  }
+}
+
+//===--- CHECK: Warn on self move with std::move. -------------------------===//
+
+void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr,
+                             SourceLocation OpLoc) {
+  if (Diags.isIgnored(diag::warn_sizeof_pointer_expr_memaccess, OpLoc))
+    return;
+
+  if (inTemplateInstantiation())
+    return;
+
+  // Strip parens and casts away.
+  LHSExpr = LHSExpr->IgnoreParenImpCasts();
+  RHSExpr = RHSExpr->IgnoreParenImpCasts();
+
+  // Check for a call to std::move or for a static_cast<T&&>(..) to an xvalue
+  // which we can treat as an inlined std::move
+  if (const auto *CE = dyn_cast<CallExpr>(RHSExpr);
+      CE && CE->getNumArgs() == 1 && CE->isCallToStdMove())
+    RHSExpr = CE->getArg(0);
+  else if (const auto *CXXSCE = dyn_cast<CXXStaticCastExpr>(RHSExpr);
+           CXXSCE && CXXSCE->isXValue())
+    RHSExpr = CXXSCE->getSubExpr();
+  else
+    return;
+
+  const DeclRefExpr *LHSDeclRef = dyn_cast<DeclRefExpr>(LHSExpr);
+  const DeclRefExpr *RHSDeclRef = dyn_cast<DeclRefExpr>(RHSExpr);
+
+  // Two DeclRefExpr's, check that the decls are the same.
+  if (LHSDeclRef && RHSDeclRef) {
+    if (!LHSDeclRef->getDecl() || !RHSDeclRef->getDecl())
+      return;
+    if (LHSDeclRef->getDecl()->getCanonicalDecl() !=
+        RHSDeclRef->getDecl()->getCanonicalDecl())
+      return;
+
+    auto D = Diag(OpLoc, diag::warn_self_move)
+             << LHSExpr->getType() << LHSExpr->getSourceRange()
+             << RHSExpr->getSourceRange();
+    if (const FieldDecl *F =
+            getSelfAssignmentClassMemberCandidate(RHSDeclRef->getDecl()))
+      D << 1 << F
+        << FixItHint::CreateInsertion(LHSDeclRef->getBeginLoc(), "this->");
+    else
+      D << 0;
+    return;
+  }
+
+  // Member variables require a different approach to check for self moves.
+  // MemberExpr's are the same if every nested MemberExpr refers to the same
+  // Decl and that the base Expr's are DeclRefExpr's with the same Decl or
+  // the base Expr's are CXXThisExpr's.
+  const Expr *LHSBase = LHSExpr;
+  const Expr *RHSBase = RHSExpr;
+  const MemberExpr *LHSME = dyn_cast<MemberExpr>(LHSExpr);
+  const MemberExpr *RHSME = dyn_cast<MemberExpr>(RHSExpr);
+  if (!LHSME || !RHSME)
+    return;
+
+  while (LHSME && RHSME) {
+    if (LHSME->getMemberDecl()->getCanonicalDecl() !=
+        RHSME->getMemberDecl()->getCanonicalDecl())
+      return;
+
+    LHSBase = LHSME->getBase();
+    RHSBase = RHSME->getBase();
+    LHSME = dyn_cast<MemberExpr>(LHSBase);
+    RHSME = dyn_cast<MemberExpr>(RHSBase);
+  }
+
+  LHSDeclRef = dyn_cast<DeclRefExpr>(LHSBase);
+  RHSDeclRef = dyn_cast<DeclRefExpr>(RHSBase);
+  if (LHSDeclRef && RHSDeclRef) {
+    if (!LHSDeclRef->getDecl() || !RHSDeclRef->getDecl())
+      return;
+    if (LHSDeclRef->getDecl()->getCanonicalDecl() !=
+        RHSDeclRef->getDecl()->getCanonicalDecl())
+      return;
+
+    Diag(OpLoc, diag::warn_self_move)
+        << LHSExpr->getType() << 0 << LHSExpr->getSourceRange()
+        << RHSExpr->getSourceRange();
+    return;
+  }
+
+  if (isa<CXXThisExpr>(LHSBase) && isa<CXXThisExpr>(RHSBase))
+    Diag(OpLoc, diag::warn_self_move)
+        << LHSExpr->getType() << 0 << LHSExpr->getSourceRange()
+        << RHSExpr->getSourceRange();
+}
+
+//===--- Layout compatibility ----------------------------------------------//
+
+static bool isLayoutCompatible(const ASTContext &C, QualType T1, QualType T2);
+
+/// Check if two enumeration types are layout-compatible.
+static bool isLayoutCompatible(const ASTContext &C, const EnumDecl *ED1,
+                               const EnumDecl *ED2) {
+  // C++11 [dcl.enum] p8:
+  // Two enumeration types are layout-compatible if they have the same
+  // underlying type.
+  return ED1->isComplete() && ED2->isComplete() &&
+         C.hasSameType(ED1->getIntegerType(), ED2->getIntegerType());
+}
+
+/// Check if two fields are layout-compatible.
+/// Can be used on union members, which are exempt from alignment requirement
+/// of common initial sequence.
+static bool isLayoutCompatible(const ASTContext &C, const FieldDecl *Field1,
+                               const FieldDecl *Field2,
+                               bool AreUnionMembers = false) {
+#ifndef NDEBUG
+  CanQualType Field1Parent = C.getCanonicalTagType(Field1->getParent());
+  CanQualType Field2Parent = C.getCanonicalTagType(Field2->getParent());
+  assert(((Field1Parent->isStructureOrClassType() &&
+           Field2Parent->isStructureOrClassType()) ||
+          (Field1Parent->isUnionType() && Field2Parent->isUnionType())) &&
+         "Can't evaluate layout compatibility between a struct field and a "
+         "union field.");
+  assert(((!AreUnionMembers && Field1Parent->isStructureOrClassType()) ||
+          (AreUnionMembers && Field1Parent->isUnionType())) &&
+         "AreUnionMembers should be 'true' for union fields (only).");
+#endif
+
+  if (!isLayoutCompatible(C, Field1->getType(), Field2->getType()))
+    return false;
+
+  if (Field1->isBitField() != Field2->isBitField())
+    return false;
+
+  if (Field1->isBitField()) {
+    // Make sure that the bit-fields are the same length.
+    unsigned Bits1 = Field1->getBitWidthValue();
+    unsigned Bits2 = Field2->getBitWidthValue();
+
+    if (Bits1 != Bits2)
+      return false;
+  }
+
+  if (Field1->hasAttr<clang::NoUniqueAddressAttr>() ||
+      Field2->hasAttr<clang::NoUniqueAddressAttr>())
+    return false;
+
+  if (!AreUnionMembers &&
+      Field1->getMaxAlignment() != Field2->getMaxAlignment())
+    return false;
+
+  return true;
+}
+
+/// Check if two standard-layout structs are layout-compatible.
+/// (C++11 [class.mem] p17)
+static bool isLayoutCompatibleStruct(const ASTContext &C, const RecordDecl *RD1,
+                                     const RecordDecl *RD2) {
+  // Get to the class where the fields are declared
+  if (const CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(RD1))
+    RD1 = D1CXX->getStandardLayoutBaseWithFields();
+
+  if (const CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(RD2))
+    RD2 = D2CXX->getStandardLayoutBaseWithFields();
+
+  // Check the fields.
+  return llvm::equal(RD1->fields(), RD2->fields(),
+                     [&C](const FieldDecl *F1, const FieldDecl *F2) -> bool {
+                       return isLayoutCompatible(C, F1, F2);
+                     });
+}
+
+/// Check if two standard-layout unions are layout-compatible.
+/// (C++11 [class.mem] p18)
+static bool isLayoutCompatibleUnion(const ASTContext &C, const RecordDecl *RD1,
+                                    const RecordDecl *RD2) {
+  llvm::SmallPtrSet<const FieldDecl *, 8> UnmatchedFields(llvm::from_range,
+                                                          RD2->fields());
+
+  for (auto *Field1 : RD1->fields()) {
+    auto I = UnmatchedFields.begin();
+    auto E = UnmatchedFields.end();
+
+    for ( ; I != E; ++I) {
+      if (isLayoutCompatible(C, Field1, *I, /*IsUnionMember=*/true)) {
+        bool Result = UnmatchedFields.erase(*I);
+        (void) Result;
+        assert(Result);
+        break;
+      }
+    }
+    if (I == E)
+      return false;
+  }
+
+  return UnmatchedFields.empty();
+}
+
+static bool isLayoutCompatible(const ASTContext &C, const RecordDecl *RD1,
+                               const RecordDecl *RD2) {
+  if (RD1->isUnion() != RD2->isUnion())
+    return false;
+
+  if (RD1->isUnion())
+    return isLayoutCompatibleUnion(C, RD1, RD2);
+  else
+    return isLayoutCompatibleStruct(C, RD1, RD2);
+}
+
+/// Check if two types are layout-compatible in C++11 sense.
+static bool isLayoutCompatible(const ASTContext &C, QualType T1, QualType T2) {
+  if (T1.isNull() || T2.isNull())
+    return false;
+
+  // C++20 [basic.types] p11:
+  // Two types cv1 T1 and cv2 T2 are layout-compatible types
+  // if T1 and T2 are the same type, layout-compatible enumerations (9.7.1),
+  // or layout-compatible standard-layout class types (11.4).
+  T1 = T1.getCanonicalType().getUnqualifiedType();
+  T2 = T2.getCanonicalType().getUnqualifiedType();
+
+  if (C.hasSameType(T1, T2))
+    return true;
+
+  const Type::TypeClass TC1 = T1->getTypeClass();
+  const Type::TypeClass TC2 = T2->getTypeClass();
+
+  if (TC1 != TC2)
+    return false;
+
+  if (TC1 == Type::Enum)
+    return isLayoutCompatible(C, T1->castAsEnumDecl(), T2->castAsEnumDecl());
+  if (TC1 == Type::Record) {
+    if (!T1->isStandardLayoutType() || !T2->isStandardLayoutType())
+      return false;
+
+    return isLayoutCompatible(C, T1->castAsRecordDecl(),
+                              T2->castAsRecordDecl());
+  }
+
+  return false;
+}
+
+bool Sema::IsLayoutCompatible(QualType T1, QualType T2) const {
+  return isLayoutCompatible(getASTContext(), T1, T2);
+}
+
+//===-------------- Pointer interconvertibility ----------------------------//
+
+bool Sema::IsPointerInterconvertibleBaseOf(const TypeSourceInfo *Base,
+                                           const TypeSourceInfo *Derived) {
+  QualType BaseT = Base->getType()->getCanonicalTypeUnqualified();
+  QualType DerivedT = Derived->getType()->getCanonicalTypeUnqualified();
+
+  if (BaseT->isStructureOrClassType() && DerivedT->isStructureOrClassType() &&
+      getASTContext().hasSameType(BaseT, DerivedT))
+    return true;
+
+  if (!IsDerivedFrom(Derived->getTypeLoc().getBeginLoc(), DerivedT, BaseT))
+    return false;
+
+  // Per [basic.compound]/4.3, containing object has to be standard-layout.
+  if (DerivedT->getAsCXXRecordDecl()->isStandardLayout())
+    return true;
+
+  return false;
+}
+
+//===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----//
+
+/// Given a type tag expression find the type tag itself.
+///
+/// \param TypeExpr Type tag expression, as it appears in user's code.
+///
+/// \param VD Declaration of an identifier that appears in a type tag.
+///
+/// \param MagicValue Type tag magic value.
+///
+/// \param isConstantEvaluated whether the evalaution should be performed in
+
+/// constant context.
+static bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx,
+                            const ValueDecl **VD, uint64_t *MagicValue,
+                            bool isConstantEvaluated) {
+  while(true) {
+    if (!TypeExpr)
+      return false;
+
+    TypeExpr = TypeExpr->IgnoreParenImpCasts()->IgnoreParenCasts();
+
+    switch (TypeExpr->getStmtClass()) {
+    case Stmt::UnaryOperatorClass: {
+      const UnaryOperator *UO = cast<UnaryOperator>(TypeExpr);
+      if (UO->getOpcode() == UO_AddrOf || UO->getOpcode() == UO_Deref) {
+        TypeExpr = UO->getSubExpr();
+        continue;
+      }
+      return false;
+    }
+
+    case Stmt::DeclRefExprClass: {
+      const DeclRefExpr *DRE = cast<DeclRefExpr>(TypeExpr);
+      *VD = DRE->getDecl();
+      return true;
+    }
+
+    case Stmt::IntegerLiteralClass: {
+      const IntegerLiteral *IL = cast<IntegerLiteral>(TypeExpr);
+      llvm::APInt MagicValueAPInt = IL->getValue();
+      if (MagicValueAPInt.getActiveBits() <= 64) {
+        *MagicValue = MagicValueAPInt.getZExtValue();
+        return true;
+      } else
+        return false;
+    }
+
+    case Stmt::BinaryConditionalOperatorClass:
+    case Stmt::ConditionalOperatorClass: {
+      const AbstractConditionalOperator *ACO =
+          cast<AbstractConditionalOperator>(TypeExpr);
+      bool Result;
+      if (ACO->getCond()->EvaluateAsBooleanCondition(Result, Ctx,
+                                                     isConstantEvaluated)) {
+        if (Result)
+          TypeExpr = ACO->getTrueExpr();
+        else
+          TypeExpr = ACO->getFalseExpr();
+        continue;
+      }
+      return false;
+    }
+
+    case Stmt::BinaryOperatorClass: {
+      const BinaryOperator *BO = cast<BinaryOperator>(TypeExpr);
+      if (BO->getOpcode() == BO_Comma) {
+        TypeExpr = BO->getRHS();
+        continue;
+      }
+      return false;
+    }
+
+    default:
+      return false;
+    }
+  }
+}
+
+/// Retrieve the C type corresponding to type tag TypeExpr.
+///
+/// \param TypeExpr Expression that specifies a type tag.
+///
+/// \param MagicValues Registered magic values.
+///
+/// \param FoundWrongKind Set to true if a type tag was found, but of a wrong
+///        kind.
+///
+/// \param TypeInfo Information about the corresponding C type.
+///
+/// \param isConstantEvaluated whether the evalaution should be performed in
+/// constant context.
+///
+/// \returns true if the corresponding C type was found.
+static bool GetMatchingCType(
+    const IdentifierInfo *ArgumentKind, const Expr *TypeExpr,
+    const ASTContext &Ctx,
+    const llvm::DenseMap<Sema::TypeTagMagicValue, Sema::TypeTagData>
+        *MagicValues,
+    bool &FoundWrongKind, Sema::TypeTagData &TypeInfo,
+    bool isConstantEvaluated) {
+  FoundWrongKind = false;
+
+  // Variable declaration that has type_tag_for_datatype attribute.
+  const ValueDecl *VD = nullptr;
+
+  uint64_t MagicValue;
+
+  if (!FindTypeTagExpr(TypeExpr, Ctx, &VD, &MagicValue, isConstantEvaluated))
+    return false;
+
+  if (VD) {
+    if (TypeTagForDatatypeAttr *I = VD->getAttr<TypeTagForDatatypeAttr>()) {
+      if (I->getArgumentKind() != ArgumentKind) {
+        FoundWrongKind = true;
+        return false;
+      }
+      TypeInfo.Type = I->getMatchingCType();
+      TypeInfo.LayoutCompatible = I->getLayoutCompatible();
+      TypeInfo.MustBeNull = I->getMustBeNull();
+      return true;
+    }
+    return false;
+  }
+
+  if (!MagicValues)
+    return false;
+
+  llvm::DenseMap<Sema::TypeTagMagicValue,
+                 Sema::TypeTagData>::const_iterator I =
+      MagicValues->find(std::make_pair(ArgumentKind, MagicValue));
+  if (I == MagicValues->end())
+    return false;
+
+  TypeInfo = I->second;
+  return true;
+}
+
+void Sema::RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind,
+                                      uint64_t MagicValue, QualType Type,
+                                      bool LayoutCompatible,
+                                      bool MustBeNull) {
+  if (!TypeTagForDatatypeMagicValues)
+    TypeTagForDatatypeMagicValues.reset(
+        new llvm::DenseMap<TypeTagMagicValue, TypeTagData>);
+
+  TypeTagMagicValue Magic(ArgumentKind, MagicValue);
+  (*TypeTagForDatatypeMagicValues)[Magic] =
+      TypeTagData(Type, LayoutCompatible, MustBeNull);
+}
+
+static bool IsSameCharType(QualType T1, QualType T2) {
+  const BuiltinType *BT1 = T1->getAs<BuiltinType>();
+  if (!BT1)
+    return false;
+
+  const BuiltinType *BT2 = T2->getAs<BuiltinType>();
+  if (!BT2)
+    return false;
+
+  BuiltinType::Kind T1Kind = BT1->getKind();
+  BuiltinType::Kind T2Kind = BT2->getKind();
+
+  return (T1Kind == BuiltinType::SChar  && T2Kind == BuiltinType::Char_S) ||
+         (T1Kind == BuiltinType::UChar  && T2Kind == BuiltinType::Char_U) ||
+         (T1Kind == BuiltinType::Char_U && T2Kind == BuiltinType::UChar) ||
+         (T1Kind == BuiltinType::Char_S && T2Kind == BuiltinType::SChar);
+}
+
+void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
+                                    const ArrayRef<const Expr *> ExprArgs,
+                                    SourceLocation CallSiteLoc) {
+  const IdentifierInfo *ArgumentKind = Attr->getArgumentKind();
+  bool IsPointerAttr = Attr->getIsPointer();
+
+  // Retrieve the argument representing the 'type_tag'.
+  unsigned TypeTagIdxAST = Attr->getTypeTagIdx().getASTIndex();
+  if (TypeTagIdxAST >= ExprArgs.size()) {
+    Diag(CallSiteLoc, diag::err_tag_index_out_of_range)
+        << 0 << Attr->getTypeTagIdx().getSourceIndex();
+    return;
+  }
+  const Expr *TypeTagExpr = ExprArgs[TypeTagIdxAST];
+  bool FoundWrongKind;
+  TypeTagData TypeInfo;
+  if (!GetMatchingCType(ArgumentKind, TypeTagExpr, Context,
+                        TypeTagForDatatypeMagicValues.get(), FoundWrongKind,
+                        TypeInfo, isConstantEvaluatedContext())) {
+    if (FoundWrongKind)
+      Diag(TypeTagExpr->getExprLoc(),
+           diag::warn_type_tag_for_datatype_wrong_kind)
+        << TypeTagExpr->getSourceRange();
+    return;
+  }
+
+  // Retrieve the argument representing the 'arg_idx'.
+  unsigned ArgumentIdxAST = Attr->getArgumentIdx().getASTIndex();
+  if (ArgumentIdxAST >= ExprArgs.size()) {
+    Diag(CallSiteLoc, diag::err_tag_index_out_of_range)
+        << 1 << Attr->getArgumentIdx().getSourceIndex();
+    return;
+  }
+  const Expr *ArgumentExpr = ExprArgs[ArgumentIdxAST];
+  if (IsPointerAttr) {
+    // Skip implicit cast of pointer to `void *' (as a function argument).
+    if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgumentExpr))
+      if (ICE->getType()->isVoidPointerType() &&
+          ICE->getCastKind() == CK_BitCast)
+        ArgumentExpr = ICE->getSubExpr();
+  }
+  QualType ArgumentType = ArgumentExpr->getType();
+
+  // Passing a `void*' pointer shouldn't trigger a warning.
+  if (IsPointerAttr && ArgumentType->isVoidPointerType())
+    return;
+
+  if (TypeInfo.MustBeNull) {
+    // Type tag with matching void type requires a null pointer.
+    if (!ArgumentExpr->isNullPointerConstant(Context,
+                                             Expr::NPC_ValueDependentIsNotNull)) {
+      Diag(ArgumentExpr->getExprLoc(),
+           diag::warn_type_safety_null_pointer_required)
+          << ArgumentKind->getName()
+          << ArgumentExpr->getSourceRange()
+          << TypeTagExpr->getSourceRange();
+    }
+    return;
+  }
+
+  QualType RequiredType = TypeInfo.Type;
+  if (IsPointerAttr)
+    RequiredType = Context.getPointerType(RequiredType);
+
+  bool mismatch = false;
+  if (!TypeInfo.LayoutCompatible) {
+    mismatch = !Context.hasSameType(ArgumentType, RequiredType);
+
+    // C++11 [basic.fundamental] p1:
+    // Plain char, signed char, and unsigned char are three distinct types.
+    //
+    // But we treat plain `char' as equivalent to `signed char' or `unsigned
+    // char' depending on the current char signedness mode.
+    if (mismatch)
+      if ((IsPointerAttr && IsSameCharType(ArgumentType->getPointeeType(),
+                                           RequiredType->getPointeeType())) ||
+          (!IsPointerAttr && IsSameCharType(ArgumentType, RequiredType)))
+        mismatch = false;
+  } else
+    if (IsPointerAttr)
+      mismatch = !isLayoutCompatible(Context,
+                                     ArgumentType->getPointeeType(),
+                                     RequiredType->getPointeeType());
+    else
+      mismatch = !isLayoutCompatible(Context, ArgumentType, RequiredType);
+
+  if (mismatch)
+    Diag(ArgumentExpr->getExprLoc(), diag::warn_type_safety_type_mismatch)
+        << ArgumentType << ArgumentKind
+        << TypeInfo.LayoutCompatible << RequiredType
+        << ArgumentExpr->getSourceRange()
+        << TypeTagExpr->getSourceRange();
+}
+
+void Sema::AddPotentialMisalignedMembers(Expr *E, RecordDecl *RD, ValueDecl *MD,
+                                         CharUnits Alignment) {
+  currentEvaluationContext().MisalignedMembers.emplace_back(E, RD, MD,
+                                                            Alignment);
+}
+
+void Sema::DiagnoseMisalignedMembers() {
+  for (MisalignedMember &m : currentEvaluationContext().MisalignedMembers) {
+    const NamedDecl *ND = m.RD;
+    if (ND->getName().empty()) {
+      if (const TypedefNameDecl *TD = m.RD->getTypedefNameForAnonDecl())
+        ND = TD;
+    }
+    Diag(m.E->getBeginLoc(), diag::warn_taking_address_of_packed_member)
+        << m.MD << ND << m.E->getSourceRange();
+  }
+  currentEvaluationContext().MisalignedMembers.clear();
+}
+
+void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) {
+  E = E->IgnoreParens();
+  if (!T->isPointerType() && !T->isIntegerType() && !T->isDependentType())
+    return;
+  if (isa<UnaryOperator>(E) &&
+      cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) {
+    auto *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();
+    if (isa<MemberExpr>(Op)) {
+      auto &MisalignedMembersForExpr =
+          currentEvaluationContext().MisalignedMembers;
+      auto *MA = llvm::find(MisalignedMembersForExpr, MisalignedMember(Op));
+      if (MA != MisalignedMembersForExpr.end() &&
+          (T->isDependentType() || T->isIntegerType() ||
+           (T->isPointerType() && (T->getPointeeType()->isIncompleteType() ||
+                                   Context.getTypeAlignInChars(
+                                       T->getPointeeType()) <= MA->Alignment))))
+        MisalignedMembersForExpr.erase(MA);
+    }
+  }
+}
+
+void Sema::RefersToMemberWithReducedAlignment(
+    Expr *E,
+    llvm::function_ref<void(Expr *, RecordDecl *, FieldDecl *, CharUnits)>
+        Action) {
+  const auto *ME = dyn_cast<MemberExpr>(E);
+  if (!ME)
+    return;
+
+  // No need to check expressions with an __unaligned-qualified type.
+  if (E->getType().getQualifiers().hasUnaligned())
+    return;
+
+  // For a chain of MemberExpr like "a.b.c.d" this list
+  // will keep FieldDecl's like [d, c, b].
+  SmallVector<FieldDecl *, 4> ReverseMemberChain;
+  const MemberExpr *TopME = nullptr;
+  bool AnyIsPacked = false;
+  do {
+    QualType BaseType = ME->getBase()->getType();
+    if (BaseType->isDependentType())
+      return;
+    if (ME->isArrow())
+      BaseType = BaseType->getPointeeType();
+    auto *RD = BaseType->castAsRecordDecl();
+    if (RD->isInvalidDecl())
+      return;
+
+    ValueDecl *MD = ME->getMemberDecl();
+    auto *FD = dyn_cast<FieldDecl>(MD);
+    // We do not care about non-data members.
+    if (!FD || FD->isInvalidDecl())
+      return;
+
+    AnyIsPacked =
+        AnyIsPacked || (RD->hasAttr<PackedAttr>() || MD->hasAttr<PackedAttr>());
+    ReverseMemberChain.push_back(FD);
+
+    TopME = ME;
+    ME = dyn_cast<MemberExpr>(ME->getBase()->IgnoreParens());
+  } while (ME);
+  assert(TopME && "We did not compute a topmost MemberExpr!");
+
+  // Not the scope of this diagnostic.
+  if (!AnyIsPacked)
+    return;
+
+  const Expr *TopBase = TopME->getBase()->IgnoreParenImpCasts();
+  const auto *DRE = dyn_cast<DeclRefExpr>(TopBase);
+  // TODO: The innermost base of the member expression may be too complicated.
+  // For now, just disregard these cases. This is left for future
+  // improvement.
+  if (!DRE && !isa<CXXThisExpr>(TopBase))
+      return;
+
+  // Alignment expected by the whole expression.
+  CharUnits ExpectedAlignment = Context.getTypeAlignInChars(E->getType());
+
+  // No need to do anything else with this case.
+  if (ExpectedAlignment.isOne())
+    return;
+
+  // Synthesize offset of the whole access.
+  CharUnits Offset;
+  for (const FieldDecl *FD : llvm::reverse(ReverseMemberChain))
+    Offset += Context.toCharUnitsFromBits(Context.getFieldOffset(FD));
+
+  // Compute the CompleteObjectAlignment as the alignment of the whole chain.
+  CharUnits CompleteObjectAlignment = Context.getTypeAlignInChars(
+      Context.getCanonicalTagType(ReverseMemberChain.back()->getParent()));
+
+  // The base expression of the innermost MemberExpr may give
+  // stronger guarantees than the class containing the member.
+  if (DRE && !TopME->isArrow()) {
+    const ValueDecl *VD = DRE->getDecl();
+    if (!VD->getType()->isReferenceType())
+      CompleteObjectAlignment =
+          std::max(CompleteObjectAlignment, Context.getDeclAlign(VD));
+  }
+
+  // Check if the synthesized offset fulfills the alignment.
+  if (!Offset.isMultipleOf(ExpectedAlignment) ||
+      // It may fulfill the offset it but the effective alignment may still be
+      // lower than the expected expression alignment.
+      CompleteObjectAlignment < ExpectedAlignment) {
+    // If this happens, we want to determine a sensible culprit of this.
+    // Intuitively, watching the chain of member expressions from right to
+    // left, we start with the required alignment (as required by the field
+    // type) but some packed attribute in that chain has reduced the alignment.
+    // It may happen that another packed structure increases it again. But if
+    // we are here such increase has not been enough. So pointing the first
+    // FieldDecl that either is packed or else its RecordDecl is,
+    // seems reasonable.
+    FieldDecl *FD = nullptr;
+    CharUnits Alignment;
+    for (FieldDecl *FDI : ReverseMemberChain) {
+      if (FDI->hasAttr<PackedAttr>() ||
+          FDI->getParent()->hasAttr<PackedAttr>()) {
+        FD = FDI;
+        Alignment = std::min(Context.getTypeAlignInChars(FD->getType()),
+                             Context.getTypeAlignInChars(
+                                 Context.getCanonicalTagType(FD->getParent())));
+        break;
+      }
+    }
+    assert(FD && "We did not find a packed FieldDecl!");
+    Action(E, FD->getParent(), FD, Alignment);
+  }
+}
+
+void Sema::CheckAddressOfPackedMember(Expr *rhs) {
+  using namespace std::placeholders;
+
+  RefersToMemberWithReducedAlignment(
+      rhs, std::bind(&Sema::AddPotentialMisalignedMembers, std::ref(*this), _1,
+                     _2, _3, _4));
+}
+
+bool Sema::PrepareBuiltinElementwiseMathOneArgCall(
+    CallExpr *TheCall, EltwiseBuiltinArgTyRestriction ArgTyRestr) {
+  if (checkArgCount(TheCall, 1))
+    return true;
+
+  ExprResult A = BuiltinVectorMathConversions(*this, TheCall->getArg(0));
+  if (A.isInvalid())
+    return true;
+
+  TheCall->setArg(0, A.get());
+  QualType TyA = A.get()->getType();
+
+  if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA,
+                                  ArgTyRestr, 1))
+    return true;
+
+  TheCall->setType(TyA);
+  return false;
+}
+
+bool Sema::BuiltinElementwiseMath(CallExpr *TheCall,
+                                  EltwiseBuiltinArgTyRestriction ArgTyRestr) {
+  if (auto Res = BuiltinVectorMath(TheCall, ArgTyRestr); Res.has_value()) {
+    TheCall->setType(*Res);
+    return false;
+  }
+  return true;
+}
+
+bool Sema::BuiltinVectorToScalarMath(CallExpr *TheCall) {
+  std::optional<QualType> Res = BuiltinVectorMath(TheCall);
+  if (!Res)
+    return true;
+
+  if (auto *VecTy0 = (*Res)->getAs<VectorType>())
+    TheCall->setType(VecTy0->getElementType());
+  else
+    TheCall->setType(*Res);
+
+  return false;
+}
+
+static bool checkBuiltinVectorMathMixedEnums(Sema &S, Expr *LHS, Expr *RHS,
+                                             SourceLocation Loc) {
+  QualType L = LHS->getEnumCoercedType(S.Context),
+           R = RHS->getEnumCoercedType(S.Context);
+  if (L->isUnscopedEnumerationType() && R->isUnscopedEnumerationType() &&
+      !S.Context.hasSameUnqualifiedType(L, R)) {
+    return S.Diag(Loc, diag::err_conv_mixed_enum_types)
+           << LHS->getSourceRange() << RHS->getSourceRange()
+           << /*Arithmetic Between*/ 0 << L << R;
+  }
+  return false;
+}
+
+/// Check if all arguments have the same type. If the types don't match, emit an
+/// error message and return true. Otherwise return false.
+///
+/// For scalars we directly compare their unqualified types. But even if we
+/// compare unqualified vector types, a difference in qualifiers in the element
+/// types can make the vector types be considered not equal. For example,
+/// vector of 4 'const float' values vs vector of 4 'float' values.
+/// So we compare unqualified types of their elements and number of elements.
+static bool checkBuiltinVectorMathArgTypes(Sema &SemaRef,
+                                           ArrayRef<Expr *> Args) {
+  assert(!Args.empty() && "Should have at least one argument.");
+
+  Expr *Arg0 = Args.front();
+  QualType Ty0 = Arg0->getType();
+
+  auto EmitError = [&](Expr *ArgI) {
+    SemaRef.Diag(Arg0->getBeginLoc(),
+                 diag::err_typecheck_call_different_arg_types)
+        << Arg0->getType() << ArgI->getType();
+  };
+
+  // Compare scalar types.
+  if (!Ty0->isVectorType()) {
+    for (Expr *ArgI : Args.drop_front())
+      if (!SemaRef.Context.hasSameUnqualifiedType(Ty0, ArgI->getType())) {
+        EmitError(ArgI);
+        return true;
+      }
+
+    return false;
+  }
+
+  // Compare vector types.
+  const auto *Vec0 = Ty0->castAs<VectorType>();
+  for (Expr *ArgI : Args.drop_front()) {
+    const auto *VecI = ArgI->getType()->getAs<VectorType>();
+    if (!VecI ||
+        !SemaRef.Context.hasSameUnqualifiedType(Vec0->getElementType(),
+                                                VecI->getElementType()) ||
+        Vec0->getNumElements() != VecI->getNumElements()) {
+      EmitError(ArgI);
+      return true;
+    }
+  }
+
+  return false;
+}
+
+std::optional<QualType>
+Sema::BuiltinVectorMath(CallExpr *TheCall,
+                        EltwiseBuiltinArgTyRestriction ArgTyRestr) {
+  if (checkArgCount(TheCall, 2))
+    return std::nullopt;
+
+  if (checkBuiltinVectorMathMixedEnums(
+          *this, TheCall->getArg(0), TheCall->getArg(1), TheCall->getExprLoc()))
+    return std::nullopt;
+
+  Expr *Args[2];
+  for (int I = 0; I < 2; ++I) {
+    ExprResult Converted =
+        BuiltinVectorMathConversions(*this, TheCall->getArg(I));
+    if (Converted.isInvalid())
+      return std::nullopt;
+    Args[I] = Converted.get();
+  }
+
+  SourceLocation LocA = Args[0]->getBeginLoc();
+  QualType TyA = Args[0]->getType();
+
+  if (checkMathBuiltinElementType(*this, LocA, TyA, ArgTyRestr, 1))
+    return std::nullopt;
+
+  if (checkBuiltinVectorMathArgTypes(*this, Args))
+    return std::nullopt;
+
+  TheCall->setArg(0, Args[0]);
+  TheCall->setArg(1, Args[1]);
+  return TyA;
+}
+
+bool Sema::BuiltinElementwiseTernaryMath(
+    CallExpr *TheCall, EltwiseBuiltinArgTyRestriction ArgTyRestr) {
+  if (checkArgCount(TheCall, 3))
+    return true;
+
+  SourceLocation Loc = TheCall->getExprLoc();
+  if (checkBuiltinVectorMathMixedEnums(*this, TheCall->getArg(0),
+                                       TheCall->getArg(1), Loc) ||
+      checkBuiltinVectorMathMixedEnums(*this, TheCall->getArg(1),
+                                       TheCall->getArg(2), Loc))
+    return true;
+
+  Expr *Args[3];
+  for (int I = 0; I < 3; ++I) {
+    ExprResult Converted =
+        BuiltinVectorMathConversions(*this, TheCall->getArg(I));
+    if (Converted.isInvalid())
+      return true;
+    Args[I] = Converted.get();
+  }
+
+  int ArgOrdinal = 1;
+  for (Expr *Arg : Args) {
+    if (checkMathBuiltinElementType(*this, Arg->getBeginLoc(), Arg->getType(),
+                                    ArgTyRestr, ArgOrdinal++))
+      return true;
+  }
+
+  if (checkBuiltinVectorMathArgTypes(*this, Args))
+    return true;
+
+  for (int I = 0; I < 3; ++I)
+    TheCall->setArg(I, Args[I]);
+
+  TheCall->setType(Args[0]->getType());
+  return false;
+}
+
+bool Sema::PrepareBuiltinReduceMathOneArgCall(CallExpr *TheCall) {
+  if (checkArgCount(TheCall, 1))
+    return true;
+
+  ExprResult A = UsualUnaryConversions(TheCall->getArg(0));
+  if (A.isInvalid())
+    return true;
+
+  TheCall->setArg(0, A.get());
+  return false;
+}
+
+bool Sema::BuiltinNonDeterministicValue(CallExpr *TheCall) {
+  if (checkArgCount(TheCall, 1))
+    return true;
+
+  ExprResult Arg = TheCall->getArg(0);
+  QualType TyArg = Arg.get()->getType();
+
+  if (!TyArg->isBuiltinType() && !TyArg->isVectorType())
+    return Diag(TheCall->getArg(0)->getBeginLoc(),
+                diag::err_builtin_invalid_arg_type)
+           << 1 << /* vector */ 2 << /* integer */ 1 << /* fp */ 1 << TyArg;
+
+  TheCall->setType(TyArg);
+  return false;
+}
+
+ExprResult Sema::BuiltinMatrixTranspose(CallExpr *TheCall,
+                                        ExprResult CallResult) {
+  if (checkArgCount(TheCall, 1))
+    return ExprError();
+
+  ExprResult MatrixArg = DefaultLvalueConversion(TheCall->getArg(0));
+  if (MatrixArg.isInvalid())
+    return MatrixArg;
+  Expr *Matrix = MatrixArg.get();
+
+  auto *MType = Matrix->getType()->getAs<ConstantMatrixType>();
+  if (!MType) {
+    Diag(Matrix->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+        << 1 << /* matrix */ 3 << /* no int */ 0 << /* no fp */ 0
+        << Matrix->getType();
+    return ExprError();
+  }
+
+  // Create returned matrix type by swapping rows and columns of the argument
+  // matrix type.
+  QualType ResultType = Context.getConstantMatrixType(
+      MType->getElementType(), MType->getNumColumns(), MType->getNumRows());
+
+  // Change the return type to the type of the returned matrix.
+  TheCall->setType(ResultType);
+
+  // Update call argument to use the possibly converted matrix argument.
+  TheCall->setArg(0, Matrix);
+  return CallResult;
+}
+
+// Get and verify the matrix dimensions.
+static std::optional<unsigned>
+getAndVerifyMatrixDimension(Expr *Expr, StringRef Name, Sema &S) {
+  std::optional<llvm::APSInt> Value = Expr->getIntegerConstantExpr(S.Context);
+  if (!Value) {
+    S.Diag(Expr->getBeginLoc(), diag::err_builtin_matrix_scalar_unsigned_arg)
+        << Name;
+    return {};
+  }
+  uint64_t Dim = Value->getZExtValue();
+  if (Dim == 0 || Dim > S.Context.getLangOpts().MaxMatrixDimension) {
+    S.Diag(Expr->getBeginLoc(), diag::err_builtin_matrix_invalid_dimension)
+        << Name << S.Context.getLangOpts().MaxMatrixDimension;
+    return {};
+  }
+  return Dim;
+}
+
+ExprResult Sema::BuiltinMatrixColumnMajorLoad(CallExpr *TheCall,
+                                              ExprResult CallResult) {
+  if (!getLangOpts().MatrixTypes) {
+    Diag(TheCall->getBeginLoc(), diag::err_builtin_matrix_disabled);
+    return ExprError();
+  }
+
+  if (getLangOpts().getDefaultMatrixMemoryLayout() !=
+      LangOptions::MatrixMemoryLayout::MatrixColMajor) {
+    Diag(TheCall->getBeginLoc(), diag::err_builtin_matrix_major_order_disabled)
+        << /*column*/ 1 << /*load*/ 0;
+    return ExprError();
+  }
+
+  if (checkArgCount(TheCall, 4))
+    return ExprError();
+
+  unsigned PtrArgIdx = 0;
+  Expr *PtrExpr = TheCall->getArg(PtrArgIdx);
+  Expr *RowsExpr = TheCall->getArg(1);
+  Expr *ColumnsExpr = TheCall->getArg(2);
+  Expr *StrideExpr = TheCall->getArg(3);
+
+  bool ArgError = false;
+
+  // Check pointer argument.
+  {
+    ExprResult PtrConv = DefaultFunctionArrayLvalueConversion(PtrExpr);
+    if (PtrConv.isInvalid())
+      return PtrConv;
+    PtrExpr = PtrConv.get();
+    TheCall->setArg(0, PtrExpr);
+    if (PtrExpr->isTypeDependent()) {
+      TheCall->setType(Context.DependentTy);
+      return TheCall;
+    }
+  }
+
+  auto *PtrTy = PtrExpr->getType()->getAs<PointerType>();
+  QualType ElementTy;
+  if (!PtrTy) {
+    Diag(PtrExpr->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+        << PtrArgIdx + 1 << 0 << /* pointer to element ty */ 5 << /* no fp */ 0
+        << PtrExpr->getType();
+    ArgError = true;
+  } else {
+    ElementTy = PtrTy->getPointeeType().getUnqualifiedType();
+
+    if (!ConstantMatrixType::isValidElementType(ElementTy, getLangOpts())) {
+      Diag(PtrExpr->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+          << PtrArgIdx + 1 << 0 << /* pointer to element ty */ 5
+          << /* no fp */ 0 << PtrExpr->getType();
+      ArgError = true;
+    }
+  }
+
+  // Apply default Lvalue conversions and convert the expression to size_t.
+  auto ApplyArgumentConversions = [this](Expr *E) {
+    ExprResult Conv = DefaultLvalueConversion(E);
+    if (Conv.isInvalid())
+      return Conv;
+
+    return tryConvertExprToType(Conv.get(), Context.getSizeType());
+  };
+
+  // Apply conversion to row and column expressions.
+  ExprResult RowsConv = ApplyArgumentConversions(RowsExpr);
+  if (!RowsConv.isInvalid()) {
+    RowsExpr = RowsConv.get();
+    TheCall->setArg(1, RowsExpr);
+  } else
+    RowsExpr = nullptr;
+
+  ExprResult ColumnsConv = ApplyArgumentConversions(ColumnsExpr);
+  if (!ColumnsConv.isInvalid()) {
+    ColumnsExpr = ColumnsConv.get();
+    TheCall->setArg(2, ColumnsExpr);
+  } else
+    ColumnsExpr = nullptr;
+
+  // If any part of the result matrix type is still pending, just use
+  // Context.DependentTy, until all parts are resolved.
+  if ((RowsExpr && RowsExpr->isTypeDependent()) ||
+      (ColumnsExpr && ColumnsExpr->isTypeDependent())) {
+    TheCall->setType(Context.DependentTy);
+    return CallResult;
+  }
+
+  // Check row and column dimensions.
+  std::optional<unsigned> MaybeRows;
+  if (RowsExpr)
+    MaybeRows = getAndVerifyMatrixDimension(RowsExpr, "row", *this);
+
+  std::optional<unsigned> MaybeColumns;
+  if (ColumnsExpr)
+    MaybeColumns = getAndVerifyMatrixDimension(ColumnsExpr, "column", *this);
+
+  // Check stride argument.
+  ExprResult StrideConv = ApplyArgumentConversions(StrideExpr);
+  if (StrideConv.isInvalid())
+    return ExprError();
+  StrideExpr = StrideConv.get();
+  TheCall->setArg(3, StrideExpr);
+
+  if (MaybeRows) {
+    if (std::optional<llvm::APSInt> Value =
+            StrideExpr->getIntegerConstantExpr(Context)) {
+      uint64_t Stride = Value->getZExtValue();
+      if (Stride < *MaybeRows) {
+        Diag(StrideExpr->getBeginLoc(),
+             diag::err_builtin_matrix_stride_too_small);
+        ArgError = true;
+      }
+    }
+  }
+
+  if (ArgError || !MaybeRows || !MaybeColumns)
+    return ExprError();
+
+  TheCall->setType(
+      Context.getConstantMatrixType(ElementTy, *MaybeRows, *MaybeColumns));
+  return CallResult;
+}
+
+ExprResult Sema::BuiltinMatrixColumnMajorStore(CallExpr *TheCall,
+                                               ExprResult CallResult) {
+  if (!getLangOpts().MatrixTypes) {
+    Diag(TheCall->getBeginLoc(), diag::err_builtin_matrix_disabled);
+    return ExprError();
+  }
+
+  if (getLangOpts().getDefaultMatrixMemoryLayout() !=
+      LangOptions::MatrixMemoryLayout::MatrixColMajor) {
+    Diag(TheCall->getBeginLoc(), diag::err_builtin_matrix_major_order_disabled)
+        << /*column*/ 1 << /*store*/ 1;
+    return ExprError();
+  }
+
+  if (checkArgCount(TheCall, 3))
+    return ExprError();
+
+  unsigned PtrArgIdx = 1;
+  Expr *MatrixExpr = TheCall->getArg(0);
+  Expr *PtrExpr = TheCall->getArg(PtrArgIdx);
+  Expr *StrideExpr = TheCall->getArg(2);
+
+  bool ArgError = false;
+
+  {
+    ExprResult MatrixConv = DefaultLvalueConversion(MatrixExpr);
+    if (MatrixConv.isInvalid())
+      return MatrixConv;
+    MatrixExpr = MatrixConv.get();
+    TheCall->setArg(0, MatrixExpr);
+  }
+  if (MatrixExpr->isTypeDependent()) {
+    TheCall->setType(Context.DependentTy);
+    return TheCall;
+  }
+
+  auto *MatrixTy = MatrixExpr->getType()->getAs<ConstantMatrixType>();
+  if (!MatrixTy) {
+    Diag(MatrixExpr->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+        << 1 << /* matrix ty */ 3 << 0 << 0 << MatrixExpr->getType();
+    ArgError = true;
+  }
+
+  {
+    ExprResult PtrConv = DefaultFunctionArrayLvalueConversion(PtrExpr);
+    if (PtrConv.isInvalid())
+      return PtrConv;
+    PtrExpr = PtrConv.get();
+    TheCall->setArg(1, PtrExpr);
+    if (PtrExpr->isTypeDependent()) {
+      TheCall->setType(Context.DependentTy);
+      return TheCall;
+    }
+  }
+
+  // Check pointer argument.
+  auto *PtrTy = PtrExpr->getType()->getAs<PointerType>();
+  if (!PtrTy) {
+    Diag(PtrExpr->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+        << PtrArgIdx + 1 << 0 << /* pointer to element ty */ 5 << 0
+        << PtrExpr->getType();
+    ArgError = true;
+  } else {
+    QualType ElementTy = PtrTy->getPointeeType();
+    if (ElementTy.isConstQualified()) {
+      Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_store_to_const);
+      ArgError = true;
+    }
+    ElementTy = ElementTy.getUnqualifiedType().getCanonicalType();
+    if (MatrixTy &&
+        !Context.hasSameType(ElementTy, MatrixTy->getElementType())) {
+      Diag(PtrExpr->getBeginLoc(),
+           diag::err_builtin_matrix_pointer_arg_mismatch)
+          << ElementTy << MatrixTy->getElementType();
+      ArgError = true;
+    }
+  }
+
+  // Apply default Lvalue conversions and convert the stride expression to
+  // size_t.
+  {
+    ExprResult StrideConv = DefaultLvalueConversion(StrideExpr);
+    if (StrideConv.isInvalid())
+      return StrideConv;
+
+    StrideConv = tryConvertExprToType(StrideConv.get(), Context.getSizeType());
+    if (StrideConv.isInvalid())
+      return StrideConv;
+    StrideExpr = StrideConv.get();
+    TheCall->setArg(2, StrideExpr);
+  }
+
+  // Check stride argument.
+  if (MatrixTy) {
+    if (std::optional<llvm::APSInt> Value =
+            StrideExpr->getIntegerConstantExpr(Context)) {
+      uint64_t Stride = Value->getZExtValue();
+      if (Stride < MatrixTy->getNumRows()) {
+        Diag(StrideExpr->getBeginLoc(),
+             diag::err_builtin_matrix_stride_too_small);
+        ArgError = true;
+      }
+    }
+  }
+
+  if (ArgError)
+    return ExprError();
+
+  return CallResult;
+}
+
+void Sema::CheckTCBEnforcement(const SourceLocation CallExprLoc,
+                               const NamedDecl *Callee) {
+  // This warning does not make sense in code that has no runtime behavior.
+  if (isUnevaluatedContext())
+    return;
+
+  const NamedDecl *Caller = getCurFunctionOrMethodDecl();
+
+  if (!Caller || !Caller->hasAttr<EnforceTCBAttr>())
+    return;
+
+  // Search through the enforce_tcb and enforce_tcb_leaf attributes to find
+  // all TCBs the callee is a part of.
+  llvm::StringSet<> CalleeTCBs;
+  for (const auto *A : Callee->specific_attrs<EnforceTCBAttr>())
+    CalleeTCBs.insert(A->getTCBName());
+  for (const auto *A : Callee->specific_attrs<EnforceTCBLeafAttr>())
+    CalleeTCBs.insert(A->getTCBName());
+
+  // Go through the TCBs the caller is a part of and emit warnings if Caller
+  // is in a TCB that the Callee is not.
+  for (const auto *A : Caller->specific_attrs<EnforceTCBAttr>()) {
+    StringRef CallerTCB = A->getTCBName();
+    if (CalleeTCBs.count(CallerTCB) == 0) {
+      this->Diag(CallExprLoc, diag::warn_tcb_enforcement_violation)
+          << Callee << CallerTCB;
+    }
+  }
+}
diff --git a/clang/test/SemaCXX/warn-unsequenced.cpp b/clang/test/SemaCXX/warn-unsequenced.cpp
index 73b1e3718b211..5b040bb1bae9f 100644
--- a/clang/test/SemaCXX/warn-unsequenced.cpp
+++ b/clang/test/SemaCXX/warn-unsequenced.cpp
@@ -1,843 +1,846 @@
-// RUN: %clang_cc1 -fsyntax-only -verify=cxx11 -std=c++11 -Wno-unused -Wno-uninitialized \
-// RUN:            -Wunsequenced -Wno-c++17-extensions -Wno-c++14-extensions %s
-// RUN: %clang_cc1 -fsyntax-only -verify=cxx17 -std=c++17 -Wno-unused -Wno-uninitialized \
-// RUN:            -Wunsequenced -Wno-c++17-extensions -Wno-c++14-extensions %s
-
-int f(int, int = 0);
-int g1();
-int g2(int);
-
-struct A {
-  int x, y;
-};
-struct S {
-  S(int, int);
-  int n;
-};
-
-void test() {
-  int a;
-  int xs[10];
-  ++a = 0; // ok
-  a + ++a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-           // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
-  a = ++a; // ok
-  a + a++; // cxx11-warning {{unsequenced modification and access to 'a'}}
-           // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
-  a = a++; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-  ++ ++a; // ok
-  (a++, a++); // ok
-  ++a + ++a; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-             // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
-  a++ + a++; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-             // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
-  (a++, a) = 0; // ok, increment is sequenced before value computation of LHS
-  a = xs[++a]; // ok
-  a = xs[a++]; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-  (a ? xs[0] : xs[1]) = ++a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-  a = (++a, ++a); // ok
-  a = (a++, ++a); // ok
-  a = (a++, a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-  f(a, a); // ok
-  f(a = 0, a); // cxx11-warning {{unsequenced modification and access to 'a'}}
-               // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
-  f(a, a += 0); // cxx11-warning {{unsequenced modification and access to 'a'}}
-                // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
-  f(a = 0, a = 0); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                   // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
-  a = f(++a); // ok
-  a = f(a++); // ok
-  a = f(++a, a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                   // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
-
-  // Compound assignment "A OP= B" is equivalent to "A = A OP B" except that A
-  // is evaluated only once.
-  (++a, a) = 1; // ok
-  (++a, a) += 1; // ok
-  a = ++a; // ok
-  a += ++a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-
-  A agg1 = { a++, a++ }; // ok
-  A agg2 = { a++ + a, a++ }; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                             // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
-
-  S str1(a++, a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                    // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
-  S str2 = { a++, a++ }; // ok
-  S str3 = { a++ + a, a++ }; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                             // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
-
-  struct Z { A a; S s; } z = { { ++a, ++a }, { ++a, ++a } }; // ok
-  a = S { ++a, a++ }.n; // ok
-  A { ++a, a++ }.x; // ok
-  a = A { ++a, a++ }.x; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-  A { ++a, a++ }.x + A { ++a, a++ }.y; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                                       // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
-
-  (xs[2] && (a = 0)) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                          // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
-  (0 && (a = 0)) + a; // ok
-  (1 && (a = 0)) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                      // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
-
-  (xs[3] || (a = 0)) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                          // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
-  (0 || (a = 0)) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                      // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
-  (1 || (a = 0)) + a; // ok
-
-  (xs[4] ? a : ++a) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                         // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
-  (0 ? a : ++a) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                     // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
-  (1 ? a : ++a) + a; // ok
-  (0 ? a : a++) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                     // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
-  (1 ? a : a++) + a; // ok
-  (xs[5] ? ++a : ++a) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                           // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
-
-  (++a, xs[6] ? ++a : 0) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                              // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
-
-  // Here, the read of the fourth 'a' might happen before or after the write to
-  // the second 'a'.
-  a += (a++, a) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                     // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
-
-  a = a++ && a; // ok
-
-  A *q = &agg1;
-  (q = &agg2)->y = q->x; // cxx11-warning {{unsequenced modification and access to 'q'}}
-
-  // This has undefined behavior if a == 0; otherwise, the side-effect of the
-  // increment is sequenced before the value computation of 'f(a, a)', which is
-  // sequenced before the value computation of the '&&', which is sequenced
-  // before the assignment. We treat the sequencing in '&&' as being
-  // unconditional.
-  a = a++ && f(a, a);
-
-  // This has undefined behavior if a != 0.
-  (a && a++) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-                  // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
-
-  // FIXME: Don't warn here.
-  (xs[7] && ++a) * (!xs[7] && ++a); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                                    // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
-
-  xs[0] = (a = 1, a); // ok
-  (a -= 128) &= 128; // ok
-  ++a += 1; // ok
-
-  xs[8] ? ++a + a++ : 0; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                         // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
-  xs[8] ? 0 : ++a + a++; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                         // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
-  xs[8] ? ++a : a++; // no-warning
-  xs[8] ? a+=1 : a+= 2; // no-warning
-  (xs[8] ? a+=1 : a+= 2) = a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-  (xs[8] ? a+=1 : a) = a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-  (xs[8] ? a : a+= 2) = a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-  a = (xs[8] ? a+=1 : a+= 2); // no-warning
-  a += (xs[8] ? a+=1 : a+= 2); // cxx11-warning {{unsequenced modification and access to 'a'}}
-
-  (false ? a+=1 : a) = a; // no-warning
-  (true ? a+=1 : a) = a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-  (false ? a : a+=2) = a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-  (true ? a : a+=2) = a; // no-warning
-
-  xs[8] && (++a + a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                        // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
-  xs[8] || (++a + a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                        // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
-
-  ((a++, false) || (a++, false)); // no-warning PR39779
-  ((a++, true) && (a++, true)); // no-warning PR39779
-
-  int i,j;
-  (i = g1(), false) || (j = g2(i)); // no-warning PR22197
-  (i = g1(), true) && (j = g2(i)); // no-warning PR22197
-
-  (a++, false) || (a++, false) || (a++, false) || (a++, false); // no-warning
-  (a++, true) || (a++, true) || (a++, true) || (a++, true); // no-warning
-  a = ((a++, false) || (a++, false) || (a++, false) || (a++, false)); // no-warning
-  a = ((a++, true) && (a++, true) && (a++, true) && (a++, true)); // no-warning
-  a = ((a++, false) || (a++, false) || (a++, false) || a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-  a = ((a++, true) && (a++, true) && (a++, true) && a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-  a = ((a++, false) || (a++, false) || (a++, false) || (a + a, false)); // no-warning
-  a = ((a++, true) && (a++, true) && (a++, true) && (a + a, true)); // no-warning
-
-  a = (false && a++); // no-warning
-  a = (true && a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-  a = (true && ++a); // no-warning
-  a = (true || a++); // no-warning
-  a = (false || a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-  a = (false || ++a); // no-warning
-
-  (a++) | (a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                 // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
-  (a++) & (a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                 // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
-  (a++) ^ (a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                 // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
-
-  (__builtin_classify_type(++a) ? 1 : 0) + ++a; // ok
-  (__builtin_constant_p(++a) ? 1 : 0) + ++a; // ok
-  (__builtin_object_size(&(++a, a), 0) ? 1 : 0) + ++a; // ok
-  (__builtin_expect(++a, 0) ? 1 : 0) + ++a; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-                                            // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
-
-
-  int *p = xs;
-  a = *(a++, p); // no-warning
-  p[(long long unsigned)(p = 0)]; // cxx11-warning {{unsequenced modification and access to 'p'}}
-  (i++, xs)[i++]; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
-  (++i, xs)[++i]; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
-  (i, xs)[++i + ++i]; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
-                      // cxx17-warning at -1 {{multiple unsequenced modifications to 'i'}}
-  p++[p == xs]; // cxx11-warning {{unsequenced modification and access to 'p'}}
-  ++p[p++ == xs]; // cxx11-warning {{unsequenced modification and access to 'p'}}
-
-  struct S { int x; } s, *ps = &s;
-  int (S::*PtrMem);
-  (PtrMem = &S::x ,s).*(PtrMem); // cxx11-warning {{unsequenced modification and access to 'PtrMem'}}
-  (PtrMem = &S::x ,s).*(PtrMem = &S::x); // cxx11-warning {{multiple unsequenced modifications to 'PtrMem'}}
-  (PtrMem = &S::x ,ps)->*(PtrMem); // cxx11-warning {{unsequenced modification and access to 'PtrMem'}}
-  (PtrMem = &S::x ,ps)->*(PtrMem = &S::x); // cxx11-warning {{multiple unsequenced modifications to 'PtrMem'}}
-  (PtrMem = nullptr) == (PtrMem = nullptr); // cxx11-warning {{multiple unsequenced modifications to 'PtrMem'}}
-                                            // cxx17-warning at -1 {{multiple unsequenced modifications to 'PtrMem'}}
-  (PtrMem = nullptr) == PtrMem; // cxx11-warning {{unsequenced modification and access to 'PtrMem'}}
-                                // cxx17-warning at -1 {{unsequenced modification and access to 'PtrMem'}}
-
-  i++ << i++; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
-  ++i << ++i; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
-  i++ << i; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i << i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i++ >> i++; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
-  ++i >> ++i; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
-  i++ >> i; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i >> i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  (i++ << i) + i; // cxx11-warning {{unsequenced modification and access to 'i'}}
-                  // cxx17-warning at -1 {{unsequenced modification and access to 'i'}}
-  (i++ << i) << i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
-
-  ++i = i++; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
-  i = i+= 1; // no-warning
-  i = i++ + ++i; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
-                 // cxx17-warning at -1 {{multiple unsequenced modifications to 'i'}}
-  ++i += ++i; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
-  ++i += i++; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
-  (i++, i) += ++i; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
-  (i++, i) += i++; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
-  i += i+= 1; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i += i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i += ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i -= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i -= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i *= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i *= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i /= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i /= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i %= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i %= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i ^= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i ^= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i |= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i |= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i &= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i &= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i <<= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i <<= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i >>= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  i >>= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
-
-  p[i++] = i; // cxx11-warning {{unsequenced modification and access to 'i'}}
-  p[i++] = (i = 42); // cxx11-warning {{multiple unsequenced modifications to 'i'}}
-  p++[i++] = (i = p ? i++ : i++); // cxx11-warning {{unsequenced modification and access to 'p'}}
-                                  // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-
-  (i++, f)(i++, 42); // cxx11-warning {{multiple unsequenced modifications to 'i'}}
-  (i++ + i++, f)(42, 42); // cxx11-warning {{multiple unsequenced modifications to 'i'}}
-                          // cxx17-warning at -1 {{multiple unsequenced modifications to 'i'}}
-  int (*pf)(int, int);
-  (pf = f)(pf != nullptr, pf != nullptr); // cxx11-warning {{unsequenced modification and access to 'pf'}}
-  pf((pf = f) != nullptr, 42); // cxx11-warning {{unsequenced modification and access to 'pf'}}
-  f((pf = f, 42), (pf = f, 42)); // cxx11-warning {{multiple unsequenced modifications to 'pf'}}
-                                 // cxx17-warning at -1 {{multiple unsequenced modifications to 'pf'}}
-  pf((pf = f) != nullptr, pf == nullptr); // cxx11-warning {{unsequenced modification and access to 'pf'}}
-                                          // cxx17-warning at -1 {{unsequenced modification and access to 'pf'}}
-}
-
-namespace PR20819 {
-  struct foo { void bar(int); };
-  foo get_foo(int);
-
-  void g() {
-    int a = 0;
-    get_foo(a).bar(a++);  // cxx11-warning {{unsequenced modification and access to 'a'}}
-  }
-}
-
-namespace overloaded_operators {
-  struct E {
-    E &operator=(E &);
-    E operator()(E);
-    E operator()(E, E);
-    E operator[](E);
-  } e;
-  // Binary operators with unsequenced operands.
-  E operator+(E,E);
-  E operator-(E,E);
-  E operator*(E,E);
-  E operator/(E,E);
-  E operator%(E,E);
-  E operator^(E,E);
-  E operator&(E,E);
-  E operator|(E,E);
-
-  E operator<(E,E);
-  E operator>(E,E);
-  E operator==(E,E);
-  E operator!=(E,E);
-  E operator>=(E,E);
-  E operator<=(E,E);
-
-  // Binary operators where the RHS is sequenced before the LHS in C++17.
-  E operator+=(E,E);
-  E operator-=(E,E);
-  E operator*=(E,E);
-  E operator/=(E,E);
-  E operator%=(E,E);
-  E operator^=(E,E);
-  E operator&=(E,E);
-  E operator|=(E,E);
-  E operator<<=(E,E);
-  E operator>>=(E,E);
-
-  // Binary operators where the LHS is sequenced before the RHS in C++17.
-  E operator<<(E,E);
-  E operator>>(E,E);
-  E operator&&(E,E);
-  E operator||(E,E);
-  E operator,(E,E);
-  E operator->*(E,E);
-
-  void test() {
-    int i = 0;
-    // Binary operators with unsequenced operands.
-    ((void)i++,e) + ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) - ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) * ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) / ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) % ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) ^ ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) & ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) | ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
-
-    ((void)i++,e) < ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) > ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) == ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) != ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) <= ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) >= ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
-
-    // Binary operators where the RHS is sequenced before the LHS in C++17.
-    ((void)i++,e) = ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) += ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) -= ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) *= ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) /= ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) %= ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) ^= ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) &= ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) |= ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) <<= ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) >>= ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-
-    operator+=(((void)i++,e), ((void)i++,e));
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
-
-    // Binary operators where the LHS is sequenced before the RHS in C++17.
-    ((void)i++,e) << ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) >> ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) || ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) && ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e) , ((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    ((void)i++,e)->*((void)i++,e);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-
-    operator<<(((void)i++,e), ((void)i++,e));
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
-
-    ((void)i++,e)[((void)i++,e)];
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-
-    ((void)i++,e)(((void)i++,e));
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    e(((void)i++,e), ((void)i++,e));
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
-
-    ((void)i++,e).operator()(((void)i++,e));
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-
-  }
-}
-
-namespace PR35340 {
-  struct S {};
-  S &operator<<(S &, int);
-
-  void test() {
-    S s;
-    int i = 0;
-    s << i++ << i++;
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-
-    operator<<(operator<<(s, i++), i++);
-    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
-    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
-  }
-}
-
-namespace members {
-
-struct S1 {
-  unsigned bf1 : 2;
-  unsigned bf2 : 2;
-  unsigned a;
-  unsigned b;
-  static unsigned x;
-  void member_f(S1 &s);
-};
-
-void S1::member_f(S1 &s) {
-  ++a + ++a; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
-             // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
-  a + ++a; // cxx11-warning {{unsequenced modification and access to 'a'}}
-           // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
-  ++a + ++b; // no-warning
-  a + ++b; // no-warning
-
-  // TODO: Warn here.
-  ++s.a + ++s.a; // no-warning TODO {{multiple unsequenced modifications to}}
-  s.a + ++s.a; // no-warning TODO {{unsequenced modification and access to}}
-  ++s.a + ++s.b; // no-warning
-  s.a + ++s.b; // no-warning
-
-  ++a + ++s.a; // no-warning
-  a + ++s.a; // no-warning
-  ++a + ++s.b; // no-warning
-  a + ++s.b; // no-warning
-
-  // TODO Warn here for bit-fields in the same memory location.
-  ++bf1 + ++bf1; // cxx11-warning {{multiple unsequenced modifications to 'bf1'}}
-                 // cxx17-warning at -1 {{multiple unsequenced modifications to 'bf1'}}
-  bf1 + ++bf1; // cxx11-warning {{unsequenced modification and access to 'bf1'}}
-               // cxx17-warning at -1 {{unsequenced modification and access to 'bf1'}}
-  ++bf1 + ++bf2; // no-warning TODO {{multiple unsequenced modifications to}}
-  bf1 + ++bf2; // no-warning TODO {{unsequenced modification and access to}}
-
-  // TODO Warn here for bit-fields in the same memory location.
-  ++s.bf1 + ++s.bf1; // no-warning TODO {{multiple unsequenced modifications to}}
-  s.bf1 + ++s.bf1; // no-warning TODO {{unsequenced modification and access to}}
-  ++s.bf1 + ++s.bf2; // no-warning TODO {{multiple unsequenced modifications to}}
-  s.bf1 + ++s.bf2; // no-warning TODO {{unsequenced modification and access to}}
-
-  ++bf1 + ++s.bf1; // no-warning
-  bf1 + ++s.bf1; // no-warning
-  ++bf1 + ++s.bf2; // no-warning
-  bf1 + ++s.bf2; // no-warning
-
-  struct Der : S1 {};
-  Der d;
-  Der &d_ref = d;
-  S1 &s1_ref = d_ref;
-
-  ++s1_ref.a + ++d_ref.a; // no-warning TODO {{multiple unsequenced modifications to member 'a' of 'd'}}
-  ++s1_ref.a + d_ref.a; // no-warning TODO {{unsequenced modification and access to member 'a' of 'd'}}
-  ++s1_ref.a + ++d_ref.b; // no-warning
-  ++s1_ref.a + d_ref.b; // no-warning
-
-  ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-             // cxx17-warning at -1 {{multiple unsequenced modifications to 'x'}}
-  ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-           // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
-  ++s.x + x; // no-warning TODO {{unsequenced modification and access to static member 'x' of 'S1'}}
-  ++this->x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-                 // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
-  ++d_ref.x + ++S1::x; // no-warning TODO {{unsequenced modification and access to static member 'x' of 'S1'}}
-}
-
-struct S2 {
-  union { unsigned x, y; };
-  void f2();
-};
-
-void S2::f2() {
-  ++x + ++x; // no-warning TODO {{multiple unsequenced modifications to}}
-  x + ++x; // no-warning TODO {{unsequenced modification and access to}}
-  ++x + ++y; // no-warning
-  x + ++y; // no-warning
-}
-
-void f2(S2 &s) {
-  ++s.x + ++s.x; // no-warning TODO {{multiple unsequenced modifications to}}
-  s.x + ++s.x; // no-warning TODO {{unsequenced modification and access to}}
-  ++s.x + ++s.y; // no-warning
-  s.x + ++s.y; // no-warning
-}
-
-struct S3 {
-  union {
-    union {
-      unsigned x;
-    };
-  };
-  unsigned y;
-  void f3();
-};
-
-void S3::f3() {
-  ++x + ++x; // no-warning TODO {{multiple unsequenced modifications to}}
-  x + ++x; // no-warning TODO {{unsequenced modification and access to}}
-  ++x + ++y; // no-warning
-  x + ++y; // no-warning
-}
-
-void f3(S3 &s) {
-  ++s.x + ++s.x; // no-warning TODO {{multiple unsequenced modifications to}}
-  s.x + ++s.x; // no-warning TODO {{unsequenced modification and access to}}
-  ++s.x + ++s.y; // no-warning
-  s.x + ++s.y; // no-warning
-}
-
-struct S4 : S3 {
-  unsigned y;
-  void f4();
-};
-
-void S4::f4() {
-  ++x + ++x; // no-warning TODO {{multiple unsequenced modifications to}}
-  x + ++x; // no-warning TODO {{unsequenced modification and access to}}
-  ++x + ++y; // no-warning
-  x + ++y; // no-warning
-  ++S3::y + ++y; // no-warning
-  S3::y + ++y; // no-warning
-}
-
-void f4(S4 &s) {
-  ++s.x + ++s.x; // no-warning TODO {{multiple unsequenced modifications to}}
-  s.x + ++s.x; // no-warning TODO {{unsequenced modification and access to}}
-  ++s.x + ++s.y; // no-warning
-  s.x + ++s.y; // no-warning
-  ++s.S3::y + ++s.y; // no-warning
-  s.S3::y + ++s.y; // no-warning
-}
-
-static union {
-  unsigned Ux;
-  unsigned Uy;
-};
-
-void f5() {
-  ++Ux + ++Ux; // no-warning TODO {{multiple unsequenced modifications to}}
-  Ux + ++Ux; // no-warning TODO {{unsequenced modification and access to}}
-  ++Ux + ++Uy; // no-warning
-  Ux + ++Uy; // no-warning
-}
-
-void f6() {
-  struct S { unsigned x, y; } s;
-  ++s.x + ++s.x; // no-warning TODO {{multiple unsequenced modifications to}}
-  s.x + ++s.x; // no-warning TODO {{unsequenced modification and access to}}
-  ++s.x + ++s.y; // no-warning
-  s.x + ++s.y; // no-warning
-
-  struct { unsigned x, y; } t;
-  ++t.x + ++t.x; // no-warning TODO {{multiple unsequenced modifications to}}
-  t.x + ++t.x; // no-warning TODO {{unsequenced modification and access to}}
-  ++t.x + ++t.y; // no-warning
-  t.x + ++t.y; // no-warning
-}
-
-} // namespace members
-
-namespace references {
-void reference_f() {
-  // TODO: Check that we can see through references.
-  // For now this is completely unhandled.
-  int a;
-  int xs[10];
-  int &b = a;
-  int &c = b;
-  int &ra1 = c;
-  int &ra2 = b;
-  int other;
-
-  ++ra1 + ++ra2; // no-warning TODO {{multiple unsequenced modifications to}}
-  ra1 + ++ra2; // no-warning TODO {{unsequenced modification and access to}}
-  ++ra1 + ++other; // no-warning
-  ra1 + ++other; // no-warning
-
-  // Make sure we handle reference cycles.
-  int &ref_cycle = ref_cycle;
-  ++ref_cycle + ++ref_cycle; // cxx11-warning {{multiple unsequenced modifications to 'ref_cycle'}}
-                             // cxx17-warning at -1 {{multiple unsequenced modifications to 'ref_cycle'}}
-  ref_cycle + ++ref_cycle; // cxx11-warning {{unsequenced modification and access to 'ref_cycle'}}
-                           // cxx17-warning at -1 {{unsequenced modification and access to 'ref_cycle'}}
-}
-} // namespace references
-
-namespace std {
-  using size_t = decltype(sizeof(0));
-  template<typename> struct tuple_size;
-  template<size_t, typename> struct tuple_element { using type = int; };
-}
-namespace bindings {
-
-  struct A { int x, y; };
-  typedef int B[2];
-  struct C { template<int> int get(); };
-  struct D : A {};
-
-} // namespace bindings
-template<> struct std::tuple_size<bindings::C> { enum { value = 2 }; };
-namespace bindings {
-void testa() {
-  A a;
-  {
-    auto [x, y] = a;
-    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // cxx17-warning at -1 {{multiple unsequenced modifications to 'x'}}
-    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-             // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
-    ++x + ++y; // no-warning
-    ++x + y; // no-warning
-    ++x + ++a.x; // no-warning
-    ++x + a.x; // no-warning
-  }
-  {
-    auto &[x, y] = a;
-    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // cxx17-warning at -1 {{multiple unsequenced modifications to 'x'}}
-    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-             // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
-    ++x + ++y; // no-warning
-    ++x + y; // no-warning
-    ++x + ++a.x; // no-warning TODO
-    ++x + a.x; // no-warning TODO
-  }
-}
-void testb() {
-  B b;
-  {
-    auto [x, y] = b;
-    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // cxx17-warning at -1 {{multiple unsequenced modifications to 'x'}}
-    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-             // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
-    ++x + ++y; // no-warning
-    ++x + y; // no-warning
-    ++x + ++b[0]; // no-warning
-    ++x + b[0]; // no-warning
-  }
-  {
-    auto &[x, y] = b;
-    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // cxx17-warning at -1 {{multiple unsequenced modifications to 'x'}}
-    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-             // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
-    ++x + ++y; // no-warning
-    ++x + y; // no-warning
-    ++x + ++b[0]; // no-warning TODO
-    ++x + b[0]; // no-warning TODO
-  }
-}
-void testc() {
-  C c;
-  {
-    auto [x, y] = c;
-    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // cxx17-warning at -1 {{multiple unsequenced modifications to 'x'}}
-    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-             // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
-    ++x + ++y; // no-warning
-    ++x + y; // no-warning
-  }
-  {
-    auto &[x, y] = c;
-    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // cxx17-warning at -1 {{multiple unsequenced modifications to 'x'}}
-    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-             // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
-    ++x + ++y; // no-warning
-    ++x + y; // no-warning
-  }
-}
-void testd() {
-  D d;
-  {
-    auto [x, y] = d;
-    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // cxx17-warning at -1 {{multiple unsequenced modifications to 'x'}}
-    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-             // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
-    ++x + ++y; // no-warning
-    ++x + y; // no-warning
-    ++x + ++d.x; // no-warning
-    ++x + d.x; // no-warning
-  }
-  {
-    auto &[x, y] = d;
-    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
-               // cxx17-warning at -1 {{multiple unsequenced modifications to 'x'}}
-    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
-             // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
-    ++x + ++y; // no-warning
-    ++x + y; // no-warning
-    ++x + ++d.x; // no-warning TODO
-    ++x + d.x; // no-warning TODO
-  }
-}
-} // namespace bindings
-
-namespace templates {
-
-template <typename T>
-struct Bar {
-  T get() { return 0; }
-};
-
-template <typename X>
-struct Foo {
-  int Run();
-  Bar<int> bar;
-};
-
-enum E {e1, e2};
-bool operator&&(E, E);
-
-void foo(int, int);
-
-template <typename X>
-int Foo<X>::Run() {
-  char num = 0;
-
-  // Before instantiation, Clang may consider the builtin operator here as
-  // unresolved function calls, and treat the arguments as unordered when
-  // the builtin operator evaluatation is well-ordered.  Waiting until
-  // instantiation to check these expressions will prevent false positives.
-  if ((num = bar.get()) < 5 && num < 10) { }
-  if ((num = bar.get()) < 5 || num < 10) { }
-  if (static_cast<E>((num = bar.get()) < 5) || static_cast<E>(num < 10)) { }
-
-  if (static_cast<E>((num = bar.get()) < 5) && static_cast<E>(num < 10)) { }
-  // cxx11-warning at -1 {{unsequenced modification and access to 'num'}}
-
-  foo(num++, num++);
-  // cxx11-warning at -1 {{multiple unsequenced modifications to 'num'}}
-  // cxx17-warning at -2 {{multiple unsequenced modifications to 'num'}}
-  return 1;
-}
-
-int x = Foo<int>().Run();
-// cxx11-note at -1 {{in instantiation of member function 'templates::Foo<int>::Run'}}
-// cxx17-note at -2 {{in instantiation of member function 'templates::Foo<int>::Run'}}
-
-
-template <typename T>
-int Run2() {
-  T t = static_cast<T>(0);
-  return (t = static_cast<T>(1)) && t;
-  // cxx11-warning at -1 {{unsequenced modification and access to 't'}}
-}
-
-int y = Run2<bool>();
-int z = Run2<E>();
-// cxx11-note at -1{{in instantiation of function template specialization 'templates::Run2<templates::E>' requested here}}
-
-template <typename T> int var = sizeof(T);
-void test_var() {
-  var<int>++ + var<int>++; // cxx11-warning {{multiple unsequenced modifications to 'var<int>'}}
-                           // cxx17-warning at -1 {{multiple unsequenced modifications to 'var<int>'}}
-  var<int>++ + var<int>; // cxx11-warning {{unsequenced modification and access to 'var<int>'}}
-                         // cxx17-warning at -1 {{unsequenced modification and access to 'var<int>'}}
-  int &r = var<int>;
-  r++ + var<int>++; // no-warning TODO {{multiple unsequenced modifications to 'var<int>'}}
-  r++ + var<long>++; // no-warning
-}
-
-} // namespace templates
-
-namespace muliple_read_volatile {
-  volatile int v1;
-  
-  void PositiveTest(){
-    int x = 0;
-    int y = 0;
-    x = v1 + v1;        // cxx11-warning {{unsequenced accesses to volatile qualified 'v1'}}
-                        // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
-    v1 = v1 * v1;       // cxx11-warning {{unsequenced accesses to volatile qualified 'v1'}}
-                        // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
-    x = v1 + (y++, v1); // cxx11-warning {{unsequenced accesses to volatile qualified 'v1'}}
-                        // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
-    x = v1 + v1 || y;   // cxx11-warning {{unsequenced accesses to volatile qualified 'v1'}}
-                        // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
-  }
-  
-  void NegativeTest(){
-    int x = 0;
-    int y = 0;
-    x = v1 + y;   // no-warning
-    v1 = v1 * y;  // no-warning
-    x = (v1, v1); // no-warning
-    x = v1 || v1; // no-warning
-  }
-} // namespace muliple_read_volatile
+// RUN: %clang_cc1 -fsyntax-only -verify=cxx11 -std=c++11 -Wno-unused -Wno-uninitialized \
+// RUN:            -Wunsequenced -Wno-c++17-extensions -Wno-c++14-extensions %s
+// RUN: %clang_cc1 -fsyntax-only -verify=cxx17 -std=c++17 -Wno-unused -Wno-uninitialized \
+// RUN:            -Wunsequenced -Wno-c++17-extensions -Wno-c++14-extensions %s
+
+int f(int, int = 0);
+int g1();
+int g2(int);
+
+struct A {
+  int x, y;
+};
+struct S {
+  S(int, int);
+  int n;
+};
+
+void test() {
+  int a;
+  int xs[10];
+  ++a = 0; // ok
+  a + ++a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+           // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
+  a = ++a; // ok
+  a + a++; // cxx11-warning {{unsequenced modification and access to 'a'}}
+           // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
+  a = a++; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+  ++ ++a; // ok
+  (a++, a++); // ok
+  ++a + ++a; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+             // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
+  a++ + a++; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+             // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
+  (a++, a) = 0; // ok, increment is sequenced before value computation of LHS
+  a = xs[++a]; // ok
+  a = xs[a++]; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+  (a ? xs[0] : xs[1]) = ++a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+  a = (++a, ++a); // ok
+  a = (a++, ++a); // ok
+  a = (a++, a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+  f(a, a); // ok
+  f(a = 0, a); // cxx11-warning {{unsequenced modification and access to 'a'}}
+               // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
+  f(a, a += 0); // cxx11-warning {{unsequenced modification and access to 'a'}}
+                // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
+  f(a = 0, a = 0); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+                   // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
+  a = f(++a); // ok
+  a = f(a++); // ok
+  a = f(++a, a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+                   // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
+
+  // Compound assignment "A OP= B" is equivalent to "A = A OP B" except that A
+  // is evaluated only once.
+  (++a, a) = 1; // ok
+  (++a, a) += 1; // ok
+  a = ++a; // ok
+  a += ++a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+
+  A agg1 = { a++, a++ }; // ok
+  A agg2 = { a++ + a, a++ }; // cxx11-warning {{unsequenced modification and access to 'a'}}
+                             // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
+
+  S str1(a++, a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+                    // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
+  S str2 = { a++, a++ }; // ok
+  S str3 = { a++ + a, a++ }; // cxx11-warning {{unsequenced modification and access to 'a'}}
+                             // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
+
+  struct Z { A a; S s; } z = { { ++a, ++a }, { ++a, ++a } }; // ok
+  a = S { ++a, a++ }.n; // ok
+  A { ++a, a++ }.x; // ok
+  a = A { ++a, a++ }.x; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+  A { ++a, a++ }.x + A { ++a, a++ }.y; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+                                       // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
+
+  (xs[2] && (a = 0)) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+                          // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
+  (0 && (a = 0)) + a; // ok
+  (1 && (a = 0)) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+                      // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
+
+  (xs[3] || (a = 0)) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+                          // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
+  (0 || (a = 0)) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+                      // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
+  (1 || (a = 0)) + a; // ok
+
+  (xs[4] ? a : ++a) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+                         // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
+  (0 ? a : ++a) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+                     // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
+  (1 ? a : ++a) + a; // ok
+  (0 ? a : a++) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+                     // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
+  (1 ? a : a++) + a; // ok
+  (xs[5] ? ++a : ++a) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+                           // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
+
+  (++a, xs[6] ? ++a : 0) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+                              // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
+
+  // Here, the read of the fourth 'a' might happen before or after the write to
+  // the second 'a'.
+  a += (a++, a) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+                     // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
+
+  a = a++ && a; // ok
+
+  A *q = &agg1;
+  (q = &agg2)->y = q->x; // cxx11-warning {{unsequenced modification and access to 'q'}}
+
+  // This has undefined behavior if a == 0; otherwise, the side-effect of the
+  // increment is sequenced before the value computation of 'f(a, a)', which is
+  // sequenced before the value computation of the '&&', which is sequenced
+  // before the assignment. We treat the sequencing in '&&' as being
+  // unconditional.
+  a = a++ && f(a, a);
+
+  // This has undefined behavior if a != 0.
+  (a && a++) + a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+                  // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
+
+  // FIXME: Don't warn here.
+  (xs[7] && ++a) * (!xs[7] && ++a); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+                                    // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
+
+  xs[0] = (a = 1, a); // ok
+  (a -= 128) &= 128; // ok
+  ++a += 1; // ok
+
+  xs[8] ? ++a + a++ : 0; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+                         // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
+  xs[8] ? 0 : ++a + a++; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+                         // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
+  xs[8] ? ++a : a++; // no-warning
+  xs[8] ? a+=1 : a+= 2; // no-warning
+  (xs[8] ? a+=1 : a+= 2) = a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+  (xs[8] ? a+=1 : a) = a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+  (xs[8] ? a : a+= 2) = a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+  a = (xs[8] ? a+=1 : a+= 2); // no-warning
+  a += (xs[8] ? a+=1 : a+= 2); // cxx11-warning {{unsequenced modification and access to 'a'}}
+
+  (false ? a+=1 : a) = a; // no-warning
+  (true ? a+=1 : a) = a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+  (false ? a : a+=2) = a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+  (true ? a : a+=2) = a; // no-warning
+
+  xs[8] && (++a + a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+                        // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
+  xs[8] || (++a + a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+                        // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
+
+  ((a++, false) || (a++, false)); // no-warning PR39779
+  ((a++, true) && (a++, true)); // no-warning PR39779
+
+  int i,j;
+  (i = g1(), false) || (j = g2(i)); // no-warning PR22197
+  (i = g1(), true) && (j = g2(i)); // no-warning PR22197
+
+  (a++, false) || (a++, false) || (a++, false) || (a++, false); // no-warning
+  (a++, true) || (a++, true) || (a++, true) || (a++, true); // no-warning
+  a = ((a++, false) || (a++, false) || (a++, false) || (a++, false)); // no-warning
+  a = ((a++, true) && (a++, true) && (a++, true) && (a++, true)); // no-warning
+  a = ((a++, false) || (a++, false) || (a++, false) || a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+  a = ((a++, true) && (a++, true) && (a++, true) && a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+  a = ((a++, false) || (a++, false) || (a++, false) || (a + a, false)); // no-warning
+  a = ((a++, true) && (a++, true) && (a++, true) && (a + a, true)); // no-warning
+
+  a = (false && a++); // no-warning
+  a = (true && a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+  a = (true && ++a); // no-warning
+  a = (true || a++); // no-warning
+  a = (false || a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+  a = (false || ++a); // no-warning
+
+  (a++) | (a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+                 // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
+  (a++) & (a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+                 // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
+  (a++) ^ (a++); // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+                 // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
+
+  (__builtin_classify_type(++a) ? 1 : 0) + ++a; // ok
+  (__builtin_constant_p(++a) ? 1 : 0) + ++a; // ok
+  (__builtin_object_size(&(++a, a), 0) ? 1 : 0) + ++a; // ok
+  (__builtin_expect(++a, 0) ? 1 : 0) + ++a; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+                                            // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
+
+
+  int *p = xs;
+  a = *(a++, p); // no-warning
+  p[(long long unsigned)(p = 0)]; // cxx11-warning {{unsequenced modification and access to 'p'}}
+  (i++, xs)[i++]; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
+  (++i, xs)[++i]; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
+  (i, xs)[++i + ++i]; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
+                      // cxx17-warning at -1 {{multiple unsequenced modifications to 'i'}}
+  p++[p == xs]; // cxx11-warning {{unsequenced modification and access to 'p'}}
+  ++p[p++ == xs]; // cxx11-warning {{unsequenced modification and access to 'p'}}
+
+  struct S { int x; } s, *ps = &s;
+  int (S::*PtrMem);
+  (PtrMem = &S::x ,s).*(PtrMem); // cxx11-warning {{unsequenced modification and access to 'PtrMem'}}
+  (PtrMem = &S::x ,s).*(PtrMem = &S::x); // cxx11-warning {{multiple unsequenced modifications to 'PtrMem'}}
+  (PtrMem = &S::x ,ps)->*(PtrMem); // cxx11-warning {{unsequenced modification and access to 'PtrMem'}}
+  (PtrMem = &S::x ,ps)->*(PtrMem = &S::x); // cxx11-warning {{multiple unsequenced modifications to 'PtrMem'}}
+  (PtrMem = nullptr) == (PtrMem = nullptr); // cxx11-warning {{multiple unsequenced modifications to 'PtrMem'}}
+                                            // cxx17-warning at -1 {{multiple unsequenced modifications to 'PtrMem'}}
+  (PtrMem = nullptr) == PtrMem; // cxx11-warning {{unsequenced modification and access to 'PtrMem'}}
+                                // cxx17-warning at -1 {{unsequenced modification and access to 'PtrMem'}}
+
+  i++ << i++; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
+  ++i << ++i; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
+  i++ << i; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i << i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i++ >> i++; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
+  ++i >> ++i; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
+  i++ >> i; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i >> i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  (i++ << i) + i; // cxx11-warning {{unsequenced modification and access to 'i'}}
+                  // cxx17-warning at -1 {{unsequenced modification and access to 'i'}}
+  (i++ << i) << i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
+
+  ++i = i++; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
+  i = i+= 1; // no-warning
+  i = i++ + ++i; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
+                 // cxx17-warning at -1 {{multiple unsequenced modifications to 'i'}}
+  ++i += ++i; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
+  ++i += i++; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
+  (i++, i) += ++i; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
+  (i++, i) += i++; // cxx11-warning {{multiple unsequenced modifications to 'i'}}
+  i += i+= 1; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i += i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i += ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i -= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i -= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i *= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i *= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i /= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i /= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i %= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i %= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i ^= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i ^= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i |= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i |= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i &= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i &= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i <<= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i <<= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i >>= i++; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  i >>= ++i; // cxx11-warning {{unsequenced modification and access to 'i'}}
+
+  p[i++] = i; // cxx11-warning {{unsequenced modification and access to 'i'}}
+  p[i++] = (i = 42); // cxx11-warning {{multiple unsequenced modifications to 'i'}}
+  p++[i++] = (i = p ? i++ : i++); // cxx11-warning {{unsequenced modification and access to 'p'}}
+                                  // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+
+  (i++, f)(i++, 42); // cxx11-warning {{multiple unsequenced modifications to 'i'}}
+  (i++ + i++, f)(42, 42); // cxx11-warning {{multiple unsequenced modifications to 'i'}}
+                          // cxx17-warning at -1 {{multiple unsequenced modifications to 'i'}}
+  int (*pf)(int, int);
+  (pf = f)(pf != nullptr, pf != nullptr); // cxx11-warning {{unsequenced modification and access to 'pf'}}
+  pf((pf = f) != nullptr, 42); // cxx11-warning {{unsequenced modification and access to 'pf'}}
+  f((pf = f, 42), (pf = f, 42)); // cxx11-warning {{multiple unsequenced modifications to 'pf'}}
+                                 // cxx17-warning at -1 {{multiple unsequenced modifications to 'pf'}}
+  pf((pf = f) != nullptr, pf == nullptr); // cxx11-warning {{unsequenced modification and access to 'pf'}}
+                                          // cxx17-warning at -1 {{unsequenced modification and access to 'pf'}}
+}
+
+namespace PR20819 {
+  struct foo { void bar(int); };
+  foo get_foo(int);
+
+  void g() {
+    int a = 0;
+    get_foo(a).bar(a++);  // cxx11-warning {{unsequenced modification and access to 'a'}}
+  }
+}
+
+namespace overloaded_operators {
+  struct E {
+    E &operator=(E &);
+    E operator()(E);
+    E operator()(E, E);
+    E operator[](E);
+  } e;
+  // Binary operators with unsequenced operands.
+  E operator+(E,E);
+  E operator-(E,E);
+  E operator*(E,E);
+  E operator/(E,E);
+  E operator%(E,E);
+  E operator^(E,E);
+  E operator&(E,E);
+  E operator|(E,E);
+
+  E operator<(E,E);
+  E operator>(E,E);
+  E operator==(E,E);
+  E operator!=(E,E);
+  E operator>=(E,E);
+  E operator<=(E,E);
+
+  // Binary operators where the RHS is sequenced before the LHS in C++17.
+  E operator+=(E,E);
+  E operator-=(E,E);
+  E operator*=(E,E);
+  E operator/=(E,E);
+  E operator%=(E,E);
+  E operator^=(E,E);
+  E operator&=(E,E);
+  E operator|=(E,E);
+  E operator<<=(E,E);
+  E operator>>=(E,E);
+
+  // Binary operators where the LHS is sequenced before the RHS in C++17.
+  E operator<<(E,E);
+  E operator>>(E,E);
+  E operator&&(E,E);
+  E operator||(E,E);
+  E operator,(E,E);
+  E operator->*(E,E);
+
+  void test() {
+    int i = 0;
+    // Binary operators with unsequenced operands.
+    ((void)i++,e) + ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) - ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) * ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) / ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) % ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) ^ ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) & ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) | ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
+
+    ((void)i++,e) < ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) > ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) == ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) != ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) <= ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) >= ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
+
+    // Binary operators where the RHS is sequenced before the LHS in C++17.
+    ((void)i++,e) = ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) += ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) -= ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) *= ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) /= ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) %= ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) ^= ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) &= ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) |= ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) <<= ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) >>= ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+
+    operator+=(((void)i++,e), ((void)i++,e));
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
+
+    // Binary operators where the LHS is sequenced before the RHS in C++17.
+    ((void)i++,e) << ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) >> ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) || ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) && ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e) , ((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    ((void)i++,e)->*((void)i++,e);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+
+    operator<<(((void)i++,e), ((void)i++,e));
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
+
+    ((void)i++,e)[((void)i++,e)];
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+
+    ((void)i++,e)(((void)i++,e));
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    e(((void)i++,e), ((void)i++,e));
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
+
+    ((void)i++,e).operator()(((void)i++,e));
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+
+  }
+}
+
+namespace PR35340 {
+  struct S {};
+  S &operator<<(S &, int);
+
+  void test() {
+    S s;
+    int i = 0;
+    s << i++ << i++;
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+
+    operator<<(operator<<(s, i++), i++);
+    // cxx11-warning at -1 {{multiple unsequenced modifications to 'i'}}
+    // cxx17-warning at -2 {{multiple unsequenced modifications to 'i'}}
+  }
+}
+
+namespace members {
+
+struct S1 {
+  unsigned bf1 : 2;
+  unsigned bf2 : 2;
+  unsigned a;
+  unsigned b;
+  static unsigned x;
+  void member_f(S1 &s);
+};
+
+void S1::member_f(S1 &s) {
+  ++a + ++a; // cxx11-warning {{multiple unsequenced modifications to 'a'}}
+             // cxx17-warning at -1 {{multiple unsequenced modifications to 'a'}}
+  a + ++a; // cxx11-warning {{unsequenced modification and access to 'a'}}
+           // cxx17-warning at -1 {{unsequenced modification and access to 'a'}}
+  ++a + ++b; // no-warning
+  a + ++b; // no-warning
+
+  // TODO: Warn here.
+  ++s.a + ++s.a; // no-warning TODO {{multiple unsequenced modifications to}}
+  s.a + ++s.a; // no-warning TODO {{unsequenced modification and access to}}
+  ++s.a + ++s.b; // no-warning
+  s.a + ++s.b; // no-warning
+
+  ++a + ++s.a; // no-warning
+  a + ++s.a; // no-warning
+  ++a + ++s.b; // no-warning
+  a + ++s.b; // no-warning
+
+  // TODO Warn here for bit-fields in the same memory location.
+  ++bf1 + ++bf1; // cxx11-warning {{multiple unsequenced modifications to 'bf1'}}
+                 // cxx17-warning at -1 {{multiple unsequenced modifications to 'bf1'}}
+  bf1 + ++bf1; // cxx11-warning {{unsequenced modification and access to 'bf1'}}
+               // cxx17-warning at -1 {{unsequenced modification and access to 'bf1'}}
+  ++bf1 + ++bf2; // no-warning TODO {{multiple unsequenced modifications to}}
+  bf1 + ++bf2; // no-warning TODO {{unsequenced modification and access to}}
+
+  // TODO Warn here for bit-fields in the same memory location.
+  ++s.bf1 + ++s.bf1; // no-warning TODO {{multiple unsequenced modifications to}}
+  s.bf1 + ++s.bf1; // no-warning TODO {{unsequenced modification and access to}}
+  ++s.bf1 + ++s.bf2; // no-warning TODO {{multiple unsequenced modifications to}}
+  s.bf1 + ++s.bf2; // no-warning TODO {{unsequenced modification and access to}}
+
+  ++bf1 + ++s.bf1; // no-warning
+  bf1 + ++s.bf1; // no-warning
+  ++bf1 + ++s.bf2; // no-warning
+  bf1 + ++s.bf2; // no-warning
+
+  struct Der : S1 {};
+  Der d;
+  Der &d_ref = d;
+  S1 &s1_ref = d_ref;
+
+  ++s1_ref.a + ++d_ref.a; // no-warning TODO {{multiple unsequenced modifications to member 'a' of 'd'}}
+  ++s1_ref.a + d_ref.a; // no-warning TODO {{unsequenced modification and access to member 'a' of 'd'}}
+  ++s1_ref.a + ++d_ref.b; // no-warning
+  ++s1_ref.a + d_ref.b; // no-warning
+
+  ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
+             // cxx17-warning at -1 {{multiple unsequenced modifications to 'x'}}
+  ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
+           // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
+  ++s.x + x; // no-warning TODO {{unsequenced modification and access to static member 'x' of 'S1'}}
+  ++this->x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
+                 // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
+  ++d_ref.x + ++S1::x; // no-warning TODO {{unsequenced modification and access to static member 'x' of 'S1'}}
+}
+
+struct S2 {
+  union { unsigned x, y; };
+  void f2();
+};
+
+void S2::f2() {
+  ++x + ++x; // no-warning TODO {{multiple unsequenced modifications to}}
+  x + ++x; // no-warning TODO {{unsequenced modification and access to}}
+  ++x + ++y; // no-warning
+  x + ++y; // no-warning
+}
+
+void f2(S2 &s) {
+  ++s.x + ++s.x; // no-warning TODO {{multiple unsequenced modifications to}}
+  s.x + ++s.x; // no-warning TODO {{unsequenced modification and access to}}
+  ++s.x + ++s.y; // no-warning
+  s.x + ++s.y; // no-warning
+}
+
+struct S3 {
+  union {
+    union {
+      unsigned x;
+    };
+  };
+  unsigned y;
+  void f3();
+};
+
+void S3::f3() {
+  ++x + ++x; // no-warning TODO {{multiple unsequenced modifications to}}
+  x + ++x; // no-warning TODO {{unsequenced modification and access to}}
+  ++x + ++y; // no-warning
+  x + ++y; // no-warning
+}
+
+void f3(S3 &s) {
+  ++s.x + ++s.x; // no-warning TODO {{multiple unsequenced modifications to}}
+  s.x + ++s.x; // no-warning TODO {{unsequenced modification and access to}}
+  ++s.x + ++s.y; // no-warning
+  s.x + ++s.y; // no-warning
+}
+
+struct S4 : S3 {
+  unsigned y;
+  void f4();
+};
+
+void S4::f4() {
+  ++x + ++x; // no-warning TODO {{multiple unsequenced modifications to}}
+  x + ++x; // no-warning TODO {{unsequenced modification and access to}}
+  ++x + ++y; // no-warning
+  x + ++y; // no-warning
+  ++S3::y + ++y; // no-warning
+  S3::y + ++y; // no-warning
+}
+
+void f4(S4 &s) {
+  ++s.x + ++s.x; // no-warning TODO {{multiple unsequenced modifications to}}
+  s.x + ++s.x; // no-warning TODO {{unsequenced modification and access to}}
+  ++s.x + ++s.y; // no-warning
+  s.x + ++s.y; // no-warning
+  ++s.S3::y + ++s.y; // no-warning
+  s.S3::y + ++s.y; // no-warning
+}
+
+static union {
+  unsigned Ux;
+  unsigned Uy;
+};
+
+void f5() {
+  ++Ux + ++Ux; // no-warning TODO {{multiple unsequenced modifications to}}
+  Ux + ++Ux; // no-warning TODO {{unsequenced modification and access to}}
+  ++Ux + ++Uy; // no-warning
+  Ux + ++Uy; // no-warning
+}
+
+void f6() {
+  struct S { unsigned x, y; } s;
+  ++s.x + ++s.x; // no-warning TODO {{multiple unsequenced modifications to}}
+  s.x + ++s.x; // no-warning TODO {{unsequenced modification and access to}}
+  ++s.x + ++s.y; // no-warning
+  s.x + ++s.y; // no-warning
+
+  struct { unsigned x, y; } t;
+  ++t.x + ++t.x; // no-warning TODO {{multiple unsequenced modifications to}}
+  t.x + ++t.x; // no-warning TODO {{unsequenced modification and access to}}
+  ++t.x + ++t.y; // no-warning
+  t.x + ++t.y; // no-warning
+}
+
+} // namespace members
+
+namespace references {
+void reference_f() {
+  // TODO: Check that we can see through references.
+  // For now this is completely unhandled.
+  int a;
+  int xs[10];
+  int &b = a;
+  int &c = b;
+  int &ra1 = c;
+  int &ra2 = b;
+  int other;
+
+  ++ra1 + ++ra2; // no-warning TODO {{multiple unsequenced modifications to}}
+  ra1 + ++ra2; // no-warning TODO {{unsequenced modification and access to}}
+  ++ra1 + ++other; // no-warning
+  ra1 + ++other; // no-warning
+
+  // Make sure we handle reference cycles.
+  int &ref_cycle = ref_cycle;
+  ++ref_cycle + ++ref_cycle; // cxx11-warning {{multiple unsequenced modifications to 'ref_cycle'}}
+                             // cxx17-warning at -1 {{multiple unsequenced modifications to 'ref_cycle'}}
+  ref_cycle + ++ref_cycle; // cxx11-warning {{unsequenced modification and access to 'ref_cycle'}}
+                           // cxx17-warning at -1 {{unsequenced modification and access to 'ref_cycle'}}
+}
+} // namespace references
+
+namespace std {
+  using size_t = decltype(sizeof(0));
+  template<typename> struct tuple_size;
+  template<size_t, typename> struct tuple_element { using type = int; };
+}
+namespace bindings {
+
+  struct A { int x, y; };
+  typedef int B[2];
+  struct C { template<int> int get(); };
+  struct D : A {};
+
+} // namespace bindings
+template<> struct std::tuple_size<bindings::C> { enum { value = 2 }; };
+namespace bindings {
+void testa() {
+  A a;
+  {
+    auto [x, y] = a;
+    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
+               // cxx17-warning at -1 {{multiple unsequenced modifications to 'x'}}
+    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
+             // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
+    ++x + ++y; // no-warning
+    ++x + y; // no-warning
+    ++x + ++a.x; // no-warning
+    ++x + a.x; // no-warning
+  }
+  {
+    auto &[x, y] = a;
+    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
+               // cxx17-warning at -1 {{multiple unsequenced modifications to 'x'}}
+    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
+             // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
+    ++x + ++y; // no-warning
+    ++x + y; // no-warning
+    ++x + ++a.x; // no-warning TODO
+    ++x + a.x; // no-warning TODO
+  }
+}
+void testb() {
+  B b;
+  {
+    auto [x, y] = b;
+    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
+               // cxx17-warning at -1 {{multiple unsequenced modifications to 'x'}}
+    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
+             // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
+    ++x + ++y; // no-warning
+    ++x + y; // no-warning
+    ++x + ++b[0]; // no-warning
+    ++x + b[0]; // no-warning
+  }
+  {
+    auto &[x, y] = b;
+    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
+               // cxx17-warning at -1 {{multiple unsequenced modifications to 'x'}}
+    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
+             // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
+    ++x + ++y; // no-warning
+    ++x + y; // no-warning
+    ++x + ++b[0]; // no-warning TODO
+    ++x + b[0]; // no-warning TODO
+  }
+}
+void testc() {
+  C c;
+  {
+    auto [x, y] = c;
+    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
+               // cxx17-warning at -1 {{multiple unsequenced modifications to 'x'}}
+    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
+             // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
+    ++x + ++y; // no-warning
+    ++x + y; // no-warning
+  }
+  {
+    auto &[x, y] = c;
+    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
+               // cxx17-warning at -1 {{multiple unsequenced modifications to 'x'}}
+    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
+             // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
+    ++x + ++y; // no-warning
+    ++x + y; // no-warning
+  }
+}
+void testd() {
+  D d;
+  {
+    auto [x, y] = d;
+    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
+               // cxx17-warning at -1 {{multiple unsequenced modifications to 'x'}}
+    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
+             // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
+    ++x + ++y; // no-warning
+    ++x + y; // no-warning
+    ++x + ++d.x; // no-warning
+    ++x + d.x; // no-warning
+  }
+  {
+    auto &[x, y] = d;
+    ++x + ++x; // cxx11-warning {{multiple unsequenced modifications to 'x'}}
+               // cxx17-warning at -1 {{multiple unsequenced modifications to 'x'}}
+    ++x + x; // cxx11-warning {{unsequenced modification and access to 'x'}}
+             // cxx17-warning at -1 {{unsequenced modification and access to 'x'}}
+    ++x + ++y; // no-warning
+    ++x + y; // no-warning
+    ++x + ++d.x; // no-warning TODO
+    ++x + d.x; // no-warning TODO
+  }
+}
+} // namespace bindings
+
+namespace templates {
+
+template <typename T>
+struct Bar {
+  T get() { return 0; }
+};
+
+template <typename X>
+struct Foo {
+  int Run();
+  Bar<int> bar;
+};
+
+enum E {e1, e2};
+bool operator&&(E, E);
+
+void foo(int, int);
+
+template <typename X>
+int Foo<X>::Run() {
+  char num = 0;
+
+  // Before instantiation, Clang may consider the builtin operator here as
+  // unresolved function calls, and treat the arguments as unordered when
+  // the builtin operator evaluatation is well-ordered.  Waiting until
+  // instantiation to check these expressions will prevent false positives.
+  if ((num = bar.get()) < 5 && num < 10) { }
+  if ((num = bar.get()) < 5 || num < 10) { }
+  if (static_cast<E>((num = bar.get()) < 5) || static_cast<E>(num < 10)) { }
+
+  if (static_cast<E>((num = bar.get()) < 5) && static_cast<E>(num < 10)) { }
+  // cxx11-warning at -1 {{unsequenced modification and access to 'num'}}
+
+  foo(num++, num++);
+  // cxx11-warning at -1 {{multiple unsequenced modifications to 'num'}}
+  // cxx17-warning at -2 {{multiple unsequenced modifications to 'num'}}
+  return 1;
+}
+
+int x = Foo<int>().Run();
+// cxx11-note at -1 {{in instantiation of member function 'templates::Foo<int>::Run'}}
+// cxx17-note at -2 {{in instantiation of member function 'templates::Foo<int>::Run'}}
+
+
+template <typename T>
+int Run2() {
+  T t = static_cast<T>(0);
+  return (t = static_cast<T>(1)) && t;
+  // cxx11-warning at -1 {{unsequenced modification and access to 't'}}
+}
+
+int y = Run2<bool>();
+int z = Run2<E>();
+// cxx11-note at -1{{in instantiation of function template specialization 'templates::Run2<templates::E>' requested here}}
+
+template <typename T> int var = sizeof(T);
+void test_var() {
+  var<int>++ + var<int>++; // cxx11-warning {{multiple unsequenced modifications to 'var<int>'}}
+                           // cxx17-warning at -1 {{multiple unsequenced modifications to 'var<int>'}}
+  var<int>++ + var<int>; // cxx11-warning {{unsequenced modification and access to 'var<int>'}}
+                         // cxx17-warning at -1 {{unsequenced modification and access to 'var<int>'}}
+  int &r = var<int>;
+  r++ + var<int>++; // no-warning TODO {{multiple unsequenced modifications to 'var<int>'}}
+  r++ + var<long>++; // no-warning
+}
+
+} // namespace templates
+
+namespace muliple_read_volatile {
+  volatile int v1, v2;
+
+  
+  void PositiveTest(){
+    int x = 0;
+    int y = 0;
+    x = v1 + v1;        // cxx11-warning    {{unsequenced accesses to volatile qualified 'v1'}}
+                        // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
+    v1 = v1 * v1;       // cxx11-warning    {{unsequenced accesses to volatile qualified 'v1'}}
+                        // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
+    x = v1 + (y++, v1); // cxx11-warning    {{unsequenced accesses to volatile qualified 'v1'}}
+                        // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}
+    x = v1 + v1 || y;   // cxx11-warning    {{unsequenced accesses to volatile qualified 'v1'}}
+                        // cxx17-warning at -1 {{unsequenced accesses to volatile qualified 'v1'}}            
+  }
+  
+  void NegativeTest(){
+    int x = 0;
+    int y = 0;
+    x = v1 + y;   // no-warning
+    x = v1 + v2;  // no-warning
+    v1 = v1 * y;  // no-warning
+    x = (v1, v1); // no-warning
+    x = v1 || v1; // no-warning
+    x = v1 && v1; // no-warning
+  }
+} // namespace muliple_read_volatile

>From 050b6254c7b89bf805a485634e880b31444ec396 Mon Sep 17 00:00:00 2001
From: Seraphimt <svet58585 at mail.ru>
Date: Thu, 20 Aug 2026 19:38:28 +0300
Subject: [PATCH 09/12] Revert "Add Wno-sequence-point in tests x2."

This reverts commit da20fc4992ed4912c071d76041dc7ee7a612d0f2.
---
 clang/test/CodeGen/PowerPC/builtins-ppc-fma.c                 | 2 +-
 .../CodeGen/SystemZ/builtins-systemz-vector-constrained.c     | 2 +-
 clang/test/CodeGen/SystemZ/builtins-systemz-zvector5.c        | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c b/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c
index e26d7793ffb2b..4dd7295d8efe1 100644
--- a/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c
+++ b/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -triple powerpc64le-gnu-linux \
-// RUN: -target-feature +vsx -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck      \
+// RUN: -target-feature +vsx -Wall -Wno-sequence-point -Werror -emit-llvm %s -o - | FileCheck      \
 // RUN: %s
 
 typedef __attribute__((vector_size(4 * sizeof(float)))) float vec_float;
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-vector-constrained.c b/clang/test/CodeGen/SystemZ/builtins-systemz-vector-constrained.c
index 0877067a1fdcd..ff24ef9a091b7 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-vector-constrained.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-vector-constrained.c
@@ -1,6 +1,6 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z13 -triple s390x-ibm-linux -flax-vector-conversions=none \
-// RUN: -ffp-exception-behavior=strict -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -ffp-exception-behavior=strict -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 
 typedef __attribute__((vector_size(16))) signed long long vec_slong;
 typedef __attribute__((vector_size(16))) double vec_double;
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector5.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector5.c
index b354219e817f0..cd0fafdb7435f 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector5.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector5.c
@@ -1,10 +1,10 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z17 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 // RUN: %clang_cc1 -target-cpu z17 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
+// RUN: -Wall -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
 
 #include <vecintrin.h>
 

>From 54d9b11be85e30ebec799ea4cb631848d1d52ccd Mon Sep 17 00:00:00 2001
From: Seraphimt <svet58585 at mail.ru>
Date: Thu, 20 Aug 2026 19:39:29 +0300
Subject: [PATCH 10/12] Revert "Add Wno-sequence-point in tests."

This reverts commit d8edb3d1f48db3da764da0d46791dd79e110befd.
---
 clang/test/CodeGen/PowerPC/builtins-ppc-fma.c                 | 2 +-
 clang/test/CodeGen/SystemZ/builtins-systemz-i128.c            | 2 +-
 clang/test/CodeGen/SystemZ/builtins-systemz-vector.c          | 2 +-
 .../CodeGen/SystemZ/builtins-systemz-vector2-constrained.c    | 2 +-
 clang/test/CodeGen/SystemZ/builtins-systemz-vector2.c         | 2 +-
 clang/test/CodeGen/SystemZ/builtins-systemz-vector3.c         | 2 +-
 clang/test/CodeGen/SystemZ/builtins-systemz-vector4.c         | 2 +-
 clang/test/CodeGen/SystemZ/builtins-systemz-vector5.c         | 2 +-
 .../CodeGen/SystemZ/builtins-systemz-zvector-constrained.c    | 4 ++--
 clang/test/CodeGen/SystemZ/builtins-systemz-zvector-error.c   | 2 +-
 clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c         | 4 ++--
 .../CodeGen/SystemZ/builtins-systemz-zvector2-constrained.c   | 4 ++--
 clang/test/CodeGen/SystemZ/builtins-systemz-zvector2.c        | 4 ++--
 clang/test/CodeGen/SystemZ/builtins-systemz-zvector3.c        | 4 ++--
 clang/test/CodeGen/SystemZ/builtins-systemz-zvector4.c        | 4 ++--
 clang/test/CodeGen/SystemZ/builtins-systemz.c                 | 4 ++--
 16 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c b/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c
index 4dd7295d8efe1..61421fbf2fecd 100644
--- a/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c
+++ b/clang/test/CodeGen/PowerPC/builtins-ppc-fma.c
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -triple powerpc64le-gnu-linux \
-// RUN: -target-feature +vsx -Wall -Wno-sequence-point -Werror -emit-llvm %s -o - | FileCheck      \
+// RUN: -target-feature +vsx -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck      \
 // RUN: %s
 
 typedef __attribute__((vector_size(4 * sizeof(float)))) float vec_float;
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-i128.c b/clang/test/CodeGen/SystemZ/builtins-systemz-i128.c
index 436d6a0039f9b..2a20607123af9 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-i128.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-i128.c
@@ -2,7 +2,7 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z14 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-unused -Wno-sequence-point -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 
 #include <vecintrin.h>
 
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-vector.c b/clang/test/CodeGen/SystemZ/builtins-systemz-vector.c
index 0cf7e3732b8c4..ae3b08a1b67eb 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-vector.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-vector.c
@@ -1,6 +1,6 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z13 -triple s390x-ibm-linux -flax-vector-conversions=none \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 
 typedef __attribute__((vector_size(16))) signed char vec_schar;
 typedef __attribute__((vector_size(16))) signed short vec_sshort;
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-vector2-constrained.c b/clang/test/CodeGen/SystemZ/builtins-systemz-vector2-constrained.c
index 682e6f613f44c..12c675041af76 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-vector2-constrained.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-vector2-constrained.c
@@ -1,6 +1,6 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z14 -triple s390x-ibm-linux -flax-vector-conversions=none \
-// RUN: -ffp-exception-behavior=strict -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -ffp-exception-behavior=strict -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 
 typedef __attribute__((vector_size(16))) double vec_double;
 typedef __attribute__((vector_size(16))) float vec_float;
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-vector2.c b/clang/test/CodeGen/SystemZ/builtins-systemz-vector2.c
index 3af63f225afad..8f9e164ebef8c 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-vector2.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-vector2.c
@@ -1,6 +1,6 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z14 -triple s390x-ibm-linux -flax-vector-conversions=none \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 
 typedef __attribute__((vector_size(16))) signed char vec_schar;
 typedef __attribute__((vector_size(16))) signed short vec_sshort;
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-vector3.c b/clang/test/CodeGen/SystemZ/builtins-systemz-vector3.c
index 0a04affb9c445..e4af1c1e54b86 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-vector3.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-vector3.c
@@ -1,6 +1,6 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z15 -triple s390x-ibm-linux -flax-vector-conversions=none \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 
 typedef __attribute__((vector_size(16))) signed char vec_schar;
 typedef __attribute__((vector_size(16))) signed short vec_sshort;
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-vector4.c b/clang/test/CodeGen/SystemZ/builtins-systemz-vector4.c
index 09ab10fac5116..c5ce47cea2ea8 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-vector4.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-vector4.c
@@ -1,6 +1,6 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z16 -triple s390x-ibm-linux -flax-vector-conversions=none \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 
 typedef __attribute__((vector_size(16))) signed char vec_schar;
 typedef __attribute__((vector_size(16))) signed short vec_sshort;
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-vector5.c b/clang/test/CodeGen/SystemZ/builtins-systemz-vector5.c
index 95fe321d606b1..b765fa64b33d4 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-vector5.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-vector5.c
@@ -1,6 +1,6 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z17 -triple s390x-ibm-linux -flax-vector-conversions=none \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 
 typedef __attribute__((vector_size(16))) signed char vec_schar;
 typedef __attribute__((vector_size(16))) signed short vec_sshort;
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector-constrained.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector-constrained.c
index af750a24767c6..4993df20df143 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector-constrained.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector-constrained.c
@@ -2,11 +2,11 @@
 // RUN: %clang_cc1 -target-cpu z13 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
 // RUN: -ffp-exception-behavior=strict \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 // RUN: %clang_cc1 -target-cpu z13 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
 // RUN: -ffp-exception-behavior=strict \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
+// RUN: -Wall -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
 
 #include <vecintrin.h>
 
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector-error.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector-error.c
index d82cbf0c51b2b..2ec1d960aa5bb 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector-error.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector-error.c
@@ -1,7 +1,7 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z13 -triple s390x-linux-gnu \
 // RUN: -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -fsyntax-only -verify %s
+// RUN: -Wall -Wno-unused -Werror -fsyntax-only -verify %s
 
 #include <vecintrin.h>
 
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c
index 9f1283724201c..42298339733d4 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c
@@ -1,10 +1,10 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z13 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 // RUN: %clang_cc1 -target-cpu z13 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
+// RUN: -Wall -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
 
 #include <vecintrin.h>
 
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector2-constrained.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector2-constrained.c
index 6dea4f6bf6600..25b3e0b68cd02 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector2-constrained.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector2-constrained.c
@@ -2,11 +2,11 @@
 // RUN: %clang_cc1 -target-cpu z14 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
 // RUN: -ffp-exception-behavior=strict \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 // RUN: %clang_cc1 -target-cpu z14 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
 // RUN: -ffp-exception-behavior=strict \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
+// RUN: -Wall -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
 
 #include <vecintrin.h>
 
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector2.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector2.c
index aedd7f734edb8..c1ef178fcfaa9 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector2.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector2.c
@@ -1,10 +1,10 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z14 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 // RUN: %clang_cc1 -target-cpu z14 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
+// RUN: -Wall -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
 
 #include <vecintrin.h>
 
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector3.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector3.c
index dd7ec19b2412f..ce8b315127237 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector3.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector3.c
@@ -1,10 +1,10 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z15 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 // RUN: %clang_cc1 -target-cpu z15 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
+// RUN: -Wall -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
 
 #include <vecintrin.h>
 
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector4.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector4.c
index 23685cdff8994..adc55927ce366 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector4.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector4.c
@@ -1,10 +1,10 @@
 // REQUIRES: systemz-registered-target
 // RUN: %clang_cc1 -target-cpu z16 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
 // RUN: %clang_cc1 -target-cpu z16 -triple s390x-linux-gnu \
 // RUN: -O2 -fzvector -flax-vector-conversions=none \
-// RUN: -Wall -Wno-sequence-point -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
+// RUN: -Wall -Wno-unused -Werror -S %s -o - | FileCheck %s --check-prefix=CHECK-ASM
 
 #include <vecintrin.h>
 
diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz.c b/clang/test/CodeGen/SystemZ/builtins-systemz.c
index 61c7cd934f7c4..4848bef4b4aad 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz.c
@@ -1,6 +1,6 @@
 // REQUIRES: systemz-registered-target
-// RUN: %clang_cc1 -target-cpu zEC12 -triple s390x-ibm-linux -Wall -Wno-unused -Wno-sequence-point -Werror -emit-llvm %s -o - | FileCheck %s
-// RUN: %clang_cc1 -target-cpu zEC12 -triple s390x-ibm-linux -Wall -Wno-unused -Wno-sequence-point -Werror -emit-llvm -x c++ %s -o - | FileCheck %s
+// RUN: %clang_cc1 -target-cpu zEC12 -triple s390x-ibm-linux -Wall -Wno-unused -Werror -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -target-cpu zEC12 -triple s390x-ibm-linux -Wall -Wno-unused -Werror -emit-llvm -x c++ %s -o - | FileCheck %s
 
 #include <stdint.h>
 #include <htmintrin.h>

>From b7a6f50048e53870b08f3b8dc5f4224125ded070 Mon Sep 17 00:00:00 2001
From: Seraphimt <svet58585 at mail.ru>
Date: Fri, 21 Aug 2026 09:53:35 +0300
Subject: [PATCH 11/12] Fix missed cases.

---
 clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c
index a78eaf3606a53..b3c232474709c 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c
@@ -58,12 +58,14 @@ volatile vector double vd2;
 volatile signed char sc;
 volatile signed short ss;
 volatile signed int si;
-volatile signed long long sl;
+volatile signed long long sl1;
+volatile signed long long sl2;
 volatile signed __int128 slll;
 volatile unsigned char uc;
 volatile unsigned short us;
 volatile unsigned int ui;
-volatile unsigned long long ul;
+volatile unsigned long long ul1;
+volatile unsigned long long ul2;
 volatile unsigned __int128 ulll;
 volatile double d;
 
@@ -769,9 +771,9 @@ void test_core(void) {
   // CHECK: call void @llvm.s390.vstl(<16 x i8> %{{.*}}, i32 %{{.*}}, ptr %{{.*}})
   // CHECK-ASM: vstl
 
-  vsl = vec_load_pair(sl + 1, sl - 1);
+  vsl = vec_load_pair(sl1 + 1, sl2 - 1);
   // CHECK-ASM: vlvgp
-  vul = vec_load_pair(ul + 1, ul - 1);
+  vul = vec_load_pair(ul1 + 1, ul1 - 1);
   // CHECK-ASM: vlvgp
 
   vuc = vec_genmask(0);

>From e187ee373f5756209112940c583725f3f9b79f8f Mon Sep 17 00:00:00 2001
From: Seraphimt <svet58585 at mail.ru>
Date: Fri, 21 Aug 2026 14:34:47 +0300
Subject: [PATCH 12/12] Missing part of the commit with the
 builtins-systemz-zvector.c fix

---
 clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c
index b3c232474709c..49e3e4cf9956c 100644
--- a/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c
+++ b/clang/test/CodeGen/SystemZ/builtins-systemz-zvector.c
@@ -58,12 +58,14 @@ volatile vector double vd2;
 volatile signed char sc;
 volatile signed short ss;
 volatile signed int si;
+volatile signed long long sl;
 volatile signed long long sl1;
 volatile signed long long sl2;
 volatile signed __int128 slll;
 volatile unsigned char uc;
 volatile unsigned short us;
 volatile unsigned int ui;
+volatile unsigned long long ul;
 volatile unsigned long long ul1;
 volatile unsigned long long ul2;
 volatile unsigned __int128 ulll;



More information about the cfe-commits mailing list