[clang] 6447abe - Revert "[BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (#90786)"
Vitaly Buka via cfe-commits
cfe-commits at lists.llvm.org
Sun May 19 05:45:01 PDT 2024
Author: Vitaly Buka
Date: 2024-05-19T05:44:40-07:00
New Revision: 6447abe067c8088a5cc093fe872719374e174068
URL: https://github.com/llvm/llvm-project/commit/6447abe067c8088a5cc093fe872719374e174068
DIFF: https://github.com/llvm/llvm-project/commit/6447abe067c8088a5cc093fe872719374e174068.diff
LOG: Revert "[BoundsSafety] Allow 'counted_by' attribute on pointers in structs in C (#90786)"
Memory leak: https://lab.llvm.org/buildbot/#/builders/5/builds/43403
Issue #92687
This reverts commit 0ec3b972e58bcbcdc1bebe1696ea37f2931287c3.
Added:
clang/test/Sema/attr-counted-by.c
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/AST/Type.h
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/Type.cpp
clang/lib/Parse/ParseDecl.cpp
clang/lib/Parse/ParseObjc.cpp
clang/lib/Sema/SemaDeclAttr.cpp
clang/lib/Sema/SemaType.cpp
clang/lib/Sema/TreeTransform.h
Removed:
clang/test/AST/attr-counted-by-late-parsed-struct-ptrs.c
clang/test/AST/attr-counted-by-struct-ptrs.c
clang/test/Sema/attr-counted-by-late-parsed-off.c
clang/test/Sema/attr-counted-by-late-parsed-struct-ptrs.c
clang/test/Sema/attr-counted-by-struct-ptrs-sizeless-types.c
clang/test/Sema/attr-counted-by-struct-ptrs.c
clang/test/Sema/attr-counted-by-vla-sizeless-types.c
clang/test/Sema/attr-counted-by-vla.c
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 2f83f5c6d54e9..7af5869d21768 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -317,8 +317,7 @@ New Compiler Flags
- ``-fexperimental-late-parse-attributes`` enables an experimental feature to
allow late parsing certain attributes in specific contexts where they would
- not normally be late parsed. Currently this allows late parsing the
- `counted_by` attribute in C. See `Attribute Changes in Clang`_.
+ not normally be late parsed.
- ``-fseparate-named-sections`` uses separate unique sections for global
symbols in named special sections (i.e. symbols annotated with
@@ -407,24 +406,6 @@ Attribute Changes in Clang
- The ``clspv_libclc_builtin`` attribute has been added to allow clspv
(`OpenCL-C to Vulkan SPIR-V compiler <https://github.com/google/clspv>`_) to identify functions coming from libclc
(`OpenCL-C builtin library <https://libclc.llvm.org>`_).
-- The ``counted_by`` attribute is now allowed on pointers that are members of a
- struct in C.
-
-- The ``counted_by`` attribute can now be late parsed in C when
- ``-fexperimental-late-parse-attributes`` is passed but only when attribute is
- used in the declaration attribute position. This allows using the
- attribute on existing code where it previously impossible to do so without
- re-ordering struct field declarations would break ABI as shown below.
-
- .. code-block:: c
-
- struct BufferTy {
- /* Refering to `count` requires late parsing */
- char* buffer __counted_by(count);
- /* Swapping `buffer` and `count` to avoid late parsing would break ABI */
- size_t count;
- };
-
Improvements to Clang's diagnostics
-----------------------------------
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index c7a8e785913b3..da3834f19ca04 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -2515,7 +2515,6 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
bool isRecordType() const;
bool isClassType() const;
bool isStructureType() const;
- bool isStructureTypeWithFlexibleArrayMember() const;
bool isObjCBoxableRecordType() const;
bool isInterfaceType() const;
bool isStructureOrClassType() const;
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 7a7721239a28f..38ee8356583be 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -2229,8 +2229,7 @@ def TypeNullUnspecified : TypeAttr {
def CountedBy : DeclOrTypeAttr {
let Spellings = [Clang<"counted_by">];
let Subjects = SubjectList<[Field], ErrorDiag>;
- let Args = [ExprArgument<"Count">, IntArgument<"NestedLevel", 1>];
- let LateParsed = LateAttrParseExperimentalExt;
+ let Args = [ExprArgument<"Count">, IntArgument<"NestedLevel">];
let ParseArgumentsAsUnevaluated = 1;
let Documentation = [CountedByDocs];
let LangOpts = [COnly];
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 8e6596410c5d0..09b1874f9fddd 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6533,10 +6533,8 @@ def warn_superclass_variable_sized_type_not_at_end : Warning<
def err_flexible_array_count_not_in_same_struct : Error<
"'counted_by' field %0 isn't within the same struct as the flexible array">;
-def err_counted_by_attr_not_on_ptr_or_flexible_array_member : Error<
- "'counted_by' only applies to pointers or C99 flexible array members">;
-def err_counted_by_attr_on_array_not_flexible_array_member : Error<
- "'counted_by' on arrays only applies to C99 flexible array members">;
+def err_counted_by_attr_not_on_flexible_array_member : Error<
+ "'counted_by' only applies to C99 flexible array members">;
def err_counted_by_attr_refer_to_itself : Error<
"'counted_by' cannot refer to the flexible array member %0">;
def err_counted_by_must_be_in_structure : Error<
@@ -6551,17 +6549,6 @@ def err_counted_by_attr_refer_to_union : Error<
"'counted_by' argument cannot refer to a union member">;
def note_flexible_array_counted_by_attr_field : Note<
"field %0 declared here">;
-def err_counted_by_attr_pointee_unknown_size : Error<
- "'counted_by' cannot be applied to %select{"
- "a pointer with pointee|" // pointer
- "an array with element}0" // array
- " of unknown size because %1 is %select{"
- "an incomplete type|" // CountedByInvalidPointeeTypeKind::INCOMPLETE
- "a sizeless type|" // CountedByInvalidPointeeTypeKind::SIZELESS
- "a function type|" // CountedByInvalidPointeeTypeKind::FUNCTION
- // CountedByInvalidPointeeTypeKind::FLEXIBLE_ARRAY_MEMBER
- "a struct type with a flexible array member"
- "}2">;
let CategoryName = "ARC Semantic Issue" in {
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index af50164a8f93f..1e796e828b10a 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -1645,8 +1645,6 @@ class Parser : public CodeCompletionHandler {
bool EnterScope, bool OnDefinition);
void ParseLexedAttribute(LateParsedAttribute &LA,
bool EnterScope, bool OnDefinition);
- void ParseLexedCAttribute(LateParsedAttribute &LA,
- ParsedAttributes *OutAttrs = nullptr);
void ParseLexedMethodDeclarations(ParsingClass &Class);
void ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM);
void ParseLexedMethodDefs(ParsingClass &Class);
@@ -2533,8 +2531,7 @@ class Parser : public CodeCompletionHandler {
void ParseStructDeclaration(
ParsingDeclSpec &DS,
- llvm::function_ref<Decl *(ParsingFieldDeclarator &)> FieldsCallback,
- LateParsedAttrList *LateFieldAttrs = nullptr);
+ llvm::function_ref<void(ParsingFieldDeclarator &)> FieldsCallback);
DeclGroupPtrTy ParseTopLevelStmtDecl();
@@ -3112,8 +3109,6 @@ class Parser : public CodeCompletionHandler {
SourceLocation ScopeLoc,
ParsedAttr::Form Form);
- void DistributeCLateParsedAttrs(Decl *Dcl, LateParsedAttrList *LateAttrs);
-
void ParseBoundsAttribute(IdentifierInfo &AttrName,
SourceLocation AttrNameLoc, ParsedAttributes &Attrs,
IdentifierInfo *ScopeName, SourceLocation ScopeLoc,
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index d4d4a82525a02..b16a304960d3f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11396,8 +11396,7 @@ class Sema final : public SemaBase {
QualType BuildMatrixType(QualType T, Expr *NumRows, Expr *NumColumns,
SourceLocation AttrLoc);
- QualType BuildCountAttributedArrayOrPointerType(QualType WrappedTy,
- Expr *CountExpr);
+ QualType BuildCountAttributedArrayType(QualType WrappedTy, Expr *CountExpr);
QualType BuildAddressSpaceAttr(QualType &T, LangAS ASIdx, Expr *AddrSpace,
SourceLocation AttrLoc);
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index f69a8f80a6393..e31741cd44240 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -632,16 +632,6 @@ bool Type::isStructureType() const {
return false;
}
-bool Type::isStructureTypeWithFlexibleArrayMember() const {
- const auto *RT = getAs<RecordType>();
- if (!RT)
- return false;
- const auto *Decl = RT->getDecl();
- if (!Decl->isStruct())
- return false;
- return Decl->hasFlexibleArrayMember();
-}
-
bool Type::isObjCBoxableRecordType() const {
if (const auto *RT = getAs<RecordType>())
return RT->getDecl()->hasAttr<ObjCBoxableAttr>();
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 8405b44685ae4..2ce8fa98089f6 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -3288,19 +3288,6 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
}
}
-void Parser::DistributeCLateParsedAttrs(Decl *Dcl,
- LateParsedAttrList *LateAttrs) {
- assert(Dcl && "Dcl cannot be null");
-
- if (!LateAttrs)
- return;
-
- for (auto *LateAttr : *LateAttrs) {
- if (LateAttr->Decls.empty())
- LateAttr->addDecl(Dcl);
- }
-}
-
/// Bounds attributes (e.g., counted_by):
/// AttrName '(' expression ')'
void Parser::ParseBoundsAttribute(IdentifierInfo &AttrName,
@@ -4838,14 +4825,13 @@ static void DiagnoseCountAttributedTypeInUnnamedAnon(ParsingDeclSpec &DS,
///
void Parser::ParseStructDeclaration(
ParsingDeclSpec &DS,
- llvm::function_ref<Decl *(ParsingFieldDeclarator &)> FieldsCallback,
- LateParsedAttrList *LateFieldAttrs) {
+ llvm::function_ref<void(ParsingFieldDeclarator &)> FieldsCallback) {
if (Tok.is(tok::kw___extension__)) {
// __extension__ silences extension warnings in the subexpression.
ExtensionRAIIObject O(Diags); // Use RAII to do this.
ConsumeToken();
- return ParseStructDeclaration(DS, FieldsCallback, LateFieldAttrs);
+ return ParseStructDeclaration(DS, FieldsCallback);
}
// Parse leading attributes.
@@ -4910,12 +4896,10 @@ void Parser::ParseStructDeclaration(
}
// If attributes exist after the declarator, parse them.
- MaybeParseGNUAttributes(DeclaratorInfo.D, LateFieldAttrs);
+ MaybeParseGNUAttributes(DeclaratorInfo.D);
// We're done with this declarator; invoke the callback.
- Decl *Field = FieldsCallback(DeclaratorInfo);
- if (Field)
- DistributeCLateParsedAttrs(Field, LateFieldAttrs);
+ FieldsCallback(DeclaratorInfo);
// If we don't have a comma, it is either the end of the list (a ';')
// or an error, bail out.
@@ -4926,69 +4910,6 @@ void Parser::ParseStructDeclaration(
}
}
-/// Finish parsing an attribute for which parsing was delayed.
-/// This will be called at the end of parsing a class declaration
-/// for each LateParsedAttribute. We consume the saved tokens and
-/// create an attribute with the arguments filled in. We add this
-/// to the Attribute list for the decl.
-void Parser::ParseLexedCAttribute(LateParsedAttribute &LA,
- ParsedAttributes *OutAttrs) {
- // Create a fake EOF so that attribute parsing won't go off the end of the
- // attribute.
- Token AttrEnd;
- AttrEnd.startToken();
- AttrEnd.setKind(tok::eof);
- AttrEnd.setLocation(Tok.getLocation());
- AttrEnd.setEofData(LA.Toks.data());
- LA.Toks.push_back(AttrEnd);
-
- // Append the current token at the end of the new token stream so that it
- // doesn't get lost.
- LA.Toks.push_back(Tok);
- PP.EnterTokenStream(LA.Toks, /*DisableMacroExpansion=*/true,
- /*IsReinject=*/true);
- // Drop the current token and bring the first cached one. It's the same token
- // as when we entered this function.
- ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
-
- ParsedAttributes Attrs(AttrFactory);
-
- assert(LA.Decls.size() <= 1 &&
- "late field attribute expects to have at most one declaration.");
-
- // Dispatch based on the attribute and parse it
- const AttributeCommonInfo::Form ParsedForm = ParsedAttr::Form::GNU();
- IdentifierInfo *ScopeName = nullptr;
- const ParsedAttr::Kind AttrKind =
- ParsedAttr::getParsedKind(&LA.AttrName, /*ScopeName=*/ScopeName,
- /*SyntaxUsed=*/ParsedForm.getSyntax());
- switch (AttrKind) {
- case ParsedAttr::Kind::AT_CountedBy:
- ParseBoundsAttribute(LA.AttrName, LA.AttrNameLoc, Attrs,
- /*ScopeName=*/ScopeName, SourceLocation(),
- /*Form=*/ParsedForm);
- break;
- default:
- llvm_unreachable("Unhandled late parsed attribute");
- }
-
- for (auto *D : LA.Decls)
- Actions.ActOnFinishDelayedAttribute(getCurScope(), D, Attrs);
-
- // Due to a parsing error, we either went over the cached tokens or
- // there are still cached tokens left, so we skip the leftover tokens.
- while (Tok.isNot(tok::eof))
- ConsumeAnyToken();
-
- // Consume the fake EOF token if it's there
- if (Tok.is(tok::eof) && Tok.getEofData() == AttrEnd.getEofData())
- ConsumeAnyToken();
-
- if (OutAttrs) {
- OutAttrs->takeAllFrom(Attrs);
- }
-}
-
/// ParseStructUnionBody
/// struct-contents:
/// struct-declaration-list
@@ -5012,11 +4933,6 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope);
Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
- // `LateAttrParseExperimentalExtOnly=true` requests that only attributes
- // marked with `LateAttrParseExperimentalExt` are late parsed.
- LateParsedAttrList LateFieldAttrs(/*PSoon=*/false,
- /*LateAttrParseExperimentalExtOnly=*/true);
-
// While we still have something to read, read the declarations in the struct.
while (!tryParseMisplacedModuleImport() && Tok.isNot(tok::r_brace) &&
Tok.isNot(tok::eof)) {
@@ -5067,19 +4983,18 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
}
if (!Tok.is(tok::at)) {
- auto CFieldCallback = [&](ParsingFieldDeclarator &FD) -> Decl * {
+ auto CFieldCallback = [&](ParsingFieldDeclarator &FD) {
// Install the declarator into the current TagDecl.
Decl *Field =
Actions.ActOnField(getCurScope(), TagDecl,
FD.D.getDeclSpec().getSourceRange().getBegin(),
FD.D, FD.BitfieldSize);
FD.complete(Field);
- return Field;
};
// Parse all the comma separated declarators.
ParsingDeclSpec DS(*this);
- ParseStructDeclaration(DS, CFieldCallback, &LateFieldAttrs);
+ ParseStructDeclaration(DS, CFieldCallback);
} else { // Handle @defs
ConsumeToken();
if (!Tok.isObjCAtKeyword(tok::objc_defs)) {
@@ -5120,12 +5035,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
ParsedAttributes attrs(AttrFactory);
// If attributes exist after struct contents, parse them.
- MaybeParseGNUAttributes(attrs, &LateFieldAttrs);
-
- // Late parse field attributes if necessary.
- assert(!getLangOpts().CPlusPlus);
- for (auto *LateAttr : LateFieldAttrs)
- ParseLexedCAttribute(*LateAttr);
+ MaybeParseGNUAttributes(attrs);
SmallVector<Decl *, 32> FieldDecls(TagDecl->fields());
diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp
index 6a2088a73c55b..89f4acbd25e49 100644
--- a/clang/lib/Parse/ParseObjc.cpp
+++ b/clang/lib/Parse/ParseObjc.cpp
@@ -780,16 +780,16 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
}
bool addedToDeclSpec = false;
- auto ObjCPropertyCallback = [&](ParsingFieldDeclarator &FD) -> Decl * {
+ auto ObjCPropertyCallback = [&](ParsingFieldDeclarator &FD) {
if (FD.D.getIdentifier() == nullptr) {
Diag(AtLoc, diag::err_objc_property_requires_field_name)
<< FD.D.getSourceRange();
- return nullptr;
+ return;
}
if (FD.BitfieldSize) {
Diag(AtLoc, diag::err_objc_property_bitfield)
<< FD.D.getSourceRange();
- return nullptr;
+ return;
}
// Map a nullability property attribute to a context-sensitive keyword
@@ -818,7 +818,6 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
MethodImplKind);
FD.complete(Property);
- return Property;
};
// Parse all the comma separated declarators.
@@ -2014,7 +2013,7 @@ void Parser::ParseObjCClassInstanceVariables(ObjCContainerDecl *interfaceDecl,
continue;
}
- auto ObjCIvarCallback = [&](ParsingFieldDeclarator &FD) -> Decl * {
+ auto ObjCIvarCallback = [&](ParsingFieldDeclarator &FD) {
assert(getObjCDeclContext() == interfaceDecl &&
"Ivar should have interfaceDecl as its decl context");
// Install the declarator into the interface decl.
@@ -2025,7 +2024,6 @@ void Parser::ParseObjCClassInstanceVariables(ObjCContainerDecl *interfaceDecl,
if (Field)
AllIvarDecls.push_back(Field);
FD.complete(Field);
- return Field;
};
// Parse all the comma separated declarators.
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index c8b71631076ba..30776ff537fb5 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -8633,82 +8633,31 @@ static const RecordDecl *GetEnclosingNamedOrTopAnonRecord(const FieldDecl *FD) {
return RD;
}
-enum class CountedByInvalidPointeeTypeKind {
- INCOMPLETE,
- SIZELESS,
- FUNCTION,
- FLEXIBLE_ARRAY_MEMBER,
- VALID,
-};
-
-static bool CheckCountedByAttrOnField(
- Sema &S, FieldDecl *FD, Expr *E,
- llvm::SmallVectorImpl<TypeCoupledDeclRefInfo> &Decls) {
- // Check the context the attribute is used in
-
+static bool
+CheckCountExpr(Sema &S, FieldDecl *FD, Expr *E,
+ llvm::SmallVectorImpl<TypeCoupledDeclRefInfo> &Decls) {
if (FD->getParent()->isUnion()) {
S.Diag(FD->getBeginLoc(), diag::err_counted_by_attr_in_union)
<< FD->getSourceRange();
return true;
}
- const auto FieldTy = FD->getType();
- if (!FieldTy->isArrayType() && !FieldTy->isPointerType()) {
- S.Diag(FD->getBeginLoc(),
- diag::err_counted_by_attr_not_on_ptr_or_flexible_array_member)
- << FD->getLocation();
+ if (!E->getType()->isIntegerType() || E->getType()->isBooleanType()) {
+ S.Diag(E->getBeginLoc(), diag::err_counted_by_attr_argument_not_integer)
+ << E->getSourceRange();
return true;
}
LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
LangOptions::StrictFlexArraysLevelKind::IncompleteOnly;
- if (FieldTy->isArrayType() &&
- !Decl::isFlexibleArrayMemberLike(S.getASTContext(), FD, FieldTy,
- StrictFlexArraysLevel, true)) {
- S.Diag(FD->getBeginLoc(),
- diag::err_counted_by_attr_on_array_not_flexible_array_member)
- << FD->getLocation();
- return true;
- }
- CountedByInvalidPointeeTypeKind InvalidTypeKind =
- CountedByInvalidPointeeTypeKind::VALID;
- QualType PointeeTy;
- int SelectPtrOrArr = 0;
- if (FieldTy->isPointerType()) {
- PointeeTy = FieldTy->getPointeeType();
- SelectPtrOrArr = 0;
- } else {
- assert(FieldTy->isArrayType());
- const ArrayType *AT = S.getASTContext().getAsArrayType(FieldTy);
- PointeeTy = AT->getElementType();
- SelectPtrOrArr = 1;
- }
- // Note: The `Decl::isFlexibleArrayMemberLike` check earlier on means
- // only `PointeeTy->isStructureTypeWithFlexibleArrayMember()` is reachable
- // when `FieldTy->isArrayType()`.
- if (PointeeTy->isIncompleteType()) {
- InvalidTypeKind = CountedByInvalidPointeeTypeKind::INCOMPLETE;
- } else if (PointeeTy->isSizelessType()) {
- InvalidTypeKind = CountedByInvalidPointeeTypeKind::SIZELESS;
- } else if (PointeeTy->isFunctionType()) {
- InvalidTypeKind = CountedByInvalidPointeeTypeKind::FUNCTION;
- } else if (PointeeTy->isStructureTypeWithFlexibleArrayMember()) {
- InvalidTypeKind = CountedByInvalidPointeeTypeKind::FLEXIBLE_ARRAY_MEMBER;
- }
-
- if (InvalidTypeKind != CountedByInvalidPointeeTypeKind::VALID) {
- S.Diag(FD->getBeginLoc(), diag::err_counted_by_attr_pointee_unknown_size)
- << SelectPtrOrArr << PointeeTy << (int)InvalidTypeKind
- << FD->getSourceRange();
- return true;
- }
-
- // Check the expression
-
- if (!E->getType()->isIntegerType() || E->getType()->isBooleanType()) {
- S.Diag(E->getBeginLoc(), diag::err_counted_by_attr_argument_not_integer)
- << E->getSourceRange();
+ if (!Decl::isFlexibleArrayMemberLike(S.getASTContext(), FD, FD->getType(),
+ StrictFlexArraysLevel, true)) {
+ // The "counted_by" attribute must be on a flexible array member.
+ SourceRange SR = FD->getLocation();
+ S.Diag(SR.getBegin(),
+ diag::err_counted_by_attr_not_on_flexible_array_member)
+ << SR;
return true;
}
@@ -8771,11 +8720,10 @@ static void handleCountedByAttrField(Sema &S, Decl *D, const ParsedAttr &AL) {
return;
llvm::SmallVector<TypeCoupledDeclRefInfo, 1> Decls;
- if (CheckCountedByAttrOnField(S, FD, CountExpr, Decls))
+ if (CheckCountExpr(S, FD, CountExpr, Decls))
return;
- QualType CAT =
- S.BuildCountAttributedArrayOrPointerType(FD->getType(), CountExpr);
+ QualType CAT = S.BuildCountAttributedArrayType(FD->getType(), CountExpr);
FD->setType(CAT);
}
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index ef0b6b701a52c..c19c8cc34dd3b 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -9345,9 +9345,9 @@ BuildTypeCoupledDecls(Expr *E,
Decls.push_back(TypeCoupledDeclRefInfo(CountDecl, /*IsDref*/ false));
}
-QualType Sema::BuildCountAttributedArrayOrPointerType(QualType WrappedTy,
- Expr *CountExpr) {
- assert(WrappedTy->isIncompleteArrayType() || WrappedTy->isPointerType());
+QualType Sema::BuildCountAttributedArrayType(QualType WrappedTy,
+ Expr *CountExpr) {
+ assert(WrappedTy->isIncompleteArrayType());
llvm::SmallVector<TypeCoupledDeclRefInfo, 1> Decls;
BuildTypeCoupledDecls(CountExpr, Decls);
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 29444f0edc2ae..b10e5ba65eb1c 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -7344,7 +7344,7 @@ QualType TreeTransform<Derived>::TransformCountAttributedType(
if (getDerived().AlwaysRebuild() || InnerTy != OldTy->desugar() ||
OldCount != NewCount) {
// Currently, CountAttributedType can only wrap incomplete array types.
- Result = SemaRef.BuildCountAttributedArrayOrPointerType(InnerTy, NewCount);
+ Result = SemaRef.BuildCountAttributedArrayType(InnerTy, NewCount);
}
TLB.push<CountAttributedTypeLoc>(Result);
diff --git a/clang/test/AST/attr-counted-by-late-parsed-struct-ptrs.c b/clang/test/AST/attr-counted-by-late-parsed-struct-ptrs.c
deleted file mode 100644
index a585a45eeff03..0000000000000
--- a/clang/test/AST/attr-counted-by-late-parsed-struct-ptrs.c
+++ /dev/null
@@ -1,45 +0,0 @@
-// RUN: %clang_cc1 -fexperimental-late-parse-attributes %s -ast-dump | FileCheck %s
-
-#define __counted_by(f) __attribute__((counted_by(f)))
-
-struct size_known {
- int field;
-};
-
-//==============================================================================
-// __counted_by on struct member pointer in decl attribute position
-//==============================================================================
-
-struct on_member_pointer_complete_ty {
- struct size_known *buf __counted_by(count);
- int count;
-};
-// CHECK-LABEL: struct on_member_pointer_complete_ty definition
-// CHECK-NEXT: |-FieldDecl {{.*}} buf 'struct size_known * __counted_by(count)':'struct size_known *'
-// CHECK-NEXT: `-FieldDecl {{.*}} referenced count 'int'
-
-struct on_pointer_anon_count {
- struct size_known *buf __counted_by(count);
- struct {
- int count;
- };
-};
-
-// CHECK-LABEL: struct on_pointer_anon_count definition
-// CHECK-NEXT: |-FieldDecl {{.*}} buf 'struct size_known * __counted_by(count)':'struct size_known *'
-// CHECK-NEXT: |-RecordDecl {{.*}} struct definition
-// CHECK-NEXT: | `-FieldDecl {{.*}} count 'int'
-// CHECK-NEXT: |-FieldDecl {{.*}} implicit 'struct on_pointer_anon_count::(anonymous at {{.*}})'
-// CHECK-NEXT: `-IndirectFieldDecl {{.*}} implicit referenced count 'int'
-// CHECK-NEXT: |-Field {{.*}} '' 'struct on_pointer_anon_count::(anonymous at {{.*}})'
-// CHECK-NEXT: `-Field {{.*}} 'count' 'int'
-
-//==============================================================================
-// __counted_by on struct member pointer in type attribute position
-//==============================================================================
-// TODO: Correctly parse counted_by as a type attribute. Currently it is parsed
-// as a declaration attribute and is **not** late parsed resulting in the `count`
-// field being unavailable.
-//
-// See `clang/test/Sema/attr-counted-by-late-parsed-struct-ptrs.c` for test
-// cases.
diff --git a/clang/test/AST/attr-counted-by-struct-ptrs.c b/clang/test/AST/attr-counted-by-struct-ptrs.c
deleted file mode 100644
index 79a453d239cd5..0000000000000
--- a/clang/test/AST/attr-counted-by-struct-ptrs.c
+++ /dev/null
@@ -1,117 +0,0 @@
-// RUN: %clang_cc1 %s -ast-dump | FileCheck %s
-
-#define __counted_by(f) __attribute__((counted_by(f)))
-
-struct size_unknown;
-struct size_known {
- int field;
-};
-
-//==============================================================================
-// __counted_by on struct member pointer in decl attribute position
-//==============================================================================
-
-// CHECK-LABEL: RecordDecl {{.+}} struct on_member_pointer_complete_ty definition
-// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
-// CHECK-NEXT: `-FieldDecl {{.+}} buf 'struct size_known * __counted_by(count)':'struct size_known *'
-struct on_member_pointer_complete_ty {
- int count;
- struct size_known * buf __counted_by(count);
-};
-
-// CHECK-LABEL: RecordDecl {{.+}} struct on_pointer_anon_buf definition
-// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
-// CHECK-NEXT: |-RecordDecl {{.+}} struct definition
-// CHECK-NEXT: | `-FieldDecl {{.+}} buf 'struct size_known * __counted_by(count)':'struct size_known *'
-// CHECK-NEXT: |-FieldDecl {{.+}} implicit 'struct on_pointer_anon_buf::(anonymous at [[ANON_STRUCT_PATH:.+]])'
-// CHECK-NEXT: `-IndirectFieldDecl {{.+}} implicit buf 'struct size_known * __counted_by(count)':'struct size_known *'
-// CHECK-NEXT: |-Field {{.+}} '' 'struct on_pointer_anon_buf::(anonymous at [[ANON_STRUCT_PATH]])'
-// CHECK-NEXT: `-Field {{.+}} 'buf' 'struct size_known * __counted_by(count)':'struct size_known *'
-struct on_pointer_anon_buf {
- int count;
- struct {
- struct size_known *buf __counted_by(count);
- };
-};
-
-struct on_pointer_anon_count {
- struct {
- int count;
- };
- struct size_known *buf __counted_by(count);
-};
-
-//==============================================================================
-// __counted_by on struct member pointer in type attribute position
-//==============================================================================
-// TODO: Correctly parse counted_by as a type attribute. Currently it is parsed
-// as a declaration attribute
-
-// CHECK-LABEL: RecordDecl {{.+}} struct on_member_pointer_complete_ty_ty_pos definition
-// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
-// CHECK-NEXT: `-FieldDecl {{.+}} buf 'struct size_known * __counted_by(count)':'struct size_known *'
-struct on_member_pointer_complete_ty_ty_pos {
- int count;
- struct size_known *__counted_by(count) buf;
-};
-
-// TODO: This should be forbidden but isn't due to counted_by being treated as a
-// declaration attribute. The attribute ends up on the outer most pointer
-// (allowed by sema) even though syntactically its supposed to be on the inner
-// pointer (would not allowed by sema due to pointee being a function type).
-// CHECK-LABEL: RecordDecl {{.+}} struct on_member_pointer_fn_ptr_ty_ty_pos_inner definition
-// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
-// CHECK-NEXT: `-FieldDecl {{.+}} fn_ptr 'void (** __counted_by(count))(void)':'void (**)(void)'
-struct on_member_pointer_fn_ptr_ty_ty_pos_inner {
- int count;
- void (* __counted_by(count) * fn_ptr)(void);
-};
-
-// FIXME: The generated AST here is wrong. The attribute should be on the inner
-// pointer.
-// CHECK-LABEL: RecordDecl {{.+}} struct on_nested_pointer_inner definition
-// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
-// CHECK-NEXT: `-FieldDecl {{.+}} buf 'struct size_known ** __counted_by(count)':'struct size_known **'
-struct on_nested_pointer_inner {
- int count;
- // TODO: This should be disallowed because in the `-fbounds-safety` model
- // `__counted_by` can only be nested when used in function parameters.
- struct size_known *__counted_by(count) *buf;
-};
-
-// CHECK-LABEL: RecordDecl {{.+}} struct on_nested_pointer_outer definition
-// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
-// CHECK-NEXT: `-FieldDecl {{.+}} buf 'struct size_known ** __counted_by(count)':'struct size_known **'
-struct on_nested_pointer_outer {
- int count;
- struct size_known **__counted_by(count) buf;
-};
-
-// CHECK-LABEL: RecordDecl {{.+}} struct on_pointer_anon_buf_ty_pos definition
-// CHECK-NEXT: |-FieldDecl {{.+}} referenced count 'int'
-// CHECK-NEXT: |-RecordDecl {{.+}} struct definition
-// CHECK-NEXT: | `-FieldDecl {{.+}} buf 'struct size_known * __counted_by(count)':'struct size_known *'
-// CHECK-NEXT: |-FieldDecl {{.+}} implicit 'struct on_pointer_anon_buf_ty_pos::(anonymous at [[ANON_STRUCT_PATH2:.+]])'
-// CHECK-NEXT: `-IndirectFieldDecl {{.+}} implicit buf 'struct size_known * __counted_by(count)':'struct size_known *'
-// CHECK-NEXT: |-Field {{.+}} '' 'struct on_pointer_anon_buf_ty_pos::(anonymous at [[ANON_STRUCT_PATH2]])'
-// CHECK-NEXT: `-Field {{.+}} 'buf' 'struct size_known * __counted_by(count)':'struct size_known *'
-struct on_pointer_anon_buf_ty_pos {
- int count;
- struct {
- struct size_known * __counted_by(count) buf;
- };
-};
-
-// CHECK-LABEL: RecordDecl {{.+}} struct on_pointer_anon_count_ty_pos definition
-// CHECK-NEXT: |-RecordDecl {{.+}} struct definition
-// CHECK-NEXT: | `-FieldDecl {{.+}} count 'int'
-// CHECK-NEXT: |-FieldDecl {{.+}} implicit 'struct on_pointer_anon_count_ty_pos::(anonymous at [[ANON_STRUCT_PATH3:.+]])'
-// CHECK-NEXT: |-IndirectFieldDecl {{.+}} implicit referenced count 'int'
-// CHECK-NEXT: | |-Field {{.+}} '' 'struct on_pointer_anon_count_ty_pos::(anonymous at [[ANON_STRUCT_PATH3]])'
-// CHECK-NEXT: | `-Field {{.+}} 'count' 'int'
-struct on_pointer_anon_count_ty_pos {
- struct {
- int count;
- };
- struct size_known *__counted_by(count) buf;
-};
diff --git a/clang/test/Sema/attr-counted-by-late-parsed-off.c b/clang/test/Sema/attr-counted-by-late-parsed-off.c
deleted file mode 100644
index 34f51d10c0838..0000000000000
--- a/clang/test/Sema/attr-counted-by-late-parsed-off.c
+++ /dev/null
@@ -1,26 +0,0 @@
-// RUN: %clang_cc1 -DNEEDS_LATE_PARSING -fno-experimental-late-parse-attributes -fsyntax-only -verify %s
-// RUN: %clang_cc1 -DNEEDS_LATE_PARSING -fsyntax-only -verify %s
-
-// RUN: %clang_cc1 -UNEEDS_LATE_PARSING -fno-experimental-late-parse-attributes -fsyntax-only -verify=ok %s
-// RUN: %clang_cc1 -UNEEDS_LATE_PARSING -fsyntax-only -verify=ok %s
-
-#define __counted_by(f) __attribute__((counted_by(f)))
-
-struct size_known { int dummy; };
-
-#ifdef NEEDS_LATE_PARSING
-struct on_decl {
- // expected-error at +1{{use of undeclared identifier 'count'}}
- struct size_known *buf __counted_by(count);
- int count;
-};
-
-#else
-
-// ok-no-diagnostics
-struct on_decl {
- int count;
- struct size_known *buf __counted_by(count);
-};
-
-#endif
diff --git a/clang/test/Sema/attr-counted-by-late-parsed-struct-ptrs.c b/clang/test/Sema/attr-counted-by-late-parsed-struct-ptrs.c
deleted file mode 100644
index 9ff3b080f6576..0000000000000
--- a/clang/test/Sema/attr-counted-by-late-parsed-struct-ptrs.c
+++ /dev/null
@@ -1,254 +0,0 @@
-// RUN: %clang_cc1 -fexperimental-late-parse-attributes -fsyntax-only -verify %s
-
-#define __counted_by(f) __attribute__((counted_by(f)))
-
-struct size_unknown;
-struct size_known {
- int field;
-};
-
-typedef void(*fn_ptr_ty)(void);
-
-//==============================================================================
-// __counted_by on struct member pointer in decl attribute position
-//==============================================================================
-
-struct on_member_pointer_complete_ty {
- struct size_known * buf __counted_by(count);
- int count;
-};
-
-struct on_member_pointer_incomplete_ty {
- struct size_unknown * buf __counted_by(count); // expected-error{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct size_unknown' is an incomplete type}}
- int count;
-};
-
-struct on_member_pointer_const_incomplete_ty {
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'const struct size_unknown' is an incomplete type}}
- const struct size_unknown * buf __counted_by(count);
- int count;
-};
-
-struct on_member_pointer_void_ty {
- void* buf __counted_by(count); // expected-error{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'void' is an incomplete type}}
- int count;
-};
-
-struct on_member_pointer_fn_ptr_ty {
- // buffer of `count` function pointers is allowed
- void (**fn_ptr)(void) __counted_by(count);
- int count;
-};
-
-
-struct on_member_pointer_fn_ptr_ty_ptr_ty {
- // buffer of `count` function pointers is allowed
- fn_ptr_ty* fn_ptr __counted_by(count);
- int count;
-};
-
-struct on_member_pointer_fn_ty {
- // buffer of `count` functions is not allowed
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'void (void)' is a function type}}
- void (*fn_ptr)(void) __counted_by(count);
- int count;
-};
-
-struct on_member_pointer_fn_ptr_ty_ty {
- // buffer of `count` functions is not allowed
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'void (void)' is a function type}}
- fn_ptr_ty fn_ptr __counted_by(count);
- int count;
-};
-
-struct has_unannotated_vla {
- int count;
- int buffer[];
-};
-
-struct on_member_pointer_struct_with_vla {
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct has_unannotated_vla' is a struct type with a flexible array member}}
- struct has_unannotated_vla* objects __counted_by(count);
- int count;
-};
-
-struct has_annotated_vla {
- int count;
- int buffer[] __counted_by(count);
-};
-
-// Currently prevented because computing the size of `objects` at runtime would
-// require an O(N) walk of `objects` to take into account the length of the VLA
-// in each struct instance.
-struct on_member_pointer_struct_with_annotated_vla {
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct has_annotated_vla' is a struct type with a flexible array member}}
- struct has_annotated_vla* objects __counted_by(count);
- int count;
-};
-
-struct on_pointer_anon_buf {
- // TODO: Support referring to parent scope
- struct {
- // expected-error at +1{{use of undeclared identifier 'count'}}
- struct size_known *buf __counted_by(count);
- };
- int count;
-};
-
-struct on_pointer_anon_count {
- struct size_known *buf __counted_by(count);
- struct {
- int count;
- };
-};
-
-//==============================================================================
-// __counted_by on struct member pointer in type attribute position
-//==============================================================================
-// TODO: Correctly parse counted_by as a type attribute. Currently it is parsed
-// as a declaration attribute and is **not** late parsed resulting in the `count`
-// field being unavailable.
-
-struct on_member_pointer_complete_ty_ty_pos {
- // TODO: Allow this
- // expected-error at +1{{use of undeclared identifier 'count'}}
- struct size_known *__counted_by(count) buf;
- int count;
-};
-
-struct on_member_pointer_incomplete_ty_ty_pos {
- // TODO: Allow this
- // expected-error at +1{{use of undeclared identifier 'count'}}
- struct size_unknown * __counted_by(count) buf;
- int count;
-};
-
-struct on_member_pointer_const_incomplete_ty_ty_pos {
- // TODO: Allow this
- // expected-error at +1{{use of undeclared identifier 'count'}}
- const struct size_unknown * __counted_by(count) buf;
- int count;
-};
-
-struct on_member_pointer_void_ty_ty_pos {
- // TODO: This should fail because the attribute is
- // on a pointer with the pointee being an incomplete type.
- // expected-error at +1{{use of undeclared identifier 'count'}}
- void *__counted_by(count) buf;
- int count;
-};
-
-// -
-
-struct on_member_pointer_fn_ptr_ty_pos {
- // TODO: buffer of `count` function pointers should be allowed
- // but fails because this isn't late parsed.
- // expected-error at +1{{use of undeclared identifier 'count'}}
- void (** __counted_by(count) fn_ptr)(void);
- int count;
-};
-
-struct on_member_pointer_fn_ptr_ty_ptr_ty_pos {
- // TODO: buffer of `count` function pointers should be allowed
- // but fails because this isn't late parsed.
- // expected-error at +1{{use of undeclared identifier 'count'}}
- fn_ptr_ty* __counted_by(count) fn_ptr;
- int count;
-};
-
-struct on_member_pointer_fn_ty_ty_pos {
- // TODO: This should fail because the attribute is
- // on a pointer with the pointee being a function type.
- // expected-error at +1{{use of undeclared identifier 'count'}}
- void (* __counted_by(count) fn_ptr)(void);
- int count;
-};
-
-struct on_member_pointer_fn_ptr_ty_ty_pos {
- // TODO: buffer of `count` function pointers should be allowed
- // expected-error at +1{{use of undeclared identifier 'count'}}
- void (** __counted_by(count) fn_ptr)(void);
- int count;
-};
-
-struct on_member_pointer_fn_ptr_ty_typedef_ty_pos {
- // TODO: This should fail because the attribute is
- // on a pointer with the pointee being a function type.
- // expected-error at +1{{use of undeclared identifier 'count'}}
- fn_ptr_ty __counted_by(count) fn_ptr;
- int count;
-};
-
-struct on_member_pointer_fn_ptr_ty_ty_pos_inner {
- // TODO: This should fail because the attribute is
- // on a pointer with the pointee being a function type.
- // expected-error at +1{{use of undeclared identifier 'count'}}
- void (* __counted_by(count) * fn_ptr)(void);
- int count;
-};
-
-struct on_member_pointer_struct_with_vla_ty_pos {
- // TODO: This should fail because the attribute is
- // on a pointer with the pointee being a struct type with a VLA.
- // expected-error at +1{{use of undeclared identifier 'count'}}
- struct has_unannotated_vla *__counted_by(count) objects;
- int count;
-};
-
-struct on_member_pointer_struct_with_annotated_vla_ty_pos {
- // TODO: This should fail because the attribute is
- // on a pointer with the pointee being a struct type with a VLA.
- // expected-error at +1{{use of undeclared identifier 'count'}}
- struct has_annotated_vla* __counted_by(count) objects;
- int count;
-};
-
-struct on_nested_pointer_inner {
- // TODO: This should be disallowed because in the `-fbounds-safety` model
- // `__counted_by` can only be nested when used in function parameters.
- // expected-error at +1{{use of undeclared identifier 'count'}}
- struct size_known *__counted_by(count) *buf;
- int count;
-};
-
-struct on_nested_pointer_outer {
- // TODO: Allow this
- // expected-error at +1{{use of undeclared identifier 'count'}}
- struct size_known **__counted_by(count) buf;
- int count;
-};
-
-struct on_pointer_anon_buf_ty_pos {
- struct {
- // TODO: Support referring to parent scope
- // expected-error at +1{{use of undeclared identifier 'count'}}
- struct size_known * __counted_by(count) buf;
- };
- int count;
-};
-
-struct on_pointer_anon_count_ty_pos {
- // TODO: Allow this
- // expected-error at +1{{use of undeclared identifier 'count'}}
- struct size_known *__counted_by(count) buf;
- struct {
- int count;
- };
-};
-
-//==============================================================================
-// __counted_by on struct non-pointer members
-//==============================================================================
-
-struct on_pod_ty {
- // expected-error at +1{{'counted_by' only applies to pointers or C99 flexible array members}}
- int wrong_ty __counted_by(count);
- int count;
-};
-
-struct on_void_ty {
- // expected-error at +2{{'counted_by' only applies to pointers or C99 flexible array members}}
- // expected-error at +1{{field has incomplete type 'void'}}
- void wrong_ty __counted_by(count);
- int count;
-};
diff --git a/clang/test/Sema/attr-counted-by-struct-ptrs-sizeless-types.c b/clang/test/Sema/attr-counted-by-struct-ptrs-sizeless-types.c
deleted file mode 100644
index 9b0f2eafb13c2..0000000000000
--- a/clang/test/Sema/attr-counted-by-struct-ptrs-sizeless-types.c
+++ /dev/null
@@ -1,17 +0,0 @@
-// __SVInt8_t is specific to ARM64 so specify that in the target triple
-// RUN: %clang_cc1 -triple arm64-apple-darwin -fsyntax-only -verify %s
-
-#define __counted_by(f) __attribute__((counted_by(f)))
-
-struct on_sizeless_pointee_ty {
- int count;
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because '__SVInt8_t' is a sizeless type}}
- __SVInt8_t* member __counted_by(count);
-};
-
-struct on_sizeless_ty {
- int count;
- // expected-error at +2{{'counted_by' only applies to pointers or C99 flexible array members}}
- // expected-error at +1{{field has sizeless type '__SVInt8_t'}}
- __SVInt8_t member __counted_by(count);
-};
diff --git a/clang/test/Sema/attr-counted-by-struct-ptrs.c b/clang/test/Sema/attr-counted-by-struct-ptrs.c
deleted file mode 100644
index cd2bfe36938b2..0000000000000
--- a/clang/test/Sema/attr-counted-by-struct-ptrs.c
+++ /dev/null
@@ -1,224 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-
-#define __counted_by(f) __attribute__((counted_by(f)))
-
-struct size_unknown;
-struct size_known {
- int field;
-};
-
-typedef void(*fn_ptr_ty)(void);
-
-//==============================================================================
-// __counted_by on struct member pointer in decl attribute position
-//==============================================================================
-
-struct on_member_pointer_complete_ty {
- int count;
- struct size_known * buf __counted_by(count);
-};
-
-struct on_member_pointer_incomplete_ty {
- int count;
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct size_unknown' is an incomplete type}}
- struct size_unknown * buf __counted_by(count);
-};
-
-struct on_member_pointer_const_incomplete_ty {
- int count;
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'const struct size_unknown' is an incomplete type}}
- const struct size_unknown * buf __counted_by(count);
-};
-
-struct on_member_pointer_void_ty {
- int count;
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'void' is an incomplete type}}
- void* buf __counted_by(count);
-};
-
-struct on_member_pointer_fn_ptr_ty {
- int count;
- // buffer of `count` function pointers is allowed
- void (**fn_ptr)(void) __counted_by(count);
-};
-
-struct on_member_pointer_fn_ptr_ty_ptr_ty {
- int count;
- // buffer of `count` function pointers is allowed
- fn_ptr_ty* fn_ptr __counted_by(count);
-};
-
-struct on_member_pointer_fn_ty {
- int count;
- // buffer of `count` functions is not allowed
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'void (void)' is a function type}}
- void (*fn_ptr)(void) __counted_by(count);
-};
-
-struct on_member_pointer_fn_ptr_ty_ty {
- int count;
- // buffer of `count` functions is not allowed
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'void (void)' is a function type}}
- fn_ptr_ty fn_ptr __counted_by(count);
-};
-
-struct has_unannotated_vla {
- int count;
- int buffer[];
-};
-
-struct on_member_pointer_struct_with_vla {
- int count;
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct has_unannotated_vla' is a struct type with a flexible array member}}
- struct has_unannotated_vla* objects __counted_by(count);
-};
-
-struct has_annotated_vla {
- int count;
- int buffer[] __counted_by(count);
-};
-
-// Currently prevented because computing the size of `objects` at runtime would
-// require an O(N) walk of `objects` to take into account the length of the VLA
-// in each struct instance.
-struct on_member_pointer_struct_with_annotated_vla {
- int count;
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct has_annotated_vla' is a struct type with a flexible array member}}
- struct has_annotated_vla* objects __counted_by(count);
-};
-
-struct on_pointer_anon_buf {
- int count;
- struct {
- struct size_known *buf __counted_by(count);
- };
-};
-
-struct on_pointer_anon_count {
- struct {
- int count;
- };
- struct size_known *buf __counted_by(count);
-};
-
-//==============================================================================
-// __counted_by on struct member pointer in type attribute position
-//==============================================================================
-// TODO: Correctly parse counted_by as a type attribute. Currently it is parsed
-// as a declaration attribute
-
-struct on_member_pointer_complete_ty_ty_pos {
- int count;
- struct size_known *__counted_by(count) buf;
-};
-
-struct on_member_pointer_incomplete_ty_ty_pos {
- int count;
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct size_unknown' is an incomplete type}}
- struct size_unknown * __counted_by(count) buf;
-};
-
-struct on_member_pointer_const_incomplete_ty_ty_pos {
- int count;
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'const struct size_unknown' is an incomplete type}}
- const struct size_unknown * __counted_by(count) buf;
-};
-
-struct on_member_pointer_void_ty_ty_pos {
- int count;
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'void' is an incomplete type}}
- void *__counted_by(count) buf;
-};
-
-// -
-
-struct on_member_pointer_fn_ptr_ty_pos {
- int count;
- // buffer of `count` function pointers is allowed
- void (** __counted_by(count) fn_ptr)(void);
-};
-
-struct on_member_pointer_fn_ptr_ty_ptr_ty_pos {
- int count;
- // buffer of `count` function pointers is allowed
- fn_ptr_ty* __counted_by(count) fn_ptr;
-};
-
-struct on_member_pointer_fn_ty_ty_pos {
- int count;
- // buffer of `count` functions is not allowed
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'void (void)' is a function type}}
- void (* __counted_by(count) fn_ptr)(void);
-};
-
-struct on_member_pointer_fn_ptr_ty_ty_pos {
- int count;
- // buffer of `count` functions is not allowed
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'void (void)' is a function type}}
- fn_ptr_ty __counted_by(count) fn_ptr;
-};
-
-// TODO: This should be forbidden but isn't due to counted_by being treated
-// as a declaration attribute.
-struct on_member_pointer_fn_ptr_ty_ty_pos_inner {
- int count;
- void (* __counted_by(count) * fn_ptr)(void);
-};
-
-struct on_member_pointer_struct_with_vla_ty_pos {
- int count;
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct has_unannotated_vla' is a struct type with a flexible array member}}
- struct has_unannotated_vla *__counted_by(count) objects;
-};
-
-// Currently prevented because computing the size of `objects` at runtime would
-// require an O(N) walk of `objects` to take into account the length of the VLA
-// in each struct instance.
-struct on_member_pointer_struct_with_annotated_vla_ty_pos {
- int count;
- // expected-error at +1{{counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct has_annotated_vla' is a struct type with a flexible array member}}
- struct has_annotated_vla* __counted_by(count) objects;
-};
-
-struct on_nested_pointer_inner {
- // TODO: This should be disallowed because in the `-fbounds-safety` model
- // `__counted_by` can only be nested when used in function parameters.
- int count;
- struct size_known *__counted_by(count) *buf;
-};
-
-struct on_nested_pointer_outer {
- int count;
- struct size_known **__counted_by(count) buf;
-};
-
-struct on_pointer_anon_buf_ty_pos {
- int count;
- struct {
- struct size_known * __counted_by(count) buf;
- };
-};
-
-struct on_pointer_anon_count_ty_pos {
- struct {
- int count;
- };
- struct size_known *__counted_by(count) buf;
-};
-
-//==============================================================================
-// __counted_by on struct non-pointer members
-//==============================================================================
-
-struct on_pod_ty {
- int count;
- // expected-error at +1{{'counted_by' only applies to pointers or C99 flexible array members}}
- int wrong_ty __counted_by(count);
-};
-
-struct on_void_ty {
- int count;
- // expected-error at +2{{'counted_by' only applies to pointers or C99 flexible array members}}
- // expected-error at +1{{field has incomplete type 'void'}}
- void wrong_ty __counted_by(count);
-};
diff --git a/clang/test/Sema/attr-counted-by-vla-sizeless-types.c b/clang/test/Sema/attr-counted-by-vla-sizeless-types.c
deleted file mode 100644
index 31c0007501c48..0000000000000
--- a/clang/test/Sema/attr-counted-by-vla-sizeless-types.c
+++ /dev/null
@@ -1,11 +0,0 @@
-// __SVInt8_t is specific to ARM64 so specify that in the target triple
-// RUN: %clang_cc1 -triple arm64-apple-darwin -fsyntax-only -verify %s
-
-#define __counted_by(f) __attribute__((counted_by(f)))
-
-struct on_sizeless_elt_ty {
- int count;
- // expected-error at +2{{'counted_by' only applies to pointers or C99 flexible array members}}
- // expected-error at +1{{array has sizeless element type '__SVInt8_t'}}
- __SVInt8_t arr[] __counted_by(count);
-};
diff --git a/clang/test/Sema/attr-counted-by-vla.c b/clang/test/Sema/attr-counted-by-vla.c
deleted file mode 100644
index 3de6bd55e2d8e..0000000000000
--- a/clang/test/Sema/attr-counted-by-vla.c
+++ /dev/null
@@ -1,193 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-
-#define __counted_by(f) __attribute__((counted_by(f)))
-
-struct bar;
-
-struct not_found {
- int count;
- struct bar *fam[] __counted_by(bork); // expected-error {{use of undeclared identifier 'bork'}}
-};
-
-struct no_found_count_not_in_substruct {
- unsigned long flags;
- unsigned char count; // expected-note {{'count' declared here}}
- struct A {
- int dummy;
- int array[] __counted_by(count); // expected-error {{'counted_by' field 'count' isn't within the same struct as the flexible array}}
- } a;
-};
-
-struct not_found_count_not_in_unnamed_substruct {
- unsigned char count; // expected-note {{'count' declared here}}
- struct {
- int dummy;
- int array[] __counted_by(count); // expected-error {{'counted_by' field 'count' isn't within the same struct as the flexible array}}
- } a;
-};
-
-struct not_found_count_not_in_unnamed_substruct_2 {
- struct {
- unsigned char count; // expected-note {{'count' declared here}}
- };
- struct {
- int dummy;
- int array[] __counted_by(count); // expected-error {{'counted_by' field 'count' isn't within the same struct as the flexible array}}
- } a;
-};
-
-struct not_found_count_in_other_unnamed_substruct {
- struct {
- unsigned char count;
- } a1;
-
- struct {
- int dummy;
- int array[] __counted_by(count); // expected-error {{use of undeclared identifier 'count'}}
- };
-};
-
-struct not_found_count_in_other_substruct {
- struct _a1 {
- unsigned char count;
- } a1;
-
- struct {
- int dummy;
- int array[] __counted_by(count); // expected-error {{use of undeclared identifier 'count'}}
- };
-};
-
-struct not_found_count_in_other_substruct_2 {
- struct _a2 {
- unsigned char count;
- } a2;
-
- int array[] __counted_by(count); // expected-error {{use of undeclared identifier 'count'}}
-};
-
-struct not_found_suggest {
- int bork;
- struct bar *fam[] __counted_by(blork); // expected-error {{use of undeclared identifier 'blork'}}
-};
-
-int global; // expected-note {{'global' declared here}}
-
-struct found_outside_of_struct {
- int bork;
- struct bar *fam[] __counted_by(global); // expected-error {{field 'global' in 'counted_by' not inside structure}}
-};
-
-struct self_referrential {
- int bork;
- struct bar *self[] __counted_by(self); // expected-error {{use of undeclared identifier 'self'}}
-};
-
-struct non_int_count {
- double dbl_count;
- struct bar *fam[] __counted_by(dbl_count); // expected-error {{'counted_by' requires a non-boolean integer type argument}}
-};
-
-struct array_of_ints_count {
- int integers[2];
- struct bar *fam[] __counted_by(integers); // expected-error {{'counted_by' requires a non-boolean integer type argument}}
-};
-
-struct not_a_fam {
- int count;
- // expected-error at +1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct bar' is an incomplete type}}
- struct bar *non_fam __counted_by(count);
-};
-
-struct not_a_c99_fam {
- int count;
- struct bar *non_c99_fam[0] __counted_by(count); // expected-error {{'counted_by' on arrays only applies to C99 flexible array members}}
-};
-
-struct annotated_with_anon_struct {
- unsigned long flags;
- struct {
- unsigned char count;
- int array[] __counted_by(crount); // expected-error {{use of undeclared identifier 'crount'}}
- };
-};
-
-//==============================================================================
-// __counted_by on a struct VLA with element type that has unknown size
-//==============================================================================
-
-struct size_unknown; // expected-note 2{{forward declaration of 'struct size_unknown'}}
-struct on_member_arr_incomplete_ty_ty_pos {
- int count;
- // expected-error at +2{{'counted_by' only applies to pointers or C99 flexible array members}}
- // expected-error at +1{{array has incomplete element type 'struct size_unknown'}}
- struct size_unknown buf[] __counted_by(count);
-};
-
-struct on_member_arr_incomplete_const_ty_ty_pos {
- int count;
- // expected-error at +2{{'counted_by' only applies to pointers or C99 flexible array members}}
- // expected-error at +1{{array has incomplete element type 'const struct size_unknown'}}
- const struct size_unknown buf[] __counted_by(count);
-};
-
-struct on_member_arr_void_ty_ty_pos {
- int count;
- // expected-error at +2{{'counted_by' only applies to pointers or C99 flexible array members}}
- // expected-error at +1{{array has incomplete element type 'void'}}
- void buf[] __counted_by(count);
-};
-
-typedef void(fn_ty)(int);
-
-struct on_member_arr_fn_ptr_ty {
- int count;
- // An Array of function pointers is allowed
- fn_ty* buf[] __counted_by(count);
-};
-
-struct on_member_arr_fn_ty {
- int count;
- // An array of functions is not allowed.
- // expected-error at +2{{'counted_by' only applies to pointers or C99 flexible array members}}
- // expected-error at +1{{'buf' declared as array of functions of type 'fn_ty' (aka 'void (int)')}}
- fn_ty buf[] __counted_by(count);
-};
-
-
-// `buffer_of_structs_with_unnannotated_vla`,
-// `buffer_of_structs_with_annotated_vla`, and
-// `buffer_of_const_structs_with_annotated_vla` are currently prevented because
-// computing the size of `Arr` at runtime would require an O(N) walk of `Arr`
-// elements to take into account the length of the VLA in each struct instance.
-
-struct has_unannotated_VLA {
- int count;
- char buffer[];
-};
-
-struct has_annotated_VLA {
- int count;
- char buffer[] __counted_by(count);
-};
-
-struct buffer_of_structs_with_unnannotated_vla {
- int count;
- // expected-error at +1{{'counted_by' cannot be applied to an array with element of unknown size because 'struct has_unannotated_VLA' is a struct type with a flexible array member}}
- struct has_unannotated_VLA Arr[] __counted_by(count);
-};
-
-
-struct buffer_of_structs_with_annotated_vla {
- int count;
- // expected-error at +1{{'counted_by' cannot be applied to an array with element of unknown size because 'struct has_annotated_VLA' is a struct type with a flexible array member}}
- struct has_annotated_VLA Arr[] __counted_by(count);
-};
-
-struct buffer_of_const_structs_with_annotated_vla {
- int count;
- // Make sure the `const` qualifier is printed when printing the element type.
- // expected-error at +1{{'counted_by' cannot be applied to an array with element of unknown size because 'const struct has_annotated_VLA' is a struct type with a flexible array member}}
- const struct has_annotated_VLA Arr[] __counted_by(count);
-};
-
diff --git a/clang/test/Sema/attr-counted-by.c b/clang/test/Sema/attr-counted-by.c
new file mode 100644
index 0000000000000..d5d4ebf557392
--- /dev/null
+++ b/clang/test/Sema/attr-counted-by.c
@@ -0,0 +1,112 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#define __counted_by(f) __attribute__((counted_by(f)))
+
+struct bar;
+
+struct not_found {
+ int count;
+ struct bar *fam[] __counted_by(bork); // expected-error {{use of undeclared identifier 'bork'}}
+};
+
+struct no_found_count_not_in_substruct {
+ unsigned long flags;
+ unsigned char count; // expected-note {{'count' declared here}}
+ struct A {
+ int dummy;
+ int array[] __counted_by(count); // expected-error {{'counted_by' field 'count' isn't within the same struct as the flexible array}}
+ } a;
+};
+
+struct not_found_count_not_in_unnamed_substruct {
+ unsigned char count; // expected-note {{'count' declared here}}
+ struct {
+ int dummy;
+ int array[] __counted_by(count); // expected-error {{'counted_by' field 'count' isn't within the same struct as the flexible array}}
+ } a;
+};
+
+struct not_found_count_not_in_unnamed_substruct_2 {
+ struct {
+ unsigned char count; // expected-note {{'count' declared here}}
+ };
+ struct {
+ int dummy;
+ int array[] __counted_by(count); // expected-error {{'counted_by' field 'count' isn't within the same struct as the flexible array}}
+ } a;
+};
+
+struct not_found_count_in_other_unnamed_substruct {
+ struct {
+ unsigned char count;
+ } a1;
+
+ struct {
+ int dummy;
+ int array[] __counted_by(count); // expected-error {{use of undeclared identifier 'count'}}
+ };
+};
+
+struct not_found_count_in_other_substruct {
+ struct _a1 {
+ unsigned char count;
+ } a1;
+
+ struct {
+ int dummy;
+ int array[] __counted_by(count); // expected-error {{use of undeclared identifier 'count'}}
+ };
+};
+
+struct not_found_count_in_other_substruct_2 {
+ struct _a2 {
+ unsigned char count;
+ } a2;
+
+ int array[] __counted_by(count); // expected-error {{use of undeclared identifier 'count'}}
+};
+
+struct not_found_suggest {
+ int bork;
+ struct bar *fam[] __counted_by(blork); // expected-error {{use of undeclared identifier 'blork'}}
+};
+
+int global; // expected-note {{'global' declared here}}
+
+struct found_outside_of_struct {
+ int bork;
+ struct bar *fam[] __counted_by(global); // expected-error {{field 'global' in 'counted_by' not inside structure}}
+};
+
+struct self_referrential {
+ int bork;
+ struct bar *self[] __counted_by(self); // expected-error {{use of undeclared identifier 'self'}}
+};
+
+struct non_int_count {
+ double dbl_count;
+ struct bar *fam[] __counted_by(dbl_count); // expected-error {{'counted_by' requires a non-boolean integer type argument}}
+};
+
+struct array_of_ints_count {
+ int integers[2];
+ struct bar *fam[] __counted_by(integers); // expected-error {{'counted_by' requires a non-boolean integer type argument}}
+};
+
+struct not_a_fam {
+ int count;
+ struct bar *non_fam __counted_by(count); // expected-error {{'counted_by' only applies to C99 flexible array members}}
+};
+
+struct not_a_c99_fam {
+ int count;
+ struct bar *non_c99_fam[0] __counted_by(count); // expected-error {{'counted_by' only applies to C99 flexible array members}}
+};
+
+struct annotated_with_anon_struct {
+ unsigned long flags;
+ struct {
+ unsigned char count;
+ int array[] __counted_by(crount); // expected-error {{use of undeclared identifier 'crount'}}
+ };
+};
More information about the cfe-commits
mailing list