void updated this revision to Diff 539219.
void added a comment.

Rebasing


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D148381/new/

https://reviews.llvm.org/D148381

Files:
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/AST/ASTImporter.cpp
  clang/lib/CodeGen/BackendUtil.cpp
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/test/Misc/pragma-attribute-supported-attributes-list.test

Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===================================================================
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -62,6 +62,7 @@
 // CHECK-NEXT: DiagnoseAsBuiltin (SubjectMatchRule_function)
 // CHECK-NEXT: DisableSanitizerInstrumentation (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_variable_is_global)
 // CHECK-NEXT: DisableTailCalls (SubjectMatchRule_function, SubjectMatchRule_objc_method)
+// CHECK-NEXT: ElementCount (SubjectMatchRule_field)
 // CHECK-NEXT: EnableIf (SubjectMatchRule_function)
 // CHECK-NEXT: EnforceTCB (SubjectMatchRule_function, SubjectMatchRule_objc_method)
 // CHECK-NEXT: EnforceTCBLeaf (SubjectMatchRule_function, SubjectMatchRule_objc_method)
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -8349,6 +8349,29 @@
   D->addAttr(ZeroCallUsedRegsAttr::Create(S.Context, Kind, AL));
 }
 
+static void handleElementCountAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+  // TODO: Probably needs more processing here. See Sema::AddAlignValueAttr.
+  SmallVector<StringRef, 2> Names;
+  SmallVector<SourceRange, 2> Ranges;
+
+  for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
+    StringRef Field;
+    SourceLocation FieldLoc;
+
+    if (!S.checkStringLiteralArgumentAttr(AL, I, Field, &FieldLoc))
+      return;
+
+    Names.push_back(Field);
+    Ranges.push_back(FieldLoc);
+  }
+
+  ElementCountAttr *ECA = ::new (S.Context) ElementCountAttr(S.Context, AL,
+                                                             Names.data(),
+                                                             Names.size());
+  ECA->addCountFieldSourceRange(Ranges);
+  D->addAttr(ECA);
+}
+
 static void handleFunctionReturnThunksAttr(Sema &S, Decl *D,
                                            const ParsedAttr &AL) {
   StringRef KindStr;
@@ -9273,6 +9296,10 @@
     handleAvailableOnlyInDefaultEvalMethod(S, D, AL);
     break;
 
+  case ParsedAttr::AT_ElementCount:
+    handleElementCountAttr(S, D, AL);
+    break;
+
   // Microsoft attributes:
   case ParsedAttr::AT_LayoutVersion:
     handleLayoutVersion(S, D, AL);
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -17786,6 +17786,44 @@
          "Broken injected-class-name");
 }
 
+static const FieldDecl *FindFieldWithElementCountAttr(const RecordDecl *RD) {
+  for (const Decl *D : RD->decls()) {
+    if (const auto *FD = dyn_cast<FieldDecl>(D))
+      if (FD->hasAttr<ElementCountAttr>())
+        return FD;
+
+    if (const auto *SubRD = dyn_cast<RecordDecl>(D))
+      if (const FieldDecl *FD = FindFieldWithElementCountAttr(SubRD))
+        return FD;
+  }
+
+  return nullptr;
+}
+
+static StringRef
+CheckElementCountAttr(const RecordDecl *RD, const FieldDecl *FD,
+                      SourceRange &Loc) {
+  const ElementCountAttr *ECA = FD->getAttr<ElementCountAttr>();
+  unsigned Idx = 0;
+
+  for (StringRef Field : ECA->elementCountFields()) {
+    Loc = ECA->getCountFieldSourceRange(Idx++);
+
+    auto DeclIter = llvm::find_if(
+        RD->fields(), [&](const FieldDecl *FD){
+          return Field == FD->getName();
+        });
+
+    if (DeclIter == RD->field_end())
+      return Field;
+
+    if (auto *SubRD = DeclIter->getType()->getAsRecordDecl())
+      RD = SubRD;
+  }
+
+  return StringRef();
+}
+
 void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD,
                                     SourceRange BraceRange) {
   AdjustDeclIfTemplate(TagD);
@@ -17843,6 +17881,19 @@
                      [](const FieldDecl *FD) { return FD->isBitField(); }))
       Diag(BraceRange.getBegin(), diag::warn_pragma_align_not_xl_compatible);
   }
+
+  // Check the "element_count" attribute to ensure that the count field exists
+  // in the struct.
+  if (const RecordDecl *RD = dyn_cast<RecordDecl>(Tag)) {
+    if (const FieldDecl *FD = FindFieldWithElementCountAttr(RD)) {
+      SourceRange SR;
+      StringRef Unknown = CheckElementCountAttr(RD, FD, SR);
+
+      if (!Unknown.empty())
+        Diag(SR.getBegin(), diag::warn_element_count_placeholder)
+            << Unknown << SR;
+    }
+  }
 }
 
 void Sema::ActOnObjCContainerFinishDefinition() {
Index: clang/lib/CodeGen/CGExpr.cpp
===================================================================
--- clang/lib/CodeGen/CGExpr.cpp
+++ clang/lib/CodeGen/CGExpr.cpp
@@ -937,6 +937,50 @@
         return CGF.getVLASize(VAT).NumElts;
       // Ignore pass_object_size here. It's not applicable on decayed pointers.
     }
+
+    if (const auto *ME = dyn_cast<MemberExpr>(CE->getSubExpr())) {
+      if (ME->isFlexibleArrayMemberLike(CGF.getContext(),
+                                        StrictFlexArraysLevel, true)) {
+        if (const auto *MD = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
+          if (const auto *ECA = MD->getAttr<ElementCountAttr>()) {
+            const RecordDecl *RD = MD->getParent();
+            MemberExpr *Mem = nullptr;
+
+            for (StringRef CountField : ECA->elementCountFields()) {
+              MemberExpr *TmpMem = nullptr;
+
+              for (FieldDecl *FD : RD->fields()) {
+                if (FD->getName() != CountField)
+                  continue;
+
+                if (Mem)
+                  TmpMem = MemberExpr::CreateImplicit(
+                      CGF.getContext(), Mem, Mem->getType()->isPointerType(),
+                      FD, FD->getType(), VK_LValue, OK_Ordinary);
+                else
+                  TmpMem = MemberExpr::CreateImplicit(
+                      CGF.getContext(), const_cast<Expr*>(ME->getBase()),
+                      ME->isArrow(), FD, FD->getType(), VK_LValue,
+                      OK_Ordinary);
+
+                if (FD->getType()->isRecordType())
+                  RD = FD->getType()->getAsRecordDecl();
+
+                break;
+              }
+
+              Mem = TmpMem;
+              if (!Mem) break;
+            }
+
+            if (Mem) {
+              IndexedType = Base->getType();
+              return CGF.EmitAnyExprToTemp(Mem).getScalarVal();
+            }
+          }
+        }
+      }
+    }
   }
 
   QualType EltTy{Base->getType()->getPointeeOrArrayElementType(), 0};
@@ -953,8 +997,6 @@
                                       bool Accessed) {
   assert(SanOpts.has(SanitizerKind::ArrayBounds) &&
          "should not be called unless adding bounds checks");
-  SanitizerScope SanScope(this);
-
   const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
     getLangOpts().getStrictFlexArraysLevel();
 
@@ -964,6 +1006,8 @@
   if (!Bound)
     return;
 
+  SanitizerScope SanScope(this);
+
   bool IndexSigned = IndexType->isSignedIntegerOrEnumerationType();
   llvm::Value *IndexVal = Builder.CreateIntCast(Index, SizeTy, IndexSigned);
   llvm::Value *BoundVal = Builder.CreateIntCast(Bound, SizeTy, false);
Index: clang/lib/CodeGen/BackendUtil.cpp
===================================================================
--- clang/lib/CodeGen/BackendUtil.cpp
+++ clang/lib/CodeGen/BackendUtil.cpp
@@ -968,7 +968,8 @@
 
     // Register callbacks to schedule sanitizer passes at the appropriate part
     // of the pipeline.
-    if (LangOpts.Sanitize.has(SanitizerKind::LocalBounds))
+    if (LangOpts.Sanitize.has(SanitizerKind::LocalBounds) ||
+        LangOpts.Sanitize.has(SanitizerKind::ArrayBounds))
       PB.registerScalarOptimizerLateEPCallback(
           [](FunctionPassManager &FPM, OptimizationLevel Level) {
             FPM.addPass(BoundsCheckingPass());
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -8808,6 +8808,12 @@
 public:
   AttrImporter(ASTImporter &I) : Importer(I), NImporter(I) {}
 
+  // Useful for accessing the imported attribute.
+  template <typename T>
+  T *getAttrAs() { return cast<T>(ToAttr); }
+  template <typename T>
+  const T *getAttrAs() const { return cast<T>(ToAttr); }
+
   // Create an "importer" for an attribute parameter.
   // Result of the 'value()' of that object is to be passed to the function
   // 'importAttr', in the order that is expected by the attribute class.
@@ -9014,6 +9020,17 @@
                   From->args_size());
     break;
   }
+  case attr::ElementCount: {
+    AI.cloneAttr(FromAttr);
+    const auto *ECA = cast<ElementCountAttr>(FromAttr);
+    for (unsigned I = 0, E = ECA->elementCountFields_size(); I != E; ++I) {
+      Expected<SourceRange> SR = Import(ECA->getCountFieldSourceRange(I)).get();
+      if (!SR)
+        return SR.takeError();
+      AI.getAttrAs<ElementCountAttr>()->addCountFieldSourceRange(SR.get());
+    }
+    break;
+  }
 
   default: {
     // The default branch works for attributes that have no arguments to import.
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3385,6 +3385,9 @@
 def err_alignment_dependent_typedef_name : Error<
   "requested alignment is dependent but declaration is not dependent">;
 
+def warn_element_count_placeholder : Warning<
+  "element count %0 doesn't exist">;
+
 def warn_alignment_builtin_useless : Warning<
   "%select{aligning a value|the result of checking whether a value is aligned}0"
   " to 1 byte is %select{a no-op|always true}0">, InGroup<TautologicalCompare>;
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -7077,3 +7077,72 @@
 (if any) of these ``cleanup`` callback functions.
 }];
 }
+
+def ElementCountDocs : Documentation {
+  let Category = DocCatField;
+  let Content = [{
+Clang supports the ``element_count`` attribute for flexible array members. The
+argument for the ``element_count`` attribute is the name of a field member in
+the same structure holding the count of elements in the flexible array.
+
+For example:
+
+.. code-block:: c
+
+  struct bar;
+
+  struct foo {
+    size_t num_fam_elements;
+    /* ... */
+    struct bar *fam[] __attribute__((element_count("num_fam_elements")));
+  };
+
+  struct foo *foo_alloc(size_t num_elements) {
+    struct foo *f;
+
+    f = malloc(sizeof(struct foo) + num_elements * sizeof(struct bar *));
+    f->num_fam_elements = num_elements;
+    return f;
+  }
+
+This attribute is used with the ``-fsantize=array-bounds`` flag to trap if a
+flexible array access is outside of the number of elements.
+
+.. code-block:: c
+
+  void mux(struct foo *);
+
+  struct bar *baz(void) {
+    struct foo *f = foo_alloc(128);
+
+    mux(f); /* Fills in fam element. */
+
+    return f->fam[256]; /* Trap. */
+  }
+
+It's possible to specify an element in a substructure. The attribute syntax can
+take a list of field names to the element count.
+
+For example:
+
+.. code-block:: c
+
+  struct bar;
+
+  struct foo {
+    struct {
+      size_t num_fam_elements;
+    } bork;
+    /* ... */
+    struct bar *fam[] __attribute__((element_count("bork", "num_fam_elements")));
+  };
+
+  struct foo *foo_alloc(size_t num_elements) {
+    struct foo *f;
+
+    f = malloc(sizeof(struct foo) + num_elements * sizeof(struct bar *));
+    f->bork.num_fam_elements = num_elements;
+    return f;
+  }
+  }];
+}
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -4199,3 +4199,22 @@
   let Documentation = [Undocumented];
 }
 
+def ElementCount : InheritableAttr {
+  let Spellings = [Clang<"element_count">];
+  let Subjects = SubjectList<[Field]>;
+  let Args = [VariadicStringArgument<"ElementCountFields">];
+  let Documentation = [ElementCountDocs];
+  let LangOpts = [COnly];
+  code AdditionalMembers = [{
+    private:
+      SmallVector<SourceRange, 2> CountFieldRanges;
+    public:
+      void addCountFieldSourceRange(ArrayRef<SourceRange> Ranges) {
+        for (SourceRange SR : Ranges)
+          CountFieldRanges.push_back(SR);
+      }
+      SourceRange getCountFieldSourceRange(unsigned Idx) const {
+        return CountFieldRanges[Idx];
+      }
+  }];
+}
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to