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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+2{{'counted_by' only applies to pointers or C99 flexible array members}} - // expected-error@+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@+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@+2{{'counted_by' only applies to pointers or C99 flexible array members}} - // expected-error@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+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@+2{{'counted_by' only applies to pointers or C99 flexible array members}} - // expected-error@+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@+2{{'counted_by' only applies to pointers or C99 flexible array members}} - // expected-error@+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@+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@+2{{'counted_by' only applies to pointers or C99 flexible array members}} - // expected-error@+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@+2{{'counted_by' only applies to pointers or C99 flexible array members}} - // expected-error@+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@+2{{'counted_by' only applies to pointers or C99 flexible array members}} - // expected-error@+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@+2{{'counted_by' only applies to pointers or C99 flexible array members}} - // expected-error@+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@+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@+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@+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'}} + }; +}; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits