Skip to content

Commit 3c09dcd

Browse files
authored
Merge pull request #11682 from hnrklssn/parse-bounds-objective-c-21.x
[Cherry-pick][6.3] Parse bounds attributes Objective-C
2 parents 0f62bb2 + 9638861 commit 3c09dcd

File tree

4 files changed

+319
-72
lines changed

4 files changed

+319
-72
lines changed

clang/include/clang/Parse/Parser.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,7 +1172,10 @@ class Parser : public CodeCompletionHandler {
11721172

11731173
void ParseLexedAttributes() override;
11741174

1175-
void addDecl(Decl *D) { Decls.push_back(D); }
1175+
void addDecl(Decl *D) {
1176+
assert(D && "cannot add null decl!");
1177+
Decls.push_back(D);
1178+
}
11761179
};
11771180

11781181
/// Contains the lexed tokens of a pragma with arguments that
@@ -5814,8 +5817,10 @@ class Parser : public CodeCompletionHandler {
58145817
/// '(' objc-type-qualifiers[opt] ')'
58155818
/// \endverbatim
58165819
///
5820+
/* TO_UPSTREAM(BoundsSafety) Added LateParsedAttrs */
58175821
ParsedType ParseObjCTypeName(ObjCDeclSpec &DS, DeclaratorContext Ctx,
5818-
ParsedAttributes *ParamAttrs);
5822+
ParsedAttributes *ParamAttrs,
5823+
LateParsedAttrList *LateParsedAttrs = nullptr);
58195824

58205825
/// \verbatim
58215826
/// objc-method-proto:

clang/lib/Parse/ParseObjc.cpp

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,9 +1094,11 @@ static void takeDeclAttributes(ParsedAttributes &attrs,
10941094
takeDeclAttributes(attrs, D.getTypeObject(i).getAttrs());
10951095
}
10961096

1097+
/// TO_UPSTREAM(BoundsSafety) Added LateParsedAttrs
10971098
ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
10981099
DeclaratorContext context,
1099-
ParsedAttributes *paramAttrs) {
1100+
ParsedAttributes *paramAttrs,
1101+
LateParsedAttrList *LateParsedAttrs) {
11001102
assert(context == DeclaratorContext::ObjCParameter ||
11011103
context == DeclaratorContext::ObjCResult);
11021104
assert((paramAttrs != nullptr) ==
@@ -1121,9 +1123,10 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
11211123
DeclSpecContext dsContext = DeclSpecContext::DSC_normal;
11221124
if (context == DeclaratorContext::ObjCResult)
11231125
dsContext = DeclSpecContext::DSC_objc_method_result;
1124-
ParseSpecifierQualifierList(declSpec, AS_none, dsContext);
1126+
ParseSpecifierQualifierList(declSpec, AS_none, dsContext, LateParsedAttrs);
11251127
Declarator declarator(declSpec, ParsedAttributesView::none(), context);
11261128
ParseDeclarator(declarator);
1129+
DistributeCLateParsedAttrs(declarator, nullptr, LateParsedAttrs);
11271130

11281131
// If that's not invalid, extract a type.
11291132
if (!declarator.isInvalidType()) {
@@ -1174,17 +1177,25 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
11741177
return nullptr;
11751178
}
11761179

1180+
/* TO_UPSTREAM(BoundsSafety) ON */
1181+
LateParsedAttrList LateParsedAttrs(/*PSoon=*/true,
1182+
/*LateAttrParseExperimentalExtOnly=*/true);
1183+
LateParsedAttrList LateParsedReturnAttrs(
1184+
/*PSoon=*/false,
1185+
/*LateAttrParseExperimentalExtOnly=*/true);
1186+
/* TO_UPSTREAM(BoundsSafety) OFF */
1187+
11771188
// Parse the return type if present.
11781189
ParsedType ReturnType;
11791190
ObjCDeclSpec DSRet;
11801191
if (Tok.is(tok::l_paren))
1181-
ReturnType =
1182-
ParseObjCTypeName(DSRet, DeclaratorContext::ObjCResult, nullptr);
1192+
ReturnType = ParseObjCTypeName(DSRet, DeclaratorContext::ObjCResult,
1193+
nullptr, &LateParsedReturnAttrs);
11831194

11841195
// If attributes exist before the method, parse them.
11851196
ParsedAttributes methodAttrs(AttrFactory);
11861197
MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),
1187-
methodAttrs);
1198+
methodAttrs, &LateParsedReturnAttrs);
11881199

11891200
if (Tok.is(tok::code_completion)) {
11901201
cutOffParsing();
@@ -1218,33 +1229,51 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
12181229
selLoc, Sel, nullptr, CParamInfo.data(), CParamInfo.size(), methodAttrs,
12191230
MethodImplKind, false, MethodDefinition);
12201231
PD.complete(Result);
1232+
/* TO_UPSTREAM(BoundsSafety) ON */
1233+
if (Result) {
1234+
for (auto *LateAttr : LateParsedReturnAttrs) {
1235+
// there are no parameters with late attrs to parse
1236+
assert(LateAttr->Decls.empty());
1237+
LateAttr->addDecl(Result);
1238+
ParseLexedCAttribute(*LateAttr, true);
1239+
}
1240+
}
1241+
/* TO_UPSTREAM(BoundsSafety) OFF */
12211242
return Result;
12221243
}
12231244

12241245
SmallVector<const IdentifierInfo *, 12> KeyIdents;
12251246
SmallVector<SourceLocation, 12> KeyLocs;
12261247
SmallVector<SemaObjC::ObjCArgInfo, 12> ArgInfos;
1248+
/* TO_UPSTREAM(BoundsSafety) ON */
1249+
SmallVector<LateParsedAttrList, 12> LateParamAttrs;
1250+
/* TO_UPSTREAM(BoundsSafety) OFF */
12271251
ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
12281252
Scope::FunctionDeclarationScope | Scope::DeclScope);
12291253

12301254
AttributePool allParamAttrs(AttrFactory);
12311255
while (true) {
12321256
ParsedAttributes paramAttrs(AttrFactory);
12331257
SemaObjC::ObjCArgInfo ArgInfo;
1258+
/* TO_UPSTREAM(BoundsSafety) ON */
1259+
LateParsedAttrList LateAttrs(/*PSoon*/ false,
1260+
/*LateAttrParseExperimentalExtOnly*/ true);
1261+
/* TO_UPSTREAM(BoundsSafety) OFF */
12341262

12351263
// Each iteration parses a single keyword argument.
12361264
if (ExpectAndConsume(tok::colon))
12371265
break;
12381266

12391267
ArgInfo.Type = nullptr;
12401268
if (Tok.is(tok::l_paren)) // Parse the argument type if present.
1241-
ArgInfo.Type = ParseObjCTypeName(
1242-
ArgInfo.DeclSpec, DeclaratorContext::ObjCParameter, &paramAttrs);
1269+
ArgInfo.Type =
1270+
ParseObjCTypeName(ArgInfo.DeclSpec, DeclaratorContext::ObjCParameter,
1271+
&paramAttrs, &LateAttrs);
12431272

12441273
// If attributes exist before the argument name, parse them.
12451274
// Regardless, collect all the attributes we've parsed so far.
12461275
MaybeParseAttributes(PAKM_CXX11 | (getLangOpts().ObjC ? PAKM_GNU : 0),
1247-
paramAttrs);
1276+
paramAttrs, &LateAttrs);
12481277
ArgInfo.ArgAttrs = paramAttrs;
12491278

12501279
// Code completion for the next piece of the selector.
@@ -1265,6 +1294,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
12651294
ConsumeToken(); // Eat the identifier.
12661295

12671296
ArgInfos.push_back(ArgInfo);
1297+
LateParamAttrs.push_back(LateAttrs); // TO_UPSTREAM(BoundsSafety)
12681298
KeyIdents.push_back(SelIdent);
12691299
KeyLocs.push_back(selLoc);
12701300

@@ -1311,13 +1341,23 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
13111341
}
13121342
DeclSpec DS(AttrFactory);
13131343
ParsedTemplateInfo TemplateInfo;
1314-
ParseDeclarationSpecifiers(DS, TemplateInfo);
1344+
ParseDeclarationSpecifiers(
1345+
DS, TemplateInfo,
1346+
/* AccessSpecifier AS */ AS_none,
1347+
/* DeclSpecContext DSC */ DeclSpecContext::DSC_normal,
1348+
&LateParsedAttrs);
13151349
// Parse the declarator.
13161350
Declarator ParmDecl(DS, ParsedAttributesView::none(),
13171351
DeclaratorContext::Prototype);
13181352
ParseDeclarator(ParmDecl);
13191353
const IdentifierInfo *ParmII = ParmDecl.getIdentifier();
13201354
Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl);
1355+
/* TO_UPSTREAM(BoundsSafety) ON */
1356+
// This will add Param to any late attrs that do not already have an
1357+
// assigned decl, so it's important that other late attrs are not mixed
1358+
// in to LateParsedAttrs without a decl at this point
1359+
DistributeCLateParsedAttrs(ParmDecl, Param, &LateParsedAttrs);
1360+
/* TO_UPSTREAM(BoundsSafety) OFF */
13211361
CParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,
13221362
ParmDecl.getIdentifierLoc(),
13231363
Param,
@@ -1329,9 +1369,18 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
13291369
// instance, if a method declares a parameter called "id", that parameter must
13301370
// not shadow the "id" type.)
13311371
SmallVector<ParmVarDecl *, 12> ObjCParamInfo;
1332-
for (auto &ArgInfo : ArgInfos) {
1372+
for (const auto &[ArgInfo, LateAttrs] : llvm::zip(ArgInfos, LateParamAttrs)) {
13331373
ParmVarDecl *Param = Actions.ObjC().ActOnMethodParmDeclaration(
13341374
getCurScope(), ArgInfo, ObjCParamInfo.size(), MethodDefinition);
1375+
/* TO_UPSTREAM(BoundsSafety) ON */
1376+
if (Param) {
1377+
for (auto *LateAttr : LateAttrs) {
1378+
assert(LateAttr->Decls.empty());
1379+
LateAttr->addDecl(Param);
1380+
}
1381+
LateParsedAttrs.append(LateAttrs);
1382+
}
1383+
/* TO_UPSTREAM(BoundsSafety) OFF */
13351384
ObjCParamInfo.push_back(Param);
13361385
}
13371386

@@ -1349,6 +1398,17 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
13491398
getCurScope(), mLoc, Tok.getLocation(), mType, DSRet, ReturnType, KeyLocs,
13501399
Sel, ObjCParamInfo.data(), CParamInfo.data(), CParamInfo.size(),
13511400
methodAttrs, MethodImplKind, isVariadic, MethodDefinition);
1401+
/* TO_UPSTREAM(BoundsSafety) ON */
1402+
if (Result) {
1403+
for (auto *LateAttr : LateParsedReturnAttrs) {
1404+
assert(LateAttr->Decls.empty());
1405+
LateAttr->addDecl(Result);
1406+
}
1407+
LateParsedAttrs.append(LateParsedReturnAttrs);
1408+
ParseLexedCAttributeList(LateParsedAttrs,
1409+
/*we already have parameters in scope*/ false);
1410+
}
1411+
/* TO_UPSTREAM(BoundsSafety) OFF */
13521412

13531413
PD.complete(Result);
13541414
return Result;

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 67 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -7176,6 +7176,7 @@ class DynamicBoundsAttrInfo {
71767176
TypedefNameDecl *TND;
71777177
ValueDecl *VD;
71787178
VarDecl *Var;
7179+
ObjCMethodDecl *ObjCMethod;
71797180
QualType DeclTy;
71807181
QualType Ty;
71817182
unsigned EffectiveLevel;
@@ -7187,7 +7188,13 @@ class DynamicBoundsAttrInfo {
71877188
TND = dyn_cast<TypedefNameDecl>(D);
71887189
VD = dyn_cast<ValueDecl>(D);
71897190
Var = dyn_cast<VarDecl>(D);
7190-
DeclTy = TND ? TND->getUnderlyingType() : VD->getType();
7191+
ObjCMethod = dyn_cast<ObjCMethodDecl>(D);
7192+
if (TND)
7193+
DeclTy = TND->getUnderlyingType();
7194+
else if (ObjCMethod)
7195+
DeclTy = ObjCMethod->getReturnType();
7196+
else
7197+
DeclTy = VD->getType();
71917198
IsFPtr = false;
71927199
EffectiveLevel = Level;
71937200
Ty = DeclTy;
@@ -7292,72 +7299,69 @@ void Sema::applyPtrCountedByEndedByAttr(Decl *D, unsigned Level,
72927299
}
72937300
}
72947301

7295-
if (Info.VD) {
7296-
const auto *FD = dyn_cast<FieldDecl>(Info.VD);
7297-
if (FD && FD->getParent()->isUnion()) {
7298-
Diag(Loc, diag::err_invalid_decl_kind_bounds_safety_union_count)
7299-
<< DiagName;
7300-
return;
7301-
}
7302+
const auto *FD = dyn_cast<FieldDecl>(D);
7303+
if (FD && FD->getParent()->isUnion()) {
7304+
Diag(Loc, diag::err_invalid_decl_kind_bounds_safety_union_count)
7305+
<< DiagName;
7306+
return;
7307+
}
73027308

7303-
if (Info.EffectiveLevel != 0 &&
7304-
(!isa<ParmVarDecl>(Info.VD) || Info.DeclTy->isBoundsAttributedType())) {
7305-
Diag(Loc, diag::err_bounds_safety_nested_dynamic_bound) << DiagName;
7306-
return;
7307-
}
7309+
if (Info.EffectiveLevel != 0 &&
7310+
(!isa<ParmVarDecl>(D) || Info.DeclTy->isBoundsAttributedType())) {
7311+
Diag(Loc, diag::err_bounds_safety_nested_dynamic_bound) << DiagName;
7312+
return;
7313+
}
73087314

7309-
// Clang causes array parameters to decay to pointers so quickly that
7310-
// attributes aren't even parsed yet. This causes arrays with both an
7311-
// explicit size and a count attribute to go to the CountAttributedType
7312-
// case of ConstructCountAttributedType, which complains that the type
7313-
// has two count attributes. See if we can produce a better diagnostic here
7314-
// instead.
7315-
if (const auto *PVD = dyn_cast_or_null<ParmVarDecl>(Info.Var)) {
7316-
QualType TSITy = PVD->getTypeSourceInfo()->getType();
7317-
if (IsEndedBy) {
7318-
if (Level == 0 && TSITy->isArrayType()) {
7319-
Diag(Loc, diag::err_attribute_pointers_only) << DiagName << 0;
7320-
return;
7321-
}
7322-
} else {
7323-
const auto *ATy = Context.getAsArrayType(TSITy);
7324-
if (Level == 0 && ATy && !ATy->isIncompleteArrayType() &&
7325-
!TSITy->hasAttr(attr::ArrayDecayDiscardsCountInParameters)) {
7326-
Diag(Loc, diag::err_bounds_safety_complete_array_with_count);
7327-
return;
7328-
}
7315+
// Clang causes array parameters to decay to pointers so quickly that
7316+
// attributes aren't even parsed yet. This causes arrays with both an
7317+
// explicit size and a count attribute to go to the CountAttributedType
7318+
// case of ConstructCountAttributedType, which complains that the type
7319+
// has two count attributes. See if we can produce a better diagnostic here
7320+
// instead.
7321+
if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) {
7322+
QualType TSITy = PVD->getTypeSourceInfo()->getType();
7323+
if (IsEndedBy) {
7324+
if (Level == 0 && TSITy->isArrayType()) {
7325+
Diag(Loc, diag::err_attribute_pointers_only) << DiagName << 0;
7326+
return;
7327+
}
7328+
} else {
7329+
const auto *ATy = Context.getAsArrayType(TSITy);
7330+
if (Level == 0 && ATy && !ATy->isIncompleteArrayType() &&
7331+
!TSITy->hasAttr(attr::ArrayDecayDiscardsCountInParameters)) {
7332+
Diag(Loc, diag::err_bounds_safety_complete_array_with_count);
7333+
return;
73297334
}
73307335
}
7336+
}
73317337

7332-
if (Info.Ty->isArrayType() && OrNull &&
7333-
(FD || Info.EffectiveLevel > 0 ||
7334-
(Info.Var && Info.Var->hasExternalStorage()))) {
7335-
auto ErrDiag = Diag(Loc, diag::err_bounds_safety_nullable_fam);
7336-
// Pointers to dynamic count types are only allowed for parameters, so any
7337-
// FieldDecl containing a dynamic count type is a FAM. I.e. a struct field
7338-
// with type 'int(*)[__counted_by(...)]' is not valid.
7339-
ErrDiag << CountInBytes << /*is FAM?*/ !!FD << DiagName;
7340-
assert(!FD || Info.EffectiveLevel == 0);
7338+
if (Info.Ty->isArrayType() && OrNull &&
7339+
(FD || Info.EffectiveLevel > 0 ||
7340+
(Info.Var && Info.Var->hasExternalStorage()))) {
7341+
auto ErrDiag = Diag(Loc, diag::err_bounds_safety_nullable_fam);
7342+
// Pointers to dynamic count types are only allowed for parameters, so any
7343+
// FieldDecl containing a dynamic count type is a FAM. I.e. a struct field
7344+
// with type 'int(*)[__counted_by(...)]' is not valid.
7345+
ErrDiag << CountInBytes << /*is FAM?*/ !!FD << DiagName;
7346+
assert(!FD || Info.EffectiveLevel == 0);
73417347

7342-
SourceLocation FixItLoc = getSourceManager().getExpansionLoc(Loc);
7343-
SourceLocation EndLoc =
7344-
Lexer::getLocForEndOfToken(FixItLoc, /* Don't include '(' */ -1,
7345-
getSourceManager(), getLangOpts());
7346-
std::string Attribute = CountInBytes ? "__sized_by" : "__counted_by";
7347-
ErrDiag << FixItHint::CreateReplacement({FixItLoc, EndLoc}, Attribute);
7348+
SourceLocation FixItLoc = getSourceManager().getExpansionLoc(Loc);
7349+
SourceLocation EndLoc =
7350+
Lexer::getLocForEndOfToken(FixItLoc, /* Don't include '(' */ -1,
7351+
getSourceManager(), getLangOpts());
7352+
std::string Attribute = CountInBytes ? "__sized_by" : "__counted_by";
7353+
ErrDiag << FixItHint::CreateReplacement({FixItLoc, EndLoc}, Attribute);
73487354

7349-
return;
7350-
}
7355+
return;
7356+
}
73517357

7352-
if (Info.Ty->isArrayType() && Info.EffectiveLevel > 0) {
7353-
auto ErrDiag =
7354-
Diag(
7355-
Loc,
7356-
diag::
7357-
err_bounds_safety_unsupported_address_of_incomplete_array_type)
7358-
<< Info.Ty;
7359-
// apply attribute anyways to avoid too misleading follow-up diagnostics
7360-
}
7358+
if (Info.Ty->isArrayType() && Info.EffectiveLevel > 0) {
7359+
auto ErrDiag =
7360+
Diag(Loc,
7361+
diag::
7362+
err_bounds_safety_unsupported_address_of_incomplete_array_type)
7363+
<< Info.Ty;
7364+
// apply attribute anyways to avoid too misleading follow-up diagnostics
73617365
}
73627366

73637367
QualType NewDeclTy{};
@@ -7379,8 +7383,9 @@ void Sema::applyPtrCountedByEndedByAttr(Decl *D, unsigned Level,
73797383
// Make started_by() pointers if VD is a field or variable. We don't want to
73807384
// create started_by(X) pointers where X is a function etc.
73817385
std::optional<TypeCoupledDeclRefInfo> StartPtrInfo;
7382-
if (Info.VD && (isa<FieldDecl>(Info.VD) || isa<VarDecl>(Info.VD))) {
7386+
if (isa<FieldDecl, VarDecl>(D)) {
73837387
assert(Level <= 1);
7388+
assert(Info.VD);
73847389
StartPtrInfo = TypeCoupledDeclRefInfo(Info.VD, /*Deref=*/Level != 0);
73857390
}
73867391

@@ -7436,6 +7441,8 @@ void Sema::applyPtrCountedByEndedByAttr(Decl *D, unsigned Level,
74367441
Info.TND->getTypeSourceInfo()->getTypeLoc().getBeginLoc();
74377442
TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(NewDeclTy, Loc);
74387443
Info.TND->setTypeSourceInfo(TSI);
7444+
} else if (Info.ObjCMethod) {
7445+
Info.ObjCMethod->setReturnType(NewDeclTy);
74397446
} else {
74407447
Info.VD->setType(NewDeclTy);
74417448
// Reconstruct implicit cast for initializer after variable type change.

0 commit comments

Comments
 (0)