[clang] [Clang] Add __builtin_counted_by_ref builtin (PR #114495)

Bill Wendling via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 1 15:44:22 PDT 2024


https://github.com/bwendling updated https://github.com/llvm/llvm-project/pull/114495

>From fe49528f47dee6d2167d07da1ac8d4cb80cf5fe0 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Tue, 6 Aug 2024 17:49:01 -0700
Subject: [PATCH 01/59] [Clang] Add __builtin_counted_by_ref builtin

The __builtin_counted_by_ref builtin is used on a flexible array
pointer and returns a pointer to the "counted_by" attribute's COUNT
argument, which is a field in the same non-anonymous struct as the
flexible array member. This is useful for automatically setting the
count field without needing the programmer's intervention. Otherwise
it's possible to get this anti-pattern:

  ptr = alloc(<ty>, ..., COUNT);
  ptr->FAM[9] = 42; /* <<< Sanitizer will complain */
  ptr->count = COUNT;

To prevent this anti-pattern, the user can create an allocator that
automatically performs the assignment:

  #define alloc(TY, FAM, COUNT) ({ \
      TY __p = alloc(get_size(TY, COUNT));             \
      if (__builtin_counted_by_ref(__p->FAM))          \
          *__builtin_counted_by_ref(__p->FAM) = COUNT; \
      __p;                                             \
  })
The builtin's behavior is heavily dependent upon the "counted_by"
attribute existing. It's main utility is during allocation to avoid
the above anti-pattern. If the flexible array member doesn't have that
attribute, the builtin becomes a no-op. Therefore, if the flexible
array member has a "count" field not referenced by "counted_by", it
must be set explicitly after the allocation as this builtin will
return a "nullptr" and the assignment will most likely be elided.
---
 clang/include/clang/Basic/Builtins.td |  6 ++++
 clang/lib/CodeGen/CGBuiltin.cpp       | 22 ++++++++++++
 clang/lib/CodeGen/CGExpr.cpp          | 29 +++++++++-------
 clang/lib/CodeGen/CodeGenFunction.h   |  8 +++++
 clang/lib/Sema/SemaExpr.cpp           | 49 +++++++++++++++++++++++++--
 5 files changed, 100 insertions(+), 14 deletions(-)

diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 9bd67e0cefebc3..81e7e581ecb243 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4914,3 +4914,9 @@ def ArithmeticFence : LangBuiltin<"ALL_LANGUAGES"> {
   let Attributes = [CustomTypeChecking, Constexpr];
   let Prototype = "void(...)";
 }
+
+def GetCountedBy : Builtin {
+  let Spellings = ["__builtin_get_counted_by"];
+  let Attributes = [NoThrow];
+  let Prototype = "size_t*(void*)";
+}
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 038057d2164ced..8b1cc9f23a7e90 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3691,6 +3691,28 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
     return RValue::get(emitBuiltinObjectSize(E->getArg(0), Type, ResType,
                                              /*EmittedE=*/nullptr, IsDynamic));
   }
+  case Builtin::BI__builtin_get_counted_by: {
+    llvm::Value *Result = nullptr;
+
+    if (const MemberExpr *ME =
+            dyn_cast<MemberExpr>(E->getArg(0)->IgnoreImpCasts())) {
+      bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
+              getContext(), getLangOpts().getStrictFlexArraysLevel(),
+              /*IgnoreTemplateOrMacroSubstitution=*/false);
+
+      // TODO: Probably have to handle horrible casting crap here.
+
+      // FIXME: Emit a diagnostic?
+      if (!ME->HasSideEffects(getContext()) && IsFlexibleArrayMember &&
+          ME->getMemberDecl()->getType()->isCountAttributedType()) {
+        const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
+        if (const FieldDecl *CountFD = FindCountedByField(FAMDecl))
+          Result = GetCountedByFieldExprGEP(ME, FAMDecl, CountFD);
+      }
+    }
+
+    return RValue::get(Result);
+  }
   case Builtin::BI__builtin_prefetch: {
     Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0));
     // FIXME: Technically these constants should of type 'int', yes?
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index e90e8da3e9f1ea..3364a00c6e9ff7 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1145,15 +1145,7 @@ static bool getGEPIndicesToField(CodeGenFunction &CGF, const RecordDecl *RD,
   return false;
 }
 
-/// This method is typically called in contexts where we can't generate
-/// side-effects, like in __builtin_dynamic_object_size. When finding
-/// expressions, only choose those that have either already been emitted or can
-/// be loaded without side-effects.
-///
-/// - \p FAMDecl: the \p Decl for the flexible array member. It may not be
-///   within the top-level struct.
-/// - \p CountDecl: must be within the same non-anonymous struct as \p FAMDecl.
-llvm::Value *CodeGenFunction::EmitLoadOfCountedByField(
+llvm::Value *CodeGenFunction::GetCountedByFieldExprGEP(
     const Expr *Base, const FieldDecl *FAMDecl, const FieldDecl *CountDecl) {
   const RecordDecl *RD = CountDecl->getParent()->getOuterLexicalRecordContext();
 
@@ -1182,12 +1174,25 @@ llvm::Value *CodeGenFunction::EmitLoadOfCountedByField(
     return nullptr;
 
   Indices.push_back(Builder.getInt32(0));
-  Res = Builder.CreateInBoundsGEP(
+  return Builder.CreateInBoundsGEP(
       ConvertType(QualType(RD->getTypeForDecl(), 0)), Res,
       RecIndicesTy(llvm::reverse(Indices)), "..counted_by.gep");
+}
 
-  return Builder.CreateAlignedLoad(ConvertType(CountDecl->getType()), Res,
-                                   getIntAlign(), "..counted_by.load");
+/// This method is typically called in contexts where we can't generate
+/// side-effects, like in __builtin_dynamic_object_size. When finding
+/// expressions, only choose those that have either already been emitted or can
+/// be loaded without side-effects.
+///
+/// - \p FAMDecl: the \p Decl for the flexible array member. It may not be
+///   within the top-level struct.
+/// - \p CountDecl: must be within the same non-anonymous struct as \p FAMDecl.
+llvm::Value *CodeGenFunction::EmitLoadOfCountedByField(
+    const Expr *Base, const FieldDecl *FAMDecl, const FieldDecl *CountDecl) {
+  if (llvm::Value *GEP = GetCountedByFieldExprGEP(Base, FAMDecl, CountDecl))
+    return Builder.CreateAlignedLoad(ConvertType(CountDecl->getType()), GEP,
+                                     getIntAlign(), "..counted_by.load");
+  return nullptr;
 }
 
 void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 3ff4458fb32024..a370a2fe5f5775 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3305,6 +3305,14 @@ class CodeGenFunction : public CodeGenTypeCache {
                                         const FieldDecl *FAMDecl,
                                         uint64_t &Offset);
 
+  /// Find the FieldDecl specified in a FAM's "counted_by" attribute. Returns
+  /// \p nullptr if either the attribute or the field doesn't exist.
+  const FieldDecl *FindCountedByField(const FieldDecl *FD);
+
+  llvm::Value *GetCountedByFieldExprGEP(const Expr *Base,
+                                        const FieldDecl *FAMDecl,
+                                        const FieldDecl *CountDecl);
+
   /// Build an expression accessing the "counted_by" field.
   llvm::Value *EmitLoadOfCountedByField(const Expr *Base,
                                         const FieldDecl *FAMDecl,
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 7f3cff1054aeed..4b83978a0d380b 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -6462,9 +6462,26 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
       currentEvaluationContext().ReferenceToConsteval.erase(DRE);
     }
   }
+
   return Call;
 }
 
+const FieldDecl *FindCountedByField(const FieldDecl *FD) {
+  if (!FD)
+    return nullptr;
+
+  const auto *CAT = FD->getType()->getAs<CountAttributedType>();
+  if (!CAT)
+    return nullptr;
+
+  const auto *CountDRE = cast<DeclRefExpr>(CAT->getCountExpr());
+  const auto *CountDecl = CountDRE->getDecl();
+  if (const auto *IFD = dyn_cast<IndirectFieldDecl>(CountDecl))
+    CountDecl = IFD->getAnonField();
+
+  return dyn_cast<FieldDecl>(CountDecl);
+}
+
 ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
                                MultiExprArg ArgExprs, SourceLocation RParenLoc,
                                Expr *ExecConfig, bool IsExecConfig,
@@ -6662,8 +6679,36 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
     return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy,
                             VK_PRValue, RParenLoc, CurFPFeatureOverrides());
   }
-  return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs, RParenLoc,
-                               ExecConfig, IsExecConfig);
+
+  Result = BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs, RParenLoc,
+                                 ExecConfig, IsExecConfig);
+
+  if (FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
+      FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_get_counted_by) {
+    if (const MemberExpr *ME =
+            dyn_cast<MemberExpr>(ArgExprs[0]->IgnoreImpCasts())) {
+      bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
+              Context, getLangOpts().getStrictFlexArraysLevel(),
+              /*IgnoreTemplateOrMacroSubstitution=*/false);
+
+      // TODO: Probably have to handle horrible casting crap here.
+
+      // FIXME: Emit a diagnostic?
+      if (!ME->HasSideEffects(Context) && IsFlexibleArrayMember &&
+          ME->getMemberDecl()->getType()->isCountAttributedType()) {
+        const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
+        if (const FieldDecl *CountFD = FindCountedByField(FAMDecl)) {
+          QualType PtrTy = Context.getPointerType(CountFD->getType());
+          Result = CStyleCastExpr::Create(
+              Context, PtrTy, VK_LValue, CK_BitCast, Result.get(), nullptr,
+              FPOptionsOverride(), Context.CreateTypeSourceInfo(PtrTy),
+              LParenLoc, RParenLoc);
+        }
+      }
+    }
+  }
+
+  return Result;
 }
 
 Expr *Sema::BuildBuiltinCallExpr(SourceLocation Loc, Builtin::ID Id,

>From e3583c785f7237667744f752f39846521caaf305 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 7 Aug 2024 10:32:28 -0700
Subject: [PATCH 02/59] If the 'counted_by' attribute doesn't exist, then
 return nullptr.

---
 clang/lib/CodeGen/CGBuiltin.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 8b1cc9f23a7e90..a6d7516e35fcdb 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3708,6 +3708,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
         const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
         if (const FieldDecl *CountFD = FindCountedByField(FAMDecl))
           Result = GetCountedByFieldExprGEP(ME, FAMDecl, CountFD);
+      } else {
+        E->getType()->dump();
+        ConvertType(E->getType())->dump();
+        Result = llvm::ConstantPointerNull::get(cast<llvm::PointerType>(ConvertType(E->getType())));
       }
     }
 

>From 053bfcd519abb766ef8ea05252751d07e480bd04 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 7 Aug 2024 10:36:01 -0700
Subject: [PATCH 03/59] Remove debugging code.

---
 clang/lib/CodeGen/CGBuiltin.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index a6d7516e35fcdb..f457ac99ee2957 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3709,8 +3709,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
         if (const FieldDecl *CountFD = FindCountedByField(FAMDecl))
           Result = GetCountedByFieldExprGEP(ME, FAMDecl, CountFD);
       } else {
-        E->getType()->dump();
-        ConvertType(E->getType())->dump();
         Result = llvm::ConstantPointerNull::get(cast<llvm::PointerType>(ConvertType(E->getType())));
       }
     }

>From 4ce6525c31f077182fc4d205a811c55f090a5748 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 7 Aug 2024 10:38:42 -0700
Subject: [PATCH 04/59] Make returning a nullptr the default.

---
 clang/lib/CodeGen/CGBuiltin.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index f457ac99ee2957..6321976c551e5e 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3692,7 +3692,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
                                              /*EmittedE=*/nullptr, IsDynamic));
   }
   case Builtin::BI__builtin_get_counted_by: {
-    llvm::Value *Result = nullptr;
+    llvm::Value *Result =
+        llvm::ConstantPointerNull::get(cast<llvm::PointerType>(ConvertType(E->getType())));
 
     if (const MemberExpr *ME =
             dyn_cast<MemberExpr>(E->getArg(0)->IgnoreImpCasts())) {
@@ -3708,8 +3709,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
         const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
         if (const FieldDecl *CountFD = FindCountedByField(FAMDecl))
           Result = GetCountedByFieldExprGEP(ME, FAMDecl, CountFD);
-      } else {
-        Result = llvm::ConstantPointerNull::get(cast<llvm::PointerType>(ConvertType(E->getType())));
       }
     }
 

>From 8017e733cc74c39a2c50fbc9dafb0966ebb59fca Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 7 Aug 2024 10:39:05 -0700
Subject: [PATCH 05/59] clang-format

---
 clang/lib/CodeGen/CGBuiltin.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 6321976c551e5e..41dc9d83f62e26 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3692,8 +3692,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
                                              /*EmittedE=*/nullptr, IsDynamic));
   }
   case Builtin::BI__builtin_get_counted_by: {
-    llvm::Value *Result =
-        llvm::ConstantPointerNull::get(cast<llvm::PointerType>(ConvertType(E->getType())));
+    llvm::Value *Result = llvm::ConstantPointerNull::get(
+        cast<llvm::PointerType>(ConvertType(E->getType())));
 
     if (const MemberExpr *ME =
             dyn_cast<MemberExpr>(E->getArg(0)->IgnoreImpCasts())) {

>From 8808431e646252f11002358a5fc6ff6f1fc29b12 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 7 Aug 2024 13:54:22 -0700
Subject: [PATCH 06/59] Use a visitor to retrieve the MemberExpr. It's
 intentionally harsh and ignores pretty much everythings that may 'hide' the
 underlying MemberExpr.

---
 clang/lib/CodeGen/CGBuiltin.cpp | 47 +++++++++++++++++++++++++++----
 clang/lib/Sema/SemaExpr.cpp     | 50 +++++++++++++++++++++++++++++----
 2 files changed, 87 insertions(+), 10 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 41dc9d83f62e26..929a00a844bbdb 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -30,6 +30,7 @@
 #include "clang/AST/OSLog.h"
 #include "clang/AST/OperationKinds.h"
 #include "clang/AST/Type.h"
+#include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/TargetBuiltins.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/TargetOptions.h"
@@ -2638,6 +2639,45 @@ static RValue EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
   return RValue::get(CGF->Builder.CreateCall(UBF, Args));
 }
 
+namespace {
+
+/// MemberExprVisitor - Find the MemberExpr through all of the casts, array
+/// subscripts, and unary ops. This intentionally avoids all of them because
+/// we're interested only in the MemberExpr to check if it's a flexible array
+/// member.
+class MemberExprVisitor
+    : public ConstStmtVisitor<MemberExprVisitor, const Expr *> {
+public:
+  //===--------------------------------------------------------------------===//
+  //                            Visitor Methods
+  //===--------------------------------------------------------------------===//
+
+  const Expr *Visit(const Expr *E) {
+    return ConstStmtVisitor<MemberExprVisitor, const Expr *>::Visit(E);
+  }
+  const Expr *VisitStmt(const Stmt *S) { return nullptr; }
+
+  const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
+
+  const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+    return Visit(E->getBase());
+  }
+  const Expr *VisitCastExpr(const CastExpr *E) {
+    return Visit(E->getSubExpr());
+  }
+  const Expr *VisitParenExpr(const ParenExpr *E) {
+    return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryAddrOf(const clang::UnaryOperator *E) {
+    return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryDeref(const clang::UnaryOperator *E) {
+    return Visit(E->getSubExpr());
+  }
+};
+
+} // anonymous namespace
+
 RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
                                         const CallExpr *E,
                                         ReturnValueSlot ReturnValue) {
@@ -3695,15 +3735,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
     llvm::Value *Result = llvm::ConstantPointerNull::get(
         cast<llvm::PointerType>(ConvertType(E->getType())));
 
-    if (const MemberExpr *ME =
-            dyn_cast<MemberExpr>(E->getArg(0)->IgnoreImpCasts())) {
+    if (const Expr *Ptr = MemberExprVisitor().Visit(E->getArg(0))) {
+      const MemberExpr *ME = cast<MemberExpr>(Ptr);
       bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
               getContext(), getLangOpts().getStrictFlexArraysLevel(),
               /*IgnoreTemplateOrMacroSubstitution=*/false);
 
-      // TODO: Probably have to handle horrible casting crap here.
-
-      // FIXME: Emit a diagnostic?
       if (!ME->HasSideEffects(getContext()) && IsFlexibleArrayMember &&
           ME->getMemberDecl()->getType()->isCountAttributedType()) {
         const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 4b83978a0d380b..1ec80fa5849a4a 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -30,6 +30,7 @@
 #include "clang/AST/OperationKinds.h"
 #include "clang/AST/ParentMapContext.h"
 #include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/AST/StmtVisitor.h"
 #include "clang/AST/Type.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/Basic/Builtins.h"
@@ -6482,6 +6483,45 @@ const FieldDecl *FindCountedByField(const FieldDecl *FD) {
   return dyn_cast<FieldDecl>(CountDecl);
 }
 
+namespace {
+
+/// MemberExprVisitor - Find the MemberExpr through all of the casts, array
+/// subscripts, and unary ops. This intentionally avoids all of them because
+/// we're interested only in the MemberExpr to check if it's a flexible array
+/// member.
+class MemberExprVisitor
+    : public ConstStmtVisitor<MemberExprVisitor, const Expr *> {
+public:
+  //===--------------------------------------------------------------------===//
+  //                            Visitor Methods
+  //===--------------------------------------------------------------------===//
+
+  const Expr *Visit(const Expr *E) {
+    return ConstStmtVisitor<MemberExprVisitor, const Expr *>::Visit(E);
+  }
+  const Expr *VisitStmt(const Stmt *S) { return nullptr; }
+
+  const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
+
+  const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+    return Visit(E->getBase());
+  }
+  const Expr *VisitCastExpr(const CastExpr *E) {
+    return Visit(E->getSubExpr());
+  }
+  const Expr *VisitParenExpr(const ParenExpr *E) {
+    return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryAddrOf(const UnaryOperator *E) {
+    return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryDeref(const UnaryOperator *E) {
+    return Visit(E->getSubExpr());
+  }
+};
+
+} // anonymous namespace
+
 ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
                                MultiExprArg ArgExprs, SourceLocation RParenLoc,
                                Expr *ExecConfig, bool IsExecConfig,
@@ -6685,19 +6725,19 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
 
   if (FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
       FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_get_counted_by) {
-    if (const MemberExpr *ME =
-            dyn_cast<MemberExpr>(ArgExprs[0]->IgnoreImpCasts())) {
+    if (const Expr *Ptr = MemberExprVisitor().Visit(ArgExprs[0])) {
+      const MemberExpr *ME = cast<MemberExpr>(Ptr);
       bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
               Context, getLangOpts().getStrictFlexArraysLevel(),
               /*IgnoreTemplateOrMacroSubstitution=*/false);
 
-      // TODO: Probably have to handle horrible casting crap here.
-
-      // FIXME: Emit a diagnostic?
       if (!ME->HasSideEffects(Context) && IsFlexibleArrayMember &&
           ME->getMemberDecl()->getType()->isCountAttributedType()) {
         const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
         if (const FieldDecl *CountFD = FindCountedByField(FAMDecl)) {
+          // The builtin returns a 'size_t *', however 'size_t' might not be
+          // the type of the count field. Thus we create an explicit c-style
+          // cast to ensure the proper types going forward.
           QualType PtrTy = Context.getPointerType(CountFD->getType());
           Result = CStyleCastExpr::Create(
               Context, PtrTy, VK_LValue, CK_BitCast, Result.get(), nullptr,

>From 122d2b858f6b3b6519bd9ed0298caa284a85e917 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 7 Aug 2024 15:11:45 -0700
Subject: [PATCH 07/59] Add testcases.

---
 clang/lib/CodeGen/CGBuiltin.cpp             |  4 +-
 clang/lib/Sema/SemaExpr.cpp                 |  4 +-
 clang/test/CodeGen/builtin-get-counted-by.c | 83 +++++++++++++++++++++
 clang/test/Sema/builtin-get-counted-by.c    | 22 ++++++
 4 files changed, 109 insertions(+), 4 deletions(-)
 create mode 100644 clang/test/CodeGen/builtin-get-counted-by.c
 create mode 100644 clang/test/Sema/builtin-get-counted-by.c

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 929a00a844bbdb..6089f6a3d66b63 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3738,8 +3738,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
     if (const Expr *Ptr = MemberExprVisitor().Visit(E->getArg(0))) {
       const MemberExpr *ME = cast<MemberExpr>(Ptr);
       bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
-              getContext(), getLangOpts().getStrictFlexArraysLevel(),
-              /*IgnoreTemplateOrMacroSubstitution=*/false);
+          getContext(), getLangOpts().getStrictFlexArraysLevel(),
+          /*IgnoreTemplateOrMacroSubstitution=*/false);
 
       if (!ME->HasSideEffects(getContext()) && IsFlexibleArrayMember &&
           ME->getMemberDecl()->getType()->isCountAttributedType()) {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 1ec80fa5849a4a..bb82791f05e4f5 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -6728,8 +6728,8 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
     if (const Expr *Ptr = MemberExprVisitor().Visit(ArgExprs[0])) {
       const MemberExpr *ME = cast<MemberExpr>(Ptr);
       bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
-              Context, getLangOpts().getStrictFlexArraysLevel(),
-              /*IgnoreTemplateOrMacroSubstitution=*/false);
+          Context, getLangOpts().getStrictFlexArraysLevel(),
+          /*IgnoreTemplateOrMacroSubstitution=*/false);
 
       if (!ME->HasSideEffects(Context) && IsFlexibleArrayMember &&
           ME->getMemberDecl()->getType()->isCountAttributedType()) {
diff --git a/clang/test/CodeGen/builtin-get-counted-by.c b/clang/test/CodeGen/builtin-get-counted-by.c
new file mode 100644
index 00000000000000..8209db6a77111e
--- /dev/null
+++ b/clang/test/CodeGen/builtin-get-counted-by.c
@@ -0,0 +1,83 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=X86_64
+// RUN: %clang_cc1 -triple i386-unknown-unknown -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=I386
+
+struct s {
+  char x;
+  short count;
+  int array[] __attribute__((counted_by(count)));
+};
+
+// X86_64-LABEL: define dso_local noalias noundef ptr @test1(
+// X86_64-SAME: i32 noundef [[SIZE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// X86_64-NEXT:  [[ENTRY:.*:]]
+// X86_64-NEXT:    [[CONV:%.*]] = sext i32 [[SIZE]] to i64
+// X86_64-NEXT:    [[MUL:%.*]] = shl nsw i64 [[CONV]], 2
+// X86_64-NEXT:    [[ADD:%.*]] = add nsw i64 [[MUL]], 4
+// X86_64-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3:[0-9]+]]
+// X86_64-NEXT:    [[CONV1:%.*]] = trunc i32 [[SIZE]] to i16
+// X86_64-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 2
+// X86_64-NEXT:    store i16 [[CONV1]], ptr [[DOT_COUNTED_BY_GEP]], align 2, !tbaa [[TBAA2:![0-9]+]]
+// X86_64-NEXT:    ret ptr [[CALL]]
+//
+// I386-LABEL: define dso_local noalias noundef ptr @test1(
+// I386-SAME: i32 noundef [[SIZE:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+// I386-NEXT:  [[ENTRY:.*:]]
+// I386-NEXT:    [[MUL:%.*]] = shl i32 [[SIZE]], 2
+// I386-NEXT:    [[ADD:%.*]] = add i32 [[MUL]], 4
+// I386-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3:[0-9]+]]
+// I386-NEXT:    [[CONV:%.*]] = trunc i32 [[SIZE]] to i16
+// I386-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i32 2
+// I386-NEXT:    store i16 [[CONV]], ptr [[DOT_COUNTED_BY_GEP]], align 2, !tbaa [[TBAA3:![0-9]+]]
+// I386-NEXT:    ret ptr [[CALL]]
+//
+struct s *test1(int size) {
+  struct s *p = __builtin_malloc(sizeof(struct s) + sizeof(int) * size);
+
+  *__builtin_get_counted_by(p->array) = size;
+  *__builtin_get_counted_by(&p->array[0]) = size;
+  return p;
+}
+
+struct z {
+  char x;
+  short count;
+  int array[];
+};
+
+// X86_64-LABEL: define dso_local noalias noundef ptr @test2(
+// X86_64-SAME: i32 noundef [[SIZE:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
+// X86_64-NEXT:  [[ENTRY:.*:]]
+// X86_64-NEXT:    [[CONV:%.*]] = sext i32 [[SIZE]] to i64
+// X86_64-NEXT:    [[MUL:%.*]] = shl nsw i64 [[CONV]], 2
+// X86_64-NEXT:    [[ADD:%.*]] = add nsw i64 [[MUL]], 4
+// X86_64-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3]]
+// X86_64-NEXT:    ret ptr [[CALL]]
+//
+// I386-LABEL: define dso_local noalias noundef ptr @test2(
+// I386-SAME: i32 noundef [[SIZE:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
+// I386-NEXT:  [[ENTRY:.*:]]
+// I386-NEXT:    [[MUL:%.*]] = shl i32 [[SIZE]], 2
+// I386-NEXT:    [[ADD:%.*]] = add i32 [[MUL]], 4
+// I386-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3]]
+// I386-NEXT:    ret ptr [[CALL]]
+//
+struct z *test2(int size) {
+  struct z *p = __builtin_malloc(sizeof(struct z) + sizeof(int) * size);
+
+  if (__builtin_get_counted_by(&p->array[0]))
+    *__builtin_get_counted_by(&p->array[0]) = size;
+
+  return p;
+}
+//.
+// X86_64: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0}
+// X86_64: [[META3]] = !{!"short", [[META4:![0-9]+]], i64 0}
+// X86_64: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0}
+// X86_64: [[META5]] = !{!"Simple C/C++ TBAA"}
+//.
+// I386: [[TBAA3]] = !{[[META4:![0-9]+]], [[META4]], i64 0}
+// I386: [[META4]] = !{!"short", [[META5:![0-9]+]], i64 0}
+// I386: [[META5]] = !{!"omnipotent char", [[META6:![0-9]+]], i64 0}
+// I386: [[META6]] = !{!"Simple C/C++ TBAA"}
+//.
diff --git a/clang/test/Sema/builtin-get-counted-by.c b/clang/test/Sema/builtin-get-counted-by.c
new file mode 100644
index 00000000000000..18cef35b0509a1
--- /dev/null
+++ b/clang/test/Sema/builtin-get-counted-by.c
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct fam_struct {
+  char x;
+  short count;
+  int array[] __attribute__((counted_by(count)));
+} *p;
+
+struct non_fam_struct {
+  char x;
+  short count;
+  int array[];
+} *q;
+
+void foo(int size) {
+  *__builtin_get_counted_by(p->array) = size;
+
+  if (__builtin_get_counted_by(q->array))
+    *__builtin_get_counted_by(q->array) = size;
+
+  *__builtin_get_counted_by(p->count) = size; // expected-error{{incompatible integer to pointer conversion passing 'short' to parameter of type 'void *'}}
+}

>From 2b58283f9e16c81bf82905f5bc2168766fba5f9e Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 8 Aug 2024 16:51:24 -0700
Subject: [PATCH 08/59] Combine the code to grab the MemberExpr, if it exists.

---
 clang/include/clang/AST/Expr.h  | 10 +++++--
 clang/lib/AST/Expr.cpp          | 43 ++++++++++++++++++++++++++++++
 clang/lib/CodeGen/CGBuiltin.cpp | 45 ++------------------------------
 clang/lib/Sema/SemaExpr.cpp     | 46 ++-------------------------------
 4 files changed, 55 insertions(+), 89 deletions(-)

diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 466c65a9685ad3..236214ac42ba64 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -537,8 +537,8 @@ class Expr : public ValueStmt {
   /// semantically correspond to a bool.
   bool isKnownToHaveBooleanValue(bool Semantic = true) const;
 
-  /// Check whether this array fits the idiom of a flexible array member,
-  /// depending on the value of -fstrict-flex-array.
+  /// isFlexibleArrayMemberLike - Check whether this array fits the idiom of a
+  /// flexible array member, depending on the value of -fstrict-flex-array.
   /// When IgnoreTemplateOrMacroSubstitution is set, it doesn't consider sizes
   /// resulting from the substitution of a macro or a template as special sizes.
   bool isFlexibleArrayMemberLike(
@@ -546,6 +546,12 @@ class Expr : public ValueStmt {
       LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel,
       bool IgnoreTemplateOrMacroSubstitution = false) const;
 
+  /// getMemberExpr - Find the first MemberExpr of the Expr. This method
+  /// intentionally looks through all casts, array subscripts, and unary
+  /// operators to find an underlying MemberExpr. If one doesn't exist, it
+  /// returns a nullptr.
+  const MemberExpr *getMemberExpr() const;
+
   /// isIntegerConstantExpr - Return the value if this expression is a valid
   /// integer constant expression.  If not a valid i-c-e, return std::nullopt
   /// and fill in Loc (if specified) with the location of the invalid
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index bf2c1b92fa6b49..c87f0f1d518e38 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -223,6 +223,49 @@ bool Expr::isFlexibleArrayMemberLike(
                                          IgnoreTemplateOrMacroSubstitution);
 }
 
+namespace {
+
+/// MemberExprVisitor - Find the MemberExpr through all of the casts, array
+/// subscripts, and unary ops. This intentionally avoids all of them because
+/// we're interested only in the MemberExpr to check if it's a flexible array
+/// member.
+class MemberExprVisitor
+    : public ConstStmtVisitor<MemberExprVisitor, const Expr *> {
+public:
+  //===--------------------------------------------------------------------===//
+  //                            Visitor Methods
+  //===--------------------------------------------------------------------===//
+
+  const Expr *Visit(const Expr *E) {
+    return ConstStmtVisitor<MemberExprVisitor, const Expr *>::Visit(E);
+  }
+  const Expr *VisitStmt(const Stmt *S) { return nullptr; }
+
+  const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
+
+  const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+    return Visit(E->getBase());
+  }
+  const Expr *VisitCastExpr(const CastExpr *E) {
+    return Visit(E->getSubExpr());
+  }
+  const Expr *VisitParenExpr(const ParenExpr *E) {
+    return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryAddrOf(const UnaryOperator *E) {
+    return Visit(E->getSubExpr());
+  }
+  const Expr *VisitUnaryDeref(const UnaryOperator *E) {
+    return Visit(E->getSubExpr());
+  }
+};
+
+} // anonymous namespace
+
+const MemberExpr *Expr::getMemberExpr() const {
+  return dyn_cast_if_present<MemberExpr>(MemberExprVisitor().Visit(this));
+}
+
 const ValueDecl *
 Expr::getAsBuiltinConstantDeclRef(const ASTContext &Context) const {
   Expr::EvalResult Eval;
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 6089f6a3d66b63..c2c7f24fa75af9 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -2639,45 +2639,6 @@ static RValue EmitHipStdParUnsupportedBuiltin(CodeGenFunction *CGF,
   return RValue::get(CGF->Builder.CreateCall(UBF, Args));
 }
 
-namespace {
-
-/// MemberExprVisitor - Find the MemberExpr through all of the casts, array
-/// subscripts, and unary ops. This intentionally avoids all of them because
-/// we're interested only in the MemberExpr to check if it's a flexible array
-/// member.
-class MemberExprVisitor
-    : public ConstStmtVisitor<MemberExprVisitor, const Expr *> {
-public:
-  //===--------------------------------------------------------------------===//
-  //                            Visitor Methods
-  //===--------------------------------------------------------------------===//
-
-  const Expr *Visit(const Expr *E) {
-    return ConstStmtVisitor<MemberExprVisitor, const Expr *>::Visit(E);
-  }
-  const Expr *VisitStmt(const Stmt *S) { return nullptr; }
-
-  const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
-
-  const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
-    return Visit(E->getBase());
-  }
-  const Expr *VisitCastExpr(const CastExpr *E) {
-    return Visit(E->getSubExpr());
-  }
-  const Expr *VisitParenExpr(const ParenExpr *E) {
-    return Visit(E->getSubExpr());
-  }
-  const Expr *VisitUnaryAddrOf(const clang::UnaryOperator *E) {
-    return Visit(E->getSubExpr());
-  }
-  const Expr *VisitUnaryDeref(const clang::UnaryOperator *E) {
-    return Visit(E->getSubExpr());
-  }
-};
-
-} // anonymous namespace
-
 RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
                                         const CallExpr *E,
                                         ReturnValueSlot ReturnValue) {
@@ -3735,11 +3696,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
     llvm::Value *Result = llvm::ConstantPointerNull::get(
         cast<llvm::PointerType>(ConvertType(E->getType())));
 
-    if (const Expr *Ptr = MemberExprVisitor().Visit(E->getArg(0))) {
-      const MemberExpr *ME = cast<MemberExpr>(Ptr);
+    if (const MemberExpr *ME = E->getArg(0)->getMemberExpr()) {
       bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
-          getContext(), getLangOpts().getStrictFlexArraysLevel(),
-          /*IgnoreTemplateOrMacroSubstitution=*/false);
+          getContext(), getLangOpts().getStrictFlexArraysLevel());
 
       if (!ME->HasSideEffects(getContext()) && IsFlexibleArrayMember &&
           ME->getMemberDecl()->getType()->isCountAttributedType()) {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index bb82791f05e4f5..8acad00485d469 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -30,7 +30,6 @@
 #include "clang/AST/OperationKinds.h"
 #include "clang/AST/ParentMapContext.h"
 #include "clang/AST/RecursiveASTVisitor.h"
-#include "clang/AST/StmtVisitor.h"
 #include "clang/AST/Type.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/Basic/Builtins.h"
@@ -6483,45 +6482,6 @@ const FieldDecl *FindCountedByField(const FieldDecl *FD) {
   return dyn_cast<FieldDecl>(CountDecl);
 }
 
-namespace {
-
-/// MemberExprVisitor - Find the MemberExpr through all of the casts, array
-/// subscripts, and unary ops. This intentionally avoids all of them because
-/// we're interested only in the MemberExpr to check if it's a flexible array
-/// member.
-class MemberExprVisitor
-    : public ConstStmtVisitor<MemberExprVisitor, const Expr *> {
-public:
-  //===--------------------------------------------------------------------===//
-  //                            Visitor Methods
-  //===--------------------------------------------------------------------===//
-
-  const Expr *Visit(const Expr *E) {
-    return ConstStmtVisitor<MemberExprVisitor, const Expr *>::Visit(E);
-  }
-  const Expr *VisitStmt(const Stmt *S) { return nullptr; }
-
-  const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
-
-  const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
-    return Visit(E->getBase());
-  }
-  const Expr *VisitCastExpr(const CastExpr *E) {
-    return Visit(E->getSubExpr());
-  }
-  const Expr *VisitParenExpr(const ParenExpr *E) {
-    return Visit(E->getSubExpr());
-  }
-  const Expr *VisitUnaryAddrOf(const UnaryOperator *E) {
-    return Visit(E->getSubExpr());
-  }
-  const Expr *VisitUnaryDeref(const UnaryOperator *E) {
-    return Visit(E->getSubExpr());
-  }
-};
-
-} // anonymous namespace
-
 ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
                                MultiExprArg ArgExprs, SourceLocation RParenLoc,
                                Expr *ExecConfig, bool IsExecConfig,
@@ -6725,11 +6685,9 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
 
   if (FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
       FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_get_counted_by) {
-    if (const Expr *Ptr = MemberExprVisitor().Visit(ArgExprs[0])) {
-      const MemberExpr *ME = cast<MemberExpr>(Ptr);
+    if (const MemberExpr *ME = ArgExprs[0]->getMemberExpr()) {
       bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
-          Context, getLangOpts().getStrictFlexArraysLevel(),
-          /*IgnoreTemplateOrMacroSubstitution=*/false);
+          Context, getLangOpts().getStrictFlexArraysLevel());
 
       if (!ME->HasSideEffects(Context) && IsFlexibleArrayMember &&
           ME->getMemberDecl()->getType()->isCountAttributedType()) {

>From 76f01fe2e4721bb608a7383d061e551c00fe8423 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 9 Aug 2024 16:38:50 -0700
Subject: [PATCH 09/59] Move FindCountedByField into a central place.

---
 clang/include/clang/AST/Decl.h      |  2 +-
 clang/lib/AST/Decl.cpp              |  2 +-
 clang/lib/CodeGen/CGBuiltin.cpp     |  4 ++--
 clang/lib/CodeGen/CGExpr.cpp        |  2 +-
 clang/lib/CodeGen/CodeGenFunction.h |  4 ----
 clang/lib/Sema/SemaExpr.cpp         | 19 +------------------
 6 files changed, 6 insertions(+), 27 deletions(-)

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 7ff35d73df5997..310427b919d28b 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3212,7 +3212,7 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
 
   /// Find the FieldDecl specified in a FAM's "counted_by" attribute. Returns
   /// \p nullptr if either the attribute or the field doesn't exist.
-  const FieldDecl *findCountedByField() const;
+  const FieldDecl *FindCountedByField() const;
 
 private:
   void setLazyInClassInitializer(LazyDeclStmtPtr NewInit);
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 86913763ef9ff5..31e1a7111a4219 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -4699,7 +4699,7 @@ void FieldDecl::printName(raw_ostream &OS, const PrintingPolicy &Policy) const {
   DeclaratorDecl::printName(OS, Policy);
 }
 
-const FieldDecl *FieldDecl::findCountedByField() const {
+const FieldDecl *FieldDecl::FindCountedByField() const {
   const auto *CAT = getType()->getAs<CountAttributedType>();
   if (!CAT)
     return nullptr;
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index c2c7f24fa75af9..097a75f154e38c 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -1083,7 +1083,7 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
     // attribute.
     return nullptr;
 
-  const FieldDecl *CountedByFD = FAMDecl->findCountedByField();
+  const FieldDecl *CountedByFD = FAMDecl->FindCountedByField();
   if (!CountedByFD)
     // Can't find the field referenced by the "counted_by" attribute.
     return nullptr;
@@ -3703,7 +3703,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
       if (!ME->HasSideEffects(getContext()) && IsFlexibleArrayMember &&
           ME->getMemberDecl()->getType()->isCountAttributedType()) {
         const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
-        if (const FieldDecl *CountFD = FindCountedByField(FAMDecl))
+        if (const FieldDecl *CountFD = FAMDecl->FindCountedByField())
           Result = GetCountedByFieldExprGEP(ME, FAMDecl, CountFD);
       }
     }
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 3364a00c6e9ff7..b6cc36f29e5dcb 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4371,7 +4371,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
           ME->isFlexibleArrayMemberLike(getContext(), StrictFlexArraysLevel) &&
           ME->getMemberDecl()->getType()->isCountAttributedType()) {
         const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
-        if (const FieldDecl *CountFD = FAMDecl->findCountedByField()) {
+        if (const FieldDecl *CountFD = FAMDecl->FindCountedByField()) {
           if (std::optional<int64_t> Diff =
                   getOffsetDifferenceInBits(*this, CountFD, FAMDecl)) {
             CharUnits OffsetDiff = CGM.getContext().toCharUnitsFromBits(*Diff);
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index a370a2fe5f5775..90dc399f1341f3 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3305,10 +3305,6 @@ class CodeGenFunction : public CodeGenTypeCache {
                                         const FieldDecl *FAMDecl,
                                         uint64_t &Offset);
 
-  /// Find the FieldDecl specified in a FAM's "counted_by" attribute. Returns
-  /// \p nullptr if either the attribute or the field doesn't exist.
-  const FieldDecl *FindCountedByField(const FieldDecl *FD);
-
   llvm::Value *GetCountedByFieldExprGEP(const Expr *Base,
                                         const FieldDecl *FAMDecl,
                                         const FieldDecl *CountDecl);
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 8acad00485d469..c905a22da14ccd 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -6462,26 +6462,9 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
       currentEvaluationContext().ReferenceToConsteval.erase(DRE);
     }
   }
-
   return Call;
 }
 
-const FieldDecl *FindCountedByField(const FieldDecl *FD) {
-  if (!FD)
-    return nullptr;
-
-  const auto *CAT = FD->getType()->getAs<CountAttributedType>();
-  if (!CAT)
-    return nullptr;
-
-  const auto *CountDRE = cast<DeclRefExpr>(CAT->getCountExpr());
-  const auto *CountDecl = CountDRE->getDecl();
-  if (const auto *IFD = dyn_cast<IndirectFieldDecl>(CountDecl))
-    CountDecl = IFD->getAnonField();
-
-  return dyn_cast<FieldDecl>(CountDecl);
-}
-
 ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
                                MultiExprArg ArgExprs, SourceLocation RParenLoc,
                                Expr *ExecConfig, bool IsExecConfig,
@@ -6692,7 +6675,7 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
       if (!ME->HasSideEffects(Context) && IsFlexibleArrayMember &&
           ME->getMemberDecl()->getType()->isCountAttributedType()) {
         const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
-        if (const FieldDecl *CountFD = FindCountedByField(FAMDecl)) {
+        if (const FieldDecl *CountFD = FAMDecl->FindCountedByField()) {
           // The builtin returns a 'size_t *', however 'size_t' might not be
           // the type of the count field. Thus we create an explicit c-style
           // cast to ensure the proper types going forward.

>From c95e38c9e8d3b6870aca5e365753d16a91c8be08 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 14 Aug 2024 12:11:27 -0700
Subject: [PATCH 10/59] Use CustomTypeChecking for the builtin. It allows us
 explicitly to set the return type based on the 'count' field's type.

---
 clang/include/clang/Basic/Builtins.td         |  4 +-
 .../clang/Basic/DiagnosticSemaKinds.td        |  5 +++
 clang/include/clang/Sema/Sema.h               |  2 +
 clang/lib/AST/Expr.cpp                        |  5 ---
 clang/lib/Sema/SemaChecking.cpp               | 42 +++++++++++++++++++
 clang/lib/Sema/SemaExpr.cpp                   | 29 +------------
 6 files changed, 53 insertions(+), 34 deletions(-)

diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 81e7e581ecb243..5f9aded810d982 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4917,6 +4917,6 @@ def ArithmeticFence : LangBuiltin<"ALL_LANGUAGES"> {
 
 def GetCountedBy : Builtin {
   let Spellings = ["__builtin_get_counted_by"];
-  let Attributes = [NoThrow];
-  let Prototype = "size_t*(void*)";
+  let Attributes = [NoThrow, CustomTypeChecking];
+  let Prototype = "int(...)";
 }
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 34ff49d7238a7f..04b1ab864f97ad 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6652,6 +6652,11 @@ def warn_counted_by_attr_elt_type_unknown_size :
   Warning<err_counted_by_attr_pointee_unknown_size.Summary>,
   InGroup<BoundsSafetyCountedByEltTyUnknownSize>;
 
+def err_builtin_get_counted_by_has_side_effects : Error<
+  "__builtin_get_counted_by cannot have side-effects">;
+def err_builtin_get_counted_by_must_be_pointer : Error<
+  "__builtin_get_counted_by argument must be a pointer">;
+
 let CategoryName = "ARC Semantic Issue" in {
 
 // ARC-mode diagnostics.
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 93d98e1cbb9c81..7dc2a39dc3a4db 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2510,6 +2510,8 @@ class Sema final : public SemaBase {
 
   bool BuiltinNonDeterministicValue(CallExpr *TheCall);
 
+  bool BuiltinGetCountedBy(CallExpr *TheCall);
+
   // Matrix builtin handling.
   ExprResult BuiltinMatrixTranspose(CallExpr *TheCall, ExprResult CallResult);
   ExprResult BuiltinMatrixColumnMajorLoad(CallExpr *TheCall,
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index c87f0f1d518e38..159a69272ebba3 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -236,11 +236,6 @@ class MemberExprVisitor
   //                            Visitor Methods
   //===--------------------------------------------------------------------===//
 
-  const Expr *Visit(const Expr *E) {
-    return ConstStmtVisitor<MemberExprVisitor, const Expr *>::Visit(E);
-  }
-  const Expr *VisitStmt(const Stmt *S) { return nullptr; }
-
   const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
 
   const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index dae271c1ff5001..9b7f6cd45f380c 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2971,6 +2971,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
     }
     break;
   }
+  case Builtin::BI__builtin_get_counted_by:
+    if (BuiltinGetCountedBy(TheCall))
+      return ExprError();
+    break;
   }
 
   if (getLangOpts().HLSL && HLSL().CheckBuiltinFunctionCall(BuiltinID, TheCall))
@@ -5573,6 +5577,44 @@ bool Sema::BuiltinSetjmp(CallExpr *TheCall) {
   return false;
 }
 
+bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
+  if (checkArgCount(TheCall, 1))
+    return true;
+
+  ExprResult ArgRes = UsualUnaryConversions(TheCall->getArg(0));
+  if (ArgRes.isInvalid())
+    return true;
+
+  const Expr *Arg = ArgRes.get();
+  if (!isa<PointerType>(Arg->getType()))
+    return Diag(Arg->getBeginLoc(),
+                diag::err_builtin_get_counted_by_must_be_pointer)
+           << Arg->getSourceRange();
+
+  if (Arg->HasSideEffects(Context))
+    return Diag(Arg->getBeginLoc(),
+                diag::err_builtin_get_counted_by_has_side_effects)
+           << Arg->getSourceRange();
+
+  // Use 'void *' as the default return type. If the argument doesn't have the
+  // 'counted_by' attribute, it'll return a "nullptr."
+  TheCall->setType(Context.VoidPtrTy);
+
+  if (const MemberExpr *ME = Arg->getMemberExpr();
+      ME &&
+      ME->isFlexibleArrayMemberLike(Context,
+                                    getLangOpts().getStrictFlexArraysLevel()) &&
+      ME->getMemberDecl()->getType()->isCountAttributedType()) {
+    if (const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl()))
+      if (const FieldDecl *CountFD = FAMDecl->FindCountedByField())
+        // The proper return type should be a pointer to the type of the
+        // counted_by's 'count' field.
+        TheCall->setType(Context.getPointerType(CountFD->getType()));
+  }
+
+  return false;
+}
+
 namespace {
 
 class UncoveredArgHandler {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index c905a22da14ccd..ba7baf1476a380 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -6663,33 +6663,8 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
                             VK_PRValue, RParenLoc, CurFPFeatureOverrides());
   }
 
-  Result = BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs, RParenLoc,
-                                 ExecConfig, IsExecConfig);
-
-  if (FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
-      FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_get_counted_by) {
-    if (const MemberExpr *ME = ArgExprs[0]->getMemberExpr()) {
-      bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
-          Context, getLangOpts().getStrictFlexArraysLevel());
-
-      if (!ME->HasSideEffects(Context) && IsFlexibleArrayMember &&
-          ME->getMemberDecl()->getType()->isCountAttributedType()) {
-        const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
-        if (const FieldDecl *CountFD = FAMDecl->FindCountedByField()) {
-          // The builtin returns a 'size_t *', however 'size_t' might not be
-          // the type of the count field. Thus we create an explicit c-style
-          // cast to ensure the proper types going forward.
-          QualType PtrTy = Context.getPointerType(CountFD->getType());
-          Result = CStyleCastExpr::Create(
-              Context, PtrTy, VK_LValue, CK_BitCast, Result.get(), nullptr,
-              FPOptionsOverride(), Context.CreateTypeSourceInfo(PtrTy),
-              LParenLoc, RParenLoc);
-        }
-      }
-    }
-  }
-
-  return Result;
+  return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs, RParenLoc,
+                               ExecConfig, IsExecConfig);
 }
 
 Expr *Sema::BuildBuiltinCallExpr(SourceLocation Loc, Builtin::ID Id,

>From 925fbd2a2cfc2c495a827ecebc7919c06e297d18 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 15 Aug 2024 05:27:19 +0000
Subject: [PATCH 11/59] [Clang][NFC] Move FindCountedByField into FieldDecl
 (#104235)

FindCountedByField can be used in more places than CodeGen. Move it into
FieldDecl to avoid layering issues.
---
 clang/include/clang/AST/Decl.h  | 2 +-
 clang/lib/AST/Decl.cpp          | 2 +-
 clang/lib/CodeGen/CGBuiltin.cpp | 2 +-
 clang/lib/CodeGen/CGExpr.cpp    | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 310427b919d28b..7ff35d73df5997 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3212,7 +3212,7 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
 
   /// Find the FieldDecl specified in a FAM's "counted_by" attribute. Returns
   /// \p nullptr if either the attribute or the field doesn't exist.
-  const FieldDecl *FindCountedByField() const;
+  const FieldDecl *findCountedByField() const;
 
 private:
   void setLazyInClassInitializer(LazyDeclStmtPtr NewInit);
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 31e1a7111a4219..86913763ef9ff5 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -4699,7 +4699,7 @@ void FieldDecl::printName(raw_ostream &OS, const PrintingPolicy &Policy) const {
   DeclaratorDecl::printName(OS, Policy);
 }
 
-const FieldDecl *FieldDecl::FindCountedByField() const {
+const FieldDecl *FieldDecl::findCountedByField() const {
   const auto *CAT = getType()->getAs<CountAttributedType>();
   if (!CAT)
     return nullptr;
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 097a75f154e38c..9d4ca330cf3cda 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -1083,7 +1083,7 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
     // attribute.
     return nullptr;
 
-  const FieldDecl *CountedByFD = FAMDecl->FindCountedByField();
+  const FieldDecl *CountedByFD = FAMDecl->findCountedByField();
   if (!CountedByFD)
     // Can't find the field referenced by the "counted_by" attribute.
     return nullptr;
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index b6cc36f29e5dcb..3364a00c6e9ff7 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4371,7 +4371,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
           ME->isFlexibleArrayMemberLike(getContext(), StrictFlexArraysLevel) &&
           ME->getMemberDecl()->getType()->isCountAttributedType()) {
         const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
-        if (const FieldDecl *CountFD = FAMDecl->FindCountedByField()) {
+        if (const FieldDecl *CountFD = FAMDecl->findCountedByField()) {
           if (std::optional<int64_t> Diff =
                   getOffsetDifferenceInBits(*this, CountFD, FAMDecl)) {
             CharUnits OffsetDiff = CGM.getContext().toCharUnitsFromBits(*Diff);

>From ec62a2b3264f56949a683d2a78f15467bb1dc159 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 14 Aug 2024 22:34:51 -0700
Subject: [PATCH 12/59] Fix a build failure.

---
 clang/lib/CodeGen/CGBuiltin.cpp | 2 +-
 clang/lib/Sema/SemaChecking.cpp | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 9d4ca330cf3cda..4552313f8c348a 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3703,7 +3703,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
       if (!ME->HasSideEffects(getContext()) && IsFlexibleArrayMember &&
           ME->getMemberDecl()->getType()->isCountAttributedType()) {
         const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
-        if (const FieldDecl *CountFD = FAMDecl->FindCountedByField())
+        if (const FieldDecl *CountFD = FAMDecl->findCountedByField())
           Result = GetCountedByFieldExprGEP(ME, FAMDecl, CountFD);
       }
     }
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 9b7f6cd45f380c..6529f5a7a38434 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5606,7 +5606,7 @@ bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
                                     getLangOpts().getStrictFlexArraysLevel()) &&
       ME->getMemberDecl()->getType()->isCountAttributedType()) {
     if (const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl()))
-      if (const FieldDecl *CountFD = FAMDecl->FindCountedByField())
+      if (const FieldDecl *CountFD = FAMDecl->findCountedByField())
         // The proper return type should be a pointer to the type of the
         // counted_by's 'count' field.
         TheCall->setType(Context.getPointerType(CountFD->getType()));

>From d3ca48c77fdafa6ff4f37f53529abf48b4f57cbb Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 15 Aug 2024 02:31:29 -0700
Subject: [PATCH 13/59] Remove empty line.

---
 clang/lib/Sema/SemaExpr.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index ba7baf1476a380..7f3cff1054aeed 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -6662,7 +6662,6 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
     return CallExpr::Create(Context, Fn, ArgExprs, Context.DependentTy,
                             VK_PRValue, RParenLoc, CurFPFeatureOverrides());
   }
-
   return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs, RParenLoc,
                                ExecConfig, IsExecConfig);
 }

>From 85b4474a52f730e7a2d905595d87f7c95147e7b6 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 15 Aug 2024 02:33:15 -0700
Subject: [PATCH 14/59] Remove merge errors.


>From 91a7d1b19bdb7b9d202894d6472a56efb9e63037 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 15 Aug 2024 03:22:54 -0700
Subject: [PATCH 15/59] Use 'size_t *' for the default return type and improve
 the testcase.

---
 clang/lib/Sema/SemaChecking.cpp          |  6 +++---
 clang/test/Sema/builtin-get-counted-by.c | 19 ++++++++++++-------
 2 files changed, 15 insertions(+), 10 deletions(-)

diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 6529f5a7a38434..262fbc740b4a14 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5596,9 +5596,9 @@ bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
                 diag::err_builtin_get_counted_by_has_side_effects)
            << Arg->getSourceRange();
 
-  // Use 'void *' as the default return type. If the argument doesn't have the
-  // 'counted_by' attribute, it'll return a "nullptr."
-  TheCall->setType(Context.VoidPtrTy);
+  // Use 'size_t *' as the default return type. If the argument doesn't have
+  // the 'counted_by' attribute, it'll return a "nullptr."
+  TheCall->setType(Context.getPointerType(Context.getSizeType()));
 
   if (const MemberExpr *ME = Arg->getMemberExpr();
       ME &&
diff --git a/clang/test/Sema/builtin-get-counted-by.c b/clang/test/Sema/builtin-get-counted-by.c
index 18cef35b0509a1..27ae4a440243a5 100644
--- a/clang/test/Sema/builtin-get-counted-by.c
+++ b/clang/test/Sema/builtin-get-counted-by.c
@@ -1,8 +1,8 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
 struct fam_struct {
-  char x;
-  short count;
+  int x;
+  char count;
   int array[] __attribute__((counted_by(count)));
 } *p;
 
@@ -12,11 +12,16 @@ struct non_fam_struct {
   int array[];
 } *q;
 
-void foo(int size) {
-  *__builtin_get_counted_by(p->array) = size;
+void test1(int size) {
+  int i = 0;
 
-  if (__builtin_get_counted_by(q->array))
-    *__builtin_get_counted_by(q->array) = size;
+  *__builtin_get_counted_by(p->array) = size;         // ok
+  *__builtin_get_counted_by(&p->array[i]) = size;     // ok
+  if (__builtin_get_counted_by(q->array))             // ok
+    *__builtin_get_counted_by(q->array) = size;       // ok
 
-  *__builtin_get_counted_by(p->count) = size; // expected-error{{incompatible integer to pointer conversion passing 'short' to parameter of type 'void *'}}
+  __builtin_get_counted_by(&p->array[i++]);           // expected-error {{__builtin_get_counted_by cannot have side-effects}}
+  __builtin_get_counted_by(p->x);                     // expected-error {{__builtin_get_counted_by argument must be a pointer}}
+  __builtin_get_counted_by();                         // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_get_counted_by(p->array, p->x, p->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
 }

>From 2d95e441b4cd4d7a1a5deb14676b1c1ca3b44431 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 15 Aug 2024 13:17:29 -0700
Subject: [PATCH 16/59] Don't use a Visitor to retrieve the MemberExpr. Instead
 accept only non-pathological expressions.

---
 clang/include/clang/AST/Expr.h                |  6 ---
 .../clang/Basic/DiagnosticSemaKinds.td        |  5 ++-
 clang/lib/AST/Expr.cpp                        | 38 -------------------
 clang/lib/CodeGen/CGBuiltin.cpp               | 12 +++++-
 clang/lib/Sema/SemaChecking.cpp               | 17 +++++++--
 clang/test/Sema/builtin-get-counted-by.c      |  3 +-
 6 files changed, 29 insertions(+), 52 deletions(-)

diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 236214ac42ba64..b00f9dab02a29e 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -546,12 +546,6 @@ class Expr : public ValueStmt {
       LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel,
       bool IgnoreTemplateOrMacroSubstitution = false) const;
 
-  /// getMemberExpr - Find the first MemberExpr of the Expr. This method
-  /// intentionally looks through all casts, array subscripts, and unary
-  /// operators to find an underlying MemberExpr. If one doesn't exist, it
-  /// returns a nullptr.
-  const MemberExpr *getMemberExpr() const;
-
   /// isIntegerConstantExpr - Return the value if this expression is a valid
   /// integer constant expression.  If not a valid i-c-e, return std::nullopt
   /// and fill in Loc (if specified) with the location of the invalid
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 04b1ab864f97ad..39c7fe6512cbb0 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6654,8 +6654,9 @@ def warn_counted_by_attr_elt_type_unknown_size :
 
 def err_builtin_get_counted_by_has_side_effects : Error<
   "__builtin_get_counted_by cannot have side-effects">;
-def err_builtin_get_counted_by_must_be_pointer : Error<
-  "__builtin_get_counted_by argument must be a pointer">;
+def err_builtin_get_counted_by_must_be_flex_array_member : Error<
+  "__builtin_get_counted_by argument must be a pointer "
+  "to a flexible array member">;
 
 let CategoryName = "ARC Semantic Issue" in {
 
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 159a69272ebba3..bf2c1b92fa6b49 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -223,44 +223,6 @@ bool Expr::isFlexibleArrayMemberLike(
                                          IgnoreTemplateOrMacroSubstitution);
 }
 
-namespace {
-
-/// MemberExprVisitor - Find the MemberExpr through all of the casts, array
-/// subscripts, and unary ops. This intentionally avoids all of them because
-/// we're interested only in the MemberExpr to check if it's a flexible array
-/// member.
-class MemberExprVisitor
-    : public ConstStmtVisitor<MemberExprVisitor, const Expr *> {
-public:
-  //===--------------------------------------------------------------------===//
-  //                            Visitor Methods
-  //===--------------------------------------------------------------------===//
-
-  const Expr *VisitMemberExpr(const MemberExpr *E) { return E; }
-
-  const Expr *VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
-    return Visit(E->getBase());
-  }
-  const Expr *VisitCastExpr(const CastExpr *E) {
-    return Visit(E->getSubExpr());
-  }
-  const Expr *VisitParenExpr(const ParenExpr *E) {
-    return Visit(E->getSubExpr());
-  }
-  const Expr *VisitUnaryAddrOf(const UnaryOperator *E) {
-    return Visit(E->getSubExpr());
-  }
-  const Expr *VisitUnaryDeref(const UnaryOperator *E) {
-    return Visit(E->getSubExpr());
-  }
-};
-
-} // anonymous namespace
-
-const MemberExpr *Expr::getMemberExpr() const {
-  return dyn_cast_if_present<MemberExpr>(MemberExprVisitor().Visit(this));
-}
-
 const ValueDecl *
 Expr::getAsBuiltinConstantDeclRef(const ASTContext &Context) const {
   Expr::EvalResult Eval;
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 4552313f8c348a..d9c37296a404e3 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3696,7 +3696,17 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
     llvm::Value *Result = llvm::ConstantPointerNull::get(
         cast<llvm::PointerType>(ConvertType(E->getType())));
 
-    if (const MemberExpr *ME = E->getArg(0)->getMemberExpr()) {
+    const Expr *Arg = E->getArg(0)->IgnoreParenImpCasts();
+
+    if (auto *UO = dyn_cast<UnaryOperator>(Arg);
+        UO && UO->getOpcode() == UO_AddrOf) {
+      Arg = UO->getSubExpr()->IgnoreParenImpCasts();
+
+      if (auto *ASE = dyn_cast<ArraySubscriptExpr>(Arg))
+        Arg = ASE->getBase()->IgnoreParenImpCasts();
+    }
+
+    if (const MemberExpr *ME = dyn_cast_if_present<MemberExpr>(Arg)) {
       bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
           getContext(), getLangOpts().getStrictFlexArraysLevel());
 
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 262fbc740b4a14..7a1cdd3c4bb7c4 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5585,10 +5585,10 @@ bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
   if (ArgRes.isInvalid())
     return true;
 
-  const Expr *Arg = ArgRes.get();
-  if (!isa<PointerType>(Arg->getType()))
+  const Expr *Arg = ArgRes.get()->IgnoreParenImpCasts();
+  if (!isa<PointerType>(Arg->getType()) && !Arg->getType()->isArrayType())
     return Diag(Arg->getBeginLoc(),
-                diag::err_builtin_get_counted_by_must_be_pointer)
+                diag::err_builtin_get_counted_by_must_be_flex_array_member)
            << Arg->getSourceRange();
 
   if (Arg->HasSideEffects(Context))
@@ -5596,11 +5596,20 @@ bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
                 diag::err_builtin_get_counted_by_has_side_effects)
            << Arg->getSourceRange();
 
+  // See if we have something like '&ptr->fam[0]`.
+  if (auto *UO = dyn_cast<UnaryOperator>(Arg);
+      UO && UO->getOpcode() == UO_AddrOf) {
+    Arg = UO->getSubExpr()->IgnoreParenImpCasts();
+
+    if (auto *ASE = dyn_cast<ArraySubscriptExpr>(Arg))
+      Arg = ASE->getBase()->IgnoreParenImpCasts();
+  }
+
   // Use 'size_t *' as the default return type. If the argument doesn't have
   // the 'counted_by' attribute, it'll return a "nullptr."
   TheCall->setType(Context.getPointerType(Context.getSizeType()));
 
-  if (const MemberExpr *ME = Arg->getMemberExpr();
+  if (const MemberExpr *ME = dyn_cast_if_present<MemberExpr>(Arg);
       ME &&
       ME->isFlexibleArrayMemberLike(Context,
                                     getLangOpts().getStrictFlexArraysLevel()) &&
diff --git a/clang/test/Sema/builtin-get-counted-by.c b/clang/test/Sema/builtin-get-counted-by.c
index 27ae4a440243a5..707d477a974238 100644
--- a/clang/test/Sema/builtin-get-counted-by.c
+++ b/clang/test/Sema/builtin-get-counted-by.c
@@ -17,11 +17,12 @@ void test1(int size) {
 
   *__builtin_get_counted_by(p->array) = size;         // ok
   *__builtin_get_counted_by(&p->array[i]) = size;     // ok
+
   if (__builtin_get_counted_by(q->array))             // ok
     *__builtin_get_counted_by(q->array) = size;       // ok
 
+  __builtin_get_counted_by(p->x);                     // expected-error {{__builtin_get_counted_by argument must be a pointer to a flexible array member}}
   __builtin_get_counted_by(&p->array[i++]);           // expected-error {{__builtin_get_counted_by cannot have side-effects}}
-  __builtin_get_counted_by(p->x);                     // expected-error {{__builtin_get_counted_by argument must be a pointer}}
   __builtin_get_counted_by();                         // expected-error {{too few arguments to function call, expected 1, have 0}}
   __builtin_get_counted_by(p->array, p->x, p->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
 }

>From 9628b0fa083a7c0efc445c50fe339c525f6295ff Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 15 Aug 2024 13:58:46 -0700
Subject: [PATCH 17/59] Improve error messages. Make the side-effects error a
 warning.

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  7 ++---
 clang/lib/Sema/SemaChecking.cpp               | 28 ++++++++++---------
 clang/test/Sema/builtin-get-counted-by.c      | 10 +++----
 3 files changed, 23 insertions(+), 22 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 39c7fe6512cbb0..aa610188c06424 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6652,11 +6652,10 @@ def warn_counted_by_attr_elt_type_unknown_size :
   Warning<err_counted_by_attr_pointee_unknown_size.Summary>,
   InGroup<BoundsSafetyCountedByEltTyUnknownSize>;
 
-def err_builtin_get_counted_by_has_side_effects : Error<
-  "__builtin_get_counted_by cannot have side-effects">;
 def err_builtin_get_counted_by_must_be_flex_array_member : Error<
-  "__builtin_get_counted_by argument must be a pointer "
-  "to a flexible array member">;
+  "'__builtin_get_counted_by' argument must reference a flexible array member">;
+def warn_builtin_get_counted_by_has_side_effects : Warning<
+  "'__builtin_get_counted_by' argument has side-effects that will be discarded">;
 
 let CategoryName = "ARC Semantic Issue" in {
 
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 7a1cdd3c4bb7c4..8a8e6de9a6866b 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5592,9 +5592,8 @@ bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
            << Arg->getSourceRange();
 
   if (Arg->HasSideEffects(Context))
-    return Diag(Arg->getBeginLoc(),
-                diag::err_builtin_get_counted_by_has_side_effects)
-           << Arg->getSourceRange();
+    Diag(Arg->getBeginLoc(), diag::warn_builtin_get_counted_by_has_side_effects)
+        << Arg->getSourceRange();
 
   // See if we have something like '&ptr->fam[0]`.
   if (auto *UO = dyn_cast<UnaryOperator>(Arg);
@@ -5609,16 +5608,19 @@ bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
   // the 'counted_by' attribute, it'll return a "nullptr."
   TheCall->setType(Context.getPointerType(Context.getSizeType()));
 
-  if (const MemberExpr *ME = dyn_cast_if_present<MemberExpr>(Arg);
-      ME &&
-      ME->isFlexibleArrayMemberLike(Context,
-                                    getLangOpts().getStrictFlexArraysLevel()) &&
-      ME->getMemberDecl()->getType()->isCountAttributedType()) {
-    if (const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl()))
-      if (const FieldDecl *CountFD = FAMDecl->findCountedByField())
-        // The proper return type should be a pointer to the type of the
-        // counted_by's 'count' field.
-        TheCall->setType(Context.getPointerType(CountFD->getType()));
+  if (const MemberExpr *ME = dyn_cast_if_present<MemberExpr>(Arg)) {
+    if (!ME->isFlexibleArrayMemberLike(
+            Context, getLangOpts().getStrictFlexArraysLevel()))
+      return Diag(Arg->getBeginLoc(),
+                  diag::err_builtin_get_counted_by_must_be_flex_array_member)
+             << Arg->getSourceRange();
+
+    if (ME->getMemberDecl()->getType()->isCountAttributedType())
+      if (const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl()))
+        if (const FieldDecl *CountFD = FAMDecl->findCountedByField())
+          // The proper return type should be a pointer to the type of the
+          // counted_by's 'count' field.
+          TheCall->setType(Context.getPointerType(CountFD->getType()));
   }
 
   return false;
diff --git a/clang/test/Sema/builtin-get-counted-by.c b/clang/test/Sema/builtin-get-counted-by.c
index 707d477a974238..6dcb1a0ab73754 100644
--- a/clang/test/Sema/builtin-get-counted-by.c
+++ b/clang/test/Sema/builtin-get-counted-by.c
@@ -8,8 +8,8 @@ struct fam_struct {
 
 struct non_fam_struct {
   char x;
+  int array[42];
   short count;
-  int array[];
 } *q;
 
 void test1(int size) {
@@ -18,11 +18,11 @@ void test1(int size) {
   *__builtin_get_counted_by(p->array) = size;         // ok
   *__builtin_get_counted_by(&p->array[i]) = size;     // ok
 
-  if (__builtin_get_counted_by(q->array))             // ok
-    *__builtin_get_counted_by(q->array) = size;       // ok
+  *__builtin_get_counted_by(q->array) = size          // expected-error {{'__builtin_get_counted_by' argument must reference a flexible array member}}
+  *__builtin_get_counted_by(&q->array[0]) = size;     // expected-error {{'__builtin_get_counted_by' argument must reference a flexible array member}}
+  __builtin_get_counted_by(p->x);                     // expected-error {{'__builtin_get_counted_by' argument must reference a flexible array member}}
+  __builtin_get_counted_by(&p->array[i++]);           // expected-warning {{'__builtin_get_counted_by' argument has side-effects that will be discarded}}
 
-  __builtin_get_counted_by(p->x);                     // expected-error {{__builtin_get_counted_by argument must be a pointer to a flexible array member}}
-  __builtin_get_counted_by(&p->array[i++]);           // expected-error {{__builtin_get_counted_by cannot have side-effects}}
   __builtin_get_counted_by();                         // expected-error {{too few arguments to function call, expected 1, have 0}}
   __builtin_get_counted_by(p->array, p->x, p->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
 }

>From c278c1f1f5db5304a75a72327a3575bfb6c3b83d Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 15 Aug 2024 14:25:09 -0700
Subject: [PATCH 18/59] Add _Generic checks.

---
 clang/lib/CodeGen/CGExpr.cpp             |  6 ++--
 clang/test/Sema/builtin-get-counted-by.c | 41 +++++++++++++++++++++++-
 2 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 3364a00c6e9ff7..024a7a47e1398d 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -1174,9 +1174,9 @@ llvm::Value *CodeGenFunction::GetCountedByFieldExprGEP(
     return nullptr;
 
   Indices.push_back(Builder.getInt32(0));
-  return Builder.CreateInBoundsGEP(
-      ConvertType(QualType(RD->getTypeForDecl(), 0)), Res,
-      RecIndicesTy(llvm::reverse(Indices)), "..counted_by.gep");
+  return Builder.CreateGEP(ConvertType(QualType(RD->getTypeForDecl(), 0)), Res,
+                           RecIndicesTy(llvm::reverse(Indices)),
+                           "..counted_by.gep");
 }
 
 /// This method is typically called in contexts where we can't generate
diff --git a/clang/test/Sema/builtin-get-counted-by.c b/clang/test/Sema/builtin-get-counted-by.c
index 6dcb1a0ab73754..898a4702950ec0 100644
--- a/clang/test/Sema/builtin-get-counted-by.c
+++ b/clang/test/Sema/builtin-get-counted-by.c
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c99 -fsyntax-only -verify %s
 
 struct fam_struct {
   int x;
@@ -26,3 +26,42 @@ void test1(int size) {
   __builtin_get_counted_by();                         // expected-error {{too few arguments to function call, expected 1, have 0}}
   __builtin_get_counted_by(p->array, p->x, p->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
 }
+
+struct char_count {
+  char count;
+  int array[] __attribute__((counted_by(count)));
+} *cp;
+
+struct short_count {
+  short count;
+  int array[] __attribute__((counted_by(count)));
+} *sp;
+
+struct int_count {
+  int count;
+  int array[] __attribute__((counted_by(count)));
+} *ip;
+
+struct unsigned_count {
+  unsigned count;
+  int array[] __attribute__((counted_by(count)));
+} *up;
+
+struct long_count {
+  long count;
+  int array[] __attribute__((counted_by(count)));
+} *lp;
+
+struct unsigned_long_count {
+  unsigned long count;
+  int array[] __attribute__((counted_by(count)));
+} *ulp;
+
+void test2(void) {
+  _Static_assert(_Generic(__builtin_get_counted_by(cp->array), char * : 1, default : 0) == 1, "wrong return type");
+  _Static_assert(_Generic(__builtin_get_counted_by(sp->array), short * : 1, default : 0) == 1, "wrong return type");
+  _Static_assert(_Generic(__builtin_get_counted_by(ip->array), int * : 1, default : 0) == 1, "wrong return type");
+  _Static_assert(_Generic(__builtin_get_counted_by(up->array), unsigned int * : 1, default : 0) == 1, "wrong return type");
+  _Static_assert(_Generic(__builtin_get_counted_by(lp->array), long * : 1, default : 0) == 1, "wrong return type");
+  _Static_assert(_Generic(__builtin_get_counted_by(ulp->array), unsigned long * : 1, default : 0) == 1, "wrong return type");
+}

>From 0f42e5d82ed93987d638681218094a95861fa678 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 21 Aug 2024 15:41:06 -0700
Subject: [PATCH 19/59] Remove unrelated change

---
 clang/include/clang/AST/Expr.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index b00f9dab02a29e..466c65a9685ad3 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -537,8 +537,8 @@ class Expr : public ValueStmt {
   /// semantically correspond to a bool.
   bool isKnownToHaveBooleanValue(bool Semantic = true) const;
 
-  /// isFlexibleArrayMemberLike - Check whether this array fits the idiom of a
-  /// flexible array member, depending on the value of -fstrict-flex-array.
+  /// Check whether this array fits the idiom of a flexible array member,
+  /// depending on the value of -fstrict-flex-array.
   /// When IgnoreTemplateOrMacroSubstitution is set, it doesn't consider sizes
   /// resulting from the substitution of a macro or a template as special sizes.
   bool isFlexibleArrayMemberLike(

>From 751a55d2a80535ec616a355b18aac0c066712989 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 21 Aug 2024 15:58:24 -0700
Subject: [PATCH 20/59] Use MemberExpr::Create instead of
 MemberExpr::CreateImplicit.

---
 clang/lib/CodeGen/CGBuiltin.cpp | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index d9c37296a404e3..ef6a4ba1b74e4b 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3712,9 +3712,21 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
 
       if (!ME->HasSideEffects(getContext()) && IsFlexibleArrayMember &&
           ME->getMemberDecl()->getType()->isCountAttributedType()) {
-        const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
-        if (const FieldDecl *CountFD = FAMDecl->findCountedByField())
-          Result = GetCountedByFieldExprGEP(ME, FAMDecl, CountFD);
+        FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
+        if (FieldDecl *CountFD = FAMDecl->findCountedByField()) {
+          QualType CountTy = CountFD->getType();
+
+          MemberExpr *NewME = MemberExpr::Create(
+              Ctx, ME->getBase(), ME->isArrow(), ME->getOperatorLoc(),
+              ME->getQualifierLoc(), ME->getTemplateKeywordLoc(), CountFD,
+              ME->getFoundDecl(),
+              DeclarationNameInfo(CountFD->getDeclName(),
+                                  CountFD->getLocation()),
+              nullptr, CountTy, VK_PRValue, OK_Ordinary, ME->isNonOdrUse());
+          Result = EmitScalarExpr(UnaryOperator::Create(
+              Ctx, NewME, UO_AddrOf, Ctx.getPointerType(CountTy), VK_LValue,
+              OK_Ordinary, SourceLocation(), false, FPOptionsOverride()));
+        }
       }
     }
 

>From 53272cf19b999807279d0a2f60da69f54e32d1a6 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 21 Aug 2024 16:00:42 -0700
Subject: [PATCH 21/59] Regenerate

---
 clang/test/CodeGen/builtin-get-counted-by.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/test/CodeGen/builtin-get-counted-by.c b/clang/test/CodeGen/builtin-get-counted-by.c
index 8209db6a77111e..6f2796850947d4 100644
--- a/clang/test/CodeGen/builtin-get-counted-by.c
+++ b/clang/test/CodeGen/builtin-get-counted-by.c
@@ -16,8 +16,8 @@ struct s {
 // X86_64-NEXT:    [[ADD:%.*]] = add nsw i64 [[MUL]], 4
 // X86_64-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3:[0-9]+]]
 // X86_64-NEXT:    [[CONV1:%.*]] = trunc i32 [[SIZE]] to i16
-// X86_64-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 2
-// X86_64-NEXT:    store i16 [[CONV1]], ptr [[DOT_COUNTED_BY_GEP]], align 2, !tbaa [[TBAA2:![0-9]+]]
+// X86_64-NEXT:    [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 2
+// X86_64-NEXT:    store i16 [[CONV1]], ptr [[COUNT]], align 2, !tbaa [[TBAA2:![0-9]+]]
 // X86_64-NEXT:    ret ptr [[CALL]]
 //
 // I386-LABEL: define dso_local noalias noundef ptr @test1(
@@ -27,8 +27,8 @@ struct s {
 // I386-NEXT:    [[ADD:%.*]] = add i32 [[MUL]], 4
 // I386-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3:[0-9]+]]
 // I386-NEXT:    [[CONV:%.*]] = trunc i32 [[SIZE]] to i16
-// I386-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i32 2
-// I386-NEXT:    store i16 [[CONV]], ptr [[DOT_COUNTED_BY_GEP]], align 2, !tbaa [[TBAA3:![0-9]+]]
+// I386-NEXT:    [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i32 2
+// I386-NEXT:    store i16 [[CONV]], ptr [[COUNT]], align 2, !tbaa [[TBAA3:![0-9]+]]
 // I386-NEXT:    ret ptr [[CALL]]
 //
 struct s *test1(int size) {

>From ecda8e07940c2bb505bcf20d6b3c88b698934679 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 21 Aug 2024 16:19:26 -0700
Subject: [PATCH 22/59] Add -W flag for warning.

---
 clang/include/clang/Basic/DiagnosticGroups.td    | 4 ++++
 clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 ++-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 72eada50a56cc9..e27a94a623fea2 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1482,6 +1482,10 @@ def NoDeref : DiagGroup<"noderef">;
 def BoundsSafetyCountedByEltTyUnknownSize :
   DiagGroup<"bounds-safety-counted-by-elt-type-unknown-size">;
 
+// counted_by warnings
+def CountedByAttribute
+    : DiagGroup<"get-counted-by-side-effects">;
+
 // A group for cross translation unit static analysis related warnings.
 def CrossTU : DiagGroup<"ctu">;
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index aa610188c06424..270bcdc56f996f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6655,7 +6655,8 @@ def warn_counted_by_attr_elt_type_unknown_size :
 def err_builtin_get_counted_by_must_be_flex_array_member : Error<
   "'__builtin_get_counted_by' argument must reference a flexible array member">;
 def warn_builtin_get_counted_by_has_side_effects : Warning<
-  "'__builtin_get_counted_by' argument has side-effects that will be discarded">;
+  "'__builtin_get_counted_by' argument has side-effects that will be discarded">,
+  InGroup<CountedByAttribute>;
 
 let CategoryName = "ARC Semantic Issue" in {
 

>From 612000fb14784eff955c05527460bf883d6aa789 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 22 Aug 2024 16:32:45 -0700
Subject: [PATCH 23/59] Handle any anonymous structs surrounding the flexible
 array member and / or count field.

---
 clang/lib/CodeGen/CGBuiltin.cpp | 50 +++++++++++++++++++++++++++------
 1 file changed, 42 insertions(+), 8 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index ef6a4ba1b74e4b..de602a178fc4da 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3715,16 +3715,50 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
         FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
         if (FieldDecl *CountFD = FAMDecl->findCountedByField()) {
           QualType CountTy = CountFD->getType();
+          SmallVector<NamedDecl *, 2> PathToFD;
+
+          // Reverse through any anonymous structs / unions surrounding the
+          // flexible array member. We'll build any necessary MemberExpr's to
+          // anonymous structs / unions when building a reference to the
+          // 'count' field.
+          RecordDecl *RD = FAMDecl->getParent();
+          DeclContext *DC = RD;
+          for (; DC->isRecord(); DC = DC->getLexicalParent()) {
+            if (!RD->isAnonymousStructOrUnion())
+              break;
+            RD = cast<RecordDecl>(DC);
+            if (auto *Base = dyn_cast<MemberExpr>(ME->getBase()))
+              ME = Base;
+          }
+
+          // See if the count's FieldDecl is within anonymous structs.
+          for (Decl *D : RD->decls()) {
+            if (auto *IFD = dyn_cast<IndirectFieldDecl>(D);
+                IFD && IFD->getAnonField() == CountFD) {
+              PathToFD.insert(PathToFD.begin(), IFD->chain_begin(),
+                              IFD->chain_end());
+              break;
+            }
+          }
+
+          if (PathToFD.empty())
+            PathToFD.push_back(CountFD);
+
+          // Build a MemberExpr to the 'count' field. This accounts for any
+          // anonymous structs / unions that may contain the field.
+          bool isArrow = ME->isArrow();
+          Expr *New = ME->getBase();
+          for (NamedDecl *ND : PathToFD) {
+            ValueDecl *VD = cast<ValueDecl>(ND);
+            New = MemberExpr::CreateImplicit(Ctx, New, isArrow, VD,
+                                             VD->getType(), VK_PRValue,
+                                             OK_Ordinary);
+            isArrow = false;
+          }
 
-          MemberExpr *NewME = MemberExpr::Create(
-              Ctx, ME->getBase(), ME->isArrow(), ME->getOperatorLoc(),
-              ME->getQualifierLoc(), ME->getTemplateKeywordLoc(), CountFD,
-              ME->getFoundDecl(),
-              DeclarationNameInfo(CountFD->getDeclName(),
-                                  CountFD->getLocation()),
-              nullptr, CountTy, VK_PRValue, OK_Ordinary, ME->isNonOdrUse());
+          // The result is a pointer to the 'count' field.
           Result = EmitScalarExpr(UnaryOperator::Create(
-              Ctx, NewME, UO_AddrOf, Ctx.getPointerType(CountTy), VK_LValue,
+              Ctx, New, UO_AddrOf, Ctx.getPointerType(CountTy), VK_LValue,
               OK_Ordinary, SourceLocation(), false, FPOptionsOverride()));
         }
       }

>From b555af9e771317da2cc4e7298855cd3fa324f9ab Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 22 Aug 2024 16:42:58 -0700
Subject: [PATCH 24/59] Add anonymous struct testcase.

---
 clang/lib/CodeGen/CGBuiltin.cpp             |  5 +-
 clang/test/CodeGen/builtin-get-counted-by.c | 71 ++++++++++++++++++---
 2 files changed, 65 insertions(+), 11 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index de602a178fc4da..034e7d55003e3b 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3750,9 +3750,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
           Expr *New = ME->getBase();
           for (NamedDecl *ND : PathToFD) {
             ValueDecl *VD = cast<ValueDecl>(ND);
-            New = MemberExpr::CreateImplicit(Ctx, New, isArrow, VD,
-                                             VD->getType(), VK_PRValue,
-                                             OK_Ordinary);
+            New = MemberExpr::CreateImplicit(
+                Ctx, New, isArrow, VD, VD->getType(), VK_PRValue, OK_Ordinary);
             isArrow = false;
           }
 
diff --git a/clang/test/CodeGen/builtin-get-counted-by.c b/clang/test/CodeGen/builtin-get-counted-by.c
index 6f2796850947d4..96d48eb0dce6aa 100644
--- a/clang/test/CodeGen/builtin-get-counted-by.c
+++ b/clang/test/CodeGen/builtin-get-counted-by.c
@@ -2,7 +2,7 @@
 // RUN: %clang_cc1 -triple x86_64-unknown-unknown -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=X86_64
 // RUN: %clang_cc1 -triple i386-unknown-unknown -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=I386
 
-struct s {
+struct a {
   char x;
   short count;
   int array[] __attribute__((counted_by(count)));
@@ -31,21 +31,74 @@ struct s {
 // I386-NEXT:    store i16 [[CONV]], ptr [[COUNT]], align 2, !tbaa [[TBAA3:![0-9]+]]
 // I386-NEXT:    ret ptr [[CALL]]
 //
-struct s *test1(int size) {
-  struct s *p = __builtin_malloc(sizeof(struct s) + sizeof(int) * size);
+struct a *test1(int size) {
+  struct a *p = __builtin_malloc(sizeof(struct a) + sizeof(int) * size);
 
   *__builtin_get_counted_by(p->array) = size;
   *__builtin_get_counted_by(&p->array[0]) = size;
   return p;
 }
 
-struct z {
+struct b {
+  int _filler;
+  struct {
+    int __filler;
+    struct {
+      int ___filler;
+      struct {
+        char count;
+      };
+    };
+  };
+  struct {
+    int filler_;
+    struct {
+      int filler__;
+      struct {
+        long array[] __attribute__((counted_by(count)));
+      };
+    };
+  };
+};
+
+// X86_64-LABEL: define dso_local noalias noundef ptr @test2(
+// X86_64-SAME: i32 noundef [[SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// X86_64-NEXT:  [[ENTRY:.*:]]
+// X86_64-NEXT:    [[CONV:%.*]] = sext i32 [[SIZE]] to i64
+// X86_64-NEXT:    [[MUL:%.*]] = shl nsw i64 [[CONV]], 2
+// X86_64-NEXT:    [[ADD:%.*]] = add nsw i64 [[MUL]], 4
+// X86_64-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3]]
+// X86_64-NEXT:    [[CONV1:%.*]] = trunc i32 [[SIZE]] to i8
+// X86_64-NEXT:    [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 12
+// X86_64-NEXT:    store i8 [[CONV1]], ptr [[TMP0]], align 1, !tbaa [[TBAA6:![0-9]+]]
+// X86_64-NEXT:    ret ptr [[CALL]]
+//
+// I386-LABEL: define dso_local noalias noundef ptr @test2(
+// I386-SAME: i32 noundef [[SIZE:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// I386-NEXT:  [[ENTRY:.*:]]
+// I386-NEXT:    [[MUL:%.*]] = shl i32 [[SIZE]], 2
+// I386-NEXT:    [[ADD:%.*]] = add i32 [[MUL]], 4
+// I386-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3]]
+// I386-NEXT:    [[CONV:%.*]] = trunc i32 [[SIZE]] to i8
+// I386-NEXT:    [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i32 12
+// I386-NEXT:    store i8 [[CONV]], ptr [[TMP0]], align 1, !tbaa [[TBAA7:![0-9]+]]
+// I386-NEXT:    ret ptr [[CALL]]
+//
+struct b *test2(int size) {
+  struct b *p = __builtin_malloc(sizeof(struct a) + sizeof(int) * size);
+
+  *__builtin_get_counted_by(p->array) = size;
+  *__builtin_get_counted_by(&p->array[0]) = size;
+  return p;
+}
+
+struct c {
   char x;
   short count;
   int array[];
 };
 
-// X86_64-LABEL: define dso_local noalias noundef ptr @test2(
+// X86_64-LABEL: define dso_local noalias noundef ptr @test3(
 // X86_64-SAME: i32 noundef [[SIZE:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
 // X86_64-NEXT:  [[ENTRY:.*:]]
 // X86_64-NEXT:    [[CONV:%.*]] = sext i32 [[SIZE]] to i64
@@ -54,7 +107,7 @@ struct z {
 // X86_64-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3]]
 // X86_64-NEXT:    ret ptr [[CALL]]
 //
-// I386-LABEL: define dso_local noalias noundef ptr @test2(
+// I386-LABEL: define dso_local noalias noundef ptr @test3(
 // I386-SAME: i32 noundef [[SIZE:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
 // I386-NEXT:  [[ENTRY:.*:]]
 // I386-NEXT:    [[MUL:%.*]] = shl i32 [[SIZE]], 2
@@ -62,8 +115,8 @@ struct z {
 // I386-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3]]
 // I386-NEXT:    ret ptr [[CALL]]
 //
-struct z *test2(int size) {
-  struct z *p = __builtin_malloc(sizeof(struct z) + sizeof(int) * size);
+struct c *test3(int size) {
+  struct c *p = __builtin_malloc(sizeof(struct c) + sizeof(int) * size);
 
   if (__builtin_get_counted_by(&p->array[0]))
     *__builtin_get_counted_by(&p->array[0]) = size;
@@ -75,9 +128,11 @@ struct z *test2(int size) {
 // X86_64: [[META3]] = !{!"short", [[META4:![0-9]+]], i64 0}
 // X86_64: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0}
 // X86_64: [[META5]] = !{!"Simple C/C++ TBAA"}
+// X86_64: [[TBAA6]] = !{[[META4]], [[META4]], i64 0}
 //.
 // I386: [[TBAA3]] = !{[[META4:![0-9]+]], [[META4]], i64 0}
 // I386: [[META4]] = !{!"short", [[META5:![0-9]+]], i64 0}
 // I386: [[META5]] = !{!"omnipotent char", [[META6:![0-9]+]], i64 0}
 // I386: [[META6]] = !{!"Simple C/C++ TBAA"}
+// I386: [[TBAA7]] = !{[[META5]], [[META5]], i64 0}
 //.

>From 48707ae3cab49d2c382c19e5ed1f6d37f4c88ac6 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 22 Aug 2024 17:09:12 -0700
Subject: [PATCH 25/59] Report a fatal error if we can't find the 'count'
 field.

---
 clang/lib/CodeGen/CGBuiltin.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 034e7d55003e3b..d2c878ba5c622a 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3759,6 +3759,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
           Result = EmitScalarExpr(UnaryOperator::Create(
               Ctx, New, UO_AddrOf, Ctx.getPointerType(CountTy), VK_LValue,
               OK_Ordinary, SourceLocation(), false, FPOptionsOverride()));
+        } else {
+          llvm::report_fatal_error("Cannot find the counted_by 'count' field");
         }
       }
     }

>From 5c778cadad865cdaf0362cd36057f0047f8c8d00 Mon Sep 17 00:00:00 2001
From: Bill Wendling <isanbard at gmail.com>
Date: Thu, 22 Aug 2024 19:14:13 -0700
Subject: [PATCH 26/59] Use 'cast' instead of 'dyn_cast' and default to 'void
 *' for the return type.

---
 clang/lib/CodeGen/CGBuiltin.cpp | 2 +-
 clang/lib/Sema/SemaChecking.cpp | 9 ++++++---
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index d2c878ba5c622a..be679d08451961 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3712,7 +3712,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
 
       if (!ME->HasSideEffects(getContext()) && IsFlexibleArrayMember &&
           ME->getMemberDecl()->getType()->isCountAttributedType()) {
-        FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl());
+        FieldDecl *FAMDecl = cast<FieldDecl>(ME->getMemberDecl());
         if (FieldDecl *CountFD = FAMDecl->findCountedByField()) {
           QualType CountTy = CountFD->getType();
           SmallVector<NamedDecl *, 2> PathToFD;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 8a8e6de9a6866b..3dfbea960cd0fc 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5578,6 +5578,9 @@ bool Sema::BuiltinSetjmp(CallExpr *TheCall) {
 }
 
 bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
+  // For simplicity, we support only a limited expressions for the argument.
+  // Specifically 'ptr->array' and '&ptr->array[0]'. This allows us to reject
+  // arguments with complex casting, which really shouldn't be a huge problem.
   if (checkArgCount(TheCall, 1))
     return true;
 
@@ -5604,9 +5607,9 @@ bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
       Arg = ASE->getBase()->IgnoreParenImpCasts();
   }
 
-  // Use 'size_t *' as the default return type. If the argument doesn't have
-  // the 'counted_by' attribute, it'll return a "nullptr."
-  TheCall->setType(Context.getPointerType(Context.getSizeType()));
+  // Use 'void *' as the default return type. If the argument doesn't have the
+  // 'counted_by' attribute, it'll return a 'nullptr'.
+  TheCall->setType(Context.getPointerType(Context.VoidTy));
 
   if (const MemberExpr *ME = dyn_cast_if_present<MemberExpr>(Arg)) {
     if (!ME->isFlexibleArrayMemberLike(

>From a1a6ead1335934cb4e84237c8fd8df2a95e3185f Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 23 Aug 2024 15:05:10 -0700
Subject: [PATCH 27/59] A 'void *' can result in an error message about
 assigning to a 'void'. Go back to 'size_t *' as the default return type.

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

diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 3dfbea960cd0fc..bbc1f207b8c7b1 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5607,9 +5607,9 @@ bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
       Arg = ASE->getBase()->IgnoreParenImpCasts();
   }
 
-  // Use 'void *' as the default return type. If the argument doesn't have the
-  // 'counted_by' attribute, it'll return a 'nullptr'.
-  TheCall->setType(Context.getPointerType(Context.VoidTy));
+  // Use 'size_t *' as the default return type. If the argument doesn't have
+  // the 'counted_by' attribute, it'll return a 'nullptr'.
+  TheCall->setType(Context.getPointerType(Context.getSizeType()));
 
   if (const MemberExpr *ME = dyn_cast_if_present<MemberExpr>(Arg)) {
     if (!ME->isFlexibleArrayMemberLike(

>From 6b388b5ce07ef6f5ab7ff29ab0e087894e52194e Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Mon, 26 Aug 2024 16:06:23 -0700
Subject: [PATCH 28/59] Add some documentation.

---
 clang/docs/LanguageExtensions.rst | 60 +++++++++++++++++++++++++++++++
 clang/docs/ReleaseNotes.rst       | 20 +++++++++++
 2 files changed, 80 insertions(+)

diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 10232ff41da15a..eb6a5edcf7c871 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3774,6 +3774,66 @@ type-generic alternative to the ``__builtin_clz{,l,ll}`` (respectively
 ``__builtin_ctz{,l,ll}``) builtins, with support for other integer types, such
 as ``unsigned __int128`` and C23 ``unsigned _BitInt(N)``.
 
+``__builtin_get_counted_by``
+----------------------------
+
+``__builtin_get_counted_by`` returns a pointer to the count field from the
+``counted_by`` attribute.
+
+the argument must be a pointer to a flexible array member. If the argument
+isn't a flexible array member or doesn't have the ``counted_by`` attribute, it
+returns ``(size_t *)0``.
+
+**Syntax**:
+
+.. code-block:: c
+
+  T *__builtin_get_counted_by(void *array)
+
+**Examples**:
+
+.. code-block:: c
+
+  #define alloc(P, FAM, COUNT) ({ \
+     typeof(P) __p = NULL;                                        \
+     __p = malloc(MAX(sizeof(*__p),                               \
+                      sizeof(*__p) + sizeof(*__p->FAM) * COUNT)); \
+     if (__builtin_get_counted_by(__p->FAM))                      \
+       *__builtin_get_counted_by(__p->FAM) = COUNT;               \
+     __p;                                                         \
+  })
+
+**Description**:
+
+the ``__builtin_get_counted_by`` builtin allows the programmer to prevent a
+common error associated with the ``counted_by`` attribute. When using the
+``counted_by`` attribute, the ``count`` field **must** be set before the
+flexible array member can be accessed. Otherwise, the sanitizers may view such
+accesses as false positives. For instance, it's not uncommon for programmers to
+initialize the flexible array before setting the ``count`` field:
+
+.. code-block:: c
+
+  struct s {
+    int dummy;
+    short count;
+    long array[];
+  };
+
+  struct s *ptr = malloc(sizeof(struct s) + sizeof(long) * COUNT);
+
+  for (int i = 0; i < COUNT; ++i)
+    ptr->array[i] = i;
+
+  ptr->count = COUNT;
+
+Enforcing the rule that ``ptr->count = COUNT;`` must occur after every
+allocation of a struct with a flexible array member that has the ``counted_by``
+attribute is prone to failure in large code bases.
+
+This builtin works best with allocators that are implemented via macros (like
+in Linux) where the assignment happens automatically.
+
 Multiprecision Arithmetic Builtins
 ----------------------------------
 
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 4e542ee91a8b36..2af78f1c2261da 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -289,6 +289,26 @@ Non-comprehensive list of changes in this release
   as well as declarations.
 - ``__builtin_abs`` function can now be used in constant expressions.
 
+- The new builtin ``__builtin_get_counted_by`` was added. In contexts where the
+  programmer needs access to the ``counted_by`` attribute's field, but it's not
+  available --- e.g. in macros. For instace, it can be used to automatically
+  set the counter during allocation in the Linux kernel:
+
+  .. code-block:: c
+
+     /* A simplified version of Linux allocation macros */
+     #define alloc(PTR, FAM, COUNT) ({ \
+         typeof(P) __p;                                        \
+         size_t __size = sizeof(*P) + sizeof(*P->FAM) * COUNT; \
+         __p = malloc(__size);                                 \
+         if (__builtin_get_counted_by(__p->FAM))               \
+           *__builtin_get_counted_by(__p->FAM) = COUNT;        \
+         __p;                                                  \
+     })
+
+  The flexible array member (FAM) can now be accessed immediately without causing
+  issues with the sanitizer because the counter is automatically set.
+
 New Compiler Flags
 ------------------
 

>From 791443b1dabe3857d55a6305e531ca0c1395a7bd Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Tue, 10 Sep 2024 14:58:35 -0700
Subject: [PATCH 29/59] Rename to __builtin_counted_by_ref.

---
 clang/docs/LanguageExtensions.rst             | 12 ++++----
 clang/docs/ReleaseNotes.rst                   |  6 ++--
 clang/include/clang/Basic/Builtins.td         |  2 +-
 .../clang/Basic/DiagnosticSemaKinds.td        |  4 +--
 clang/lib/CodeGen/CGBuiltin.cpp               |  2 +-
 clang/lib/Sema/SemaChecking.cpp               |  2 +-
 clang/test/CodeGen/builtin-get-counted-by.c   | 12 ++++----
 clang/test/Sema/builtin-get-counted-by.c      | 28 +++++++++----------
 8 files changed, 34 insertions(+), 34 deletions(-)

diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index eb6a5edcf7c871..e584ea51e515c8 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3774,10 +3774,10 @@ type-generic alternative to the ``__builtin_clz{,l,ll}`` (respectively
 ``__builtin_ctz{,l,ll}``) builtins, with support for other integer types, such
 as ``unsigned __int128`` and C23 ``unsigned _BitInt(N)``.
 
-``__builtin_get_counted_by``
+``__builtin_counted_by_ref``
 ----------------------------
 
-``__builtin_get_counted_by`` returns a pointer to the count field from the
+``__builtin_counted_by_ref`` returns a pointer to the count field from the
 ``counted_by`` attribute.
 
 the argument must be a pointer to a flexible array member. If the argument
@@ -3788,7 +3788,7 @@ returns ``(size_t *)0``.
 
 .. code-block:: c
 
-  T *__builtin_get_counted_by(void *array)
+  T *__builtin_counted_by_ref(void *array)
 
 **Examples**:
 
@@ -3798,14 +3798,14 @@ returns ``(size_t *)0``.
      typeof(P) __p = NULL;                                        \
      __p = malloc(MAX(sizeof(*__p),                               \
                       sizeof(*__p) + sizeof(*__p->FAM) * COUNT)); \
-     if (__builtin_get_counted_by(__p->FAM))                      \
-       *__builtin_get_counted_by(__p->FAM) = COUNT;               \
+     if (__builtin_counted_by_ref(__p->FAM))                      \
+       *__builtin_counted_by_ref(__p->FAM) = COUNT;               \
      __p;                                                         \
   })
 
 **Description**:
 
-the ``__builtin_get_counted_by`` builtin allows the programmer to prevent a
+the ``__builtin_counted_by_ref`` builtin allows the programmer to prevent a
 common error associated with the ``counted_by`` attribute. When using the
 ``counted_by`` attribute, the ``count`` field **must** be set before the
 flexible array member can be accessed. Otherwise, the sanitizers may view such
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 2af78f1c2261da..d63697cd37a86f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -289,7 +289,7 @@ Non-comprehensive list of changes in this release
   as well as declarations.
 - ``__builtin_abs`` function can now be used in constant expressions.
 
-- The new builtin ``__builtin_get_counted_by`` was added. In contexts where the
+- The new builtin ``__builtin_counted_by_ref`` was added. In contexts where the
   programmer needs access to the ``counted_by`` attribute's field, but it's not
   available --- e.g. in macros. For instace, it can be used to automatically
   set the counter during allocation in the Linux kernel:
@@ -301,8 +301,8 @@ Non-comprehensive list of changes in this release
          typeof(P) __p;                                        \
          size_t __size = sizeof(*P) + sizeof(*P->FAM) * COUNT; \
          __p = malloc(__size);                                 \
-         if (__builtin_get_counted_by(__p->FAM))               \
-           *__builtin_get_counted_by(__p->FAM) = COUNT;        \
+         if (__builtin_counted_by_ref(__p->FAM))               \
+           *__builtin_counted_by_ref(__p->FAM) = COUNT;        \
          __p;                                                  \
      })
 
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 5f9aded810d982..57959fb0f30454 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4916,7 +4916,7 @@ def ArithmeticFence : LangBuiltin<"ALL_LANGUAGES"> {
 }
 
 def GetCountedBy : Builtin {
-  let Spellings = ["__builtin_get_counted_by"];
+  let Spellings = ["__builtin_counted_by_ref"];
   let Attributes = [NoThrow, CustomTypeChecking];
   let Prototype = "int(...)";
 }
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 270bcdc56f996f..cfcbc8bc588435 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6653,9 +6653,9 @@ def warn_counted_by_attr_elt_type_unknown_size :
   InGroup<BoundsSafetyCountedByEltTyUnknownSize>;
 
 def err_builtin_get_counted_by_must_be_flex_array_member : Error<
-  "'__builtin_get_counted_by' argument must reference a flexible array member">;
+  "'__builtin_counted_by_ref' argument must reference a flexible array member">;
 def warn_builtin_get_counted_by_has_side_effects : Warning<
-  "'__builtin_get_counted_by' argument has side-effects that will be discarded">,
+  "'__builtin_counted_by_ref' argument has side-effects that will be discarded">,
   InGroup<CountedByAttribute>;
 
 let CategoryName = "ARC Semantic Issue" in {
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index be679d08451961..b6b30beede8c29 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3692,7 +3692,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
     return RValue::get(emitBuiltinObjectSize(E->getArg(0), Type, ResType,
                                              /*EmittedE=*/nullptr, IsDynamic));
   }
-  case Builtin::BI__builtin_get_counted_by: {
+  case Builtin::BI__builtin_counted_by_ref: {
     llvm::Value *Result = llvm::ConstantPointerNull::get(
         cast<llvm::PointerType>(ConvertType(E->getType())));
 
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index bbc1f207b8c7b1..8b61ed3523f552 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2971,7 +2971,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
     }
     break;
   }
-  case Builtin::BI__builtin_get_counted_by:
+  case Builtin::BI__builtin_counted_by_ref:
     if (BuiltinGetCountedBy(TheCall))
       return ExprError();
     break;
diff --git a/clang/test/CodeGen/builtin-get-counted-by.c b/clang/test/CodeGen/builtin-get-counted-by.c
index 96d48eb0dce6aa..3d4c042e5731ea 100644
--- a/clang/test/CodeGen/builtin-get-counted-by.c
+++ b/clang/test/CodeGen/builtin-get-counted-by.c
@@ -34,8 +34,8 @@ struct a {
 struct a *test1(int size) {
   struct a *p = __builtin_malloc(sizeof(struct a) + sizeof(int) * size);
 
-  *__builtin_get_counted_by(p->array) = size;
-  *__builtin_get_counted_by(&p->array[0]) = size;
+  *__builtin_counted_by_ref(p->array) = size;
+  *__builtin_counted_by_ref(&p->array[0]) = size;
   return p;
 }
 
@@ -87,8 +87,8 @@ struct b {
 struct b *test2(int size) {
   struct b *p = __builtin_malloc(sizeof(struct a) + sizeof(int) * size);
 
-  *__builtin_get_counted_by(p->array) = size;
-  *__builtin_get_counted_by(&p->array[0]) = size;
+  *__builtin_counted_by_ref(p->array) = size;
+  *__builtin_counted_by_ref(&p->array[0]) = size;
   return p;
 }
 
@@ -118,8 +118,8 @@ struct c {
 struct c *test3(int size) {
   struct c *p = __builtin_malloc(sizeof(struct c) + sizeof(int) * size);
 
-  if (__builtin_get_counted_by(&p->array[0]))
-    *__builtin_get_counted_by(&p->array[0]) = size;
+  if (__builtin_counted_by_ref(&p->array[0]))
+    *__builtin_counted_by_ref(&p->array[0]) = size;
 
   return p;
 }
diff --git a/clang/test/Sema/builtin-get-counted-by.c b/clang/test/Sema/builtin-get-counted-by.c
index 898a4702950ec0..09547120f330e7 100644
--- a/clang/test/Sema/builtin-get-counted-by.c
+++ b/clang/test/Sema/builtin-get-counted-by.c
@@ -15,16 +15,16 @@ struct non_fam_struct {
 void test1(int size) {
   int i = 0;
 
-  *__builtin_get_counted_by(p->array) = size;         // ok
-  *__builtin_get_counted_by(&p->array[i]) = size;     // ok
+  *__builtin_counted_by_ref(p->array) = size;         // ok
+  *__builtin_counted_by_ref(&p->array[i]) = size;     // ok
 
-  *__builtin_get_counted_by(q->array) = size          // expected-error {{'__builtin_get_counted_by' argument must reference a flexible array member}}
-  *__builtin_get_counted_by(&q->array[0]) = size;     // expected-error {{'__builtin_get_counted_by' argument must reference a flexible array member}}
-  __builtin_get_counted_by(p->x);                     // expected-error {{'__builtin_get_counted_by' argument must reference a flexible array member}}
-  __builtin_get_counted_by(&p->array[i++]);           // expected-warning {{'__builtin_get_counted_by' argument has side-effects that will be discarded}}
+  *__builtin_counted_by_ref(q->array) = size          // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+  *__builtin_counted_by_ref(&q->array[0]) = size;     // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+  __builtin_counted_by_ref(p->x);                     // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+  __builtin_counted_by_ref(&p->array[i++]);           // expected-warning {{'__builtin_counted_by_ref' argument has side-effects that will be discarded}}
 
-  __builtin_get_counted_by();                         // expected-error {{too few arguments to function call, expected 1, have 0}}
-  __builtin_get_counted_by(p->array, p->x, p->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
+  __builtin_counted_by_ref();                         // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_counted_by_ref(p->array, p->x, p->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
 }
 
 struct char_count {
@@ -58,10 +58,10 @@ struct unsigned_long_count {
 } *ulp;
 
 void test2(void) {
-  _Static_assert(_Generic(__builtin_get_counted_by(cp->array), char * : 1, default : 0) == 1, "wrong return type");
-  _Static_assert(_Generic(__builtin_get_counted_by(sp->array), short * : 1, default : 0) == 1, "wrong return type");
-  _Static_assert(_Generic(__builtin_get_counted_by(ip->array), int * : 1, default : 0) == 1, "wrong return type");
-  _Static_assert(_Generic(__builtin_get_counted_by(up->array), unsigned int * : 1, default : 0) == 1, "wrong return type");
-  _Static_assert(_Generic(__builtin_get_counted_by(lp->array), long * : 1, default : 0) == 1, "wrong return type");
-  _Static_assert(_Generic(__builtin_get_counted_by(ulp->array), unsigned long * : 1, default : 0) == 1, "wrong return type");
+  _Static_assert(_Generic(__builtin_counted_by_ref(cp->array), char * : 1, default : 0) == 1, "wrong return type");
+  _Static_assert(_Generic(__builtin_counted_by_ref(sp->array), short * : 1, default : 0) == 1, "wrong return type");
+  _Static_assert(_Generic(__builtin_counted_by_ref(ip->array), int * : 1, default : 0) == 1, "wrong return type");
+  _Static_assert(_Generic(__builtin_counted_by_ref(up->array), unsigned int * : 1, default : 0) == 1, "wrong return type");
+  _Static_assert(_Generic(__builtin_counted_by_ref(lp->array), long * : 1, default : 0) == 1, "wrong return type");
+  _Static_assert(_Generic(__builtin_counted_by_ref(ulp->array), unsigned long * : 1, default : 0) == 1, "wrong return type");
 }

>From 768e7b1573f66555c2cf84457030162493afedc8 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Tue, 10 Sep 2024 15:09:57 -0700
Subject: [PATCH 30/59] Rename method to reflect new builtin name.

---
 clang/include/clang/Basic/Builtins.td | 2 +-
 clang/include/clang/Sema/Sema.h       | 2 +-
 clang/lib/Sema/SemaChecking.cpp       | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 57959fb0f30454..3ae6f190dc56f0 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4915,7 +4915,7 @@ def ArithmeticFence : LangBuiltin<"ALL_LANGUAGES"> {
   let Prototype = "void(...)";
 }
 
-def GetCountedBy : Builtin {
+def CountedByRef : Builtin {
   let Spellings = ["__builtin_counted_by_ref"];
   let Attributes = [NoThrow, CustomTypeChecking];
   let Prototype = "int(...)";
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 7dc2a39dc3a4db..742e0565e50887 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2510,7 +2510,7 @@ class Sema final : public SemaBase {
 
   bool BuiltinNonDeterministicValue(CallExpr *TheCall);
 
-  bool BuiltinGetCountedBy(CallExpr *TheCall);
+  bool BuiltinCountedByRef(CallExpr *TheCall);
 
   // Matrix builtin handling.
   ExprResult BuiltinMatrixTranspose(CallExpr *TheCall, ExprResult CallResult);
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 8b61ed3523f552..3757f75ff5a556 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2972,7 +2972,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
     break;
   }
   case Builtin::BI__builtin_counted_by_ref:
-    if (BuiltinGetCountedBy(TheCall))
+    if (BuiltinCountedByRef(TheCall))
       return ExprError();
     break;
   }
@@ -5577,7 +5577,7 @@ bool Sema::BuiltinSetjmp(CallExpr *TheCall) {
   return false;
 }
 
-bool Sema::BuiltinGetCountedBy(CallExpr *TheCall) {
+bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
   // For simplicity, we support only a limited expressions for the argument.
   // Specifically 'ptr->array' and '&ptr->array[0]'. This allows us to reject
   // arguments with complex casting, which really shouldn't be a huge problem.

>From 4111cc0c10fbf45d6346b793848a0ec2eb8ae0c7 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 11 Sep 2024 14:18:00 -0700
Subject: [PATCH 31/59] Emit an error if the 'count' reference is assigned to a
 variable, used as a function arg, or in a return.

---
 clang/docs/LanguageExtensions.rst               | 17 ++++++++++-------
 .../include/clang/Basic/DiagnosticSemaKinds.td  |  9 +++++++--
 clang/lib/Sema/SemaChecking.cpp                 |  6 +++---
 clang/lib/Sema/SemaExpr.cpp                     |  9 +++++++++
 ...et-counted-by.c => builtin-counted-by-ref.c} |  0
 ...et-counted-by.c => builtin-counted-by-ref.c} | 10 +++++++++-
 6 files changed, 38 insertions(+), 13 deletions(-)
 rename clang/test/CodeGen/{builtin-get-counted-by.c => builtin-counted-by-ref.c} (100%)
 rename clang/test/Sema/{builtin-get-counted-by.c => builtin-counted-by-ref.c} (76%)

diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index e584ea51e515c8..c9915a16480c98 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3780,9 +3780,9 @@ as ``unsigned __int128`` and C23 ``unsigned _BitInt(N)``.
 ``__builtin_counted_by_ref`` returns a pointer to the count field from the
 ``counted_by`` attribute.
 
-the argument must be a pointer to a flexible array member. If the argument
-isn't a flexible array member or doesn't have the ``counted_by`` attribute, it
-returns ``(size_t *)0``.
+The argument must be a pointer to a flexible array member. If the argument
+isn't a flexible array member or doesn't have the ``counted_by`` attribute, the
+builtin returns ``(size_t *)0``.
 
 **Syntax**:
 
@@ -3805,7 +3805,7 @@ returns ``(size_t *)0``.
 
 **Description**:
 
-the ``__builtin_counted_by_ref`` builtin allows the programmer to prevent a
+The ``__builtin_counted_by_ref`` builtin allows the programmer to prevent a
 common error associated with the ``counted_by`` attribute. When using the
 ``counted_by`` attribute, the ``count`` field **must** be set before the
 flexible array member can be accessed. Otherwise, the sanitizers may view such
@@ -3829,10 +3829,13 @@ initialize the flexible array before setting the ``count`` field:
 
 Enforcing the rule that ``ptr->count = COUNT;`` must occur after every
 allocation of a struct with a flexible array member that has the ``counted_by``
-attribute is prone to failure in large code bases.
+attribute is prone to failure in large code bases. This builtin mitigates this
+for allocators (like in Linux) that are implemented via macros where the
+assignment happens automatically.
 
-This builtin works best with allocators that are implemented via macros (like
-in Linux) where the assignment happens automatically.
+**Note: The value returned by ``__builtin_counted_by_ref`` cannot be assigned
+to a variable or passed into a function. Doing so violates bounds safety
+conventions.**
 
 Multiprecision Arithmetic Builtins
 ----------------------------------
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index cfcbc8bc588435..f732c11a4f461e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6652,9 +6652,14 @@ def warn_counted_by_attr_elt_type_unknown_size :
   Warning<err_counted_by_attr_pointee_unknown_size.Summary>,
   InGroup<BoundsSafetyCountedByEltTyUnknownSize>;
 
-def err_builtin_get_counted_by_must_be_flex_array_member : Error<
+// __builtin_counted_by_ref diagnostics:
+def err_builtin_counted_by_ref_must_be_flex_array_member : Error<
   "'__builtin_counted_by_ref' argument must reference a flexible array member">;
-def warn_builtin_get_counted_by_has_side_effects : Warning<
+def err_builtin_counted_by_ref_cannot_leak_reference : Error<
+  "value returned by '__builtin_counted_by_ref' cannot be assigned to a "
+  "variable or used as a function argument">;
+
+def warn_builtin_counted_by_ref_has_side_effects : Warning<
   "'__builtin_counted_by_ref' argument has side-effects that will be discarded">,
   InGroup<CountedByAttribute>;
 
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 3757f75ff5a556..273d4a1ee37816 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5591,11 +5591,11 @@ bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
   const Expr *Arg = ArgRes.get()->IgnoreParenImpCasts();
   if (!isa<PointerType>(Arg->getType()) && !Arg->getType()->isArrayType())
     return Diag(Arg->getBeginLoc(),
-                diag::err_builtin_get_counted_by_must_be_flex_array_member)
+                diag::err_builtin_counted_by_ref_must_be_flex_array_member)
            << Arg->getSourceRange();
 
   if (Arg->HasSideEffects(Context))
-    Diag(Arg->getBeginLoc(), diag::warn_builtin_get_counted_by_has_side_effects)
+    Diag(Arg->getBeginLoc(), diag::warn_builtin_counted_by_ref_has_side_effects)
         << Arg->getSourceRange();
 
   // See if we have something like '&ptr->fam[0]`.
@@ -5615,7 +5615,7 @@ bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
     if (!ME->isFlexibleArrayMemberLike(
             Context, getLangOpts().getStrictFlexArraysLevel()))
       return Diag(Arg->getBeginLoc(),
-                  diag::err_builtin_get_counted_by_must_be_flex_array_member)
+                  diag::err_builtin_counted_by_ref_must_be_flex_array_member)
              << Arg->getSourceRange();
 
     if (ME->getMemberDecl()->getType()->isCountAttributedType())
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 7f3cff1054aeed..e4688bb0f74abc 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -9187,6 +9187,15 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
   LHSType = Context.getCanonicalType(LHSType).getUnqualifiedType();
   RHSType = Context.getCanonicalType(RHSType).getUnqualifiedType();
 
+  // __builtin_counted_by_ref cannot be assigned to a variable, used in
+  // function call, or in a return.
+  if (auto *CE = dyn_cast<CallExpr>(RHS.get())) {
+    if (FunctionDecl *FDecl = CE->getDirectCallee();
+        FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_counted_by_ref)
+      Diag(RHS.get()->getExprLoc(),
+           diag::err_builtin_counted_by_ref_cannot_leak_reference);
+  }
+
   // Common case: no conversion required.
   if (LHSType == RHSType) {
     Kind = CK_NoOp;
diff --git a/clang/test/CodeGen/builtin-get-counted-by.c b/clang/test/CodeGen/builtin-counted-by-ref.c
similarity index 100%
rename from clang/test/CodeGen/builtin-get-counted-by.c
rename to clang/test/CodeGen/builtin-counted-by-ref.c
diff --git a/clang/test/Sema/builtin-get-counted-by.c b/clang/test/Sema/builtin-counted-by-ref.c
similarity index 76%
rename from clang/test/Sema/builtin-get-counted-by.c
rename to clang/test/Sema/builtin-counted-by-ref.c
index 09547120f330e7..c9f6cc32cab395 100644
--- a/clang/test/Sema/builtin-get-counted-by.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -12,8 +12,14 @@ struct non_fam_struct {
   short count;
 } *q;
 
-void test1(int size) {
+void g(char *);
+
+void *test1(int size) {
   int i = 0;
+  char *ref = __builtin_counted_by_ref(p->array);     // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+
+  ref = __builtin_counted_by_ref(p->array);           // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+  g(__builtin_counted_by_ref(p->array));              // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
 
   *__builtin_counted_by_ref(p->array) = size;         // ok
   *__builtin_counted_by_ref(&p->array[i]) = size;     // ok
@@ -25,6 +31,8 @@ void test1(int size) {
 
   __builtin_counted_by_ref();                         // expected-error {{too few arguments to function call, expected 1, have 0}}
   __builtin_counted_by_ref(p->array, p->x, p->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
+
+  return __builtin_counted_by_ref(p->array);          // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
 }
 
 struct char_count {

>From d897d09e5889800dc480f554ca76f8885d75c336 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 11 Sep 2024 15:34:30 -0700
Subject: [PATCH 32/59] Ignore paren casts.

---
 clang/lib/Sema/SemaExpr.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index e4688bb0f74abc..f5d67e8b0bdceb 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -9189,7 +9189,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
 
   // __builtin_counted_by_ref cannot be assigned to a variable, used in
   // function call, or in a return.
-  if (auto *CE = dyn_cast<CallExpr>(RHS.get())) {
+  if (auto *CE = dyn_cast<CallExpr>(RHS.get()->IgnoreParenCasts())) {
     if (FunctionDecl *FDecl = CE->getDirectCallee();
         FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_counted_by_ref)
       Diag(RHS.get()->getExprLoc(),

>From 4f1c3133d4543444f12c4e3cab62a1345c7e3449 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 11 Sep 2024 16:11:14 -0700
Subject: [PATCH 33/59] Don't allow __builtin_counted_by_ref in complex
 expressions.

---
 clang/lib/Sema/SemaExpr.cpp              | 26 ++++++++++++++++++------
 clang/test/Sema/builtin-counted-by-ref.c |  1 +
 2 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index f5d67e8b0bdceb..866271df8b8f82 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -9189,12 +9189,26 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
 
   // __builtin_counted_by_ref cannot be assigned to a variable, used in
   // function call, or in a return.
-  if (auto *CE = dyn_cast<CallExpr>(RHS.get()->IgnoreParenCasts())) {
-    if (FunctionDecl *FDecl = CE->getDirectCallee();
-        FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_counted_by_ref)
-      Diag(RHS.get()->getExprLoc(),
-           diag::err_builtin_counted_by_ref_cannot_leak_reference);
-  }
+  auto FindBuiltinCountedByRefExpr = [](Expr *E) {
+    struct BuiltinCountedByRefVisitor
+        : public RecursiveASTVisitor<BuiltinCountedByRefVisitor> {
+      CallExpr *TheCall = nullptr;
+      bool VisitCallExpr(CallExpr *E) {
+        if (FunctionDecl *FD = E->getDirectCallee())
+          if (FD->getBuiltinID() == Builtin::BI__builtin_counted_by_ref) {
+            TheCall = E;
+            return true;
+          }
+        return false;
+      }
+    } V;
+    V.TraverseStmt(E);
+    return V.TheCall;
+  };
+
+  if (auto *CE = FindBuiltinCountedByRefExpr(RHS.get()))
+    Diag(RHS.get()->getExprLoc(),
+         diag::err_builtin_counted_by_ref_cannot_leak_reference);
 
   // Common case: no conversion required.
   if (LHSType == RHSType) {
diff --git a/clang/test/Sema/builtin-counted-by-ref.c b/clang/test/Sema/builtin-counted-by-ref.c
index c9f6cc32cab395..3f358bf9523120 100644
--- a/clang/test/Sema/builtin-counted-by-ref.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -19,6 +19,7 @@ void *test1(int size) {
   char *ref = __builtin_counted_by_ref(p->array);     // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
 
   ref = __builtin_counted_by_ref(p->array);           // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+  ref = (char *)(int *)(42 + &*__builtin_counted_by_ref(p->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
   g(__builtin_counted_by_ref(p->array));              // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
 
   *__builtin_counted_by_ref(p->array) = size;         // ok

>From 7002f50b19dedf201c6deda3593e2252f744c256 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 11 Sep 2024 16:16:25 -0700
Subject: [PATCH 34/59] Add test case for pointers.

---
 clang/test/Sema/builtin-counted-by-ref.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/clang/test/Sema/builtin-counted-by-ref.c b/clang/test/Sema/builtin-counted-by-ref.c
index 3f358bf9523120..d41a886addef45 100644
--- a/clang/test/Sema/builtin-counted-by-ref.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -8,6 +8,7 @@ struct fam_struct {
 
 struct non_fam_struct {
   char x;
+  long *pointer;
   int array[42];
   short count;
 } *q;
@@ -27,6 +28,8 @@ void *test1(int size) {
 
   *__builtin_counted_by_ref(q->array) = size          // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
   *__builtin_counted_by_ref(&q->array[0]) = size;     // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+  *__builtin_counted_by_ref(q->pointer) = size;       // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+  *__builtin_counted_by_ref(&q->pointer[0]) = size;   // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
   __builtin_counted_by_ref(p->x);                     // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
   __builtin_counted_by_ref(&p->array[i++]);           // expected-warning {{'__builtin_counted_by_ref' argument has side-effects that will be discarded}}
 

>From 7ef517b6d27b7d78d04c049a932b0229bbf1ef0e Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 12 Sep 2024 13:29:01 -0700
Subject: [PATCH 35/59] Add SourceRange to the diagnostic.

---
 clang/lib/Sema/SemaExpr.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 866271df8b8f82..a59c00b7678521 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -9207,8 +9207,9 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
   };
 
   if (auto *CE = FindBuiltinCountedByRefExpr(RHS.get()))
-    Diag(RHS.get()->getExprLoc(),
-         diag::err_builtin_counted_by_ref_cannot_leak_reference);
+    Diag(CE->getExprLoc(),
+         diag::err_builtin_counted_by_ref_cannot_leak_reference)
+        << CE->getSourceRange();
 
   // Common case: no conversion required.
   if (LHSType == RHSType) {

>From 19e00f1f2f75060c9c9049ea7bb63ec0fca3622d Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 12 Sep 2024 18:08:25 -0700
Subject: [PATCH 36/59] Check that __builtin_counted_by_ref isn't used on the
 LHS by a complex equation.

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  3 ++
 clang/lib/Sema/SemaExpr.cpp                   | 37 ++++++++++++++++++-
 clang/test/Sema/builtin-counted-by-ref.c      |  3 ++
 3 files changed, 42 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f732c11a4f461e..cb8660ada25664 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6658,6 +6658,9 @@ def err_builtin_counted_by_ref_must_be_flex_array_member : Error<
 def err_builtin_counted_by_ref_cannot_leak_reference : Error<
   "value returned by '__builtin_counted_by_ref' cannot be assigned to a "
   "variable or used as a function argument">;
+def err_builtin_counted_by_ref_invalid_lhs_use : Error<
+  "value returned by '__builtin_counted_by_ref' cannot be used in "
+  "%select{array subscript|binary}0 expression">;
 
 def warn_builtin_counted_by_ref_has_side_effects : Warning<
   "'__builtin_counted_by_ref' argument has side-effects that will be discarded">,
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index a59c00b7678521..36f9a4f87e9d07 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -9205,7 +9205,6 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
     V.TraverseStmt(E);
     return V.TheCall;
   };
-
   if (auto *CE = FindBuiltinCountedByRefExpr(RHS.get()))
     Diag(CE->getExprLoc(),
          diag::err_builtin_counted_by_ref_cannot_leak_reference)
@@ -13759,6 +13758,42 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
     ConvTy = CheckAssignmentConstraints(Loc, LHSType, RHSType);
   }
 
+  // __builtin_counted_by_ref can't be used in a binary expression or array
+  // subscript on the LHS.
+  int DiagOption = -1;
+  auto FindBuiltinCountedByRefExpr = [&](Expr *E) {
+    struct BuiltinCountedByRefVisitor
+        : public RecursiveASTVisitor<BuiltinCountedByRefVisitor> {
+      CallExpr *TheCall = nullptr;
+      bool InvalidUse = false;
+      int Option = -1;
+
+      bool VisitCallExpr(CallExpr *E) {
+        if (FunctionDecl *FD = E->getDirectCallee();
+            FD && FD->getBuiltinID() == Builtin::BI__builtin_counted_by_ref)
+          TheCall = E;
+        return false;
+      }
+
+      bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
+        InvalidUse = true;
+        Option = 0; // report 'array expression' in diagnostic.
+        return VisitStmt(E->getBase()) || VisitStmt(E->getIdx());
+      }
+      bool VisitBinaryOperator(BinaryOperator *E) {
+        InvalidUse = true;
+        Option = 1; // report 'binary expression' in diagnostic.
+        return VisitStmt(E->getLHS()) || VisitStmt(E->getRHS());
+      }
+    } V;
+    V.TraverseStmt(E);
+    DiagOption = V.Option;
+    return V.InvalidUse ? V.TheCall : nullptr;
+  };
+  if (auto *CE = FindBuiltinCountedByRefExpr(LHSExpr))
+    Diag(CE->getExprLoc(), diag::err_builtin_counted_by_ref_invalid_lhs_use)
+        << DiagOption << CE->getSourceRange();
+
   if (DiagnoseAssignmentResult(ConvTy, Loc, LHSType, RHSType, RHS.get(),
                                AssignmentAction::Assigning))
     return QualType();
diff --git a/clang/test/Sema/builtin-counted-by-ref.c b/clang/test/Sema/builtin-counted-by-ref.c
index d41a886addef45..10938ed4c59bb1 100644
--- a/clang/test/Sema/builtin-counted-by-ref.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -23,6 +23,9 @@ void *test1(int size) {
   ref = (char *)(int *)(42 + &*__builtin_counted_by_ref(p->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
   g(__builtin_counted_by_ref(p->array));              // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
 
+  *(__builtin_counted_by_ref(p->array) + 4) = 37;     // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in binary expression}}
+  __builtin_counted_by_ref(p->array)[3] = 37;         // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in array subscript expression}}
+
   *__builtin_counted_by_ref(p->array) = size;         // ok
   *__builtin_counted_by_ref(&p->array[i]) = size;     // ok
 

>From 8f6ef2847cbb36709db3cc14c63d19bb89c0570f Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 13 Sep 2024 20:16:19 +0000
Subject: [PATCH 37/59] Update clang/include/clang/Basic/DiagnosticSemaKinds.td

make the grammar better.

Co-authored-by: Aaron Ballman <aaron at aaronballman.com>
---
 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 cb8660ada25664..637cf13ad53f4d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6660,7 +6660,7 @@ def err_builtin_counted_by_ref_cannot_leak_reference : Error<
   "variable or used as a function argument">;
 def err_builtin_counted_by_ref_invalid_lhs_use : Error<
   "value returned by '__builtin_counted_by_ref' cannot be used in "
-  "%select{array subscript|binary}0 expression">;
+  "%select{an array subscript|a binary}0 expression">;
 
 def warn_builtin_counted_by_ref_has_side_effects : Warning<
   "'__builtin_counted_by_ref' argument has side-effects that will be discarded">,

>From cd65acca21b260cdfd08d58f5ce4b384783d4114 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 19 Sep 2024 14:47:21 -0700
Subject: [PATCH 38/59] Add a flag indicating that the 'MemberExpr' was once a
 call to '__builtin_counted_by_ref' so that we can issue proper diagnostics.

---
 clang/include/clang/AST/Decl.h              | 13 +++-
 clang/lib/Sema/SemaBoundsSafety.cpp         |  2 +
 clang/lib/Sema/SemaChecking.cpp             | 70 +++++++++++++++++++--
 clang/lib/Sema/SemaExpr.cpp                 | 42 ++++++-------
 clang/test/CodeGen/builtin-counted-by-ref.c |  4 +-
 clang/test/Sema/builtin-counted-by-ref.c    | 62 +++++++++---------
 6 files changed, 131 insertions(+), 62 deletions(-)

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 7ff35d73df5997..96ac7799fb05c0 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3059,9 +3059,11 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
   unsigned BitField : 1;
   LLVM_PREFERRED_TYPE(bool)
   unsigned Mutable : 1;
+  LLVM_PREFERRED_TYPE(bool)
+  unsigned IsBoundsSafetyCounter : 1;
   LLVM_PREFERRED_TYPE(InitStorageKind)
   unsigned StorageKind : 2;
-  mutable unsigned CachedFieldIndex : 28;
+  mutable unsigned CachedFieldIndex : 27;
 
   /// If this is a bitfield with a default member initializer, this
   /// structure is used to represent the two expressions.
@@ -3096,8 +3098,8 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
             TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
             InClassInitStyle InitStyle)
       : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), BitField(false),
-        Mutable(Mutable), StorageKind((InitStorageKind)InitStyle),
-        CachedFieldIndex(0), Init() {
+        Mutable(Mutable), IsBoundsSafetyCounter(false),
+        StorageKind((InitStorageKind)InitStyle), CachedFieldIndex(0), Init() {
     if (BW)
       setBitWidth(BW);
   }
@@ -3127,6 +3129,11 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
   /// Determines whether this is an unnamed bitfield.
   bool isUnnamedBitField() const { return isBitField() && !getDeclName(); }
 
+  /// Returns true if this field decl is referenced by one of the bounds
+  /// safety counter attributes.
+  bool isBoundsSafetyCounter() const { return IsBoundsSafetyCounter; }
+  void setBoundsSafetyCounter(bool V) { IsBoundsSafetyCounter = V; }
+
   /// Determines whether this field is a
   /// representative for an anonymous struct or union. Such fields are
   /// unnamed and are implicitly generated by the implementation to
diff --git a/clang/lib/Sema/SemaBoundsSafety.cpp b/clang/lib/Sema/SemaBoundsSafety.cpp
index d63a2389ea11de..7d39cbd39c98ed 100644
--- a/clang/lib/Sema/SemaBoundsSafety.cpp
+++ b/clang/lib/Sema/SemaBoundsSafety.cpp
@@ -162,6 +162,8 @@ bool Sema::CheckCountedByAttrOnField(FieldDecl *FD, Expr *E, bool CountInBytes,
     return true;
   }
 
+  CountFD->setBoundsSafetyCounter(true);
+
   if (FD->getParent() != CountFD->getParent()) {
     if (CountFD->getParent()->isUnion()) {
       Diag(CountFD->getBeginLoc(), diag::err_count_attr_refer_to_union)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 273d4a1ee37816..bab44c2dd7acf8 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5618,12 +5618,70 @@ bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
                   diag::err_builtin_counted_by_ref_must_be_flex_array_member)
              << Arg->getSourceRange();
 
-    if (ME->getMemberDecl()->getType()->isCountAttributedType())
-      if (const FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl()))
-        if (const FieldDecl *CountFD = FAMDecl->findCountedByField())
-          // The proper return type should be a pointer to the type of the
-          // counted_by's 'count' field.
-          TheCall->setType(Context.getPointerType(CountFD->getType()));
+    if (ME->getMemberDecl()->getType()->isCountAttributedType()) {
+      if (FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
+        if (FieldDecl *CountFD = FAMDecl->findCountedByField()) {
+          // Reverse through any anonymous structs / unions surrounding the
+          // flexible array member. We'll build any necessary MemberExpr's to
+          // anonymous structs / unions when building a reference to the
+          // 'count' field.
+          RecordDecl *RD = FAMDecl->getParent();
+          DeclContext *DC = RD;
+          for (; DC->isRecord(); DC = DC->getLexicalParent()) {
+            if (!RD->isAnonymousStructOrUnion())
+              break;
+            RD = cast<RecordDecl>(DC);
+            if (auto *Base = dyn_cast<MemberExpr>(ME->getBase()))
+              ME = Base;
+          }
+
+          // See if the count's FieldDecl is within anonymous structs.
+          SmallVector<NamedDecl *, 2> PathToFD;
+          for (Decl *D : RD->decls()) {
+            if (auto *IFD = dyn_cast<IndirectFieldDecl>(D);
+                IFD && IFD->getAnonField() == CountFD) {
+              PathToFD.insert(PathToFD.begin(), IFD->chain_begin(),
+                              IFD->chain_end());
+              break;
+            }
+          }
+
+          if (PathToFD.empty())
+            PathToFD.push_back(CountFD);
+
+          // Build a MemberExpr to the 'count' field. This accounts for any
+          // anonymous structs / unions that may contain the field. Use the
+          // CallExpr's SourceLocation for future diagnostics.
+          SourceLocation Loc = TheCall->getBeginLoc();
+          bool isArrow = ME->isArrow();
+          Expr *New = ME->getBase();
+          for (NamedDecl *ND : PathToFD) {
+            ValueDecl *VD = cast<ValueDecl>(ND);
+            auto *ME = MemberExpr::CreateImplicit(Context, New, isArrow, VD,
+                                                  VD->getType(), VK_PRValue,
+                                                  OK_Ordinary);
+            ME->setMemberLoc(Loc);
+            New = ME;
+            isArrow = false;
+          }
+
+          return ExprResult(UnaryOperator::Create(
+              Context, New, UO_AddrOf,
+              Context.getPointerType(CountFD->getType()), VK_LValue,
+              OK_Ordinary, Loc, false, FPOptionsOverride()));
+        } else {
+          auto *A = FAMDecl->getAttr<CountedByAttr>();
+          auto *CountDecl = cast<DeclRefExpr>(A->getCount())->getDecl();
+
+          Diag(Arg->getBeginLoc(), diag::err_count_attr_must_be_in_structure)
+              << CountDecl << 0 << Arg->getSourceRange();
+          Diag(CountDecl->getBeginLoc(),
+               diag::note_flexible_array_counted_by_attr_field)
+              << CountDecl << CountDecl->getSourceRange();
+          return ExprError();
+        }
+      }
+    }
   }
 
   return false;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 36f9a4f87e9d07..d980955728d820 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -9192,18 +9192,16 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
   auto FindBuiltinCountedByRefExpr = [](Expr *E) {
     struct BuiltinCountedByRefVisitor
         : public RecursiveASTVisitor<BuiltinCountedByRefVisitor> {
-      CallExpr *TheCall = nullptr;
-      bool VisitCallExpr(CallExpr *E) {
-        if (FunctionDecl *FD = E->getDirectCallee())
-          if (FD->getBuiltinID() == Builtin::BI__builtin_counted_by_ref) {
-            TheCall = E;
-            return true;
-          }
-        return false;
+      MemberExpr *ME = nullptr;
+      bool VisitMemberExpr(MemberExpr *E) {
+        if (auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
+            FD && FD->isBoundsSafetyCounter())
+          ME = E;
+        return true;
       }
     } V;
     V.TraverseStmt(E);
-    return V.TheCall;
+    return V.ME;
   };
   if (auto *CE = FindBuiltinCountedByRefExpr(RHS.get()))
     Diag(CE->getExprLoc(),
@@ -13761,38 +13759,38 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
   // __builtin_counted_by_ref can't be used in a binary expression or array
   // subscript on the LHS.
   int DiagOption = -1;
-  auto FindBuiltinCountedByRefExpr = [&](Expr *E) {
+  auto FindInvalidUseOfBoundsSafetyCounter = [&](Expr *E) {
     struct BuiltinCountedByRefVisitor
         : public RecursiveASTVisitor<BuiltinCountedByRefVisitor> {
-      CallExpr *TheCall = nullptr;
+      MemberExpr *ME = nullptr;
       bool InvalidUse = false;
       int Option = -1;
 
-      bool VisitCallExpr(CallExpr *E) {
-        if (FunctionDecl *FD = E->getDirectCallee();
-            FD && FD->getBuiltinID() == Builtin::BI__builtin_counted_by_ref)
-          TheCall = E;
-        return false;
+      bool VisitMemberExpr(MemberExpr *E) {
+        if (auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
+            FD && FD->isBoundsSafetyCounter())
+          ME = E;
+        return true;
       }
 
       bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
         InvalidUse = true;
         Option = 0; // report 'array expression' in diagnostic.
-        return VisitStmt(E->getBase()) || VisitStmt(E->getIdx());
+        return VisitStmt(E->getBase()) && VisitStmt(E->getIdx());
       }
       bool VisitBinaryOperator(BinaryOperator *E) {
         InvalidUse = true;
         Option = 1; // report 'binary expression' in diagnostic.
-        return VisitStmt(E->getLHS()) || VisitStmt(E->getRHS());
+        return VisitStmt(E->getLHS()) && VisitStmt(E->getRHS());
       }
     } V;
     V.TraverseStmt(E);
     DiagOption = V.Option;
-    return V.InvalidUse ? V.TheCall : nullptr;
+    return V.InvalidUse ? V.ME : nullptr;
   };
-  if (auto *CE = FindBuiltinCountedByRefExpr(LHSExpr))
-    Diag(CE->getExprLoc(), diag::err_builtin_counted_by_ref_invalid_lhs_use)
-        << DiagOption << CE->getSourceRange();
+  if (auto *E = FindInvalidUseOfBoundsSafetyCounter(LHSExpr))
+    Diag(E->getExprLoc(), diag::err_builtin_counted_by_ref_invalid_lhs_use)
+        << DiagOption << E->getSourceRange();
 
   if (DiagnoseAssignmentResult(ConvTy, Loc, LHSType, RHSType, RHS.get(),
                                AssignmentAction::Assigning))
diff --git a/clang/test/CodeGen/builtin-counted-by-ref.c b/clang/test/CodeGen/builtin-counted-by-ref.c
index 3d4c042e5731ea..f27db821702f57 100644
--- a/clang/test/CodeGen/builtin-counted-by-ref.c
+++ b/clang/test/CodeGen/builtin-counted-by-ref.c
@@ -69,7 +69,7 @@ struct b {
 // X86_64-NEXT:    [[ADD:%.*]] = add nsw i64 [[MUL]], 4
 // X86_64-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3]]
 // X86_64-NEXT:    [[CONV1:%.*]] = trunc i32 [[SIZE]] to i8
-// X86_64-NEXT:    [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 12
+// X86_64-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 12
 // X86_64-NEXT:    store i8 [[CONV1]], ptr [[TMP0]], align 1, !tbaa [[TBAA6:![0-9]+]]
 // X86_64-NEXT:    ret ptr [[CALL]]
 //
@@ -80,7 +80,7 @@ struct b {
 // I386-NEXT:    [[ADD:%.*]] = add i32 [[MUL]], 4
 // I386-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3]]
 // I386-NEXT:    [[CONV:%.*]] = trunc i32 [[SIZE]] to i8
-// I386-NEXT:    [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i32 12
+// I386-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i32 12
 // I386-NEXT:    store i8 [[CONV]], ptr [[TMP0]], align 1, !tbaa [[TBAA7:![0-9]+]]
 // I386-NEXT:    ret ptr [[CALL]]
 //
diff --git a/clang/test/Sema/builtin-counted-by-ref.c b/clang/test/Sema/builtin-counted-by-ref.c
index 10938ed4c59bb1..ec6985d1a4fd3a 100644
--- a/clang/test/Sema/builtin-counted-by-ref.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -4,42 +4,46 @@ struct fam_struct {
   int x;
   char count;
   int array[] __attribute__((counted_by(count)));
-} *p;
+};
 
-struct non_fam_struct {
-  char x;
-  long *pointer;
-  int array[42];
-  short count;
-} *q;
-
-void g(char *);
+void test1(struct fam_struct *ptr, int size, int idx) {
+  *__builtin_counted_by_ref(ptr->array) = size;             // ok
+  *__builtin_counted_by_ref(&ptr->array[idx]) = size;       // ok
+}
 
-void *test1(int size) {
-  int i = 0;
-  char *ref = __builtin_counted_by_ref(p->array);     // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+void test2(struct fam_struct *ptr, int idx) {
+  __builtin_counted_by_ref();                               // expected-error {{too few arguments to function call, expected 1, have 0}}
+  __builtin_counted_by_ref(ptr->array, ptr->x, ptr->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
+  __builtin_counted_by_ref(ptr->x);                         // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+  __builtin_counted_by_ref(&ptr->array[idx++]);             // expected-warning {{'__builtin_counted_by_ref' argument has side-effects that will be discarded}} expected-warning {{expression result unused}}
+}
 
-  ref = __builtin_counted_by_ref(p->array);           // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
-  ref = (char *)(int *)(42 + &*__builtin_counted_by_ref(p->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
-  g(__builtin_counted_by_ref(p->array));              // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+void foo(char *);
 
-  *(__builtin_counted_by_ref(p->array) + 4) = 37;     // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in binary expression}}
-  __builtin_counted_by_ref(p->array)[3] = 37;         // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in array subscript expression}}
+void *test3(struct fam_struct *ptr, int size, int idx) {
+  char *ref = __builtin_counted_by_ref(ptr->array);         // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
 
-  *__builtin_counted_by_ref(p->array) = size;         // ok
-  *__builtin_counted_by_ref(&p->array[i]) = size;     // ok
+  ref = __builtin_counted_by_ref(ptr->array);               // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+  ref = (char *)(int *)(42 + &*__builtin_counted_by_ref(ptr->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+  foo(__builtin_counted_by_ref(ptr->array));                // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+  *(__builtin_counted_by_ref(ptr->array) + 4) = 37;         // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in a binary expression}}
+  __builtin_counted_by_ref(ptr->array)[3] = 37;             // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in an array subscript expression}}
 
-  *__builtin_counted_by_ref(q->array) = size          // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
-  *__builtin_counted_by_ref(&q->array[0]) = size;     // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
-  *__builtin_counted_by_ref(q->pointer) = size;       // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
-  *__builtin_counted_by_ref(&q->pointer[0]) = size;   // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
-  __builtin_counted_by_ref(p->x);                     // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
-  __builtin_counted_by_ref(&p->array[i++]);           // expected-warning {{'__builtin_counted_by_ref' argument has side-effects that will be discarded}}
+  return __builtin_counted_by_ref(ptr->array);              // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+}
 
-  __builtin_counted_by_ref();                         // expected-error {{too few arguments to function call, expected 1, have 0}}
-  __builtin_counted_by_ref(p->array, p->x, p->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
+struct non_fam_struct {
+  char x;
+  long *pointer;
+  int array[42];
+  short count;
+};
 
-  return __builtin_counted_by_ref(p->array);          // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+void *test4(struct non_fam_struct *ptr, int size) {
+  *__builtin_counted_by_ref(ptr->array) = size          // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+  *__builtin_counted_by_ref(&ptr->array[0]) = size;     // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+  *__builtin_counted_by_ref(ptr->pointer) = size;       // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+  *__builtin_counted_by_ref(&ptr->pointer[0]) = size;   // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
 }
 
 struct char_count {
@@ -72,7 +76,7 @@ struct unsigned_long_count {
   int array[] __attribute__((counted_by(count)));
 } *ulp;
 
-void test2(void) {
+void test5(void) {
   _Static_assert(_Generic(__builtin_counted_by_ref(cp->array), char * : 1, default : 0) == 1, "wrong return type");
   _Static_assert(_Generic(__builtin_counted_by_ref(sp->array), short * : 1, default : 0) == 1, "wrong return type");
   _Static_assert(_Generic(__builtin_counted_by_ref(ip->array), int * : 1, default : 0) == 1, "wrong return type");

>From 9b36f190be82f3300210cd8e6924aeaf2f54dc2f Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 20 Sep 2024 14:26:50 -0700
Subject: [PATCH 39/59] Remove invalid tests that take the address of the
 bounds counter.

---
 clang/test/CodeGen/attr-counted-by.c | 431 +++++++++++----------------
 1 file changed, 179 insertions(+), 252 deletions(-)

diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c
index f70e552bca26ab..ec350991f176ef 100644
--- a/clang/test/CodeGen/attr-counted-by.c
+++ b/clang/test/CodeGen/attr-counted-by.c
@@ -931,79 +931,6 @@ size_t test10_bdos(struct union_of_fams *p) {
   return __builtin_dynamic_object_size(p->bytes, 1);
 }
 
-// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test11(
-// SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
-// SANITIZE-WITH-ATTR-NEXT:  entry:
-// SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
-// SANITIZE-WITH-ATTR-NEXT:    [[DOTCOUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
-// SANITIZE-WITH-ATTR-NEXT:    [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOTCOUNTED_BY_GEP]], align 4
-// SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = zext i32 [[DOTCOUNTED_BY_LOAD]] to i64, !nosanitize [[META2]]
-// SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = icmp ult i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META2]]
-// SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP1]], label [[CONT3:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
-// SANITIZE-WITH-ATTR:       handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB16:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
-// SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
-// SANITIZE-WITH-ATTR:       cont3:
-// SANITIZE-WITH-ATTR-NEXT:    [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
-// SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[IDXPROM]]
-// SANITIZE-WITH-ATTR-NEXT:    store i32 4, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4]]
-// SANITIZE-WITH-ATTR-NEXT:    ret void
-//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test11(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef writeonly [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
-// NO-SANITIZE-WITH-ATTR-NEXT:  entry:
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[IDXPROM]]
-// NO-SANITIZE-WITH-ATTR-NEXT:    store i32 4, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
-// NO-SANITIZE-WITH-ATTR-NEXT:    ret void
-//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test11(
-// SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
-// SANITIZE-WITHOUT-ATTR-NEXT:  entry:
-// SANITIZE-WITHOUT-ATTR-NEXT:    [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
-// SANITIZE-WITHOUT-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
-// SANITIZE-WITHOUT-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[IDXPROM]]
-// SANITIZE-WITHOUT-ATTR-NEXT:    store i32 4, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
-// SANITIZE-WITHOUT-ATTR-NEXT:    ret void
-//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test11(
-// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef writeonly [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
-// NO-SANITIZE-WITHOUT-ATTR-NEXT:  entry:
-// NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
-// NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
-// NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr [[ARRAY]], i64 0, i64 [[IDXPROM]]
-// NO-SANITIZE-WITHOUT-ATTR-NEXT:    store i32 4, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
-// NO-SANITIZE-WITHOUT-ATTR-NEXT:    ret void
-//
-void test11(struct annotated *p, int index) {
-  p->array[index] = __builtin_dynamic_object_size(&p->count, 1);
-}
-
-// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test11_bdos(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
-// SANITIZE-WITH-ATTR-NEXT:  entry:
-// SANITIZE-WITH-ATTR-NEXT:    ret i64 4
-//
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test11_bdos(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
-// NO-SANITIZE-WITH-ATTR-NEXT:  entry:
-// NO-SANITIZE-WITH-ATTR-NEXT:    ret i64 4
-//
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test11_bdos(
-// SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
-// SANITIZE-WITHOUT-ATTR-NEXT:  entry:
-// SANITIZE-WITHOUT-ATTR-NEXT:    ret i64 4
-//
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test11_bdos(
-// NO-SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR1]] {
-// NO-SANITIZE-WITHOUT-ATTR-NEXT:  entry:
-// NO-SANITIZE-WITHOUT-ATTR-NEXT:    ret i64 4
-//
-size_t test11_bdos(struct annotated *p) {
-  return __builtin_dynamic_object_size(&p->count, 1);
-}
-
 struct {
   struct {
     struct {
@@ -1011,62 +938,62 @@ struct {
     };
   };
   int entries[] __attribute__((__counted_by__(num_entries)));
-} test12_foo;
+} test11_foo;
 
 struct hang {
   int entries[6];
-} test12_bar;
+} test11_bar;
 
-int test12_a, test12_b;
+int test11_a, test11_b;
 
-// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test12(
-// SANITIZE-WITH-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR4:[0-9]+]] {
+// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test11(
+// SANITIZE-WITH-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    [[BAZ:%.*]] = alloca [[STRUCT_HANG:%.*]], align 4
-// SANITIZE-WITH-ATTR-NEXT:    call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR10:[0-9]+]]
-// SANITIZE-WITH-ATTR-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test12_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT9:![0-9]+]]
+// SANITIZE-WITH-ATTR-NEXT:    call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR11:[0-9]+]]
+// SANITIZE-WITH-ATTR-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test11_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT9:![0-9]+]]
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[INDEX]], 6
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = zext i32 [[INDEX]] to i64
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP0]], label [[CONT:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB18:[0-9]+]], i64 [[TMP1]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB17:[0-9]+]], i64 [[TMP1]]) #[[ATTR10]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont:
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [6 x i32], ptr [[BAZ]], i64 0, i64 [[TMP1]]
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4]]
-// SANITIZE-WITH-ATTR-NEXT:    store i32 [[TMP2]], ptr @test12_b, align 4, !tbaa [[TBAA4]]
-// SANITIZE-WITH-ATTR-NEXT:    [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr @test12_foo, align 4
+// SANITIZE-WITH-ATTR-NEXT:    store i32 [[TMP2]], ptr @test11_b, align 4, !tbaa [[TBAA4]]
+// SANITIZE-WITH-ATTR-NEXT:    [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr @test11_foo, align 4
 // SANITIZE-WITH-ATTR-NEXT:    [[DOTNOT:%.*]] = icmp eq i32 [[DOTCOUNTED_BY_LOAD]], 0
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[DOTNOT]], label [[HANDLER_OUT_OF_BOUNDS4:%.*]], label [[HANDLER_TYPE_MISMATCH6:%.*]], !prof [[PROF10:![0-9]+]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds4:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB20:[0-9]+]], i64 0) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB19:[0-9]+]], i64 0) #[[ATTR10]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.type_mismatch6:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_type_mismatch_v1_abort(ptr nonnull @[[GLOB21:[0-9]+]], i64 ptrtoint (ptr getelementptr inbounds nuw (i8, ptr @test12_foo, i64 4) to i64)) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_type_mismatch_v1_abort(ptr nonnull @[[GLOB20:[0-9]+]], i64 ptrtoint (ptr getelementptr inbounds nuw (i8, ptr @test11_foo, i64 4) to i64)) #[[ATTR10]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 //
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test12(
-// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR4:[0-9]+]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test11(
+// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[BAZ:%.*]] = alloca [[STRUCT_HANG:%.*]], align 4
-// NO-SANITIZE-WITH-ATTR-NEXT:    call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR11:[0-9]+]]
-// NO-SANITIZE-WITH-ATTR-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test12_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT7:![0-9]+]]
+// NO-SANITIZE-WITH-ATTR-NEXT:    call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR12:[0-9]+]]
+// NO-SANITIZE-WITH-ATTR-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test11_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT7:![0-9]+]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [6 x i32], ptr [[BAZ]], i64 0, i64 [[IDXPROM]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
-// NO-SANITIZE-WITH-ATTR-NEXT:    store i32 [[TMP0]], ptr @test12_b, align 4, !tbaa [[TBAA2]]
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @test12_foo, i64 4), align 4, !tbaa [[TBAA2]]
-// NO-SANITIZE-WITH-ATTR-NEXT:    store i32 [[TMP1]], ptr @test12_a, align 4, !tbaa [[TBAA2]]
+// NO-SANITIZE-WITH-ATTR-NEXT:    store i32 [[TMP0]], ptr @test11_b, align 4, !tbaa [[TBAA2]]
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @test11_foo, i64 4), align 4, !tbaa [[TBAA2]]
+// NO-SANITIZE-WITH-ATTR-NEXT:    store i32 [[TMP1]], ptr @test11_a, align 4, !tbaa [[TBAA2]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    br label [[FOR_COND:%.*]]
 // NO-SANITIZE-WITH-ATTR:       for.cond:
 // NO-SANITIZE-WITH-ATTR-NEXT:    br label [[FOR_COND]]
 //
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i32 @test12(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i32 @test11(
 // SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR3:[0-9]+]] {
 // SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[BAZ:%.*]] = alloca [[STRUCT_HANG:%.*]], align 4
 // SANITIZE-WITHOUT-ATTR-NEXT:    call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR7:[0-9]+]]
-// SANITIZE-WITHOUT-ATTR-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test12_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT7:![0-9]+]]
+// SANITIZE-WITHOUT-ATTR-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test11_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT7:![0-9]+]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[INDEX]], 6
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP1:%.*]] = zext i32 [[INDEX]] to i64
 // SANITIZE-WITHOUT-ATTR-NEXT:    br i1 [[TMP0]], label [[CONT:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF8:![0-9]+]], !nosanitize [[META9:![0-9]+]]
@@ -1076,63 +1003,63 @@ int test12_a, test12_b;
 // SANITIZE-WITHOUT-ATTR:       cont:
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [6 x i32], ptr [[BAZ]], i64 0, i64 [[TMP1]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
-// SANITIZE-WITHOUT-ATTR-NEXT:    store i32 [[TMP2]], ptr @test12_b, align 4, !tbaa [[TBAA2]]
-// SANITIZE-WITHOUT-ATTR-NEXT:    [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr @test12_foo, align 4
+// SANITIZE-WITHOUT-ATTR-NEXT:    store i32 [[TMP2]], ptr @test11_b, align 4, !tbaa [[TBAA2]]
+// SANITIZE-WITHOUT-ATTR-NEXT:    [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr @test11_foo, align 4
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[DOTNOT:%.*]] = icmp eq i32 [[DOTCOUNTED_BY_LOAD]], 0
 // SANITIZE-WITHOUT-ATTR-NEXT:    br i1 [[DOTNOT]], label [[HANDLER_OUT_OF_BOUNDS4:%.*]], label [[HANDLER_TYPE_MISMATCH6:%.*]], !prof [[PROF10:![0-9]+]], !nosanitize [[META9]]
 // SANITIZE-WITHOUT-ATTR:       handler.out_of_bounds4:
 // SANITIZE-WITHOUT-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB4:[0-9]+]], i64 0) #[[ATTR8]], !nosanitize [[META9]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    unreachable, !nosanitize [[META9]]
 // SANITIZE-WITHOUT-ATTR:       handler.type_mismatch6:
-// SANITIZE-WITHOUT-ATTR-NEXT:    tail call void @__ubsan_handle_type_mismatch_v1_abort(ptr nonnull @[[GLOB5:[0-9]+]], i64 ptrtoint (ptr getelementptr inbounds nuw (i8, ptr @test12_foo, i64 4) to i64)) #[[ATTR8]], !nosanitize [[META9]]
+// SANITIZE-WITHOUT-ATTR-NEXT:    tail call void @__ubsan_handle_type_mismatch_v1_abort(ptr nonnull @[[GLOB5:[0-9]+]], i64 ptrtoint (ptr getelementptr inbounds nuw (i8, ptr @test11_foo, i64 4) to i64)) #[[ATTR8]], !nosanitize [[META9]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    unreachable, !nosanitize [[META9]]
 //
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i32 @test12(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i32 @test11(
 // NO-SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[BAZ:%.*]] = alloca [[STRUCT_HANG:%.*]], align 4
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR9:[0-9]+]]
-// NO-SANITIZE-WITHOUT-ATTR-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test12_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT7:![0-9]+]]
+// NO-SANITIZE-WITHOUT-ATTR-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test11_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT7:![0-9]+]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [6 x i32], ptr [[BAZ]], i64 0, i64 [[IDXPROM]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
-// NO-SANITIZE-WITHOUT-ATTR-NEXT:    store i32 [[TMP0]], ptr @test12_b, align 4, !tbaa [[TBAA2]]
-// NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP1:%.*]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @test12_foo, i64 4), align 4, !tbaa [[TBAA2]]
-// NO-SANITIZE-WITHOUT-ATTR-NEXT:    store i32 [[TMP1]], ptr @test12_a, align 4, !tbaa [[TBAA2]]
+// NO-SANITIZE-WITHOUT-ATTR-NEXT:    store i32 [[TMP0]], ptr @test11_b, align 4, !tbaa [[TBAA2]]
+// NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP1:%.*]] = load i32, ptr getelementptr inbounds nuw (i8, ptr @test11_foo, i64 4), align 4, !tbaa [[TBAA2]]
+// NO-SANITIZE-WITHOUT-ATTR-NEXT:    store i32 [[TMP1]], ptr @test11_a, align 4, !tbaa [[TBAA2]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    br label [[FOR_COND:%.*]]
 // NO-SANITIZE-WITHOUT-ATTR:       for.cond:
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    br label [[FOR_COND]]
 //
-int test12(int index) {
-  struct hang baz = test12_bar;
+int test11(int index) {
+  struct hang baz = test11_bar;
 
-  for (;; test12_a = (&test12_foo)->entries[0])
-    test12_b = baz.entries[index];
+  for (;; test11_a = (&test11_foo)->entries[0])
+    test11_b = baz.entries[index];
 
-  return test12_b;
+  return test11_b;
 }
 
-struct test13_foo {
-  struct test13_bar *domain;
-} test13_f;
+struct test12_foo {
+  struct test12_bar *domain;
+} test12_f;
 
-struct test13_bar {
-  struct test13_bar *parent;
+struct test12_bar {
+  struct test12_bar *parent;
   int revmap_size;
-  struct test13_foo *revmap[] __attribute__((__counted_by__(revmap_size)));
+  struct test12_foo *revmap[] __attribute__((__counted_by__(revmap_size)));
 };
 
-// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test13(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test12(
 // SANITIZE-WITH-ATTR-SAME: i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
-// SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr @test13_f, align 8, !tbaa [[TBAA11:![0-9]+]]
+// SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr @test12_f, align 8, !tbaa [[TBAA11:![0-9]+]]
 // SANITIZE-WITH-ATTR-NEXT:    [[DOTCOUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 8
 // SANITIZE-WITH-ATTR-NEXT:    [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOTCOUNTED_BY_GEP]], align 4
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = zext i32 [[DOTCOUNTED_BY_LOAD]] to i64, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP2:%.*]] = icmp ult i64 [[INDEX]], [[TMP1]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP2]], label [[CONT5:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB24:[0-9]+]], i64 [[INDEX]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB23:[0-9]+]], i64 [[INDEX]]) #[[ATTR10]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont5:
 // SANITIZE-WITH-ATTR-NEXT:    [[REVMAP:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 16
@@ -1140,19 +1067,19 @@ struct test13_bar {
 // SANITIZE-WITH-ATTR-NEXT:    store ptr null, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA14:![0-9]+]]
 // SANITIZE-WITH-ATTR-NEXT:    ret i32 0
 //
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test13(
-// NO-SANITIZE-WITH-ATTR-SAME: i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR7:[0-9]+]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test12(
+// NO-SANITIZE-WITH-ATTR-SAME: i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR8:[0-9]+]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr @test13_f, align 8, !tbaa [[TBAA8:![0-9]+]]
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr @test12_f, align 8, !tbaa [[TBAA8:![0-9]+]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[REVMAP:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 16
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x ptr], ptr [[REVMAP]], i64 0, i64 [[INDEX]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    store ptr null, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA11:![0-9]+]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i32 0
 //
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i32 @test13(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i32 @test12(
 // SANITIZE-WITHOUT-ATTR-SAME: i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITHOUT-ATTR-NEXT:  entry:
-// SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr @test13_f, align 8, !tbaa [[TBAA11:![0-9]+]]
+// SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr @test12_f, align 8, !tbaa [[TBAA11:![0-9]+]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[DOTCOUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 8
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[DOTCOUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOTCOUNTED_BY_GEP]], align 4
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP1:%.*]] = zext i32 [[DOTCOUNTED_BY_LOAD]] to i64, !nosanitize [[META9]]
@@ -1167,42 +1094,42 @@ struct test13_bar {
 // SANITIZE-WITHOUT-ATTR-NEXT:    store ptr null, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA14:![0-9]+]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    ret i32 0
 //
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i32 @test13(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i32 @test12(
 // NO-SANITIZE-WITHOUT-ATTR-SAME: i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:  entry:
-// NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr @test13_f, align 8, !tbaa [[TBAA8:![0-9]+]]
+// NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr @test12_f, align 8, !tbaa [[TBAA8:![0-9]+]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[REVMAP:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 16
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x ptr], ptr [[REVMAP]], i64 0, i64 [[INDEX]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    store ptr null, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA11:![0-9]+]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    ret i32 0
 //
-int test13(long index) {
-  test13_f.domain->revmap[index] = 0;
+int test12(long index) {
+  test12_f.domain->revmap[index] = 0;
   return 0;
 }
 
-struct test14_foo {
+struct test13_foo {
   int x, y;
   int blah[] __attribute__((counted_by(x)));
 };
 
-// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test14(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test13(
 // SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = icmp eq i32 [[IDX]], 0
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP0]], label [[TRAP:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
 // SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB25:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB24:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       trap:
 // SANITIZE-WITH-ATTR-NEXT:    tail call void @llvm.trap() #[[ATTR9]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable
 //
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test14(
-// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test13(
+// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR4]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_TEST14_FOO:%.*]], align 4
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_TEST13_FOO:%.*]], align 4
 // NO-SANITIZE-WITH-ATTR-NEXT:    store i32 1, ptr [[DOTCOMPOUNDLITERAL]], align 4, !tbaa [[TBAA2]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[DOTCOMPOUNDLITERAL]], i64 4
 // NO-SANITIZE-WITH-ATTR-NEXT:    store i32 2, ptr [[Y]], align 4, !tbaa [[TBAA2]]
@@ -1212,7 +1139,7 @@ struct test14_foo {
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i32 [[TMP0]]
 //
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test14(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test13(
 // SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = icmp eq i32 [[IDX]], 0
@@ -1225,10 +1152,10 @@ struct test14_foo {
 // SANITIZE-WITHOUT-ATTR-NEXT:    tail call void @llvm.trap() #[[ATTR8]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    unreachable
 //
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test14(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test13(
 // NO-SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR1]] {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:  entry:
-// NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_TEST14_FOO:%.*]], align 4
+// NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_TEST13_FOO:%.*]], align 4
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    store i32 1, ptr [[DOTCOMPOUNDLITERAL]], align 4, !tbaa [[TBAA2]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[Y:%.*]] = getelementptr inbounds nuw i8, ptr [[DOTCOMPOUNDLITERAL]], i64 4
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    store i32 2, ptr [[Y]], align 4, !tbaa [[TBAA2]]
@@ -1238,32 +1165,32 @@ struct test14_foo {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    ret i32 [[TMP0]]
 //
-int test14(int idx) {
-  return (struct test14_foo){ 1, 2 }.blah[idx];
+int test13(int idx) {
+  return (struct test13_foo){ 1, 2 }.blah[idx];
 }
 
-// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test15(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test14(
 // SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = icmp eq i32 [[IDX]], 0
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP0]], label [[TRAP:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
 // SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB27:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB26:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       trap:
 // SANITIZE-WITH-ATTR-NEXT:    tail call void @llvm.trap() #[[ATTR9]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable
 //
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test15(
-// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test14(
+// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR4]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr getelementptr inbounds nuw (i8, ptr @__const.test15.foo, i64 8), i64 0, i64 [[IDXPROM]]
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr getelementptr inbounds nuw (i8, ptr @__const.test14.foo, i64 8), i64 0, i64 [[IDXPROM]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i32 [[TMP0]]
 //
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test15(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test14(
 // SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = icmp eq i32 [[IDX]], 0
@@ -1276,15 +1203,15 @@ int test14(int idx) {
 // SANITIZE-WITHOUT-ATTR-NEXT:    tail call void @llvm.trap() #[[ATTR8]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    unreachable
 //
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test15(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test14(
 // NO-SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR1]] {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
-// NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr getelementptr inbounds nuw (i8, ptr @__const.test15.foo, i64 8), i64 0, i64 [[IDXPROM]]
+// NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr getelementptr inbounds nuw (i8, ptr @__const.test14.foo, i64 8), i64 0, i64 [[IDXPROM]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    ret i32 [[TMP0]]
 //
-int test15(int idx) {
+int test14(int idx) {
   struct {
     int x, y;
     int blah[] __attribute__((counted_by(x)));
@@ -1293,127 +1220,127 @@ int test15(int idx) {
   return foo.blah[idx];
 }
 
-// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test19(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test15(
+// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    ret i64 -1
 //
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test19(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test15(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i64 -1
 //
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test19(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test15(
 // SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // SANITIZE-WITHOUT-ATTR-NEXT:    ret i64 -1
 //
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test19(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i64 @test15(
 // NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR1]] {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    ret i64 -1
 //
-size_t test19(struct annotated *p) {
+size_t test15(struct annotated *p) {
   // Avoid pointer arithmetic. It could lead to security issues.
   return __builtin_dynamic_object_size(&(p + 42)->array[2], 1);
 }
 
-// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test20(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test16(
+// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    ret i64 -1
 //
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test20(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test16(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i64 -1
 //
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test20(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test16(
 // SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // SANITIZE-WITHOUT-ATTR-NEXT:    ret i64 -1
 //
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test20(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test16(
 // NO-SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR1]] {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    ret i64 -1
 //
-size_t test20(struct annotated *p) {
+size_t test16(struct annotated *p) {
   // Avoid side-effects.
   return __builtin_dynamic_object_size(&(++p)->array[2], 1);
 }
 
-// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test21(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test17(
+// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    ret i64 -1
 //
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test21(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test17(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i64 -1
 //
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test21(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test17(
 // SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // SANITIZE-WITHOUT-ATTR-NEXT:    ret i64 -1
 //
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test21(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test17(
 // NO-SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR1]] {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    ret i64 -1
 //
-size_t test21(struct annotated *p) {
+size_t test17(struct annotated *p) {
   // Avoid side-effects.
   return __builtin_dynamic_object_size(&(p++)->array[2], 1);
 }
 
-// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test22(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test18(
+// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    ret i64 -1
 //
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test22(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test18(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i64 -1
 //
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test22(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test18(
 // SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // SANITIZE-WITHOUT-ATTR-NEXT:    ret i64 -1
 //
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test22(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test18(
 // NO-SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR1]] {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    ret i64 -1
 //
-size_t test22(struct annotated *p) {
+size_t test18(struct annotated *p) {
   // Avoid side-effects.
   return __builtin_dynamic_object_size(&(--p)->array[2], 1);
 }
 
-// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test23(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test19(
 // SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    ret i64 -1
 //
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test23(
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test19(
 // NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i64 -1
 //
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test23(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test19(
 // SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // SANITIZE-WITHOUT-ATTR-NEXT:    ret i64 -1
 //
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test23(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local noundef i64 @test19(
 // NO-SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR1]] {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    ret i64 -1
 //
-size_t test23(struct annotated *p) {
+size_t test19(struct annotated *p) {
   // Avoid side-effects.
   return __builtin_dynamic_object_size(&(p--)->array[2], 1);
 }
@@ -1423,7 +1350,7 @@ struct tests_foo {
   int arr[] __counted_by(count);
 };
 
-// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test24(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test20(
 // SANITIZE-WITH-ATTR-SAME: i32 noundef [[C:%.*]], ptr noundef [[VAR:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[VAR]], i64 40
@@ -1431,40 +1358,40 @@ struct tests_foo {
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = icmp ugt i32 [[DOTCOUNTED_BY_LOAD]], 10
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP0]], label [[CONT4:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB28:[0-9]+]], i64 10) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB27:[0-9]+]], i64 10) #[[ATTR10]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont4:
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX2:%.*]] = getelementptr inbounds i8, ptr [[VAR]], i64 84
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = load i32, ptr [[ARRAYIDX2]], align 4, !tbaa [[TBAA4]]
 // SANITIZE-WITH-ATTR-NEXT:    ret i32 [[TMP1]]
 //
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test24(
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test20(
 // NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[VAR:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, ptr [[VAR]], i64 84
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX1]], align 4, !tbaa [[TBAA2]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i32 [[TMP0]]
 //
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test24(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test20(
 // SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[C:%.*]], ptr noundef [[VAR:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, ptr [[VAR]], i64 84
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX1]], align 4, !tbaa [[TBAA2]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    ret i32 [[TMP0]]
 //
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test24(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test20(
 // NO-SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[VAR:%.*]]) local_unnamed_addr #[[ATTR6:[0-9]+]] {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, ptr [[VAR]], i64 84
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX1]], align 4, !tbaa [[TBAA2]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    ret i32 [[TMP0]]
 //
-int test24(int c, struct tests_foo *var) {
+int test20(int c, struct tests_foo *var) {
   // Invalid: there can't be an array of flexible arrays.
   return var[10].arr[10];
 }
 
-// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test25(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test21(
 // SANITIZE-WITH-ATTR-SAME: i32 noundef [[C:%.*]], ptr noundef [[VAR:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[VAR]], align 8, !tbaa [[TBAA14]]
@@ -1472,22 +1399,22 @@ int test24(int c, struct tests_foo *var) {
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = icmp ugt i32 [[DOTCOUNTED_BY_LOAD]], 10
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP1]], label [[CONT5:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB29:[0-9]+]], i64 10) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB28:[0-9]+]], i64 10) #[[ATTR10]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont5:
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 44
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4]]
 // SANITIZE-WITH-ATTR-NEXT:    ret i32 [[TMP2]]
 //
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test25(
-// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[VAR:%.*]]) local_unnamed_addr #[[ATTR8:[0-9]+]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test21(
+// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[VAR:%.*]]) local_unnamed_addr #[[ATTR9:[0-9]+]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[VAR]], align 8, !tbaa [[TBAA11]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 44
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i32 [[TMP1]]
 //
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test25(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test21(
 // SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[C:%.*]], ptr noundef [[VAR:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[VAR]], align 8, !tbaa [[TBAA14]]
@@ -1495,7 +1422,7 @@ int test24(int c, struct tests_foo *var) {
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    ret i32 [[TMP1]]
 //
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test25(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test21(
 // NO-SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[VAR:%.*]]) local_unnamed_addr #[[ATTR7:[0-9]+]] {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[VAR]], align 8, !tbaa [[TBAA11]]
@@ -1503,18 +1430,18 @@ int test24(int c, struct tests_foo *var) {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    ret i32 [[TMP1]]
 //
-int test25(int c, struct tests_foo **var) {
+int test21(int c, struct tests_foo **var) {
   // Double dereferenced variable.
   return (**var).arr[10];
 }
 
 // Outer struct
-struct test26_foo {
+struct test22_foo {
   int a;
   struct tests_foo s;
 };
 
-// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test26(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test22(
 // SANITIZE-WITH-ATTR-SAME: i32 noundef [[C:%.*]], ptr noundef [[FOO:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    [[S:%.*]] = getelementptr inbounds i8, ptr [[FOO]], i64 4
@@ -1524,7 +1451,7 @@ struct test26_foo {
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = icmp ult i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP1]], label [[CONT5:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB30:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB29:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont5:
 // SANITIZE-WITH-ATTR-NEXT:    [[ARR:%.*]] = getelementptr inbounds nuw i8, ptr [[FOO]], i64 8
@@ -1532,7 +1459,7 @@ struct test26_foo {
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP2:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4]]
 // SANITIZE-WITH-ATTR-NEXT:    ret i32 [[TMP2]]
 //
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test26(
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test22(
 // NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[FOO:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ARR:%.*]] = getelementptr inbounds nuw i8, ptr [[FOO]], i64 8
@@ -1541,7 +1468,7 @@ struct test26_foo {
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i32 [[TMP0]]
 //
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test26(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test22(
 // SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[C:%.*]], ptr noundef [[FOO:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[ARR:%.*]] = getelementptr inbounds nuw i8, ptr [[FOO]], i64 8
@@ -1550,7 +1477,7 @@ struct test26_foo {
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    ret i32 [[TMP0]]
 //
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test26(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test22(
 // NO-SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[FOO:%.*]]) local_unnamed_addr #[[ATTR6]] {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[ARR:%.*]] = getelementptr inbounds nuw i8, ptr [[FOO]], i64 8
@@ -1559,22 +1486,22 @@ struct test26_foo {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    ret i32 [[TMP0]]
 //
-int test26(int c, struct test26_foo *foo) {
+int test22(int c, struct test22_foo *foo) {
   // Invalid: A structure with a flexible array must be a pointer.
   return foo->s.arr[c];
 }
 
-struct test27_baz;
+struct test23_baz;
 
-struct test27_bar {
+struct test23_bar {
   unsigned char type;
   unsigned char flags;
   unsigned short use_cnt;
   unsigned char hw_priv;
 };
 
-struct test27_foo {
-  struct test27_baz *a;
+struct test23_foo {
+  struct test23_baz *a;
 
   unsigned char bit1 : 1;
   unsigned char bit2 : 1;
@@ -1582,10 +1509,10 @@ struct test27_foo {
 
   unsigned int n_tables;
   unsigned long missed;
-  struct test27_bar *entries[] __counted_by(n_tables);
+  struct test23_bar *entries[] __counted_by(n_tables);
 };
 
-// SANITIZE-WITH-ATTR-LABEL: define dso_local ptr @test27(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local ptr @test23(
 // SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[I:%.*]], i32 noundef [[J:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[I]] to i64
@@ -1595,17 +1522,17 @@ struct test27_foo {
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = icmp ult i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP1]], label [[CONT3:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB32:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB31:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont3:
 // SANITIZE-WITH-ATTR-NEXT:    [[ENTRIES:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 24
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x ptr], ptr [[ENTRIES]], i64 0, i64 [[IDXPROM]]
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP2:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA14]]
 // SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM4:%.*]] = sext i32 [[J]] to i64
-// SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX5:%.*]] = getelementptr inbounds [[STRUCT_TEST27_BAR:%.*]], ptr [[TMP2]], i64 [[IDXPROM4]]
+// SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX5:%.*]] = getelementptr inbounds [[STRUCT_TEST23_BAR:%.*]], ptr [[TMP2]], i64 [[IDXPROM4]]
 // SANITIZE-WITH-ATTR-NEXT:    ret ptr [[ARRAYIDX5]]
 //
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local ptr @test27(
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local ptr @test23(
 // NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]], i32 noundef [[I:%.*]], i32 noundef [[J:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ENTRIES:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 24
@@ -1613,10 +1540,10 @@ struct test27_foo {
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x ptr], ptr [[ENTRIES]], i64 0, i64 [[IDXPROM]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA11]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM1:%.*]] = sext i32 [[J]] to i64
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX2:%.*]] = getelementptr inbounds [[STRUCT_TEST27_BAR:%.*]], ptr [[TMP0]], i64 [[IDXPROM1]]
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX2:%.*]] = getelementptr inbounds [[STRUCT_TEST23_BAR:%.*]], ptr [[TMP0]], i64 [[IDXPROM1]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret ptr [[ARRAYIDX2]]
 //
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local ptr @test27(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local ptr @test23(
 // SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[I:%.*]], i32 noundef [[J:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[ENTRIES:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 24
@@ -1624,10 +1551,10 @@ struct test27_foo {
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x ptr], ptr [[ENTRIES]], i64 0, i64 [[IDXPROM]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA14]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[IDXPROM3:%.*]] = sext i32 [[J]] to i64
-// SANITIZE-WITHOUT-ATTR-NEXT:    [[ARRAYIDX4:%.*]] = getelementptr inbounds [[STRUCT_TEST27_BAR:%.*]], ptr [[TMP0]], i64 [[IDXPROM3]]
+// SANITIZE-WITHOUT-ATTR-NEXT:    [[ARRAYIDX4:%.*]] = getelementptr inbounds [[STRUCT_TEST23_BAR:%.*]], ptr [[TMP0]], i64 [[IDXPROM3]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    ret ptr [[ARRAYIDX4]]
 //
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local ptr @test27(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local ptr @test23(
 // NO-SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]], i32 noundef [[I:%.*]], i32 noundef [[J:%.*]]) local_unnamed_addr #[[ATTR6]] {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[ENTRIES:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 24
@@ -1635,20 +1562,20 @@ struct test27_foo {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x ptr], ptr [[ENTRIES]], i64 0, i64 [[IDXPROM]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA11]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[IDXPROM1:%.*]] = sext i32 [[J]] to i64
-// NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[ARRAYIDX2:%.*]] = getelementptr inbounds [[STRUCT_TEST27_BAR:%.*]], ptr [[TMP0]], i64 [[IDXPROM1]]
+// NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[ARRAYIDX2:%.*]] = getelementptr inbounds [[STRUCT_TEST23_BAR:%.*]], ptr [[TMP0]], i64 [[IDXPROM1]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    ret ptr [[ARRAYIDX2]]
 //
-struct test27_bar *test27(struct test27_foo *p, int i, int j) {
+struct test23_bar *test23(struct test23_foo *p, int i, int j) {
   return &p->entries[i][j];
 }
 
-struct test28_foo {
-  struct test28_foo *s;
+struct test24_foo {
+  struct test24_foo *s;
   int count;
   int arr[] __counted_by(count);
 };
 
-// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test28(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test24(
 // SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[P]], align 8, !tbaa [[TBAA14]]
@@ -1661,7 +1588,7 @@ struct test28_foo {
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP4:%.*]] = icmp ult i64 [[IDXPROM]], [[TMP3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP4]], label [[CONT17:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB34:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB33:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont17:
 // SANITIZE-WITH-ATTR-NEXT:    [[ARR:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP2]], i64 12
@@ -1669,8 +1596,8 @@ struct test28_foo {
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP5:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA4]]
 // SANITIZE-WITH-ATTR-NEXT:    ret i32 [[TMP5]]
 //
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test28(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR8]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test24(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR9]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[P]], align 8, !tbaa [[TBAA11]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = load ptr, ptr [[TMP0]], align 8, !tbaa [[TBAA11]]
@@ -1681,7 +1608,7 @@ struct test28_foo {
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP3:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i32 [[TMP3]]
 //
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test28(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test24(
 // SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[P]], align 8, !tbaa [[TBAA14]]
@@ -1693,7 +1620,7 @@ struct test28_foo {
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP3:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    ret i32 [[TMP3]]
 //
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test28(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test24(
 // NO-SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR7]] {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[P]], align 8, !tbaa [[TBAA11]]
@@ -1705,7 +1632,7 @@ struct test28_foo {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP3:%.*]] = load i32, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    ret i32 [[TMP3]]
 //
-int test28(struct test28_foo *p, int i) {
+int test24(struct test24_foo *p, int i) {
   return p->s->s->s->arr[i];
 }
 
@@ -1716,14 +1643,14 @@ struct annotated_struct_array {
   int array[] __counted_by(count);
 };
 
-// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test29(
+// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test25(
 // SANITIZE-WITH-ATTR-SAME: ptr noundef [[ANN:%.*]], i32 noundef [[IDX1:%.*]], i32 noundef [[IDX2:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[IDX1]], 10
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = zext i32 [[IDX1]] to i64
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP0]], label [[CONT3:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB36:[0-9]+]], i64 [[TMP1]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB35:[0-9]+]], i64 [[TMP1]]) #[[ATTR10]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont3:
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x ptr], ptr [[ANN]], i64 0, i64 [[TMP1]]
@@ -1735,7 +1662,7 @@ struct annotated_struct_array {
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP4:%.*]] = icmp ult i64 [[IDXPROM15]], [[TMP3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP4]], label [[CONT20:%.*]], label [[HANDLER_OUT_OF_BOUNDS16:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds16:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB37:[0-9]+]], i64 [[IDXPROM15]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB36:[0-9]+]], i64 [[IDXPROM15]]) #[[ATTR10]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont20:
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP2]], i64 12
@@ -1746,8 +1673,8 @@ struct annotated_struct_array {
 // SANITIZE-WITH-ATTR-NEXT:    store i32 [[CONV]], ptr [[ARRAYIDX18]], align 4, !tbaa [[TBAA4]]
 // SANITIZE-WITH-ATTR-NEXT:    ret void
 //
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test29(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[ANN:%.*]], i32 noundef [[IDX1:%.*]], i32 noundef [[IDX2:%.*]]) local_unnamed_addr #[[ATTR9:[0-9]+]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test25(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[ANN:%.*]], i32 noundef [[IDX1:%.*]], i32 noundef [[IDX2:%.*]]) local_unnamed_addr #[[ATTR10:[0-9]+]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[IDX1]] to i64
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x ptr], ptr [[ANN]], i64 0, i64 [[IDXPROM]]
@@ -1763,7 +1690,7 @@ struct annotated_struct_array {
 // NO-SANITIZE-WITH-ATTR-NEXT:    store i32 [[CONV]], ptr [[ARRAYIDX5]], align 4, !tbaa [[TBAA2]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret void
 //
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test29(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test25(
 // SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[ANN:%.*]], i32 noundef [[IDX1:%.*]], i32 noundef [[IDX2:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[IDX1]], 10
@@ -1781,7 +1708,7 @@ struct annotated_struct_array {
 // SANITIZE-WITHOUT-ATTR-NEXT:    store i32 -1, ptr [[ARRAYIDX19]], align 4, !tbaa [[TBAA2]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    ret void
 //
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test29(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test25(
 // NO-SANITIZE-WITHOUT-ATTR-SAME: ptr nocapture noundef readonly [[ANN:%.*]], i32 noundef [[IDX1:%.*]], i32 noundef [[IDX2:%.*]]) local_unnamed_addr #[[ATTR8:[0-9]+]] {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[IDX1]] to i64
@@ -1793,30 +1720,30 @@ struct annotated_struct_array {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    store i32 -1, ptr [[ARRAYIDX6]], align 4, !tbaa [[TBAA2]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    ret void
 //
-void test29(struct annotated_struct_array *ann, int idx1, int idx2) {
+void test25(struct annotated_struct_array *ann, int idx1, int idx2) {
   ann->ann_array[idx1]->array[idx2] = __builtin_dynamic_object_size(ann->ann_array[idx1]->array, 1);
 }
 
 typedef struct {
   char __padding[0];
-} test30_spinlock_t;
+} test26_spinlock_t;
 
-struct test30_struct {
-  struct test30_decl *name_node;
+struct test26_struct {
+  struct test26_decl *name_node;
   int priv_len;
-  test30_spinlock_t pcpu_refcnt;
+  test26_spinlock_t pcpu_refcnt;
   char priv[] __counted_by(priv_len);
 };
 
-// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test30(
-// SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// SANITIZE-WITH-ATTR-LABEL: define dso_local void @test26(
+// SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR5]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = zext i32 [[IDX]] to i64, !nosanitize [[META2]]
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB39:[0-9]+]], i64 [[TMP0]]) #[[ATTR9]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB38:[0-9]+]], i64 [[TMP0]]) #[[ATTR10]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 //
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test30(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test26(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR1]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[PCPU_REFCNT:%.*]] = getelementptr inbounds nuw i8, ptr [[PTR]], i64 12
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
@@ -1824,14 +1751,14 @@ struct test30_struct {
 // NO-SANITIZE-WITH-ATTR-NEXT:    store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret void
 //
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test30(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test26(
 // SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] {
 // SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = zext i32 [[IDX]] to i64, !nosanitize [[META9]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB15:[0-9]+]], i64 [[TMP0]]) #[[ATTR8]], !nosanitize [[META9]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    unreachable, !nosanitize [[META9]]
 //
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test30(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local void @test26(
 // NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[PCPU_REFCNT:%.*]] = getelementptr inbounds nuw i8, ptr [[PTR]], i64 12
@@ -1840,38 +1767,38 @@ struct test30_struct {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    store i8 -1, ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    ret void
 //
-void test30(struct test30_struct *ptr, int idx) {
+void test26(struct test26_struct *ptr, int idx) {
   ptr->pcpu_refcnt.__padding[idx] = __builtin_dynamic_object_size(ptr, 1);
 }
 
-struct test31_empty {};
+struct test27_empty {};
 
-struct test31_struct {
-  struct test31_empty y;
+struct test27_struct {
+  struct test27_empty y;
   int s;
   int x[] __counted_by(s);
 };
 
-// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test31(
-// SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test27(
+// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    ret i32 -1
 //
-// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test31(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] {
+// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test27(
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i32 -1
 //
-// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test31(
+// SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test27(
 // SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // SANITIZE-WITHOUT-ATTR-NEXT:    ret i32 -1
 //
-// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test31(
+// NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test27(
 // NO-SANITIZE-WITHOUT-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR1]] {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    ret i32 -1
 //
-int test31(struct test31_struct *ptr, int idx) {
+int test27(struct test27_struct *ptr, int idx) {
   return __builtin_dynamic_object_size(ptr, 0);
 }

>From c08d8d96815d445d55b99b42163bbe18029b99a9 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 20 Sep 2024 14:59:08 -0700
Subject: [PATCH 40/59] Add testcase that discards side-effects.

---
 clang/test/CodeGen/builtin-counted-by-ref.c | 38 +++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/clang/test/CodeGen/builtin-counted-by-ref.c b/clang/test/CodeGen/builtin-counted-by-ref.c
index f27db821702f57..2c7994a92b3d6c 100644
--- a/clang/test/CodeGen/builtin-counted-by-ref.c
+++ b/clang/test/CodeGen/builtin-counted-by-ref.c
@@ -123,6 +123,44 @@ struct c *test3(int size) {
 
   return p;
 }
+
+struct d {
+  char x;
+  short count;
+  int array[] __attribute__((counted_by(count)));
+};
+
+// X86_64-LABEL: define dso_local noalias noundef ptr @test4(
+// X86_64-SAME: i32 noundef [[SIZE:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// X86_64-NEXT:  [[ENTRY:.*:]]
+// X86_64-NEXT:    [[CONV:%.*]] = sext i32 [[SIZE]] to i64
+// X86_64-NEXT:    [[MUL:%.*]] = shl nsw i64 [[CONV]], 2
+// X86_64-NEXT:    [[ADD:%.*]] = add nsw i64 [[MUL]], 4
+// X86_64-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3]]
+// X86_64-NEXT:    [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 2
+// X86_64-NEXT:    [[CONV1:%.*]] = trunc i32 [[SIZE]] to i16
+// X86_64-NEXT:    store i16 [[CONV1]], ptr [[COUNT]], align 2, !tbaa [[TBAA2]]
+// X86_64-NEXT:    ret ptr [[CALL]]
+//
+// I386-LABEL: define dso_local noalias noundef ptr @test4(
+// I386-SAME: i32 noundef [[SIZE:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
+// I386-NEXT:  [[ENTRY:.*:]]
+// I386-NEXT:    [[MUL:%.*]] = shl i32 [[SIZE]], 2
+// I386-NEXT:    [[ADD:%.*]] = add i32 [[MUL]], 4
+// I386-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3]]
+// I386-NEXT:    [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i32 2
+// I386-NEXT:    [[CONV:%.*]] = trunc i32 [[SIZE]] to i16
+// I386-NEXT:    store i16 [[CONV]], ptr [[COUNT]], align 2, !tbaa [[TBAA3]]
+// I386-NEXT:    ret ptr [[CALL]]
+//
+struct d *test4(int size, int idx) {
+  struct d *p = __builtin_malloc(sizeof(struct d) + sizeof(int) * size);
+
+  if (__builtin_counted_by_ref(&p->array[0]))
+    *__builtin_counted_by_ref(&p->array[idx++]) = size;
+
+  return p;
+}
 //.
 // X86_64: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0}
 // X86_64: [[META3]] = !{!"short", [[META4:![0-9]+]], i64 0}

>From 906dd2e7b3da3ea17bc33774b9734bedbc814358 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 26 Sep 2024 14:40:21 -0700
Subject: [PATCH 41/59] Delay warnings for _Generic statements.

---
 clang/docs/LanguageExtensions.rst           | 24 +++++++++-------
 clang/lib/AST/Decl.cpp                      |  4 +++
 clang/lib/Parse/ParseExpr.cpp               |  2 ++
 clang/lib/Sema/AnalysisBasedWarnings.cpp    | 31 +++++++++++++++++++--
 clang/lib/Sema/SemaChecking.cpp             | 27 +++++++++++++++++-
 clang/lib/Sema/SemaExpr.cpp                 |  1 -
 clang/test/CodeGen/builtin-counted-by-ref.c | 14 +++++++---
 clang/test/Sema/builtin-counted-by-ref.c    |  7 +++++
 8 files changed, 92 insertions(+), 18 deletions(-)

diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index c9915a16480c98..2d487a09617d7f 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3782,7 +3782,7 @@ as ``unsigned __int128`` and C23 ``unsigned _BitInt(N)``.
 
 The argument must be a pointer to a flexible array member. If the argument
 isn't a flexible array member or doesn't have the ``counted_by`` attribute, the
-builtin returns ``(size_t *)0``.
+builtin returns ``(void *)0``.
 
 **Syntax**:
 
@@ -3794,12 +3794,16 @@ builtin returns ``(size_t *)0``.
 
 .. code-block:: c
 
-  #define alloc(P, FAM, COUNT) ({ \
+  #define alloc(P, FAM, COUNT) ({                                 \
+     sizeof_t __ignored_assignment;                               \
      typeof(P) __p = NULL;                                        \
      __p = malloc(MAX(sizeof(*__p),                               \
                       sizeof(*__p) + sizeof(*__p->FAM) * COUNT)); \
-     if (__builtin_counted_by_ref(__p->FAM))                      \
-       *__builtin_counted_by_ref(__p->FAM) = COUNT;               \
+                                                                  \
+     *_Generic(                                                   \
+       __builtin_counted_by_ref(__p->FAM),                        \
+         void *: &__ignored_assignment,                           \
+         default: __builtin_counted_by_ref(__p->FAM)) = COUNT;    \
      __p;                                                         \
   })
 
@@ -3817,7 +3821,7 @@ initialize the flexible array before setting the ``count`` field:
   struct s {
     int dummy;
     short count;
-    long array[];
+    long array[] __attribute__((counted_by(count)));
   };
 
   struct s *ptr = malloc(sizeof(struct s) + sizeof(long) * COUNT);
@@ -3828,14 +3832,14 @@ initialize the flexible array before setting the ``count`` field:
   ptr->count = COUNT;
 
 Enforcing the rule that ``ptr->count = COUNT;`` must occur after every
-allocation of a struct with a flexible array member that has the ``counted_by``
+allocation of a struct with a flexible array member with the ``counted_by``
 attribute is prone to failure in large code bases. This builtin mitigates this
-for allocators (like in Linux) that are implemented via macros where the
-assignment happens automatically.
+for allocators (like in Linux) that are implemented in a way where the counter
+assignment can happen automatically.
 
 **Note: The value returned by ``__builtin_counted_by_ref`` cannot be assigned
-to a variable or passed into a function. Doing so violates bounds safety
-conventions.**
+to a variable or passed into a function, because doing so violates bounds
+safety conventions.**
 
 Multiprecision Arithmetic Builtins
 ----------------------------------
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 86913763ef9ff5..29c10d9be3b585 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3656,6 +3656,10 @@ unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const {
       (!hasAttr<ArmBuiltinAliasAttr>() && !hasAttr<BuiltinAliasAttr>()))
     return 0;
 
+  if (getASTContext().getLangOpts().CPlusPlus &&
+      BuiltinID == Builtin::BI__builtin_counted_by_ref)
+    return 0;
+
   const ASTContext &Context = getASTContext();
   if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
     return BuiltinID;
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 4570a18bc0d5e5..c9856ce1547945 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -3536,6 +3536,8 @@ ExprResult Parser::ParseGenericSelectionExpression() {
 
     // FIXME: These expressions should be parsed in a potentially potentially
     // evaluated context.
+    EnterExpressionEvaluationContext PotentiallyEvaluatedIfUsed(
+        Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed);
     ExprResult ER(
         Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()));
     if (ER.isInvalid()) {
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index c76733e9a774b6..968c4d5644de8d 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2697,8 +2697,35 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
               break;
             }
           }
-          // If we cannot map to a basic block, assume the statement is
-          // reachable.
+
+          // A Stmt in a _Generic statement may not be reachable and so we
+          // don't want to emit diagnostics.
+          auto FindGenericSelectionParent = [&](const Stmt *S) ->
+              std::pair<const GenericSelectionExpr *, const Stmt *> {
+            ParentMap &PM = AC.getParentMap();
+
+            while (PM.hasParent(S)) {
+              const Stmt *Parent = PM.getParent(S);
+              if (const auto *GSE = dyn_cast<GenericSelectionExpr>(Parent))
+                return std::make_pair(GSE, S);
+              S = Parent;
+            }
+
+            return std::make_pair(nullptr, nullptr);
+          };
+          if (auto GenericStmt = FindGenericSelectionParent(S);
+              GenericStmt.first) {
+            const GenericSelectionExpr *GSE =
+                cast<GenericSelectionExpr>(GenericStmt.first);
+            const Stmt *Entry = GenericStmt.second;
+
+            if (GSE->getControllingExpr() != Entry &&
+                GSE->getResultExpr() != Entry)
+              AllReachable = false;
+          }
+
+          // If we cannot map to a basic block or _Generic statement, assume
+          // the statement is reachable.
         }
 
         if (AllReachable)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index bab44c2dd7acf8..86f73575d9dd98 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -31,6 +31,7 @@
 #include "clang/AST/NSAPI.h"
 #include "clang/AST/NonTrivialTypeVisitor.h"
 #include "clang/AST/OperationKinds.h"
+#include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/RecordLayout.h"
 #include "clang/AST/Stmt.h"
 #include "clang/AST/TemplateBase.h"
@@ -5665,6 +5666,22 @@ bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
             isArrow = false;
           }
 
+          // Mark the DeclRefExpr as used.
+          auto DoMarkDeclRefUsed = [&](Expr *E) {
+            struct FindDeclRefVisitor
+                : public RecursiveASTVisitor<FindDeclRefVisitor> {
+              DeclRefExpr *DRE = nullptr;
+              bool VisitDeclRefExpr(DeclRefExpr *E) {
+                DRE = E;
+                return true;
+              }
+            } V;
+            V.TraverseStmt(E);
+            return V.DRE;
+          };
+          if (DeclRefExpr *DRE = DoMarkDeclRefUsed(New))
+            DRE->getDecl()->setIsUsed();
+
           return ExprResult(UnaryOperator::Create(
               Context, New, UO_AddrOf,
               Context.getPointerType(CountFD->getType()), VK_LValue,
@@ -5684,7 +5701,15 @@ bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
     }
   }
 
-  return false;
+  QualType SizeTypePtrTy = Context.VoidPtrTy;
+  QualType NullPtrTy =
+      Context.getIntTypeForBitwidth(Context.getIntWidth(SizeTypePtrTy), true);
+
+  return ExprResult(ImplicitCastExpr::Create(
+      Context, SizeTypePtrTy, CK_IntegralToPointer,
+      IntegerLiteral::Create(Context, Context.MakeIntValue(0, NullPtrTy),
+                             NullPtrTy, SourceLocation()),
+      nullptr, VK_LValue, FPOptionsOverride()));
 }
 
 namespace {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index d980955728d820..bc02a519e06a14 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -28,7 +28,6 @@
 #include "clang/AST/ExprOpenMP.h"
 #include "clang/AST/MangleNumberingContext.h"
 #include "clang/AST/OperationKinds.h"
-#include "clang/AST/ParentMapContext.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/Type.h"
 #include "clang/AST/TypeLoc.h"
diff --git a/clang/test/CodeGen/builtin-counted-by-ref.c b/clang/test/CodeGen/builtin-counted-by-ref.c
index 2c7994a92b3d6c..12da2bfba8bce7 100644
--- a/clang/test/CodeGen/builtin-counted-by-ref.c
+++ b/clang/test/CodeGen/builtin-counted-by-ref.c
@@ -117,9 +117,12 @@ struct c {
 //
 struct c *test3(int size) {
   struct c *p = __builtin_malloc(sizeof(struct c) + sizeof(int) * size);
+  unsigned long int __ignored;
 
-  if (__builtin_counted_by_ref(&p->array[0]))
-    *__builtin_counted_by_ref(&p->array[0]) = size;
+  *_Generic(
+    __builtin_counted_by_ref(&p->array[0]),
+      void *: &__ignored,
+      default: __builtin_counted_by_ref(&p->array[0])) = size;
 
   return p;
 }
@@ -155,9 +158,12 @@ struct d {
 //
 struct d *test4(int size, int idx) {
   struct d *p = __builtin_malloc(sizeof(struct d) + sizeof(int) * size);
+  unsigned long int __ignored;
 
-  if (__builtin_counted_by_ref(&p->array[0]))
-    *__builtin_counted_by_ref(&p->array[idx++]) = size;
+  *_Generic(
+    __builtin_counted_by_ref(&p->array[0]),
+      void *: &__ignored,
+      default: __builtin_counted_by_ref(&p->array[idx++])) = size;
 
   return p;
 }
diff --git a/clang/test/Sema/builtin-counted-by-ref.c b/clang/test/Sema/builtin-counted-by-ref.c
index ec6985d1a4fd3a..2013cec3e82655 100644
--- a/clang/test/Sema/builtin-counted-by-ref.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -9,6 +9,13 @@ struct fam_struct {
 void test1(struct fam_struct *ptr, int size, int idx) {
   *__builtin_counted_by_ref(ptr->array) = size;             // ok
   *__builtin_counted_by_ref(&ptr->array[idx]) = size;       // ok
+
+  {
+      size_t __ignored_assignment;
+      *_Generic(__builtin_counted_by_ref(p->array),
+               void *: &__ignored_assignment,
+               default: __builtin_counted_by_ref(p->array)) = 42; // ok
+  }
 }
 
 void test2(struct fam_struct *ptr, int idx) {

>From e3fbc031a403dd1c00726ec9339c7714537e8888 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 3 Oct 2024 16:43:56 -0700
Subject: [PATCH 42/59] Marking some diagnostics as 'potentially evaluated'
 somehow prevented variables from being marked as 'used'. >_<

---
 clang/lib/Parse/ParseExpr.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index c9856ce1547945..4570a18bc0d5e5 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -3536,8 +3536,6 @@ ExprResult Parser::ParseGenericSelectionExpression() {
 
     // FIXME: These expressions should be parsed in a potentially potentially
     // evaluated context.
-    EnterExpressionEvaluationContext PotentiallyEvaluatedIfUsed(
-        Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed);
     ExprResult ER(
         Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()));
     if (ER.isInvalid()) {

>From ac5ff7ce1067b9cacca9904c5b14561ea3e9e62f Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 3 Oct 2024 16:51:31 -0700
Subject: [PATCH 43/59] Regenerate testcase.

---
 clang/test/CodeGen/builtin-counted-by-ref.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/test/CodeGen/builtin-counted-by-ref.c b/clang/test/CodeGen/builtin-counted-by-ref.c
index 12da2bfba8bce7..8fcab0086521fd 100644
--- a/clang/test/CodeGen/builtin-counted-by-ref.c
+++ b/clang/test/CodeGen/builtin-counted-by-ref.c
@@ -140,8 +140,8 @@ struct d {
 // X86_64-NEXT:    [[MUL:%.*]] = shl nsw i64 [[CONV]], 2
 // X86_64-NEXT:    [[ADD:%.*]] = add nsw i64 [[MUL]], 4
 // X86_64-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3]]
-// X86_64-NEXT:    [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 2
 // X86_64-NEXT:    [[CONV1:%.*]] = trunc i32 [[SIZE]] to i16
+// X86_64-NEXT:    [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 2
 // X86_64-NEXT:    store i16 [[CONV1]], ptr [[COUNT]], align 2, !tbaa [[TBAA2]]
 // X86_64-NEXT:    ret ptr [[CALL]]
 //
@@ -151,8 +151,8 @@ struct d {
 // I386-NEXT:    [[MUL:%.*]] = shl i32 [[SIZE]], 2
 // I386-NEXT:    [[ADD:%.*]] = add i32 [[MUL]], 4
 // I386-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3]]
-// I386-NEXT:    [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i32 2
 // I386-NEXT:    [[CONV:%.*]] = trunc i32 [[SIZE]] to i16
+// I386-NEXT:    [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i32 2
 // I386-NEXT:    store i16 [[CONV]], ptr [[COUNT]], align 2, !tbaa [[TBAA3]]
 // I386-NEXT:    ret ptr [[CALL]]
 //

>From 072f7e4acf46c8e10cc208d3e8b5da27b91aec5d Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 3 Oct 2024 16:53:47 -0700
Subject: [PATCH 44/59] Fix testcase.

---
 clang/test/Sema/builtin-counted-by-ref.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/clang/test/Sema/builtin-counted-by-ref.c b/clang/test/Sema/builtin-counted-by-ref.c
index 2013cec3e82655..ff863f06007bb2 100644
--- a/clang/test/Sema/builtin-counted-by-ref.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -1,5 +1,7 @@
 // RUN: %clang_cc1 -std=c99 -fsyntax-only -verify %s
 
+typedef unsigned long int size_t;
+
 struct fam_struct {
   int x;
   char count;
@@ -12,9 +14,9 @@ void test1(struct fam_struct *ptr, int size, int idx) {
 
   {
       size_t __ignored_assignment;
-      *_Generic(__builtin_counted_by_ref(p->array),
+      *_Generic(__builtin_counted_by_ref(ptr->array),
                void *: &__ignored_assignment,
-               default: __builtin_counted_by_ref(p->array)) = 42; // ok
+               default: __builtin_counted_by_ref(ptr->array)) = 42; // ok
   }
 }
 

>From 391e2f683c44ad3322e623c3078742ea35ee0795 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 4 Oct 2024 16:04:19 -0700
Subject: [PATCH 45/59] Fix some of the naming and remove dead code.

---
 clang/docs/LanguageExtensions.rst             |  1 +
 clang/docs/ReleaseNotes.rst                   | 15 +++++----
 clang/include/clang/Basic/DiagnosticGroups.td |  4 +--
 .../clang/Basic/DiagnosticSemaKinds.td        |  2 +-
 clang/lib/Sema/AnalysisBasedWarnings.cpp      | 31 ++-----------------
 clang/lib/Sema/SemaChecking.cpp               | 16 ----------
 6 files changed, 15 insertions(+), 54 deletions(-)

diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 2d487a09617d7f..40a0cc6542f555 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3804,6 +3804,7 @@ builtin returns ``(void *)0``.
        __builtin_counted_by_ref(__p->FAM),                        \
          void *: &__ignored_assignment,                           \
          default: __builtin_counted_by_ref(__p->FAM)) = COUNT;    \
+                                                                  \
      __p;                                                         \
   })
 
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index d63697cd37a86f..7ce8647e7b7cfd 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -298,12 +298,15 @@ Non-comprehensive list of changes in this release
 
      /* A simplified version of Linux allocation macros */
      #define alloc(PTR, FAM, COUNT) ({ \
-         typeof(P) __p;                                        \
-         size_t __size = sizeof(*P) + sizeof(*P->FAM) * COUNT; \
-         __p = malloc(__size);                                 \
-         if (__builtin_counted_by_ref(__p->FAM))               \
-           *__builtin_counted_by_ref(__p->FAM) = COUNT;        \
-         __p;                                                  \
+         sizeof_t __ignored_assignment;                             \
+         typeof(P) __p;                                             \
+         size_t __size = sizeof(*P) + sizeof(*P->FAM) * COUNT;      \
+         __p = malloc(__size);                                      \
+         *_Generic(                                                 \
+           __builtin_counted_by_ref(__p->FAM),                      \
+             void *: &__ignored_assignment,                         \
+             default: __builtin_counted_by_ref(__p->FAM)) = COUNT;  \
+         __p;                                                       \
      })
 
   The flexible array member (FAM) can now be accessed immediately without causing
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index e27a94a623fea2..f5e9c252b1a209 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1483,8 +1483,8 @@ def BoundsSafetyCountedByEltTyUnknownSize :
   DiagGroup<"bounds-safety-counted-by-elt-type-unknown-size">;
 
 // counted_by warnings
-def CountedByAttribute
-    : DiagGroup<"get-counted-by-side-effects">;
+def CountedByRefSideEffects
+    : DiagGroup<"counted-by-ref-side-effects">;
 
 // A group for cross translation unit static analysis related warnings.
 def CrossTU : DiagGroup<"ctu">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 637cf13ad53f4d..6b07589eb9eb47 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6664,7 +6664,7 @@ def err_builtin_counted_by_ref_invalid_lhs_use : Error<
 
 def warn_builtin_counted_by_ref_has_side_effects : Warning<
   "'__builtin_counted_by_ref' argument has side-effects that will be discarded">,
-  InGroup<CountedByAttribute>;
+  InGroup<CountedByRefSideEffects>;
 
 let CategoryName = "ARC Semantic Issue" in {
 
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 968c4d5644de8d..c76733e9a774b6 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2697,35 +2697,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings(
               break;
             }
           }
-
-          // A Stmt in a _Generic statement may not be reachable and so we
-          // don't want to emit diagnostics.
-          auto FindGenericSelectionParent = [&](const Stmt *S) ->
-              std::pair<const GenericSelectionExpr *, const Stmt *> {
-            ParentMap &PM = AC.getParentMap();
-
-            while (PM.hasParent(S)) {
-              const Stmt *Parent = PM.getParent(S);
-              if (const auto *GSE = dyn_cast<GenericSelectionExpr>(Parent))
-                return std::make_pair(GSE, S);
-              S = Parent;
-            }
-
-            return std::make_pair(nullptr, nullptr);
-          };
-          if (auto GenericStmt = FindGenericSelectionParent(S);
-              GenericStmt.first) {
-            const GenericSelectionExpr *GSE =
-                cast<GenericSelectionExpr>(GenericStmt.first);
-            const Stmt *Entry = GenericStmt.second;
-
-            if (GSE->getControllingExpr() != Entry &&
-                GSE->getResultExpr() != Entry)
-              AllReachable = false;
-          }
-
-          // If we cannot map to a basic block or _Generic statement, assume
-          // the statement is reachable.
+          // If we cannot map to a basic block, assume the statement is
+          // reachable.
         }
 
         if (AllReachable)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 86f73575d9dd98..54448d8c66e430 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5666,22 +5666,6 @@ bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
             isArrow = false;
           }
 
-          // Mark the DeclRefExpr as used.
-          auto DoMarkDeclRefUsed = [&](Expr *E) {
-            struct FindDeclRefVisitor
-                : public RecursiveASTVisitor<FindDeclRefVisitor> {
-              DeclRefExpr *DRE = nullptr;
-              bool VisitDeclRefExpr(DeclRefExpr *E) {
-                DRE = E;
-                return true;
-              }
-            } V;
-            V.TraverseStmt(E);
-            return V.DRE;
-          };
-          if (DeclRefExpr *DRE = DoMarkDeclRefUsed(New))
-            DRE->getDecl()->setIsUsed();
-
           return ExprResult(UnaryOperator::Create(
               Context, New, UO_AddrOf,
               Context.getPointerType(CountFD->getType()), VK_LValue,

>From 45557631ecbe94477a27a4e7f48378f579ef1578 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 4 Oct 2024 16:22:24 -0700
Subject: [PATCH 46/59] Correct include ordering.

---
 clang/lib/Sema/SemaChecking.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 54448d8c66e430..04c447b8b92531 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -31,8 +31,8 @@
 #include "clang/AST/NSAPI.h"
 #include "clang/AST/NonTrivialTypeVisitor.h"
 #include "clang/AST/OperationKinds.h"
-#include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/RecordLayout.h"
+#include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/Stmt.h"
 #include "clang/AST/TemplateBase.h"
 #include "clang/AST/Type.h"

>From 4e22bd6882a3178faa78e4369f673e98edc88435 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Wed, 16 Oct 2024 15:16:49 -0700
Subject: [PATCH 47/59] Improve the argument checking so that it's checking
 specifically for 'counted_by' and not other counting attributes. Also make
 the documentation better.

---
 clang/docs/LanguageExtensions.rst             |  12 +-
 clang/include/clang/AST/Decl.h                |   3 +
 .../clang/Basic/DiagnosticSemaKinds.td        |   2 +-
 clang/lib/Sema/SemaChecking.cpp               | 126 +++++++++---------
 clang/lib/Sema/SemaExpr.cpp                   |   4 +-
 clang/test/Sema/builtin-counted-by-ref.c      |  17 ++-
 6 files changed, 84 insertions(+), 80 deletions(-)

diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 40a0cc6542f555..de6dcc0298b8c9 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -3780,9 +3780,9 @@ as ``unsigned __int128`` and C23 ``unsigned _BitInt(N)``.
 ``__builtin_counted_by_ref`` returns a pointer to the count field from the
 ``counted_by`` attribute.
 
-The argument must be a pointer to a flexible array member. If the argument
-isn't a flexible array member or doesn't have the ``counted_by`` attribute, the
-builtin returns ``(void *)0``.
+The argument must be a flexible array member. If the argument isn't a flexible
+array member or doesn't have the ``counted_by`` attribute, the builtin returns
+``(void *)0``.
 
 **Syntax**:
 
@@ -3795,7 +3795,7 @@ builtin returns ``(void *)0``.
 .. code-block:: c
 
   #define alloc(P, FAM, COUNT) ({                                 \
-     sizeof_t __ignored_assignment;                               \
+     size_t __ignored_assignment;                                 \
      typeof(P) __p = NULL;                                        \
      __p = malloc(MAX(sizeof(*__p),                               \
                       sizeof(*__p) + sizeof(*__p->FAM) * COUNT)); \
@@ -3839,8 +3839,8 @@ for allocators (like in Linux) that are implemented in a way where the counter
 assignment can happen automatically.
 
 **Note: The value returned by ``__builtin_counted_by_ref`` cannot be assigned
-to a variable or passed into a function, because doing so violates bounds
-safety conventions.**
+to a variable, have its address taken, or passed into or returned from a
+function, because doing so violates bounds safety conventions.**
 
 Multiprecision Arithmetic Builtins
 ----------------------------------
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 96ac7799fb05c0..68bafa572bd82a 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3059,6 +3059,9 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
   unsigned BitField : 1;
   LLVM_PREFERRED_TYPE(bool)
   unsigned Mutable : 1;
+  // FIXME: IsBoundsSafetyCounter can be made into an attribute, once some
+  // downstream work is in mainline.
+  // See https://github.com/llvm/llvm-project/issues/112586
   LLVM_PREFERRED_TYPE(bool)
   unsigned IsBoundsSafetyCounter : 1;
   LLVM_PREFERRED_TYPE(InitStorageKind)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 6b07589eb9eb47..5d7eafedcbd0d6 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6657,7 +6657,7 @@ def err_builtin_counted_by_ref_must_be_flex_array_member : Error<
   "'__builtin_counted_by_ref' argument must reference a flexible array member">;
 def err_builtin_counted_by_ref_cannot_leak_reference : Error<
   "value returned by '__builtin_counted_by_ref' cannot be assigned to a "
-  "variable or used as a function argument">;
+  "variable, have its address taken, or passed into or returned from a function">;
 def err_builtin_counted_by_ref_invalid_lhs_use : Error<
   "value returned by '__builtin_counted_by_ref' cannot be used in "
   "%select{an array subscript|a binary}0 expression">;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 04c447b8b92531..71aa660c8ed2cb 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5578,10 +5578,9 @@ bool Sema::BuiltinSetjmp(CallExpr *TheCall) {
   return false;
 }
 
-bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
-  // For simplicity, we support only a limited expressions for the argument.
-  // Specifically 'ptr->array' and '&ptr->array[0]'. This allows us to reject
-  // arguments with complex casting, which really shouldn't be a huge problem.
+ExprResult Sema::BuiltinCountedByRef(ExprResult TheCallResult) {
+  CallExpr *TheCall = cast<CallExpr>(TheCallResult.get());
+
   if (checkArgCount(TheCall, 1))
     return true;
 
@@ -5589,6 +5588,9 @@ bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
   if (ArgRes.isInvalid())
     return true;
 
+  // For simplicity, we support only limited expressions for the argument.
+  // Specifically 'ptr->array' and '&ptr->array[0]'. This allows us to reject
+  // arguments with complex casting, which really shouldn't be a huge problem.
   const Expr *Arg = ArgRes.get()->IgnoreParenImpCasts();
   if (!isa<PointerType>(Arg->getType()) && !Arg->getType()->isArrayType())
     return Diag(Arg->getBeginLoc(),
@@ -5608,81 +5610,73 @@ bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
       Arg = ASE->getBase()->IgnoreParenImpCasts();
   }
 
-  // Use 'size_t *' as the default return type. If the argument doesn't have
-  // the 'counted_by' attribute, it'll return a 'nullptr'.
-  TheCall->setType(Context.getPointerType(Context.getSizeType()));
-
-  if (const MemberExpr *ME = dyn_cast_if_present<MemberExpr>(Arg)) {
+  if (const MemberExpr *ME = dyn_cast<MemberExpr>(Arg)) {
     if (!ME->isFlexibleArrayMemberLike(
             Context, getLangOpts().getStrictFlexArraysLevel()))
       return Diag(Arg->getBeginLoc(),
                   diag::err_builtin_counted_by_ref_must_be_flex_array_member)
              << Arg->getSourceRange();
 
-    if (ME->getMemberDecl()->getType()->isCountAttributedType()) {
+    if (auto *CATy =
+            ME->getMemberDecl()->getType()->getAs<CountAttributedType>();
+        CATy && CATy->getKind() == CountAttributedType::CountedBy) {
       if (FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
-        if (FieldDecl *CountFD = FAMDecl->findCountedByField()) {
-          // Reverse through any anonymous structs / unions surrounding the
-          // flexible array member. We'll build any necessary MemberExpr's to
-          // anonymous structs / unions when building a reference to the
-          // 'count' field.
-          RecordDecl *RD = FAMDecl->getParent();
-          DeclContext *DC = RD;
-          for (; DC->isRecord(); DC = DC->getLexicalParent()) {
-            if (!RD->isAnonymousStructOrUnion())
-              break;
-            RD = cast<RecordDecl>(DC);
-            if (auto *Base = dyn_cast<MemberExpr>(ME->getBase()))
-              ME = Base;
-          }
-
-          // See if the count's FieldDecl is within anonymous structs.
-          SmallVector<NamedDecl *, 2> PathToFD;
-          for (Decl *D : RD->decls()) {
-            if (auto *IFD = dyn_cast<IndirectFieldDecl>(D);
-                IFD && IFD->getAnonField() == CountFD) {
-              PathToFD.insert(PathToFD.begin(), IFD->chain_begin(),
-                              IFD->chain_end());
-              break;
-            }
-          }
+        FieldDecl *CountFD = FAMDecl->findCountedByField();
+        assert(CountFD && "'count' field couldn't be found");
+
+        // Reverse through any anonymous structs / unions surrounding the
+        // flexible array member. We'll build any necessary MemberExpr's to
+        // anonymous structs / unions when building a reference to the
+        // 'count' field.
+        RecordDecl *RD = FAMDecl->getParent();
+        DeclContext *DC = RD;
+        for (; DC->isRecord(); DC = DC->getLexicalParent()) {
+          if (!RD->isAnonymousStructOrUnion())
+            break;
+          RD = cast<RecordDecl>(DC);
+          if (auto *Base = dyn_cast<MemberExpr>(ME->getBase()))
+            ME = Base;
+        }
 
-          if (PathToFD.empty())
-            PathToFD.push_back(CountFD);
-
-          // Build a MemberExpr to the 'count' field. This accounts for any
-          // anonymous structs / unions that may contain the field. Use the
-          // CallExpr's SourceLocation for future diagnostics.
-          SourceLocation Loc = TheCall->getBeginLoc();
-          bool isArrow = ME->isArrow();
-          Expr *New = ME->getBase();
-          for (NamedDecl *ND : PathToFD) {
-            ValueDecl *VD = cast<ValueDecl>(ND);
-            auto *ME = MemberExpr::CreateImplicit(Context, New, isArrow, VD,
-                                                  VD->getType(), VK_PRValue,
-                                                  OK_Ordinary);
-            ME->setMemberLoc(Loc);
-            New = ME;
-            isArrow = false;
+        // See if the count's FieldDecl is within anonymous structs.
+        SmallVector<NamedDecl *, 2> PathToFD;
+        for (Decl *D : RD->decls()) {
+          if (auto *IFD = dyn_cast<IndirectFieldDecl>(D);
+              IFD && IFD->getAnonField() == CountFD) {
+            PathToFD.insert(PathToFD.begin(), IFD->chain_begin(),
+                            IFD->chain_end());
+            break;
           }
+        }
 
-          return ExprResult(UnaryOperator::Create(
-              Context, New, UO_AddrOf,
-              Context.getPointerType(CountFD->getType()), VK_LValue,
-              OK_Ordinary, Loc, false, FPOptionsOverride()));
-        } else {
-          auto *A = FAMDecl->getAttr<CountedByAttr>();
-          auto *CountDecl = cast<DeclRefExpr>(A->getCount())->getDecl();
-
-          Diag(Arg->getBeginLoc(), diag::err_count_attr_must_be_in_structure)
-              << CountDecl << 0 << Arg->getSourceRange();
-          Diag(CountDecl->getBeginLoc(),
-               diag::note_flexible_array_counted_by_attr_field)
-              << CountDecl << CountDecl->getSourceRange();
-          return ExprError();
+        if (PathToFD.empty())
+          PathToFD.push_back(CountFD);
+
+        // Build a MemberExpr to the 'count' field. This accounts for any
+        // anonymous structs / unions that may contain the field. Use the
+        // CallExpr's SourceLocation for future diagnostics.
+        SourceLocation Loc = TheCall->getBeginLoc();
+        bool isArrow = ME->isArrow();
+        Expr *New = ME->getBase();
+        for (NamedDecl *ND : PathToFD) {
+          ValueDecl *VD = cast<ValueDecl>(ND);
+          auto *ME = MemberExpr::CreateImplicit(Context, New, isArrow, VD,
+                                                VD->getType(), VK_PRValue,
+                                                OK_Ordinary);
+          ME->setMemberLoc(Loc);
+          New = ME;
+          isArrow = false;
         }
+
+        return ExprResult(UnaryOperator::Create(
+            Context, New, UO_AddrOf, Context.getPointerType(CountFD->getType()),
+            VK_LValue, OK_Ordinary, Loc, false, FPOptionsOverride()));
       }
     }
+  } else {
+    return Diag(Arg->getBeginLoc(),
+                diag::err_builtin_counted_by_ref_must_be_flex_array_member)
+           << Arg->getSourceRange();
   }
 
   QualType SizeTypePtrTy = Context.VoidPtrTy;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index bc02a519e06a14..2fe5bd61f41d1b 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -13775,12 +13775,12 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
       bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
         InvalidUse = true;
         Option = 0; // report 'array expression' in diagnostic.
-        return VisitStmt(E->getBase()) && VisitStmt(E->getIdx());
+        return true;
       }
       bool VisitBinaryOperator(BinaryOperator *E) {
         InvalidUse = true;
         Option = 1; // report 'binary expression' in diagnostic.
-        return VisitStmt(E->getLHS()) && VisitStmt(E->getRHS());
+        return true;
       }
     } V;
     V.TraverseStmt(E);
diff --git a/clang/test/Sema/builtin-counted-by-ref.c b/clang/test/Sema/builtin-counted-by-ref.c
index ff863f06007bb2..48c470948e265e 100644
--- a/clang/test/Sema/builtin-counted-by-ref.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -2,6 +2,9 @@
 
 typedef unsigned long int size_t;
 
+int global_array[42];
+int global_int;
+
 struct fam_struct {
   int x;
   char count;
@@ -24,21 +27,25 @@ void test2(struct fam_struct *ptr, int idx) {
   __builtin_counted_by_ref();                               // expected-error {{too few arguments to function call, expected 1, have 0}}
   __builtin_counted_by_ref(ptr->array, ptr->x, ptr->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
   __builtin_counted_by_ref(ptr->x);                         // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+  __builtin_counted_by_ref(&ptr->x);                        // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+  __builtin_counted_by_ref(global_array);                   // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+  __builtin_counted_by_ref(global_int);                     // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+  __builtin_counted_by_ref(&global_int);                    // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
   __builtin_counted_by_ref(&ptr->array[idx++]);             // expected-warning {{'__builtin_counted_by_ref' argument has side-effects that will be discarded}} expected-warning {{expression result unused}}
 }
 
 void foo(char *);
 
 void *test3(struct fam_struct *ptr, int size, int idx) {
-  char *ref = __builtin_counted_by_ref(ptr->array);         // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+  char *ref = __builtin_counted_by_ref(ptr->array);         // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
 
-  ref = __builtin_counted_by_ref(ptr->array);               // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
-  ref = (char *)(int *)(42 + &*__builtin_counted_by_ref(ptr->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
-  foo(__builtin_counted_by_ref(ptr->array));                // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+  ref = __builtin_counted_by_ref(ptr->array);               // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
+  ref = (char *)(int *)(42 + &*__builtin_counted_by_ref(ptr->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
+  foo(__builtin_counted_by_ref(ptr->array));                // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
   *(__builtin_counted_by_ref(ptr->array) + 4) = 37;         // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in a binary expression}}
   __builtin_counted_by_ref(ptr->array)[3] = 37;             // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in an array subscript expression}}
 
-  return __builtin_counted_by_ref(ptr->array);              // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable or used as a function argument}}
+  return __builtin_counted_by_ref(ptr->array);              // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
 }
 
 struct non_fam_struct {

>From 985cd02c9e778c8ac5ccd2dd835ca0af6764fddb Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 18 Oct 2024 14:41:18 -0700
Subject: [PATCH 48/59] Move setting that the counter is a bounds-safety
 counter to where __builtin_counted_by_ref is processed so that future sema
 checks are concerned only with that code path.

---
 clang/lib/Sema/SemaBoundsSafety.cpp | 2 --
 clang/lib/Sema/SemaChecking.cpp     | 2 ++
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaBoundsSafety.cpp b/clang/lib/Sema/SemaBoundsSafety.cpp
index 7d39cbd39c98ed..d63a2389ea11de 100644
--- a/clang/lib/Sema/SemaBoundsSafety.cpp
+++ b/clang/lib/Sema/SemaBoundsSafety.cpp
@@ -162,8 +162,6 @@ bool Sema::CheckCountedByAttrOnField(FieldDecl *FD, Expr *E, bool CountInBytes,
     return true;
   }
 
-  CountFD->setBoundsSafetyCounter(true);
-
   if (FD->getParent() != CountFD->getParent()) {
     if (CountFD->getParent()->isUnion()) {
       Diag(CountFD->getBeginLoc(), diag::err_count_attr_refer_to_union)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 71aa660c8ed2cb..59915c671d31bf 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5668,6 +5668,8 @@ ExprResult Sema::BuiltinCountedByRef(ExprResult TheCallResult) {
           isArrow = false;
         }
 
+        CountFD->setBoundsSafetyCounter(true);
+
         return ExprResult(UnaryOperator::Create(
             Context, New, UO_AddrOf, Context.getPointerType(CountFD->getType()),
             VK_LValue, OK_Ordinary, Loc, false, FPOptionsOverride()));

>From f9ebf9f1747e9aba3e9e8d25d2594b0360281ce3 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 31 Oct 2024 17:12:00 -0700
Subject: [PATCH 49/59] Retain the __builtin_counted_by_ref CallExpr for AST
 dumping reasons. We'll lower it during CodeGen.

---
 clang/include/clang/AST/Decl.h  | 16 ++------
 clang/lib/Sema/SemaChecking.cpp | 72 +--------------------------------
 clang/lib/Sema/SemaExpr.cpp     | 33 ++++++++-------
 3 files changed, 21 insertions(+), 100 deletions(-)

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 68bafa572bd82a..7ff35d73df5997 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3059,14 +3059,9 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
   unsigned BitField : 1;
   LLVM_PREFERRED_TYPE(bool)
   unsigned Mutable : 1;
-  // FIXME: IsBoundsSafetyCounter can be made into an attribute, once some
-  // downstream work is in mainline.
-  // See https://github.com/llvm/llvm-project/issues/112586
-  LLVM_PREFERRED_TYPE(bool)
-  unsigned IsBoundsSafetyCounter : 1;
   LLVM_PREFERRED_TYPE(InitStorageKind)
   unsigned StorageKind : 2;
-  mutable unsigned CachedFieldIndex : 27;
+  mutable unsigned CachedFieldIndex : 28;
 
   /// If this is a bitfield with a default member initializer, this
   /// structure is used to represent the two expressions.
@@ -3101,8 +3096,8 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
             TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
             InClassInitStyle InitStyle)
       : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), BitField(false),
-        Mutable(Mutable), IsBoundsSafetyCounter(false),
-        StorageKind((InitStorageKind)InitStyle), CachedFieldIndex(0), Init() {
+        Mutable(Mutable), StorageKind((InitStorageKind)InitStyle),
+        CachedFieldIndex(0), Init() {
     if (BW)
       setBitWidth(BW);
   }
@@ -3132,11 +3127,6 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
   /// Determines whether this is an unnamed bitfield.
   bool isUnnamedBitField() const { return isBitField() && !getDeclName(); }
 
-  /// Returns true if this field decl is referenced by one of the bounds
-  /// safety counter attributes.
-  bool isBoundsSafetyCounter() const { return IsBoundsSafetyCounter; }
-  void setBoundsSafetyCounter(bool V) { IsBoundsSafetyCounter = V; }
-
   /// Determines whether this field is a
   /// representative for an anonymous struct or union. Such fields are
   /// unnamed and are implicitly generated by the implementation to
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 59915c671d31bf..cf24584c918fe8 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -32,7 +32,6 @@
 #include "clang/AST/NonTrivialTypeVisitor.h"
 #include "clang/AST/OperationKinds.h"
 #include "clang/AST/RecordLayout.h"
-#include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/Stmt.h"
 #include "clang/AST/TemplateBase.h"
 #include "clang/AST/Type.h"
@@ -5610,86 +5609,19 @@ ExprResult Sema::BuiltinCountedByRef(ExprResult TheCallResult) {
       Arg = ASE->getBase()->IgnoreParenImpCasts();
   }
 
-  if (const MemberExpr *ME = dyn_cast<MemberExpr>(Arg)) {
+  if (const auto *ME = dyn_cast<MemberExpr>(Arg)) {
     if (!ME->isFlexibleArrayMemberLike(
             Context, getLangOpts().getStrictFlexArraysLevel()))
       return Diag(Arg->getBeginLoc(),
                   diag::err_builtin_counted_by_ref_must_be_flex_array_member)
              << Arg->getSourceRange();
-
-    if (auto *CATy =
-            ME->getMemberDecl()->getType()->getAs<CountAttributedType>();
-        CATy && CATy->getKind() == CountAttributedType::CountedBy) {
-      if (FieldDecl *FAMDecl = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
-        FieldDecl *CountFD = FAMDecl->findCountedByField();
-        assert(CountFD && "'count' field couldn't be found");
-
-        // Reverse through any anonymous structs / unions surrounding the
-        // flexible array member. We'll build any necessary MemberExpr's to
-        // anonymous structs / unions when building a reference to the
-        // 'count' field.
-        RecordDecl *RD = FAMDecl->getParent();
-        DeclContext *DC = RD;
-        for (; DC->isRecord(); DC = DC->getLexicalParent()) {
-          if (!RD->isAnonymousStructOrUnion())
-            break;
-          RD = cast<RecordDecl>(DC);
-          if (auto *Base = dyn_cast<MemberExpr>(ME->getBase()))
-            ME = Base;
-        }
-
-        // See if the count's FieldDecl is within anonymous structs.
-        SmallVector<NamedDecl *, 2> PathToFD;
-        for (Decl *D : RD->decls()) {
-          if (auto *IFD = dyn_cast<IndirectFieldDecl>(D);
-              IFD && IFD->getAnonField() == CountFD) {
-            PathToFD.insert(PathToFD.begin(), IFD->chain_begin(),
-                            IFD->chain_end());
-            break;
-          }
-        }
-
-        if (PathToFD.empty())
-          PathToFD.push_back(CountFD);
-
-        // Build a MemberExpr to the 'count' field. This accounts for any
-        // anonymous structs / unions that may contain the field. Use the
-        // CallExpr's SourceLocation for future diagnostics.
-        SourceLocation Loc = TheCall->getBeginLoc();
-        bool isArrow = ME->isArrow();
-        Expr *New = ME->getBase();
-        for (NamedDecl *ND : PathToFD) {
-          ValueDecl *VD = cast<ValueDecl>(ND);
-          auto *ME = MemberExpr::CreateImplicit(Context, New, isArrow, VD,
-                                                VD->getType(), VK_PRValue,
-                                                OK_Ordinary);
-          ME->setMemberLoc(Loc);
-          New = ME;
-          isArrow = false;
-        }
-
-        CountFD->setBoundsSafetyCounter(true);
-
-        return ExprResult(UnaryOperator::Create(
-            Context, New, UO_AddrOf, Context.getPointerType(CountFD->getType()),
-            VK_LValue, OK_Ordinary, Loc, false, FPOptionsOverride()));
-      }
-    }
   } else {
     return Diag(Arg->getBeginLoc(),
                 diag::err_builtin_counted_by_ref_must_be_flex_array_member)
            << Arg->getSourceRange();
   }
 
-  QualType SizeTypePtrTy = Context.VoidPtrTy;
-  QualType NullPtrTy =
-      Context.getIntTypeForBitwidth(Context.getIntWidth(SizeTypePtrTy), true);
-
-  return ExprResult(ImplicitCastExpr::Create(
-      Context, SizeTypePtrTy, CK_IntegralToPointer,
-      IntegerLiteral::Create(Context, Context.MakeIntValue(0, NullPtrTy),
-                             NullPtrTy, SourceLocation()),
-      nullptr, VK_LValue, FPOptionsOverride()));
+  return false;
 }
 
 namespace {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 2fe5bd61f41d1b..1fcbee174106d4 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -28,6 +28,7 @@
 #include "clang/AST/ExprOpenMP.h"
 #include "clang/AST/MangleNumberingContext.h"
 #include "clang/AST/OperationKinds.h"
+#include "clang/AST/ParentMapContext.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/Type.h"
 #include "clang/AST/TypeLoc.h"
@@ -9191,16 +9192,15 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
   auto FindBuiltinCountedByRefExpr = [](Expr *E) {
     struct BuiltinCountedByRefVisitor
         : public RecursiveASTVisitor<BuiltinCountedByRefVisitor> {
-      MemberExpr *ME = nullptr;
-      bool VisitMemberExpr(MemberExpr *E) {
-        if (auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
-            FD && FD->isBoundsSafetyCounter())
-          ME = E;
-        return true;
+      CallExpr *CE = nullptr;
+      bool VisitCallExpr(CallExpr *E) {
+        if (E->getBuiltinCallee() == Builtin::BI__builtin_counted_by_ref)
+          CE = E;
+        return false;
       }
     } V;
     V.TraverseStmt(E);
-    return V.ME;
+    return V.CE;
   };
   if (auto *CE = FindBuiltinCountedByRefExpr(RHS.get()))
     Diag(CE->getExprLoc(),
@@ -13761,15 +13761,14 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
   auto FindInvalidUseOfBoundsSafetyCounter = [&](Expr *E) {
     struct BuiltinCountedByRefVisitor
         : public RecursiveASTVisitor<BuiltinCountedByRefVisitor> {
-      MemberExpr *ME = nullptr;
+      CallExpr *CE = nullptr;
       bool InvalidUse = false;
       int Option = -1;
 
-      bool VisitMemberExpr(MemberExpr *E) {
-        if (auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
-            FD && FD->isBoundsSafetyCounter())
-          ME = E;
-        return true;
+      bool VisitCallExpr(CallExpr *E) {
+        if (E->getBuiltinCallee() == Builtin::BI__builtin_counted_by_ref)
+          CE = E;
+        return false;
       }
 
       bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
@@ -13785,11 +13784,11 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
     } V;
     V.TraverseStmt(E);
     DiagOption = V.Option;
-    return V.InvalidUse ? V.ME : nullptr;
+    return V.InvalidUse ? V.CE : nullptr;
   };
-  if (auto *E = FindInvalidUseOfBoundsSafetyCounter(LHSExpr))
-    Diag(E->getExprLoc(), diag::err_builtin_counted_by_ref_invalid_lhs_use)
-        << DiagOption << E->getSourceRange();
+  if (auto *CE = FindInvalidUseOfBoundsSafetyCounter(LHSExpr))
+    Diag(CE->getExprLoc(), diag::err_builtin_counted_by_ref_invalid_lhs_use)
+        << DiagOption << CE->getSourceRange();
 
   if (DiagnoseAssignmentResult(ConvTy, Loc, LHSType, RHSType, RHS.get(),
                                AssignmentAction::Assigning))

>From a5245e5d6e026f389e64245a8ce4df643abec4a5 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 31 Oct 2024 17:59:11 -0700
Subject: [PATCH 50/59] Fix

---
 clang/lib/Sema/SemaChecking.cpp | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index cf24584c918fe8..f5969cf3e26e8d 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5577,9 +5577,7 @@ bool Sema::BuiltinSetjmp(CallExpr *TheCall) {
   return false;
 }
 
-ExprResult Sema::BuiltinCountedByRef(ExprResult TheCallResult) {
-  CallExpr *TheCall = cast<CallExpr>(TheCallResult.get());
-
+bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
   if (checkArgCount(TheCall, 1))
     return true;
 

>From 271bb8f9a3d80ca9e3f51c3401d8561496be0355 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 31 Oct 2024 18:10:49 -0700
Subject: [PATCH 51/59] Reformat

---
 clang/lib/CodeGen/CGBuiltin.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index b6b30beede8c29..c28f5dd26e3bd9 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -30,7 +30,6 @@
 #include "clang/AST/OSLog.h"
 #include "clang/AST/OperationKinds.h"
 #include "clang/AST/Type.h"
-#include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/TargetBuiltins.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/TargetOptions.h"
@@ -3692,6 +3691,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
     return RValue::get(emitBuiltinObjectSize(E->getArg(0), Type, ResType,
                                              /*EmittedE=*/nullptr, IsDynamic));
   }
+#if 0
   case Builtin::BI__builtin_counted_by_ref: {
     llvm::Value *Result = llvm::ConstantPointerNull::get(
         cast<llvm::PointerType>(ConvertType(E->getType())));
@@ -3767,6 +3767,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
 
     return RValue::get(Result);
   }
+#endif
   case Builtin::BI__builtin_prefetch: {
     Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0));
     // FIXME: Technically these constants should of type 'int', yes?

>From ceb43e5ee00c34fcd6bfc87e7af1a4e57b0bc57f Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 31 Oct 2024 19:37:17 -0700
Subject: [PATCH 52/59] Add correct attribute checking and set the return type.

---
 clang/lib/Sema/SemaChecking.cpp | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index f5969cf3e26e8d..3b0bcb63d4cb5f 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -5613,12 +5613,23 @@ bool Sema::BuiltinCountedByRef(CallExpr *TheCall) {
       return Diag(Arg->getBeginLoc(),
                   diag::err_builtin_counted_by_ref_must_be_flex_array_member)
              << Arg->getSourceRange();
+
+    if (auto *CATy =
+            ME->getMemberDecl()->getType()->getAs<CountAttributedType>();
+        CATy && CATy->getKind() == CountAttributedType::CountedBy) {
+      const auto *FAMDecl = cast<FieldDecl>(ME->getMemberDecl());
+      if (const FieldDecl *CountFD = FAMDecl->findCountedByField()) {
+        TheCall->setType(Context.getPointerType(CountFD->getType()));
+        return false;
+      }
+    }
   } else {
     return Diag(Arg->getBeginLoc(),
                 diag::err_builtin_counted_by_ref_must_be_flex_array_member)
            << Arg->getSourceRange();
   }
 
+  TheCall->setType(Context.getPointerType(Context.VoidTy));
   return false;
 }
 

>From b01526d897516fe35a7a50403a5eed39075fbe97 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 31 Oct 2024 19:38:01 -0700
Subject: [PATCH 53/59] Generate LLVM IR for the __builtin_counted_by_ref.

---
 clang/lib/CodeGen/CGBuiltin.cpp | 66 +++++----------------------------
 1 file changed, 9 insertions(+), 57 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index c28f5dd26e3bd9..e382f8b3d3d2cf 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3691,10 +3691,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
     return RValue::get(emitBuiltinObjectSize(E->getArg(0), Type, ResType,
                                              /*EmittedE=*/nullptr, IsDynamic));
   }
-#if 0
   case Builtin::BI__builtin_counted_by_ref: {
+    // Default to returning '(void *) 0'.
     llvm::Value *Result = llvm::ConstantPointerNull::get(
-        cast<llvm::PointerType>(ConvertType(E->getType())));
+        llvm::PointerType::getUnqual(getLLVMContext()));
 
     const Expr *Arg = E->getArg(0)->IgnoreParenImpCasts();
 
@@ -3707,67 +3707,19 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
     }
 
     if (const MemberExpr *ME = dyn_cast_if_present<MemberExpr>(Arg)) {
-      bool IsFlexibleArrayMember = ME->isFlexibleArrayMemberLike(
-          getContext(), getLangOpts().getStrictFlexArraysLevel());
-
-      if (!ME->HasSideEffects(getContext()) && IsFlexibleArrayMember &&
-          ME->getMemberDecl()->getType()->isCountAttributedType()) {
-        FieldDecl *FAMDecl = cast<FieldDecl>(ME->getMemberDecl());
-        if (FieldDecl *CountFD = FAMDecl->findCountedByField()) {
-          QualType CountTy = CountFD->getType();
-          SmallVector<NamedDecl *, 2> PathToFD;
-
-          // Reverse through any anonymous structs / unions surrounding the
-          // flexible array member. We'll build any necessary MemberExpr's to
-          // anonymous structs / unions when building a reference to the
-          // 'count' field.
-          RecordDecl *RD = FAMDecl->getParent();
-          DeclContext *DC = RD;
-          for (; DC->isRecord(); DC = DC->getLexicalParent()) {
-            if (!RD->isAnonymousStructOrUnion())
-              break;
-            RD = cast<RecordDecl>(DC);
-            if (auto *Base = dyn_cast<MemberExpr>(ME->getBase()))
-              ME = Base;
-          }
-
-          // See if the count's FieldDecl is within anonymous structs.
-          for (Decl *D : RD->decls()) {
-            if (auto *IFD = dyn_cast<IndirectFieldDecl>(D);
-                IFD && IFD->getAnonField() == CountFD) {
-              PathToFD.insert(PathToFD.begin(), IFD->chain_begin(),
-                              IFD->chain_end());
-              break;
-            }
-          }
-
-          if (PathToFD.empty())
-            PathToFD.push_back(CountFD);
-
-          // Build a MemberExpr to the 'count' field. This accounts for any
-          // anonymous structs / unions that may contain the field.
-          bool isArrow = ME->isArrow();
-          Expr *New = ME->getBase();
-          for (NamedDecl *ND : PathToFD) {
-            ValueDecl *VD = cast<ValueDecl>(ND);
-            New = MemberExpr::CreateImplicit(
-                Ctx, New, isArrow, VD, VD->getType(), VK_PRValue, OK_Ordinary);
-            isArrow = false;
-          }
-
-          // The result is a pointer to the 'count' field.
-          Result = EmitScalarExpr(UnaryOperator::Create(
-              Ctx, New, UO_AddrOf, Ctx.getPointerType(CountTy), VK_LValue,
-              OK_Ordinary, SourceLocation(), false, FPOptionsOverride()));
-        } else {
+      if (auto *CATy =
+              ME->getMemberDecl()->getType()->getAs<CountAttributedType>();
+          CATy && CATy->getKind() == CountAttributedType::CountedBy) {
+        const auto *FAMDecl = cast<FieldDecl>(ME->getMemberDecl());
+        if (const FieldDecl *CountFD = FAMDecl->findCountedByField())
+          Result = GetCountedByFieldExprGEP(Arg, FAMDecl, CountFD);
+        else
           llvm::report_fatal_error("Cannot find the counted_by 'count' field");
-        }
       }
     }
 
     return RValue::get(Result);
   }
-#endif
   case Builtin::BI__builtin_prefetch: {
     Value *Locality, *RW, *Address = EmitScalarExpr(E->getArg(0));
     // FIXME: Technically these constants should of type 'int', yes?

>From 76aabde4db66343a2181e39098b546e45a5fc8d3 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 31 Oct 2024 19:58:11 -0700
Subject: [PATCH 54/59] Set InBounds on the GEP.

---
 clang/lib/CodeGen/CGBuiltin.cpp      |   7 +-
 clang/test/CodeGen/attr-counted-by.c | 124 +++++++++++++--------------
 2 files changed, 67 insertions(+), 64 deletions(-)

diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index e382f8b3d3d2cf..fb517803e77141 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -3711,10 +3711,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
               ME->getMemberDecl()->getType()->getAs<CountAttributedType>();
           CATy && CATy->getKind() == CountAttributedType::CountedBy) {
         const auto *FAMDecl = cast<FieldDecl>(ME->getMemberDecl());
-        if (const FieldDecl *CountFD = FAMDecl->findCountedByField())
+        if (const FieldDecl *CountFD = FAMDecl->findCountedByField()) {
           Result = GetCountedByFieldExprGEP(Arg, FAMDecl, CountFD);
-        else
+          cast<llvm::GetElementPtrInst>(Result)->setNoWrapFlags(
+              GEPNoWrapFlags::inBounds());
+        } else {
           llvm::report_fatal_error("Cannot find the counted_by 'count' field");
+        }
       }
     }
 
diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c
index ec350991f176ef..20406c5b86cc48 100644
--- a/clang/test/CodeGen/attr-counted-by.c
+++ b/clang/test/CodeGen/attr-counted-by.c
@@ -108,7 +108,7 @@ void test1(struct annotated *p, int index, int val) {
 // SANITIZE-WITH-ATTR-LABEL: define dso_local void @test2(
 // SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
-// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = zext i32 [[DOT_COUNTED_BY_LOAD]] to i64, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = icmp ult i64 [[INDEX]], [[TMP0]], !nosanitize [[META2]]
@@ -128,7 +128,7 @@ void test1(struct annotated *p, int index, int val) {
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test2(
 // NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD]], 2
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOTINV:%.*]] = icmp slt i32 [[DOT_COUNTED_BY_LOAD]], 0
@@ -161,7 +161,7 @@ void test2(struct annotated *p, size_t index) {
 // SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -8589934592, 8589934589) i64 @test2_bdos(
 // SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
-// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = sext i32 [[DOT_COUNTED_BY_LOAD]] to i64
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = shl nsw i64 [[TMP0]], 2
@@ -172,7 +172,7 @@ void test2(struct annotated *p, size_t index) {
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -8589934592, 8589934589) i64 @test2_bdos(
 // NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = sext i32 [[DOT_COUNTED_BY_LOAD]] to i64
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = shl nsw i64 [[TMP0]], 2
@@ -268,7 +268,7 @@ size_t test3_bdos(struct annotated *p) {
 // SANITIZE-WITH-ATTR-LABEL: define dso_local void @test4(
 // SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]], i32 noundef [[FAM_IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
-// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 12
 // SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
@@ -330,7 +330,7 @@ size_t test3_bdos(struct annotated *p) {
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test4(
 // NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[INDEX:%.*]], i32 noundef [[FAM_IDX:%.*]]) local_unnamed_addr #[[ATTR1]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD]], 2
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = add i32 [[TMP0]], 244
@@ -412,7 +412,7 @@ void test4(struct annotated *p, int index, int fam_idx) {
 // SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -17179869180, 17179869181) i64 @test4_bdos(
 // SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
-// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = sext i32 [[DOT_COUNTED_BY_LOAD]] to i64
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = sext i32 [[INDEX]] to i64
@@ -427,7 +427,7 @@ void test4(struct annotated *p, int index, int fam_idx) {
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -17179869180, 17179869181) i64 @test4_bdos(
 // NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = sext i32 [[DOT_COUNTED_BY_LOAD]] to i64
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = sext i32 [[INDEX]] to i64
@@ -528,7 +528,7 @@ size_t test5_bdos(struct anon_struct *p) {
 // SANITIZE-WITH-ATTR-LABEL: define dso_local void @test6(
 // SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
-// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i64, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = icmp ugt i64 [[DOT_COUNTED_BY_LOAD]], [[IDXPROM]], !nosanitize [[META2]]
@@ -549,7 +549,7 @@ size_t test5_bdos(struct anon_struct *p) {
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test6(
 // NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i64, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOTINV:%.*]] = icmp slt i64 [[DOT_COUNTED_BY_LOAD]], 0
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD_TR:%.*]] = trunc i64 [[DOT_COUNTED_BY_LOAD]] to i32
@@ -586,7 +586,7 @@ void test6(struct anon_struct *p, int index) {
 // SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, -3) i64 @test6_bdos(
 // SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
-// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i64, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = shl nuw i64 [[DOT_COUNTED_BY_LOAD]], 2
 // SANITIZE-WITH-ATTR-NEXT:    [[DOTINV:%.*]] = icmp slt i64 [[DOT_COUNTED_BY_LOAD]], 0
@@ -596,7 +596,7 @@ void test6(struct anon_struct *p, int index) {
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, -3) i64 @test6_bdos(
 // NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i64, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = shl nuw i64 [[DOT_COUNTED_BY_LOAD]], 2
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOTINV:%.*]] = icmp slt i64 [[DOT_COUNTED_BY_LOAD]], 0
@@ -693,7 +693,7 @@ size_t test7_bdos(struct union_of_fams *p) {
 // SANITIZE-WITH-ATTR-LABEL: define dso_local void @test8(
 // SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
-// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i8, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = zext i8 [[DOT_COUNTED_BY_LOAD]] to i64, !nosanitize [[META2]]
@@ -703,7 +703,7 @@ size_t test7_bdos(struct union_of_fams *p) {
 // SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB12:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont7:
-// SANITIZE-WITH-ATTR-NEXT:    [[INTS:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 9
+// SANITIZE-WITH-ATTR-NEXT:    [[INTS:%.*]] = getelementptr i8, ptr [[P]], i64 9
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[IDXPROM]]
 // SANITIZE-WITH-ATTR-NEXT:    store i8 [[DOT_COUNTED_BY_LOAD]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA8]]
 // SANITIZE-WITH-ATTR-NEXT:    ret void
@@ -711,9 +711,9 @@ size_t test7_bdos(struct union_of_fams *p) {
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test8(
 // NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i8, ptr [[DOT_COUNTED_BY_GEP]], align 4
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[INTS:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 9
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[INTS:%.*]] = getelementptr i8, ptr [[P]], i64 9
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[INTS]], i64 0, i64 [[IDXPROM]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    store i8 [[DOT_COUNTED_BY_LOAD]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]]
@@ -744,7 +744,7 @@ void test8(struct union_of_fams *p, int index) {
 // SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, 256) i64 @test8_bdos(
 // SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
-// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i8, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = zext i8 [[DOT_COUNTED_BY_LOAD]] to i64
 // SANITIZE-WITH-ATTR-NEXT:    ret i64 [[TMP0]]
@@ -752,7 +752,7 @@ void test8(struct union_of_fams *p, int index) {
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, 256) i64 @test8_bdos(
 // NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i8, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = zext i8 [[DOT_COUNTED_BY_LOAD]] to i64
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i64 [[TMP0]]
@@ -847,7 +847,7 @@ size_t test9_bdos(struct union_of_fams *p) {
 // SANITIZE-WITH-ATTR-LABEL: define dso_local void @test10(
 // SANITIZE-WITH-ATTR-SAME: ptr noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
-// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = zext i32 [[DOT_COUNTED_BY_LOAD]] to i64, !nosanitize [[META2]]
@@ -857,7 +857,7 @@ size_t test9_bdos(struct union_of_fams *p) {
 // SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB15:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont7:
-// SANITIZE-WITH-ATTR-NEXT:    [[BYTES:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12
+// SANITIZE-WITH-ATTR-NEXT:    [[BYTES:%.*]] = getelementptr i8, ptr [[P]], i64 12
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[IDXPROM]]
 // SANITIZE-WITH-ATTR-NEXT:    [[NARROW:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0)
 // SANITIZE-WITH-ATTR-NEXT:    [[CONV:%.*]] = trunc i32 [[NARROW]] to i8
@@ -867,11 +867,11 @@ size_t test9_bdos(struct union_of_fams *p) {
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test10(
 // NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[P:%.*]], i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR1]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[NARROW:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0)
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[CONV:%.*]] = trunc i32 [[NARROW]] to i8
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[BYTES:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 12
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[BYTES:%.*]] = getelementptr i8, ptr [[P]], i64 12
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i8], ptr [[BYTES]], i64 0, i64 [[IDXPROM]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    store i8 [[CONV]], ptr [[ARRAYIDX]], align 1, !tbaa [[TBAA6]]
@@ -902,7 +902,7 @@ void test10(struct union_of_fams *p, int index) {
 // SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, 2147483648) i64 @test10_bdos(
 // SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
-// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // SANITIZE-WITH-ATTR-NEXT:    [[NARROW:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0)
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = zext nneg i32 [[NARROW]] to i64
@@ -911,7 +911,7 @@ void test10(struct union_of_fams *p, int index) {
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, 2147483648) i64 @test10_bdos(
 // NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[P]], i64 8
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[NARROW:%.*]] = tail call i32 @llvm.smax.i32(i32 [[DOT_COUNTED_BY_LOAD]], i32 0)
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = zext nneg i32 [[NARROW]] to i64
@@ -947,16 +947,16 @@ struct hang {
 int test11_a, test11_b;
 
 // SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test11(
-// SANITIZE-WITH-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] {
+// SANITIZE-WITH-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR4:[0-9]+]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    [[BAZ:%.*]] = alloca [[STRUCT_HANG:%.*]], align 4
-// SANITIZE-WITH-ATTR-NEXT:    call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR11:[0-9]+]]
+// SANITIZE-WITH-ATTR-NEXT:    call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR10:[0-9]+]]
 // SANITIZE-WITH-ATTR-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test11_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT9:![0-9]+]]
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[INDEX]], 6
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = zext i32 [[INDEX]] to i64
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP0]], label [[CONT:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB17:[0-9]+]], i64 [[TMP1]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB17:[0-9]+]], i64 [[TMP1]]) #[[ATTR9]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont:
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [6 x i32], ptr [[BAZ]], i64 0, i64 [[TMP1]]
@@ -966,17 +966,17 @@ int test11_a, test11_b;
 // SANITIZE-WITH-ATTR-NEXT:    [[DOTNOT:%.*]] = icmp eq i32 [[DOTCOUNTED_BY_LOAD]], 0
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[DOTNOT]], label [[HANDLER_OUT_OF_BOUNDS4:%.*]], label [[HANDLER_TYPE_MISMATCH6:%.*]], !prof [[PROF10:![0-9]+]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds4:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB19:[0-9]+]], i64 0) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB19:[0-9]+]], i64 0) #[[ATTR9]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.type_mismatch6:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_type_mismatch_v1_abort(ptr nonnull @[[GLOB20:[0-9]+]], i64 ptrtoint (ptr getelementptr inbounds nuw (i8, ptr @test11_foo, i64 4) to i64)) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_type_mismatch_v1_abort(ptr nonnull @[[GLOB20:[0-9]+]], i64 ptrtoint (ptr getelementptr inbounds nuw (i8, ptr @test11_foo, i64 4) to i64)) #[[ATTR9]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 //
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test11(
-// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] {
+// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR4:[0-9]+]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[BAZ:%.*]] = alloca [[STRUCT_HANG:%.*]], align 4
-// NO-SANITIZE-WITH-ATTR-NEXT:    call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR12:[0-9]+]]
+// NO-SANITIZE-WITH-ATTR-NEXT:    call void @llvm.lifetime.start.p0(i64 24, ptr nonnull [[BAZ]]) #[[ATTR11:[0-9]+]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(24) [[BAZ]], ptr noundef nonnull align 4 dereferenceable(24) @test11_bar, i64 24, i1 false), !tbaa.struct [[TBAA_STRUCT7:![0-9]+]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [6 x i32], ptr [[BAZ]], i64 0, i64 [[IDXPROM]]
@@ -1059,7 +1059,7 @@ struct test12_bar {
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP2:%.*]] = icmp ult i64 [[INDEX]], [[TMP1]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP2]], label [[CONT5:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB23:[0-9]+]], i64 [[INDEX]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB23:[0-9]+]], i64 [[INDEX]]) #[[ATTR9]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont5:
 // SANITIZE-WITH-ATTR-NEXT:    [[REVMAP:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 16
@@ -1068,7 +1068,7 @@ struct test12_bar {
 // SANITIZE-WITH-ATTR-NEXT:    ret i32 0
 //
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i32 @test12(
-// NO-SANITIZE-WITH-ATTR-SAME: i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR8:[0-9]+]] {
+// NO-SANITIZE-WITH-ATTR-SAME: i64 noundef [[INDEX:%.*]]) local_unnamed_addr #[[ATTR7:[0-9]+]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr @test12_f, align 8, !tbaa [[TBAA8:![0-9]+]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[REVMAP:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 16
@@ -1120,14 +1120,14 @@ struct test13_foo {
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP0]], label [[TRAP:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
 // SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB24:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB24:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       trap:
 // SANITIZE-WITH-ATTR-NEXT:    tail call void @llvm.trap() #[[ATTR9]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable
 //
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test13(
-// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOTCOMPOUNDLITERAL:%.*]] = alloca [[STRUCT_TEST13_FOO:%.*]], align 4
 // NO-SANITIZE-WITH-ATTR-NEXT:    store i32 1, ptr [[DOTCOMPOUNDLITERAL]], align 4, !tbaa [[TBAA2]]
@@ -1176,14 +1176,14 @@ int test13(int idx) {
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP0]], label [[TRAP:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
 // SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB26:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB26:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       trap:
 // SANITIZE-WITH-ATTR-NEXT:    tail call void @llvm.trap() #[[ATTR9]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable
 //
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test14(
-// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [0 x i32], ptr getelementptr inbounds nuw (i8, ptr @__const.test14.foo, i64 8), i64 0, i64 [[IDXPROM]]
@@ -1221,12 +1221,12 @@ int test14(int idx) {
 }
 
 // SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test15(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    ret i64 -1
 //
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test15(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i64 -1
 //
@@ -1246,12 +1246,12 @@ size_t test15(struct annotated *p) {
 }
 
 // SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test16(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    ret i64 -1
 //
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test16(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i64 -1
 //
@@ -1271,12 +1271,12 @@ size_t test16(struct annotated *p) {
 }
 
 // SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test17(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    ret i64 -1
 //
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test17(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i64 -1
 //
@@ -1296,12 +1296,12 @@ size_t test17(struct annotated *p) {
 }
 
 // SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test18(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    ret i64 -1
 //
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local noundef i64 @test18(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR4]] {
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readnone [[P:%.*]]) local_unnamed_addr #[[ATTR3]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i64 -1
 //
@@ -1358,7 +1358,7 @@ struct tests_foo {
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = icmp ugt i32 [[DOTCOUNTED_BY_LOAD]], 10
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP0]], label [[CONT4:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB27:[0-9]+]], i64 10) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB27:[0-9]+]], i64 10) #[[ATTR9]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont4:
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX2:%.*]] = getelementptr inbounds i8, ptr [[VAR]], i64 84
@@ -1399,7 +1399,7 @@ int test20(int c, struct tests_foo *var) {
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = icmp ugt i32 [[DOTCOUNTED_BY_LOAD]], 10
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP1]], label [[CONT5:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB28:[0-9]+]], i64 10) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB28:[0-9]+]], i64 10) #[[ATTR9]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont5:
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 44
@@ -1407,7 +1407,7 @@ int test20(int c, struct tests_foo *var) {
 // SANITIZE-WITH-ATTR-NEXT:    ret i32 [[TMP2]]
 //
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test21(
-// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[VAR:%.*]]) local_unnamed_addr #[[ATTR9:[0-9]+]] {
+// NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[C:%.*]], ptr nocapture noundef readonly [[VAR:%.*]]) local_unnamed_addr #[[ATTR8:[0-9]+]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[VAR]], align 8, !tbaa [[TBAA11]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 44
@@ -1451,7 +1451,7 @@ struct test22_foo {
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = icmp ult i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP1]], label [[CONT5:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB29:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB29:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont5:
 // SANITIZE-WITH-ATTR-NEXT:    [[ARR:%.*]] = getelementptr inbounds nuw i8, ptr [[FOO]], i64 8
@@ -1522,7 +1522,7 @@ struct test23_foo {
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = icmp ult i64 [[IDXPROM]], [[TMP0]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP1]], label [[CONT3:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB31:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB31:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont3:
 // SANITIZE-WITH-ATTR-NEXT:    [[ENTRIES:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 24
@@ -1588,7 +1588,7 @@ struct test24_foo {
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP4:%.*]] = icmp ult i64 [[IDXPROM]], [[TMP3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP4]], label [[CONT17:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB33:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB33:[0-9]+]], i64 [[IDXPROM]]) #[[ATTR9]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont17:
 // SANITIZE-WITH-ATTR-NEXT:    [[ARR:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP2]], i64 12
@@ -1597,7 +1597,7 @@ struct test24_foo {
 // SANITIZE-WITH-ATTR-NEXT:    ret i32 [[TMP5]]
 //
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test24(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR9]] {
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]], i32 noundef [[I:%.*]]) local_unnamed_addr #[[ATTR8]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[P]], align 8, !tbaa [[TBAA11]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = load ptr, ptr [[TMP0]], align 8, !tbaa [[TBAA11]]
@@ -1650,19 +1650,19 @@ struct annotated_struct_array {
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = zext i32 [[IDX1]] to i64
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP0]], label [[CONT3:%.*]], label [[HANDLER_OUT_OF_BOUNDS:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB35:[0-9]+]], i64 [[TMP1]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB35:[0-9]+]], i64 [[TMP1]]) #[[ATTR9]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont3:
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x ptr], ptr [[ANN]], i64 0, i64 [[TMP1]]
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP2:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA14]]
-// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP2]], i64 8
+// SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[TMP2]], i64 8
 // SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM15:%.*]] = sext i32 [[IDX2]] to i64
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP3:%.*]] = zext i32 [[DOT_COUNTED_BY_LOAD]] to i64, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP4:%.*]] = icmp ult i64 [[IDXPROM15]], [[TMP3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP4]], label [[CONT20:%.*]], label [[HANDLER_OUT_OF_BOUNDS16:%.*]], !prof [[PROF3]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       handler.out_of_bounds16:
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB36:[0-9]+]], i64 [[IDXPROM15]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB36:[0-9]+]], i64 [[IDXPROM15]]) #[[ATTR9]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR:       cont20:
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP2]], i64 12
@@ -1674,12 +1674,12 @@ struct annotated_struct_array {
 // SANITIZE-WITH-ATTR-NEXT:    ret void
 //
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test25(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[ANN:%.*]], i32 noundef [[IDX1:%.*]], i32 noundef [[IDX2:%.*]]) local_unnamed_addr #[[ATTR10:[0-9]+]] {
+// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[ANN:%.*]], i32 noundef [[IDX1:%.*]], i32 noundef [[IDX2:%.*]]) local_unnamed_addr #[[ATTR9:[0-9]+]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[IDX1]] to i64
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x ptr], ptr [[ANN]], i64 0, i64 [[IDXPROM]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA11]]
-// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 8
+// NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[TMP0]], i64 8
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = shl i32 [[DOT_COUNTED_BY_LOAD]], 2
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOTINV:%.*]] = icmp slt i32 [[DOT_COUNTED_BY_LOAD]], 0
@@ -1736,14 +1736,14 @@ struct test26_struct {
 };
 
 // SANITIZE-WITH-ATTR-LABEL: define dso_local void @test26(
-// SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR5]] {
+// SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR4]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = zext i32 [[IDX]] to i64, !nosanitize [[META2]]
-// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB38:[0-9]+]], i64 [[TMP0]]) #[[ATTR10]], !nosanitize [[META2]]
+// SANITIZE-WITH-ATTR-NEXT:    tail call void @__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB38:[0-9]+]], i64 [[TMP0]]) #[[ATTR9]], !nosanitize [[META2]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META2]]
 //
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local void @test26(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR1]] {
+// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[PCPU_REFCNT:%.*]] = getelementptr inbounds nuw i8, ptr [[PTR]], i64 12
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
@@ -1780,12 +1780,12 @@ struct test27_struct {
 };
 
 // SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test27(
-// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] {
 // SANITIZE-WITH-ATTR-NEXT:  entry:
 // SANITIZE-WITH-ATTR-NEXT:    ret i32 -1
 //
 // NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i32 @test27(
-// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// NO-SANITIZE-WITH-ATTR-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[IDX:%.*]]) local_unnamed_addr #[[ATTR3]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  entry:
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i32 -1
 //

>From c3901685b754eec3a949365f00b608c06db20d51 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 31 Oct 2024 19:59:42 -0700
Subject: [PATCH 55/59] Regenerate testcase.

---
 clang/test/CodeGen/builtin-counted-by-ref.c | 24 ++++++++++-----------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/clang/test/CodeGen/builtin-counted-by-ref.c b/clang/test/CodeGen/builtin-counted-by-ref.c
index 8fcab0086521fd..fdb63c17673962 100644
--- a/clang/test/CodeGen/builtin-counted-by-ref.c
+++ b/clang/test/CodeGen/builtin-counted-by-ref.c
@@ -16,8 +16,8 @@ struct a {
 // X86_64-NEXT:    [[ADD:%.*]] = add nsw i64 [[MUL]], 4
 // X86_64-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3:[0-9]+]]
 // X86_64-NEXT:    [[CONV1:%.*]] = trunc i32 [[SIZE]] to i16
-// X86_64-NEXT:    [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 2
-// X86_64-NEXT:    store i16 [[CONV1]], ptr [[COUNT]], align 2, !tbaa [[TBAA2:![0-9]+]]
+// X86_64-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 2
+// X86_64-NEXT:    store i16 [[CONV1]], ptr [[DOT_COUNTED_BY_GEP]], align 2, !tbaa [[TBAA2:![0-9]+]]
 // X86_64-NEXT:    ret ptr [[CALL]]
 //
 // I386-LABEL: define dso_local noalias noundef ptr @test1(
@@ -27,8 +27,8 @@ struct a {
 // I386-NEXT:    [[ADD:%.*]] = add i32 [[MUL]], 4
 // I386-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3:[0-9]+]]
 // I386-NEXT:    [[CONV:%.*]] = trunc i32 [[SIZE]] to i16
-// I386-NEXT:    [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i32 2
-// I386-NEXT:    store i16 [[CONV]], ptr [[COUNT]], align 2, !tbaa [[TBAA3:![0-9]+]]
+// I386-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i32 2
+// I386-NEXT:    store i16 [[CONV]], ptr [[DOT_COUNTED_BY_GEP]], align 2, !tbaa [[TBAA3:![0-9]+]]
 // I386-NEXT:    ret ptr [[CALL]]
 //
 struct a *test1(int size) {
@@ -69,8 +69,8 @@ struct b {
 // X86_64-NEXT:    [[ADD:%.*]] = add nsw i64 [[MUL]], 4
 // X86_64-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3]]
 // X86_64-NEXT:    [[CONV1:%.*]] = trunc i32 [[SIZE]] to i8
-// X86_64-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 12
-// X86_64-NEXT:    store i8 [[CONV1]], ptr [[TMP0]], align 1, !tbaa [[TBAA6:![0-9]+]]
+// X86_64-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 12
+// X86_64-NEXT:    store i8 [[CONV1]], ptr [[DOT_COUNTED_BY_GEP]], align 1, !tbaa [[TBAA6:![0-9]+]]
 // X86_64-NEXT:    ret ptr [[CALL]]
 //
 // I386-LABEL: define dso_local noalias noundef ptr @test2(
@@ -80,8 +80,8 @@ struct b {
 // I386-NEXT:    [[ADD:%.*]] = add i32 [[MUL]], 4
 // I386-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3]]
 // I386-NEXT:    [[CONV:%.*]] = trunc i32 [[SIZE]] to i8
-// I386-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i32 12
-// I386-NEXT:    store i8 [[CONV]], ptr [[TMP0]], align 1, !tbaa [[TBAA7:![0-9]+]]
+// I386-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i32 12
+// I386-NEXT:    store i8 [[CONV]], ptr [[DOT_COUNTED_BY_GEP]], align 1, !tbaa [[TBAA7:![0-9]+]]
 // I386-NEXT:    ret ptr [[CALL]]
 //
 struct b *test2(int size) {
@@ -141,8 +141,8 @@ struct d {
 // X86_64-NEXT:    [[ADD:%.*]] = add nsw i64 [[MUL]], 4
 // X86_64-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i64 noundef [[ADD]]) #[[ATTR3]]
 // X86_64-NEXT:    [[CONV1:%.*]] = trunc i32 [[SIZE]] to i16
-// X86_64-NEXT:    [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i64 2
-// X86_64-NEXT:    store i16 [[CONV1]], ptr [[COUNT]], align 2, !tbaa [[TBAA2]]
+// X86_64-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i64 2
+// X86_64-NEXT:    store i16 [[CONV1]], ptr [[DOT_COUNTED_BY_GEP]], align 2, !tbaa [[TBAA2]]
 // X86_64-NEXT:    ret ptr [[CALL]]
 //
 // I386-LABEL: define dso_local noalias noundef ptr @test4(
@@ -152,8 +152,8 @@ struct d {
 // I386-NEXT:    [[ADD:%.*]] = add i32 [[MUL]], 4
 // I386-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i32 noundef [[ADD]]) #[[ATTR3]]
 // I386-NEXT:    [[CONV:%.*]] = trunc i32 [[SIZE]] to i16
-// I386-NEXT:    [[COUNT:%.*]] = getelementptr inbounds nuw i8, ptr [[CALL]], i32 2
-// I386-NEXT:    store i16 [[CONV]], ptr [[COUNT]], align 2, !tbaa [[TBAA3]]
+// I386-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[CALL]], i32 2
+// I386-NEXT:    store i16 [[CONV]], ptr [[DOT_COUNTED_BY_GEP]], align 2, !tbaa [[TBAA3]]
 // I386-NEXT:    ret ptr [[CALL]]
 //
 struct d *test4(int size, int idx) {

>From 213b00df1ee1e39dc555f0c6ac6210043fc2655f Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 31 Oct 2024 20:05:46 -0700
Subject: [PATCH 56/59] Remove warning that no longer shows up.

---
 clang/test/Sema/builtin-counted-by-ref.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/Sema/builtin-counted-by-ref.c b/clang/test/Sema/builtin-counted-by-ref.c
index 48c470948e265e..20fa634fcbdf07 100644
--- a/clang/test/Sema/builtin-counted-by-ref.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -31,7 +31,7 @@ void test2(struct fam_struct *ptr, int idx) {
   __builtin_counted_by_ref(global_array);                   // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
   __builtin_counted_by_ref(global_int);                     // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
   __builtin_counted_by_ref(&global_int);                    // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
-  __builtin_counted_by_ref(&ptr->array[idx++]);             // expected-warning {{'__builtin_counted_by_ref' argument has side-effects that will be discarded}} expected-warning {{expression result unused}}
+  __builtin_counted_by_ref(&ptr->array[idx++]);             // expected-warning {{'__builtin_counted_by_ref' argument has side-effects that will be discarded}}
 }
 
 void foo(char *);

>From c4509f2d26c4f3308ef1d0d97499ed76b59940e3 Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Thu, 31 Oct 2024 20:07:20 -0700
Subject: [PATCH 57/59] Regenerate testcase

---
 clang/test/CodeGen/attr-counted-by-pr110385.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/clang/test/CodeGen/attr-counted-by-pr110385.c b/clang/test/CodeGen/attr-counted-by-pr110385.c
index e120dcc583578d..6136ce77a2570b 100644
--- a/clang/test/CodeGen/attr-counted-by-pr110385.c
+++ b/clang/test/CodeGen/attr-counted-by-pr110385.c
@@ -31,7 +31,7 @@ void init(void * __attribute__((pass_dynamic_object_size(0))));
 // CHECK-NEXT:    [[GROWABLE:%.*]] = getelementptr inbounds nuw i8, ptr [[FOO]], i64 8
 // CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr [[GROWABLE]], align 8, !tbaa [[TBAA2:![0-9]+]]
 // CHECK-NEXT:    [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP0]], i64 12
-// CHECK-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 8
+// CHECK-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[TMP0]], i64 8
 // CHECK-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // CHECK-NEXT:    [[TMP1:%.*]] = sext i32 [[DOT_COUNTED_BY_LOAD]] to i64
 // CHECK-NEXT:    [[TMP2:%.*]] = shl nsw i64 [[TMP1]], 1
@@ -48,7 +48,7 @@ void test1(struct bucket *foo) {
 // CHECK-SAME: ptr noundef [[FOO:%.*]]) local_unnamed_addr #[[ATTR0]] {
 // CHECK-NEXT:  entry:
 // CHECK-NEXT:    [[ARRAY:%.*]] = getelementptr inbounds nuw i8, ptr [[FOO]], i64 16
-// CHECK-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[FOO]], i64 12
+// CHECK-NEXT:    [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr i8, ptr [[FOO]], i64 12
 // CHECK-NEXT:    [[DOT_COUNTED_BY_LOAD:%.*]] = load i32, ptr [[DOT_COUNTED_BY_GEP]], align 4
 // CHECK-NEXT:    [[TMP0:%.*]] = sext i32 [[DOT_COUNTED_BY_LOAD]] to i64
 // CHECK-NEXT:    [[TMP1:%.*]] = shl nsw i64 [[TMP0]], 1
@@ -60,3 +60,11 @@ void test1(struct bucket *foo) {
 void test2(struct bucket2 *foo) {
         init(foo->growable.array);
 }
+//.
+// CHECK: [[TBAA2]] = !{[[META3:![0-9]+]], [[META7:![0-9]+]], i64 8}
+// CHECK: [[META3]] = !{!"bucket", [[META4:![0-9]+]], i64 0, [[META7]], i64 8, [[META4]], i64 16}
+// CHECK: [[META4]] = !{!"int", [[META5:![0-9]+]], i64 0}
+// CHECK: [[META5]] = !{!"omnipotent char", [[META6:![0-9]+]], i64 0}
+// CHECK: [[META6]] = !{!"Simple C/C++ TBAA"}
+// CHECK: [[META7]] = !{!"any pointer", [[META5]], i64 0}
+//.

>From e22f7ef2028ef4e2e4ccab94a19d393cffcf29ad Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 1 Nov 2024 15:28:12 -0700
Subject: [PATCH 58/59] Expand testing. This includes a hack to prevent
 multiple diagnostics for the same issue.

---
 clang/lib/Sema/SemaExpr.cpp              | 34 +++++++++++++++++-------
 clang/test/Sema/builtin-counted-by-ref.c | 28 +++++++++++++++----
 2 files changed, 47 insertions(+), 15 deletions(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 1fcbee174106d4..fc3438bc1207b6 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -9189,23 +9189,35 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
 
   // __builtin_counted_by_ref cannot be assigned to a variable, used in
   // function call, or in a return.
-  auto FindBuiltinCountedByRefExpr = [](Expr *E) {
+  auto FindBuiltinCountedByRefExpr = [&](Expr *E) -> CallExpr * {
     struct BuiltinCountedByRefVisitor
         : public RecursiveASTVisitor<BuiltinCountedByRefVisitor> {
-      CallExpr *CE = nullptr;
-      bool VisitCallExpr(CallExpr *E) {
-        if (E->getBuiltinCallee() == Builtin::BI__builtin_counted_by_ref)
-          CE = E;
+      CallExpr *TheCall = nullptr;
+      bool VisitCallExpr(CallExpr *CE) {
+        if (CE->getBuiltinCallee() == Builtin::BI__builtin_counted_by_ref) {
+          TheCall = CE;
+          return false;
+        }
+        return true;
+      }
+      bool VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *UE) {
+        // A UnaryExprOrTypeTraitExpr---e.g. sizeof, __alignof, etc.---isn't
+        // the same as a CallExpr, so if we find a __builtin_counted_by_ref()
+        // call in one, ignore it.
         return false;
       }
     } V;
     V.TraverseStmt(E);
-    return V.CE;
+    return V.TheCall;
   };
-  if (auto *CE = FindBuiltinCountedByRefExpr(RHS.get()))
+  static llvm::SmallPtrSet<CallExpr *, 4> Diagnosed;
+  if (auto *CE = FindBuiltinCountedByRefExpr(RHS.get());
+      CE && !Diagnosed.count(CE)) {
+    Diagnosed.insert(CE);
     Diag(CE->getExprLoc(),
          diag::err_builtin_counted_by_ref_cannot_leak_reference)
         << CE->getSourceRange();
+  }
 
   // Common case: no conversion required.
   if (LHSType == RHSType) {
@@ -13758,7 +13770,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
   // __builtin_counted_by_ref can't be used in a binary expression or array
   // subscript on the LHS.
   int DiagOption = -1;
-  auto FindInvalidUseOfBoundsSafetyCounter = [&](Expr *E) {
+  auto FindInvalidUseOfBoundsSafetyCounter = [&](Expr *E) -> CallExpr * {
     struct BuiltinCountedByRefVisitor
         : public RecursiveASTVisitor<BuiltinCountedByRefVisitor> {
       CallExpr *CE = nullptr;
@@ -13766,9 +13778,11 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
       int Option = -1;
 
       bool VisitCallExpr(CallExpr *E) {
-        if (E->getBuiltinCallee() == Builtin::BI__builtin_counted_by_ref)
+        if (E->getBuiltinCallee() == Builtin::BI__builtin_counted_by_ref) {
           CE = E;
-        return false;
+          return false;
+        }
+        return true;
       }
 
       bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
diff --git a/clang/test/Sema/builtin-counted-by-ref.c b/clang/test/Sema/builtin-counted-by-ref.c
index 20fa634fcbdf07..c3f59197fdc5e1 100644
--- a/clang/test/Sema/builtin-counted-by-ref.c
+++ b/clang/test/Sema/builtin-counted-by-ref.c
@@ -12,6 +12,8 @@ struct fam_struct {
 };
 
 void test1(struct fam_struct *ptr, int size, int idx) {
+  size_t size_of = sizeof(__builtin_counted_by_ref(ptr->array)); // ok
+
   *__builtin_counted_by_ref(ptr->array) = size;             // ok
   *__builtin_counted_by_ref(&ptr->array[idx]) = size;       // ok
 
@@ -26,28 +28,44 @@ void test1(struct fam_struct *ptr, int size, int idx) {
 void test2(struct fam_struct *ptr, int idx) {
   __builtin_counted_by_ref();                               // expected-error {{too few arguments to function call, expected 1, have 0}}
   __builtin_counted_by_ref(ptr->array, ptr->x, ptr->count); // expected-error {{too many arguments to function call, expected 1, have 3}}
+}
+
+void test3(struct fam_struct *ptr, int idx) {
   __builtin_counted_by_ref(ptr->x);                         // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
   __builtin_counted_by_ref(&ptr->x);                        // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
   __builtin_counted_by_ref(global_array);                   // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
   __builtin_counted_by_ref(global_int);                     // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
   __builtin_counted_by_ref(&global_int);                    // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
+}
+
+void test4(struct fam_struct *ptr, int idx) {
   __builtin_counted_by_ref(&ptr->array[idx++]);             // expected-warning {{'__builtin_counted_by_ref' argument has side-effects that will be discarded}}
 }
 
 void foo(char *);
 
-void *test3(struct fam_struct *ptr, int size, int idx) {
+void *test5(struct fam_struct *ptr, int size, int idx) {
   char *ref = __builtin_counted_by_ref(ptr->array);         // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
 
   ref = __builtin_counted_by_ref(ptr->array);               // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
   ref = (char *)(int *)(42 + &*__builtin_counted_by_ref(ptr->array)); // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
   foo(__builtin_counted_by_ref(ptr->array));                // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
-  *(__builtin_counted_by_ref(ptr->array) + 4) = 37;         // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in a binary expression}}
-  __builtin_counted_by_ref(ptr->array)[3] = 37;             // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in an array subscript expression}}
+  foo(ref = __builtin_counted_by_ref(ptr->array));          // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
+
+  if ((ref = __builtin_counted_by_ref(ptr->array)))         // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
+    ;
+
+  for (char *p = __builtin_counted_by_ref(ptr->array); p && *p; ++p) // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
+    ;
 
   return __builtin_counted_by_ref(ptr->array);              // expected-error {{value returned by '__builtin_counted_by_ref' cannot be assigned to a variable, have its address taken, or passed into or returned from a function}}
 }
 
+void test6(struct fam_struct *ptr, int size, int idx) {
+  *(__builtin_counted_by_ref(ptr->array) + 4) = 37;         // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in a binary expression}}
+  __builtin_counted_by_ref(ptr->array)[3] = 37;             // expected-error {{value returned by '__builtin_counted_by_ref' cannot be used in an array subscript expression}}
+}
+
 struct non_fam_struct {
   char x;
   long *pointer;
@@ -55,7 +73,7 @@ struct non_fam_struct {
   short count;
 };
 
-void *test4(struct non_fam_struct *ptr, int size) {
+void *test7(struct non_fam_struct *ptr, int size) {
   *__builtin_counted_by_ref(ptr->array) = size          // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
   *__builtin_counted_by_ref(&ptr->array[0]) = size;     // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
   *__builtin_counted_by_ref(ptr->pointer) = size;       // expected-error {{'__builtin_counted_by_ref' argument must reference a flexible array member}}
@@ -92,7 +110,7 @@ struct unsigned_long_count {
   int array[] __attribute__((counted_by(count)));
 } *ulp;
 
-void test5(void) {
+void test8(void) {
   _Static_assert(_Generic(__builtin_counted_by_ref(cp->array), char * : 1, default : 0) == 1, "wrong return type");
   _Static_assert(_Generic(__builtin_counted_by_ref(sp->array), short * : 1, default : 0) == 1, "wrong return type");
   _Static_assert(_Generic(__builtin_counted_by_ref(ip->array), int * : 1, default : 0) == 1, "wrong return type");

>From 90d6ea82c7a01d1ce5e67f07762838efc826f8db Mon Sep 17 00:00:00 2001
From: Bill Wendling <morbo at google.com>
Date: Fri, 1 Nov 2024 15:43:38 -0700
Subject: [PATCH 59/59] Add test rejecting using of 'counted_by' in C++.

---
 clang/test/Sema/builtin-counted-by-ref.cpp | 8 ++++++++
 1 file changed, 8 insertions(+)
 create mode 100644 clang/test/Sema/builtin-counted-by-ref.cpp

diff --git a/clang/test/Sema/builtin-counted-by-ref.cpp b/clang/test/Sema/builtin-counted-by-ref.cpp
new file mode 100644
index 00000000000000..b9ec9c908dcaa6
--- /dev/null
+++ b/clang/test/Sema/builtin-counted-by-ref.cpp
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -x c++ -fsyntax-only -verify %s
+
+struct fam_struct {
+  int x;
+  char count;
+  int array[] __attribute__((counted_by(count))); // expected-warning {{'counted_by' attribute ignored}}
+};
+



More information about the cfe-commits mailing list