aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Parse/ParseDecl.cpp
diff options
context:
space:
mode:
authorYeoul Na <yeoul_na@apple.com>2024-03-20 13:36:56 +0900
committerGitHub <noreply@github.com>2024-03-20 13:36:56 +0900
commit3eb9ff30959a670559bcba03d149d4c51bf7c9c9 (patch)
treef64783446a5463a010e0ed2e39dcd4275e0a09d8 /clang/lib/Parse/ParseDecl.cpp
parentb2082a98175b0e5356f23bf21d3dc5b76edea390 (diff)
downloadllvm-3eb9ff30959a670559bcba03d149d4c51bf7c9c9.zip
llvm-3eb9ff30959a670559bcba03d149d4c51bf7c9c9.tar.gz
llvm-3eb9ff30959a670559bcba03d149d4c51bf7c9c9.tar.bz2
Turn 'counted_by' into a type attribute and parse it into 'CountAttributedType' (#78000)
In `-fbounds-safety`, bounds annotations are considered type attributes rather than declaration attributes. Constructing them as type attributes allows us to extend the attribute to apply nested pointers, which is essential to annotate functions that involve out parameters: `void foo(int *__counted_by(*out_count) *out_buf, int *out_count)`. We introduce a new sugar type to support bounds annotated types, `CountAttributedType`. In order to maintain extra data (the bounds expression and the dependent declaration information) that is not trackable in `AttributedType` we create a new type dedicate to this functionality. This patch also extends the parsing logic to parse the `counted_by` argument as an expression, which will allow us to extend the model to support arguments beyond an identifier, e.g., `__counted_by(n + m)` in the future as specified by `-fbounds-safety`. This also adjusts `__bdos` and array-bounds sanitizer code that already uses `CountedByAttr` to check `CountAttributedType` instead to get the field referred to by the attribute.
Diffstat (limited to 'clang/lib/Parse/ParseDecl.cpp')
-rw-r--r--clang/lib/Parse/ParseDecl.cpp90
1 files changed, 90 insertions, 0 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index dd17941..0aa14b0 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -629,6 +629,10 @@ void Parser::ParseGNUAttributeArgs(
ParseAttributeWithTypeArg(*AttrName, AttrNameLoc, Attrs, ScopeName,
ScopeLoc, Form);
return;
+ } else if (AttrKind == ParsedAttr::AT_CountedBy) {
+ ParseBoundsAttribute(*AttrName, AttrNameLoc, Attrs, ScopeName, ScopeLoc,
+ Form);
+ return;
}
// These may refer to the function arguments, but need to be parsed early to
@@ -3250,6 +3254,54 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs,
}
}
+/// Bounds attributes (e.g., counted_by):
+/// AttrName '(' expression ')'
+void Parser::ParseBoundsAttribute(IdentifierInfo &AttrName,
+ SourceLocation AttrNameLoc,
+ ParsedAttributes &Attrs,
+ IdentifierInfo *ScopeName,
+ SourceLocation ScopeLoc,
+ ParsedAttr::Form Form) {
+ assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('");
+
+ BalancedDelimiterTracker Parens(*this, tok::l_paren);
+ Parens.consumeOpen();
+
+ if (Tok.is(tok::r_paren)) {
+ Diag(Tok.getLocation(), diag::err_argument_required_after_attribute);
+ Parens.consumeClose();
+ return;
+ }
+
+ ArgsVector ArgExprs;
+ // Don't evaluate argument when the attribute is ignored.
+ using ExpressionKind =
+ Sema::ExpressionEvaluationContextRecord::ExpressionKind;
+ EnterExpressionEvaluationContext EC(
+ Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, nullptr,
+ ExpressionKind::EK_BoundsAttrArgument);
+
+ ExprResult ArgExpr(
+ Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()));
+
+ if (ArgExpr.isInvalid()) {
+ Parens.skipToEnd();
+ return;
+ }
+
+ ArgExprs.push_back(ArgExpr.get());
+ Parens.consumeClose();
+
+ ASTContext &Ctx = Actions.getASTContext();
+
+ ArgExprs.push_back(IntegerLiteral::Create(
+ Ctx, llvm::APInt(Ctx.getTypeSize(Ctx.getSizeType()), 0),
+ Ctx.getSizeType(), SourceLocation()));
+
+ Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, Parens.getCloseLocation()),
+ ScopeName, ScopeLoc, ArgExprs.data(), ArgExprs.size(), Form);
+}
+
ExprResult Parser::ParseExtIntegerArgument() {
assert(Tok.isOneOf(tok::kw__ExtInt, tok::kw__BitInt) &&
"Not an extended int type");
@@ -4679,6 +4731,39 @@ void Parser::ParseDeclarationSpecifiers(
}
}
+static void DiagnoseCountAttributedTypeInUnnamedAnon(ParsingDeclSpec &DS,
+ Parser &P) {
+
+ if (DS.getTypeSpecType() != DeclSpec::TST_struct)
+ return;
+
+ auto *RD = dyn_cast<RecordDecl>(DS.getRepAsDecl());
+ // We're only interested in unnamed, non-anonymous struct
+ if (!RD || !RD->getName().empty() || RD->isAnonymousStructOrUnion())
+ return;
+
+ for (auto *I : RD->decls()) {
+ auto *VD = dyn_cast<ValueDecl>(I);
+ if (!VD)
+ continue;
+
+ auto *CAT = VD->getType()->getAs<CountAttributedType>();
+ if (!CAT)
+ continue;
+
+ for (const auto &DD : CAT->dependent_decls()) {
+ if (!RD->containsDecl(DD.getDecl())) {
+ P.Diag(VD->getBeginLoc(),
+ diag::err_flexible_array_count_not_in_same_struct)
+ << DD.getDecl();
+ P.Diag(DD.getDecl()->getBeginLoc(),
+ diag::note_flexible_array_counted_by_attr_field)
+ << DD.getDecl();
+ }
+ }
+ }
+}
+
/// ParseStructDeclaration - Parse a struct declaration without the terminating
/// semicolon.
///
@@ -4759,6 +4844,11 @@ void Parser::ParseStructDeclaration(
} else
DeclaratorInfo.D.SetIdentifier(nullptr, Tok.getLocation());
+ // Here, we now know that the unnamed struct is not an anonymous struct.
+ // Report an error if a counted_by attribute refers to a field in a
+ // different named struct.
+ DiagnoseCountAttributedTypeInUnnamedAnon(DS, *this);
+
if (TryConsumeToken(tok::colon)) {
ExprResult Res(ParseConstantExpression());
if (Res.isInvalid())