void updated this revision to Diff 518546.
void added a comment.
Improve error message to use the unknown field's name.
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/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
@@ -61,6 +61,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
@@ -8238,6 +8238,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<IdentifierInfo *, 2> Names;
+ SmallVector<SourceRange, 2> Ranges;
+ for (unsigned ArgNo = 0; ArgNo < getNumAttributeArgs(AL); ++ArgNo) {
+ if (!AL.isArgIdent(ArgNo)) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
+ << AL << AANT_ArgumentIdentifier;
+ return;
+ }
+
+ IdentifierLoc *IL = AL.getArgAsIdent(ArgNo);
+ Names.push_back(IL->Ident);
+ Ranges.push_back(IL->Loc);
+ }
+
+ 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;
@@ -9136,6 +9159,9 @@
case ParsedAttr::AT_FunctionReturnThunks:
handleFunctionReturnThunksAttr(S, D, AL);
break;
+ case ParsedAttr::AT_ElementCount:
+ handleElementCountAttr(S, D, AL);
+ break;
// Microsoft attributes:
case ParsedAttr::AT_LayoutVersion:
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -17692,6 +17692,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 const IdentifierInfo *
+CheckElementCountAttr(const RecordDecl *RD, const FieldDecl *FD,
+ SourceRange &Loc) {
+ const ElementCountAttr *ECA = FD->getAttr<ElementCountAttr>();
+ unsigned Idx = 0;
+
+ for (const IdentifierInfo *II : ECA->elementCountFields()) {
+ Loc = ECA->getCountFieldSourceRange(Idx++);
+
+ auto DeclIter = llvm::find_if(
+ RD->fields(), [&](const FieldDecl *FD){
+ return II->getName() == FD->getName();
+ });
+
+ if (DeclIter == RD->field_end())
+ return II;
+
+ if (auto *SubRD = DeclIter->getType()->getAsRecordDecl())
+ RD = SubRD;
+ }
+
+ return nullptr;
+}
+
void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD,
SourceRange BraceRange) {
AdjustDeclIfTemplate(TagD);
@@ -17749,6 +17787,17 @@
[](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;
+ if (const IdentifierInfo *II = CheckElementCountAttr(RD, FD, SR))
+ Diag(SR.getBegin(), diag::warn_element_count_placeholder)
+ << II << SR;
+ }
+ }
}
void Sema::ActOnObjCContainerFinishDefinition() {
Index: clang/lib/CodeGen/CGExpr.cpp
===================================================================
--- clang/lib/CodeGen/CGExpr.cpp
+++ clang/lib/CodeGen/CGExpr.cpp
@@ -946,6 +946,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 (const IdentifierInfo *CountField : ECA->elementCountFields()) {
+ MemberExpr *TmpMem = nullptr;
+
+ for (FieldDecl *FD : RD->fields()) {
+ if (FD->getName() != CountField->getName())
+ 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};
@@ -962,8 +1006,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();
@@ -973,6 +1015,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/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -8773,6 +8773,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.
@@ -8979,6 +8985,15 @@
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) {
+ SourceRange SR = Import(ECA->getCountFieldSourceRange(I)).get();
+ AI.getAttrAs<ElementCountAttr>()->addCountFieldSourceRange(SR);
+ }
+ 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
@@ -3366,6 +3366,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
@@ -6988,3 +6988,72 @@
its underlying representation to be a WebAssembly ``funcref``.
}];
}
+
+def ElementCountDocs : Documentation {
+ let Category = DocCatField;
+ let Content = [{
+Clang supports the ``element_count`` attribute for flexible array members. The
+field for the ``element_count`` attribute is 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
@@ -4168,3 +4168,23 @@
let Subjects = SubjectList<[Record]>;
let Documentation = [ReadOnlyPlacementDocs];
}
+
+def ElementCount : InheritableAttr {
+ let Spellings = [Clang<"element_count">];
+ let Subjects = SubjectList<[Field]>;
+ let Args = [VariadicIdentifierArgument<"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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits