Skip to content

Commit 2dce772

Browse files
committed
Revert "[Clang] Implement the 'counted_by' attribute (#76348)"
This reverts commit fefdef8. Breaks check-clang, see #76348 (comment) Also revert follow-on "[Clang] Update 'counted_by' documentation" This reverts commit 4a3fb9c.
1 parent d85a13b commit 2dce772

20 files changed

+92
-2905
lines changed

clang/docs/ReleaseNotes.rst

-5
Original file line numberDiff line numberDiff line change
@@ -208,11 +208,6 @@ C Language Changes
208208
- Enums will now be represented in TBAA metadata using their actual underlying
209209
integer type. Previously they were treated as chars, which meant they could
210210
alias with all other types.
211-
- Clang now supports the C-only attribute ``counted_by``. When applied to a
212-
struct's flexible array member, it points to the struct field that holds the
213-
number of elements in the flexible array member. This information can improve
214-
the results of the array bound sanitizer and the
215-
``__builtin_dynamic_object_size`` builtin.
216211

217212
C23 Feature Support
218213
^^^^^^^^^^^^^^^^^^^

clang/include/clang/AST/DeclBase.h

-10
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#include "clang/AST/SelectorLocationsKind.h"
2020
#include "clang/Basic/IdentifierTable.h"
2121
#include "clang/Basic/LLVM.h"
22-
#include "clang/Basic/LangOptions.h"
2322
#include "clang/Basic/SourceLocation.h"
2423
#include "clang/Basic/Specifiers.h"
2524
#include "llvm/ADT/ArrayRef.h"
@@ -489,15 +488,6 @@ class alignas(8) Decl {
489488
// Return true if this is a FileContext Decl.
490489
bool isFileContextDecl() const;
491490

492-
/// Whether it resembles a flexible array member. This is a static member
493-
/// because we want to be able to call it with a nullptr. That allows us to
494-
/// perform non-Decl specific checks based on the object's type and strict
495-
/// flex array level.
496-
static bool isFlexibleArrayMemberLike(
497-
ASTContext &Context, const Decl *D, QualType Ty,
498-
LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel,
499-
bool IgnoreTemplateOrMacroSubstitution);
500-
501491
ASTContext &getASTContext() const LLVM_READONLY;
502492

503493
/// Helper to get the language options from the ASTContext.

clang/include/clang/Basic/Attr.td

-18
Original file line numberDiff line numberDiff line change
@@ -4372,21 +4372,3 @@ def CodeAlign: StmtAttr {
43724372
static constexpr int MaximumAlignment = 4096;
43734373
}];
43744374
}
4375-
4376-
def CountedBy : InheritableAttr {
4377-
let Spellings = [Clang<"counted_by">];
4378-
let Subjects = SubjectList<[Field]>;
4379-
let Args = [IdentifierArgument<"CountedByField">];
4380-
let Documentation = [CountedByDocs];
4381-
let LangOpts = [COnly];
4382-
// FIXME: This is ugly. Let using a DeclArgument would be nice, but a Decl
4383-
// isn't yet available due to the fact that we're still parsing the
4384-
// structure. Maybe that code could be changed sometime in the future.
4385-
code AdditionalMembers = [{
4386-
private:
4387-
SourceRange CountedByFieldLoc;
4388-
public:
4389-
SourceRange getCountedByFieldLoc() const { return CountedByFieldLoc; }
4390-
void setCountedByFieldLoc(SourceRange Loc) { CountedByFieldLoc = Loc; }
4391-
}];
4392-
}

clang/include/clang/Basic/AttrDocs.td

-106
Original file line numberDiff line numberDiff line change
@@ -7749,109 +7749,3 @@ but do not pass them to the underlying coroutine or pass them by value.
77497749
.. _`CRT`: https://clang.llvm.org/docs/AttributeReference.html#coro-return-type
77507750
}];
77517751
}
7752-
7753-
def CountedByDocs : Documentation {
7754-
let Category = DocCatField;
7755-
let Content = [{
7756-
Clang supports the ``counted_by`` attribute on the flexible array member of a
7757-
structure in C. The argument for the attribute is the name of a field member
7758-
holding the count of elements in the flexible array. This information can be
7759-
used to improve the results of the array bound sanitizer and the
7760-
``__builtin_dynamic_object_size`` builtin. The ``count`` field member must be
7761-
within the same non-anonymous, enclosing struct as the flexible array member.
7762-
7763-
This example specifies that the flexible array member ``array`` has the number
7764-
of elements allocated for it in ``count``:
7765-
7766-
.. code-block:: c
7767-
7768-
struct bar;
7769-
7770-
struct foo {
7771-
size_t count;
7772-
char other;
7773-
struct bar *array[] __attribute__((counted_by(count)));
7774-
};
7775-
7776-
This establishes a relationship between ``array`` and ``count``. Specifically,
7777-
``array`` must have at least ``count`` number of elements available. It's the
7778-
user's responsibility to ensure that this relationship is maintained through
7779-
changes to the structure.
7780-
7781-
In the following example, the allocated array erroneously has fewer elements
7782-
than what's specified by ``p->count``. This would result in an out-of-bounds
7783-
access not being detected.
7784-
7785-
.. code-block:: c
7786-
7787-
#define SIZE_INCR 42
7788-
7789-
struct foo *p;
7790-
7791-
void foo_alloc(size_t count) {
7792-
p = malloc(MAX(sizeof(struct foo),
7793-
offsetof(struct foo, array[0]) + count * sizeof(struct bar *)));
7794-
p->count = count + SIZE_INCR;
7795-
}
7796-
7797-
The next example updates ``p->count``, but breaks the relationship requirement
7798-
that ``p->array`` must have at least ``p->count`` number of elements available:
7799-
7800-
.. code-block:: c
7801-
7802-
#define SIZE_INCR 42
7803-
7804-
struct foo *p;
7805-
7806-
void foo_alloc(size_t count) {
7807-
p = malloc(MAX(sizeof(struct foo),
7808-
offsetof(struct foo, array[0]) + count * sizeof(struct bar *)));
7809-
p->count = count;
7810-
}
7811-
7812-
void use_foo(int index, int val) {
7813-
p->count += SIZE_INCR + 1; /* 'count' is now larger than the number of elements of 'array'. */
7814-
p->array[index] = val; /* The sanitizer can't properly check this access. */
7815-
}
7816-
7817-
In this example, an update to ``p->count`` maintains the relationship
7818-
requirement:
7819-
7820-
.. code-block:: c
7821-
7822-
void use_foo(int index, int val) {
7823-
if (p->count == 0)
7824-
return;
7825-
--p->count;
7826-
p->array[index] = val;
7827-
}
7828-
7829-
Flexible array members, with the ``counted_by`` attribute, in unions are
7830-
supported with one limitation. If multiple flexible array members have the
7831-
``counted_by`` attribute, ``__builtin_dynamic_object_size`` won't be able to
7832-
calculate the object's size. For instance, in this example:
7833-
7834-
.. code-block:: c
7835-
7836-
struct union_of_fams {
7837-
int flags;
7838-
union {
7839-
unsigned long normal_field;
7840-
struct {
7841-
int count1;
7842-
int arr1[] __counted_by(count1);
7843-
};
7844-
struct {
7845-
signed char count2;
7846-
int arr2[] __counted_by(count2);
7847-
};
7848-
};
7849-
};
7850-
7851-
size_t get_size(struct union_of_fams *p) {
7852-
return __builtin_dynamic_object_size(p, 1);
7853-
}
7854-
7855-
a call to ``get_size`` will return ``-1``.
7856-
}];
7857-
}

clang/include/clang/Basic/DiagnosticSemaKinds.td

-13
Original file line numberDiff line numberDiff line change
@@ -6441,19 +6441,6 @@ def warn_superclass_variable_sized_type_not_at_end : Warning<
64416441
"field %0 can overwrite instance variable %1 with variable sized type %2"
64426442
" in superclass %3">, InGroup<ObjCFlexibleArray>;
64436443

6444-
def err_flexible_array_count_not_in_same_struct : Error<
6445-
"'counted_by' field %0 isn't within the same struct as the flexible array">;
6446-
def err_counted_by_attr_not_on_flexible_array_member : Error<
6447-
"'counted_by' only applies to C99 flexible array members">;
6448-
def err_counted_by_attr_refers_to_flexible_array : Error<
6449-
"'counted_by' cannot refer to the flexible array %0">;
6450-
def err_counted_by_must_be_in_structure : Error<
6451-
"field %0 in 'counted_by' not inside structure">;
6452-
def err_flexible_array_counted_by_attr_field_not_integer : Error<
6453-
"field %0 in 'counted_by' must be a non-boolean integer type">;
6454-
def note_flexible_array_counted_by_attr_field : Note<
6455-
"field %0 declared here">;
6456-
64576444
let CategoryName = "ARC Semantic Issue" in {
64586445

64596446
// ARC-mode diagnostics.

clang/include/clang/Sema/Sema.h

-3
Original file line numberDiff line numberDiff line change
@@ -4799,8 +4799,6 @@ class Sema final {
47994799
bool CheckAlwaysInlineAttr(const Stmt *OrigSt, const Stmt *CurSt,
48004800
const AttributeCommonInfo &A);
48014801

4802-
bool CheckCountedByAttr(Scope *Scope, const FieldDecl *FD);
4803-
48044802
/// Adjust the calling convention of a method to be the ABI default if it
48054803
/// wasn't specified explicitly. This handles method types formed from
48064804
/// function type typedefs and typename template arguments.
@@ -5644,7 +5642,6 @@ class Sema final {
56445642
CorrectionCandidateCallback &CCC,
56455643
TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr,
56465644
ArrayRef<Expr *> Args = std::nullopt,
5647-
DeclContext *LookupCtx = nullptr,
56485645
TypoExpr **Out = nullptr);
56495646

56505647
DeclResult LookupIvarInObjCMethod(LookupResult &Lookup, Scope *S,

clang/include/clang/Sema/TypoCorrection.h

+4-8
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ class CorrectionCandidateCallback {
282282
public:
283283
static const unsigned InvalidDistance = TypoCorrection::InvalidDistance;
284284

285-
explicit CorrectionCandidateCallback(const IdentifierInfo *Typo = nullptr,
285+
explicit CorrectionCandidateCallback(IdentifierInfo *Typo = nullptr,
286286
NestedNameSpecifier *TypoNNS = nullptr)
287287
: Typo(Typo), TypoNNS(TypoNNS) {}
288288

@@ -319,7 +319,7 @@ class CorrectionCandidateCallback {
319319
/// this method.
320320
virtual std::unique_ptr<CorrectionCandidateCallback> clone() = 0;
321321

322-
void setTypoName(const IdentifierInfo *II) { Typo = II; }
322+
void setTypoName(IdentifierInfo *II) { Typo = II; }
323323
void setTypoNNS(NestedNameSpecifier *NNS) { TypoNNS = NNS; }
324324

325325
// Flags for context-dependent keywords. WantFunctionLikeCasts is only
@@ -345,13 +345,13 @@ class CorrectionCandidateCallback {
345345
candidate.getCorrectionSpecifier() == TypoNNS;
346346
}
347347

348-
const IdentifierInfo *Typo;
348+
IdentifierInfo *Typo;
349349
NestedNameSpecifier *TypoNNS;
350350
};
351351

352352
class DefaultFilterCCC final : public CorrectionCandidateCallback {
353353
public:
354-
explicit DefaultFilterCCC(const IdentifierInfo *Typo = nullptr,
354+
explicit DefaultFilterCCC(IdentifierInfo *Typo = nullptr,
355355
NestedNameSpecifier *TypoNNS = nullptr)
356356
: CorrectionCandidateCallback(Typo, TypoNNS) {}
357357

@@ -365,10 +365,6 @@ class DefaultFilterCCC final : public CorrectionCandidateCallback {
365365
template <class C>
366366
class DeclFilterCCC final : public CorrectionCandidateCallback {
367367
public:
368-
explicit DeclFilterCCC(const IdentifierInfo *Typo = nullptr,
369-
NestedNameSpecifier *TypoNNS = nullptr)
370-
: CorrectionCandidateCallback(Typo, TypoNNS) {}
371-
372368
bool ValidateCandidate(const TypoCorrection &candidate) override {
373369
return candidate.getCorrectionDeclAs<C>();
374370
}

clang/lib/AST/ASTImporter.cpp

-13
Original file line numberDiff line numberDiff line change
@@ -9030,10 +9030,6 @@ class AttrImporter {
90309030
public:
90319031
AttrImporter(ASTImporter &I) : Importer(I), NImporter(I) {}
90329032

9033-
// Useful for accessing the imported attribute.
9034-
template <typename T> T *castAttrAs() { return cast<T>(ToAttr); }
9035-
template <typename T> const T *castAttrAs() const { return cast<T>(ToAttr); }
9036-
90379033
// Create an "importer" for an attribute parameter.
90389034
// Result of the 'value()' of that object is to be passed to the function
90399035
// 'importAttr', in the order that is expected by the attribute class.
@@ -9247,15 +9243,6 @@ Expected<Attr *> ASTImporter::Import(const Attr *FromAttr) {
92479243
From->args_size());
92489244
break;
92499245
}
9250-
case attr::CountedBy: {
9251-
AI.cloneAttr(FromAttr);
9252-
const auto *CBA = cast<CountedByAttr>(FromAttr);
9253-
Expected<SourceRange> SR = Import(CBA->getCountedByFieldLoc()).get();
9254-
if (!SR)
9255-
return SR.takeError();
9256-
AI.castAttrAs<CountedByAttr>()->setCountedByFieldLoc(SR.get());
9257-
break;
9258-
}
92599246

92609247
default: {
92619248
// The default branch works for attributes that have no arguments to import.

clang/lib/AST/DeclBase.cpp

+1-73
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "clang/AST/Type.h"
3030
#include "clang/Basic/IdentifierTable.h"
3131
#include "clang/Basic/LLVM.h"
32+
#include "clang/Basic/LangOptions.h"
3233
#include "clang/Basic/Module.h"
3334
#include "clang/Basic/ObjCRuntime.h"
3435
#include "clang/Basic/PartialDiagnostic.h"
@@ -410,79 +411,6 @@ bool Decl::isFileContextDecl() const {
410411
return DC && DC->isFileContext();
411412
}
412413

413-
bool Decl::isFlexibleArrayMemberLike(
414-
ASTContext &Ctx, const Decl *D, QualType Ty,
415-
LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel,
416-
bool IgnoreTemplateOrMacroSubstitution) {
417-
// For compatibility with existing code, we treat arrays of length 0 or
418-
// 1 as flexible array members.
419-
const auto *CAT = Ctx.getAsConstantArrayType(Ty);
420-
if (CAT) {
421-
using FAMKind = LangOptions::StrictFlexArraysLevelKind;
422-
423-
llvm::APInt Size = CAT->getSize();
424-
if (StrictFlexArraysLevel == FAMKind::IncompleteOnly)
425-
return false;
426-
427-
// GCC extension, only allowed to represent a FAM.
428-
if (Size.isZero())
429-
return true;
430-
431-
if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete && Size.uge(1))
432-
return false;
433-
434-
if (StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete && Size.uge(2))
435-
return false;
436-
} else if (!Ctx.getAsIncompleteArrayType(Ty)) {
437-
return false;
438-
}
439-
440-
if (const auto *OID = dyn_cast_if_present<ObjCIvarDecl>(D))
441-
return OID->getNextIvar() == nullptr;
442-
443-
const auto *FD = dyn_cast_if_present<FieldDecl>(D);
444-
if (!FD)
445-
return false;
446-
447-
if (CAT) {
448-
// GCC treats an array memeber of a union as an FAM if the size is one or
449-
// zero.
450-
llvm::APInt Size = CAT->getSize();
451-
if (FD->getParent()->isUnion() && (Size.isZero() || Size.isOne()))
452-
return true;
453-
}
454-
455-
// Don't consider sizes resulting from macro expansions or template argument
456-
// substitution to form C89 tail-padded arrays.
457-
if (IgnoreTemplateOrMacroSubstitution) {
458-
TypeSourceInfo *TInfo = FD->getTypeSourceInfo();
459-
while (TInfo) {
460-
TypeLoc TL = TInfo->getTypeLoc();
461-
462-
// Look through typedefs.
463-
if (TypedefTypeLoc TTL = TL.getAsAdjusted<TypedefTypeLoc>()) {
464-
const TypedefNameDecl *TDL = TTL.getTypedefNameDecl();
465-
TInfo = TDL->getTypeSourceInfo();
466-
continue;
467-
}
468-
469-
if (auto CTL = TL.getAs<ConstantArrayTypeLoc>()) {
470-
if (const Expr *SizeExpr =
471-
dyn_cast_if_present<IntegerLiteral>(CTL.getSizeExpr());
472-
!SizeExpr || SizeExpr->getExprLoc().isMacroID())
473-
return false;
474-
}
475-
476-
break;
477-
}
478-
}
479-
480-
// Test that the field is the last in the structure.
481-
RecordDecl::field_iterator FI(
482-
DeclContext::decl_iterator(const_cast<FieldDecl *>(FD)));
483-
return ++FI == FD->getParent()->field_end();
484-
}
485-
486414
TranslationUnitDecl *Decl::getTranslationUnitDecl() {
487415
if (auto *TUD = dyn_cast<TranslationUnitDecl>(this))
488416
return TUD;

0 commit comments

Comments
 (0)