https://github.com/pdherbemont updated https://github.com/llvm/llvm-project/pull/94216
>From ccf6699197b608f95deea2b03b1ee87e29fbc8e1 Mon Sep 17 00:00:00 2001 From: Pierre d'Herbemont <pdherbem...@apple.com> Date: Wed, 29 May 2024 11:11:03 +0200 Subject: [PATCH] Support [[guarded_by(mutex)]] attribute inside C struct Today, it's only supported inside C++ classes or top level C/C++ declaration. I mostly copied and adapted over the code from the [[counted_by(value)]] lookup. --- clang/include/clang/Parse/Parser.h | 6 ++ clang/lib/Parse/ParseDecl.cpp | 59 +++++++++++++++++++ clang/test/Sema/warn-thread-safety-analysis.c | 10 +++- .../SemaCXX/warn-thread-safety-parsing.cpp | 6 +- 4 files changed, 75 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index d054b8cf0d240..308f6ea121eab 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3128,6 +3128,12 @@ class Parser : public CodeCompletionHandler { IdentifierInfo *ScopeName, SourceLocation ScopeLoc, ParsedAttr::Form Form); + void ParseGuardedByAttribute(IdentifierInfo &AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, + IdentifierInfo *ScopeName, + SourceLocation ScopeLoc, ParsedAttr::Form Form); + void ParseTypeofSpecifier(DeclSpec &DS); SourceLocation ParseDecltypeSpecifier(DeclSpec &DS); void AnnotateExistingDecltypeSpecifier(const DeclSpec &DS, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index c528917437332..58a3de7210455 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -671,6 +671,14 @@ void Parser::ParseGNUAttributeArgs( ParseBoundsAttribute(*AttrName, AttrNameLoc, Attrs, ScopeName, ScopeLoc, Form); return; + } else if (AttrKind == ParsedAttr::AT_GuardedBy) { + ParseGuardedByAttribute(*AttrName, AttrNameLoc, Attrs, ScopeName, ScopeLoc, + Form); + return; + } else if (AttrKind == ParsedAttr::AT_PtGuardedBy) { + ParseGuardedByAttribute(*AttrName, AttrNameLoc, Attrs, ScopeName, ScopeLoc, + Form); + return; } else if (AttrKind == ParsedAttr::AT_CXXAssume) { ParseCXXAssumeAttributeArg(Attrs, AttrName, AttrNameLoc, EndLoc, Form); return; @@ -3330,6 +3338,57 @@ 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, + 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()); + + auto &AL = *Attrs.addNew( + &AttrName, SourceRange(AttrNameLoc, Parens.getCloseLocation()), ScopeName, + ScopeLoc, ArgExprs.data(), ArgExprs.size(), Form); + + if (!Tok.is(tok::r_paren)) { + Diag(Tok.getLocation(), diag::err_attribute_wrong_number_arguments) + << AL << 1; + Parens.skipToEnd(); + return; + } + + Parens.consumeClose(); +} + /// Bounds attributes (e.g., counted_by): /// AttrName '(' expression ')' void Parser::ParseBoundsAttribute(IdentifierInfo &AttrName, diff --git a/clang/test/Sema/warn-thread-safety-analysis.c b/clang/test/Sema/warn-thread-safety-analysis.c index 642ea88ec3c96..abad65b0b9154 100644 --- a/clang/test/Sema/warn-thread-safety-analysis.c +++ b/clang/test/Sema/warn-thread-safety-analysis.c @@ -28,7 +28,12 @@ struct LOCKABLE Mutex {}; struct Foo { - struct Mutex *mu_; + struct Mutex *mu_; + struct Bar { + struct Mutex *other_mu; + } bar; + int a_value GUARDED_BY(mu_); + int* a_ptr PT_GUARDED_BY(bar.other_mu); }; // Declare mutex lock/unlock functions. @@ -136,6 +141,9 @@ int main(void) { // Cleanup happens automatically -> no warning. } + foo_.a_value = 0; // expected-warning {{writing variable 'a_value' requires holding mutex 'mu_' exclusively}} + *foo_.a_ptr = 1; // expected-warning {{writing the value pointed to by 'a_ptr' requires holding mutex 'bar.other_mu' exclusively}} + return 0; } diff --git a/clang/test/SemaCXX/warn-thread-safety-parsing.cpp b/clang/test/SemaCXX/warn-thread-safety-parsing.cpp index 0c5b0cc85897b..1626e8375892a 100644 --- a/clang/test/SemaCXX/warn-thread-safety-parsing.cpp +++ b/clang/test/SemaCXX/warn-thread-safety-parsing.cpp @@ -1516,11 +1516,7 @@ class Foo { mutable Mutex mu; int a GUARDED_BY(mu); - static int si GUARDED_BY(mu); -//FIXME: Bug 32066 - Error should be emitted irrespective of C++ dialect -#if __cplusplus <= 199711L - // expected-error@-3 {{invalid use of non-static data member 'mu'}} -#endif + static int si GUARDED_BY(mu); // expected-error {{invalid use of non-static data member 'mu'}} static void foo() EXCLUSIVE_LOCKS_REQUIRED(mu); //FIXME: Bug 32066 - Error should be emitted irrespective of C++ dialect _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits