diff options
author | Pierre d'Herbemont <pdherbemont@gmail.com> | 2024-06-12 20:20:05 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-12 11:20:05 -0700 |
commit | af0d7128c8fd053d3de8af208d7d1682bc7a525a (patch) | |
tree | 221a1e0e7302f1b4a2e82fd452c96f6263f68659 /clang/lib | |
parent | 7665d3d90da7f32e56cb57eb192dc8f189730686 (diff) | |
download | llvm-af0d7128c8fd053d3de8af208d7d1682bc7a525a.zip llvm-af0d7128c8fd053d3de8af208d7d1682bc7a525a.tar.gz llvm-af0d7128c8fd053d3de8af208d7d1682bc7a525a.tar.bz2 |
Support `guarded_by` attribute and related attributes inside C structs and support late parsing them (#94216)
This fixes #20777.
Previously the `guarded_by`, `pt_guarded_by`, `acquired_after`, and `acquired_before` attributes were only supported inside C++ classes or top level C/C++ declaration.
This patch allows these attributes to be added to struct members in C. These attributes have also now support experimental late parsing. This is off by default but can be enabled by passing `-fexperimental-late-parse-attributes`. This is useful for referring to a struct member after the annotated member. E.g.
```
struct Example {
int a_value_defined_before __attribute__ ((guarded_by(a_mutex)));
struct Mutex *a_mutex;
};
```
Patch by Pierre d'Herbemont (@pdherbemont)
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 118 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 4 |
2 files changed, 119 insertions, 3 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index c528917..c7663d4 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -671,6 +671,16 @@ void Parser::ParseGNUAttributeArgs( ParseBoundsAttribute(*AttrName, AttrNameLoc, Attrs, ScopeName, ScopeLoc, Form); return; + } else if (AttrKind == ParsedAttr::AT_GuardedBy || + AttrKind == ParsedAttr::AT_PtGuardedBy) { + ParseGuardedByAttribute(*AttrName, AttrNameLoc, Attrs, ScopeName, ScopeLoc, + EndLoc, Form); + return; + } else if (AttrKind == ParsedAttr::AT_AcquiredAfter || + AttrKind == ParsedAttr::AT_AcquiredBefore) { + ParseAcquiredAttribute(*AttrName, AttrNameLoc, Attrs, ScopeName, ScopeLoc, + EndLoc, Form); + return; } else if (AttrKind == ParsedAttr::AT_CXXAssume) { ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc, Form); return; @@ -3330,6 +3340,112 @@ void Parser::DistributeCLateParsedAttrs(Decl *Dcl, } } +/// GuardedBy attributes (e.g., guarded_by): +/// AttrName '(' expression ')' +void Parser::ParseGuardedByAttribute( + IdentifierInfo &AttrName, SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, + SourceLocation *EndLoc, 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_AttrArgument); + + ExprResult ArgExpr( + Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression())); + + if (ArgExpr.isInvalid()) { + Parens.skipToEnd(); + return; + } + + ArgExprs.push_back(ArgExpr.get()); + + auto RParens = Tok.getLocation(); + auto &AL = + *Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, RParens), ScopeName, + ScopeLoc, ArgExprs.data(), ArgExprs.size(), Form); + + if (EndLoc) + *EndLoc = RParens; + + if (!Tok.is(tok::r_paren)) { + Diag(Tok.getLocation(), diag::err_attribute_wrong_number_arguments) + << AL << 1; + Parens.skipToEnd(); + return; + } + + Parens.consumeClose(); +} + +/// Acquired attributes (e.g., acquired_before, acquired_after): +/// AttrName '(' expression-list ')' +void Parser::ParseAcquiredAttribute( + IdentifierInfo &AttrName, SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, IdentifierInfo *ScopeName, SourceLocation ScopeLoc, + SourceLocation *EndLoc, 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; + } + + auto ArgStart = Tok.getLocation(); + + ArgsVector ArgExprs; + + do { + + // Don't evaluate argument when the attribute is ignored. + using ExpressionKind = + Sema::ExpressionEvaluationContextRecord::ExpressionKind; + EnterExpressionEvaluationContext EC( + Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, + nullptr, ExpressionKind::EK_AttrArgument); + + ExprResult ArgExpr( + Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression())); + + if (ArgExpr.isInvalid()) { + Parens.skipToEnd(); + return; + } + + ArgExprs.push_back(ArgExpr.get()); + + } while (TryConsumeToken(tok::comma)); + + auto ArgEnd = Tok.getLocation(); + + Attrs.addNew(&AttrName, SourceRange(ArgStart, ArgEnd), ScopeName, ScopeLoc, + ArgExprs.data(), ArgExprs.size(), Form); + + if (EndLoc) + *EndLoc = ArgEnd; + + Parens.consumeClose(); +} + /// Bounds attributes (e.g., counted_by): /// AttrName '(' expression ')' void Parser::ParseBoundsAttribute(IdentifierInfo &AttrName, @@ -3355,7 +3471,7 @@ void Parser::ParseBoundsAttribute(IdentifierInfo &AttrName, Sema::ExpressionEvaluationContextRecord::ExpressionKind; EnterExpressionEvaluationContext EC( Actions, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, nullptr, - ExpressionKind::EK_BoundsAttrArgument); + ExpressionKind::EK_AttrArgument); ExprResult ArgExpr( Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression())); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 44f886b..3869e99 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2723,7 +2723,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, // appertains to a type of C struct field such that the name lookup // within a struct finds the member name, which is not the case for other // contexts in C. - if (isBoundsAttrContext() && !getLangOpts().CPlusPlus && S->isClassScope()) { + if (isAttrContext() && !getLangOpts().CPlusPlus && S->isClassScope()) { // See if this is reference to a field of struct. LookupResult R(*this, NameInfo, LookupMemberName); // LookupName handles a name lookup from within anonymous struct. @@ -3357,7 +3357,7 @@ ExprResult Sema::BuildDeclarationNameExpr( case Decl::Field: case Decl::IndirectField: case Decl::ObjCIvar: - assert((getLangOpts().CPlusPlus || isBoundsAttrContext()) && + assert((getLangOpts().CPlusPlus || isAttrContext()) && "building reference to field in C?"); // These can't have reference type in well-formed programs, but |