https://github.com/Caryoake updated 
https://github.com/llvm/llvm-project/pull/199241

>From 0230ce5c8d2eb7a558cb8255f8a28659ac73df01 Mon Sep 17 00:00:00 2001
From: Karthik <[email protected]>
Date: Fri, 22 May 2026 21:23:33 -0700
Subject: [PATCH] [Clang][AST][Sema] Introduce CThisExpr to support C bounds
 safety attributes

- Introduced and added CThisExpr to represent the implicit context object in C 
structs.
- Updated SemaDeclAttr to intercept DeclRefExprs in __counted_by which then 
wrap them in a valid MemberExpr utilizing CThisExpr.
- Refactored SemaType so that it  dynamically handles both DeclRefExpr and 
MemberExpr to prevent assertions during type building.
- Added AST traversal, serialization, and printing stubs for CThisExpr.
- I also added AST dump tests for CThisExpr validation.
---
 clang/include/clang/AST/Expr.h                | 35 +++++++++++++++++++
 clang/include/clang/AST/RecursiveASTVisitor.h |  1 +
 clang/include/clang/Basic/StmtNodes.td        |  1 +
 clang/lib/AST/Expr.cpp                        | 10 ++++++
 clang/lib/AST/StmtPrinter.cpp                 |  4 +++
 clang/lib/AST/StmtProfile.cpp                 |  4 +++
 clang/lib/Sema/SemaDeclAttr.cpp               | 15 ++++++++
 clang/lib/Sema/SemaType.cpp                   | 14 ++++++--
 clang/lib/Sema/TreeTransform.h                |  5 +++
 clang/lib/Serialization/ASTReaderStmt.cpp     |  4 +++
 clang/lib/Serialization/ASTWriterStmt.cpp     |  4 +++
 clang/test/AST/ast-dump-cthis-counted-by.c    | 11 ++++++
 12 files changed, 105 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/AST/ast-dump-cthis-counted-by.c

diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 393fe275c62692..aa0811cbe19f42 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -1510,6 +1510,41 @@ class DeclRefExpr final
   }
 };
 
+class CThisExpr : public Expr {
+  SourceLocation Loc;
+
+  CThisExpr(SourceLocation L, QualType Ty)
+      : Expr(CThisExprClass, Ty, VK_PRValue, OK_Ordinary), Loc(L) {
+    setDependence(ExprDependence::None); 
+  }
+
+  CThisExpr(EmptyShell Empty) : Expr(CThisExprClass, Empty) {}
+
+public:
+  static CThisExpr *Create(const ASTContext &Ctx, SourceLocation L,
+                           QualType Ty);
+
+  static CThisExpr *CreateEmpty(const ASTContext &Ctx);
+
+  SourceLocation getLocation() const { return Loc; }
+  void setLocation(SourceLocation L) { Loc = L; }
+
+  SourceLocation getBeginLoc() const { return getLocation(); }
+  SourceLocation getEndLoc() const { return getLocation(); }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CThisExprClass;
+  }
+
+  child_range children() {
+    return child_range(child_iterator(), child_iterator());
+  }
+
+  const_child_range children() const {
+    return const_child_range(const_child_iterator(), const_child_iterator());
+  }
+};
+
 class IntegerLiteral : public Expr, public APIntStorage {
   SourceLocation Loc;
 
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h 
b/clang/include/clang/AST/RecursiveASTVisitor.h
index b5be0910194bd4..94058e99c9ce8d 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2974,6 +2974,7 @@ DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
 })
 
 DEF_TRAVERSE_STMT(CXXThisExpr, {})
+DEF_TRAVERSE_STMT(CThisExpr, {})
 DEF_TRAVERSE_STMT(CXXThrowExpr, {})
 DEF_TRAVERSE_STMT(UserDefinedLiteral, {})
 DEF_TRAVERSE_STMT(DesignatedInitExpr, {})
diff --git a/clang/include/clang/Basic/StmtNodes.td 
b/clang/include/clang/Basic/StmtNodes.td
index e166894ea024b0..1eb9a7b6faf01e 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -137,6 +137,7 @@ def UserDefinedLiteral : StmtNode<CallExpr>;
 def CXXBoolLiteralExpr : StmtNode<Expr>;
 def CXXNullPtrLiteralExpr : StmtNode<Expr>;
 def CXXThisExpr : StmtNode<Expr>;
+def CThisExpr : StmtNode<Expr>; 
 def CXXThrowExpr : StmtNode<Expr>;
 def CXXDefaultArgExpr : StmtNode<Expr>;
 def CXXDefaultInitExpr : StmtNode<Expr>;
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index eb452f5da67874..0cc223987e6622 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -432,6 +432,16 @@ APValue ConstantExpr::getAPValueResult() const {
   llvm_unreachable("invalid ResultKind");
 }
 
+CThisExpr *CThisExpr::Create(const ASTContext &Ctx, SourceLocation L,
+                             QualType Ty) {
+  return new (Ctx) CThisExpr(L, Ty);
+}
+
+CThisExpr *CThisExpr::CreateEmpty(const ASTContext &Ctx) {
+  return new (Ctx) CThisExpr(EmptyShell());
+}
+
+
 DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, ValueDecl *D,
                          bool RefersToEnclosingVariableOrCapture, QualType T,
                          ExprValueKind VK, SourceLocation L,
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 6c3294573e9d4c..d569d8637f3fb0 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -2281,6 +2281,10 @@ void StmtPrinter::VisitCXXThisExpr(CXXThisExpr *Node) {
   OS << "this";
 }
 
+void StmtPrinter::VisitCThisExpr(CThisExpr *Node) {
+  OS << "this";
+}
+
 void StmtPrinter::VisitCXXThrowExpr(CXXThrowExpr *Node) {
   if (!Node->getSubExpr())
     OS << "throw";
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index eb25e5260fd1a3..d1abd6d75509ba 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2124,6 +2124,10 @@ void StmtProfiler::VisitCXXThisExpr(const CXXThisExpr 
*S) {
   ID.AddBoolean(S->isCapturedByCopyInLambdaWithExplicitObjectParameter());
 }
 
+void StmtProfiler::VisitCThisExpr(const CThisExpr *S) {
+  VisitExpr(S);
+}
+
 void StmtProfiler::VisitCXXThrowExpr(const CXXThrowExpr *S) {
   VisitExpr(S);
 }
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 55b6cbcbba57d9..1e5b35346234c7 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -6993,6 +6993,21 @@ static void handleCountedByAttrField(Sema &S, Decl *D, 
const ParsedAttr &AL) {
   if (S.CheckCountedByAttrOnField(FD, CountExpr, CountInBytes, OrNull))
     return;
 
+  // --- CThisExpr Interception Block (This block swaps the DeclRefExpr out)---
+  if (auto *DRE = dyn_cast<DeclRefExpr>(CountExpr)) {
+    if (auto *TargetField = dyn_cast<FieldDecl>(DRE->getDecl())) {
+      QualType StructTy = 
S.Context.getTypeDeclType(cast<TypeDecl>(FD->getParent()));
+      QualType ThisPtrTy = S.Context.getPointerType(StructTy);
+      
+      Expr *CThis = CThisExpr::Create(S.Context, DRE->getBeginLoc(), 
ThisPtrTy);
+
+      CountExpr = MemberExpr::CreateImplicit(S.Context, CThis, 
/*IsArrow=*/true,
+                                             TargetField, 
TargetField->getType(),
+                                             VK_LValue, OK_Ordinary);
+    }
+  }
+  // ------------------------------------
+  
   QualType CAT = S.BuildCountAttributedArrayOrPointerType(
       FD->getType(), CountExpr, CountInBytes, OrNull);
   FD->setType(CAT);
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 44ac4f6630690b..6475c8555b4171 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -9967,9 +9967,17 @@ QualType Sema::BuildTypeofExprType(Expr *E, TypeOfKind 
Kind) {
 static void
 BuildTypeCoupledDecls(Expr *E,
                       llvm::SmallVectorImpl<TypeCoupledDeclRefInfo> &Decls) {
-  // Currently, 'counted_by' only allows direct DeclRefExpr to FieldDecl.
-  auto *CountDecl = cast<DeclRefExpr>(E)->getDecl();
-  Decls.push_back(TypeCoupledDeclRefInfo(CountDecl, /*IsDref*/ false));
+  ValueDecl *CountDecl = nullptr;
+  
+  if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
+    CountDecl = DRE->getDecl();
+  } else if (auto *ME = dyn_cast<MemberExpr>(E)) {
+    CountDecl = ME->getMemberDecl();
+  } else {
+    llvm_unreachable("CountExpr must be a DeclRefExpr or a MemberExpr");
+  }
+
+  Decls.push_back(TypeCoupledDeclRefInfo(CountDecl, /*IsDref=*/false));
 }
 
 QualType Sema::BuildCountAttributedArrayOrPointerType(QualType WrappedTy,
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 444795c3b67b90..88c767421faa44 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -14760,6 +14760,11 @@ 
TreeTransform<Derived>::TransformCXXThisExpr(CXXThisExpr *E) {
   return getDerived().RebuildCXXThisExpr(E->getBeginLoc(), T, E->isImplicit());
 }
 
+template<typename Derived>
+ExprResult TreeTransform<Derived>::TransformCThisExpr(CThisExpr *E) {
+  return E;
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformCXXThrowExpr(CXXThrowExpr *E) {
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp 
b/clang/lib/Serialization/ASTReaderStmt.cpp
index 4ada1dc58042d0..61af99b9dbc41b 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1933,6 +1933,10 @@ void ASTStmtReader::VisitCXXThisExpr(CXXThisExpr *E) {
   E->setCapturedByCopyInLambdaWithExplicitObjectParameter(Record.readInt());
 }
 
+void ASTStmtReader::VisitCThisExpr(CThisExpr *E) {
+  VisitExpr(E);
+}
+
 void ASTStmtReader::VisitCXXThrowExpr(CXXThrowExpr *E) {
   VisitExpr(E);
   E->CXXThrowExprBits.ThrowLoc = readSourceLocation();
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp 
b/clang/lib/Serialization/ASTWriterStmt.cpp
index 47cbef06c3cc44..9a4152da3903bb 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -1951,6 +1951,10 @@ void ASTStmtWriter::VisitCXXThisExpr(CXXThisExpr *E) {
   Code = serialization::EXPR_CXX_THIS;
 }
 
+void ASTStmtWriter::VisitCThisExpr(CThisExpr *E) {
+  VisitExpr(E);
+}
+
 void ASTStmtWriter::VisitCXXThrowExpr(CXXThrowExpr *E) {
   VisitExpr(E);
   Record.AddSourceLocation(E->getThrowLoc());
diff --git a/clang/test/AST/ast-dump-cthis-counted-by.c 
b/clang/test/AST/ast-dump-cthis-counted-by.c
new file mode 100644
index 00000000000000..6a4c6e4812c906
--- /dev/null
+++ b/clang/test/AST/ast-dump-cthis-counted-by.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -fsyntax-only -ast-dump %s | FileCheck %s
+
+// Verifying that CThisExpr generation works for sturct fields
+struct Packet {
+    int size;
+    int *data __attribute__((counted_by(size)));
+};
+
+// CHECK: RecordDecl {{.*}} struct Packet definition
+// CHECK: FieldDecl {{.*}} size 'int'
+// CHECK: FieldDecl {{.*}} data 'int * __counted_by(this->size)':'int *'

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to