[libc-commits] [clang] [clang-tools-extra] [llvm] [libcxx] [flang] [compiler-rt] [libc] [Clang] Generate the GEP instead of adding AST nodes (PR #73730)

Yeoul Na via libc-commits libc-commits at lists.llvm.org
Tue Dec 12 01:04:21 PST 2023


================
@@ -956,60 +951,199 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF,
   return nullptr;
 }
 
-const Expr *
-CodeGenFunction::BuildCountedByFieldExpr(const Expr *Base,
-                                         const ValueDecl *CountedByVD) {
+namespace {
+
+/// \p StructAccessBase returns the base \p Expr of a field access. It returns
+/// either a \p DeclRefExpr, representing the base pointer to the struct, i.e.:
+///
+///     p in p-> a.b.c
+///
+/// or a \p MemberExpr, if the \p MemberExpr has the \p RecordDecl we're
+/// looking for:
+///
+///     struct s {
+///       struct s *ptr;
+///       int count;
+///       char array[] __attribute__((counted_by(count)));
+///     };
+///
+/// If we have an expression like \p p->ptr->array[index], we want the
+/// \p MemberExpr for \p p->ptr instead of \p p.
+class StructAccessBase : public StmtVisitor<StructAccessBase, Expr *> {
+  const RecordDecl *ExpectedRD;
+
+  bool IsExpectedRecordDecl(const Expr *E) const {
+    QualType Ty = E->getType();
+    if (Ty->isPointerType())
+      Ty = Ty->getPointeeType();
+    return ExpectedRD == Ty->getAsRecordDecl();
+  }
+
+public:
+  StructAccessBase(const RecordDecl *ExpectedRD) : ExpectedRD(ExpectedRD) {}
+
+  //===--------------------------------------------------------------------===//
+  //                            Visitor Methods
+  //===--------------------------------------------------------------------===//
+
+  // NOTE: If we build C++ support for counted_by, then we'll have to handle
+  // horrors like this:
+  //
+  //     struct S {
+  //       int x, y;
+  //       int blah[] __attribute__((counted_by(x)));
+  //     } s;
+  //
+  //     int foo(int index, int val) {
+  //       int (S::*IHatePMDs)[] = &S::blah;
+  //       (s.*IHatePMDs)[index] = val;
+  //     }
+
+  Expr *Visit(Expr *E) {
+    return StmtVisitor<StructAccessBase, Expr *>::Visit(E);
+  }
+
+  Expr *VisitStmt(Stmt *S) { return nullptr; }
+
+  // These are the types we expect to return (in order of most to least
+  // likely):
+  //
+  //   1. DeclRefExpr - This is the expression for the base of the structure.
+  //      It's exactly what we want to build an access to the \p counted_by
+  //      field.
+  //   2. MemberExpr - This is the expression that has the same \p RecordDecl
+  //      as the flexble array member's lexical enclosing \p RecordDecl. This
+  //      allows us to catch things like: "p->p->array"
+  //   3. CompoundLiteralExpr - This is for people who create something
+  //      heretical like (struct foo has a flexible array member):
+  //
+  //        (struct foo){ 1, 2 }.blah[idx];
+  Expr *VisitDeclRefExpr(DeclRefExpr *E) {
+    return IsExpectedRecordDecl(E) ? E : nullptr;
+  }
+  Expr *VisitMemberExpr(MemberExpr *E) {
+    if (IsExpectedRecordDecl(E) && E->isArrow())
+      return E;
+    Expr *Res = Visit(E->getBase());
+    return !Res && IsExpectedRecordDecl(E) ? E : Res;
+  }
+  Expr *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
+    return IsExpectedRecordDecl(E) ? E : nullptr;
+  }
+
+  // "Pass This On" --The Knife
+  Expr *VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
+    if (IsExpectedRecordDecl(E))
+      return E;
+    return Visit(E->getBase());
+  }
+  Expr *VisitCastExpr(CastExpr *E) { return Visit(E->getSubExpr()); }
----------------
rapidsna wrote:

So this seems to look through cast expressions. Does it mean casts to/from flexible base would work as below? Are these intended?

```C
struct foo {
  int c;
  int fam[__counted_by(c)];
};

void bar(void) {
  char buf[100];
  __bdos((struct foo *)buf, 0); // the base foo will not be identified. is it intended?
};

struct not_foo {
  int c;
};

void baz(struct foo *p) {
  __bdos((struct not_foo*)p, 0); // the base will be identified as `struct foo *`. is it intended?
};
```

https://github.com/llvm/llvm-project/pull/73730


More information about the libc-commits mailing list