https://github.com/Caryoake updated https://github.com/llvm/llvm-project/pull/199241
>From a5dc9c3a3509c405e528b408a4699df06d78ffd6 Mon Sep 17 00:00:00 2001 From: Karthik <[email protected]> Date: Fri, 22 May 2026 10:05:02 -0700 Subject: [PATCH] [AST][Sema] Introduce CThisExpr for C __counted_by attributes - I introduced CThisExpr to represent the implicit context object in C. - Updated SemaDeclAttr to intercept DeclRefExprs in __counted_by which then wraps them in a MEmberExpr which utilizes CThisExpr. - Updated SemaType to dynamically handle both DeclRefExpr and MemberExpr to prevent assertions during type building. - Added AST traversal, serialization, and printing stubs for CThisExpr. - Also added some AST dump tests for CThisExpr validation. --- clang/include/clang/AST/Expr.h | 40 +++++++++++++++++++ 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, 110 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 393fe275c6269..d210f7717478b 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -1510,6 +1510,46 @@ class DeclRefExpr final } }; +class CThisExpr : public Expr { + SourceLocation Loc; + bool IsImplicit; + + CThisExpr(SourceLocation L, QualType Ty, bool IsImplicit) + : Expr(CThisExprClass, Ty, VK_PRValue, OK_Ordinary), Loc(L), + IsImplicit(IsImplicit) { + setDependence(ExprDependence::None); + } + + CThisExpr(EmptyShell Empty) : Expr(CThisExprClass, Empty) {} + +public: + static CThisExpr *Create(const ASTContext &Ctx, SourceLocation L, + QualType Ty, bool IsImplicit); + + 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(); } + + bool isImplicit() const { return IsImplicit; } + void setImplicit(bool I) { IsImplicit = I; } + + 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 b5be0910194bd..94058e99c9ce8 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 e166894ea024b..1eb9a7b6faf01 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 eb452f5da6787..2a284c6f05d77 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, bool IsImplicit) { + return new (Ctx) CThisExpr(L, Ty, IsImplicit); +} + +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 6c3294573e9d4..d569d8637f3fb 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 eb25e5260fd1a..d1abd6d75509b 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 55b6cbcbba57d..a06c78e5cc214 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, /*IsImplicit=*/true); + + 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 44ac4f6630690..6475c8555b417 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 444795c3b67b9..88c767421faa4 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 4ada1dc58042d..61af99b9dbc41 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 47cbef06c3cc4..9a4152da3903b 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 0000000000000..6a4c6e4812c90 --- /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
