Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,15 @@ CoroutineHostileRAIICheck::CoroutineHostileRAIICheck(StringRef Name,

void CoroutineHostileRAIICheck::registerMatchers(MatchFinder *Finder) {
// A suspension happens with co_await or co_yield.
auto ScopedLockable = varDecl(hasType(hasCanonicalType(hasDeclaration(
hasAttr(attr::Kind::ScopedLockable)))))
.bind("scoped-lockable");
auto ScopedCapability = varDecl(hasType(hasCanonicalType(hasDeclaration(
hasAttr(attr::Kind::ScopedCapability)))))
.bind("scoped-lockable");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we rename the binding name as well (and update its uses)?

auto OtherRAII = varDecl(typeWithNameIn(RAIITypesList)).bind("raii");
auto AllowedSuspend = awaitable(typeWithNameIn(AllowedAwaitablesList));
Finder->addMatcher(
expr(anyOf(coawaitExpr(unless(AllowedSuspend)), coyieldExpr()),
forEachPrevStmt(
declStmt(forEach(varDecl(anyOf(ScopedLockable, OtherRAII))))))
declStmt(forEach(varDecl(anyOf(ScopedCapability, OtherRAII))))))
.bind("suspension"),
this);
}
Expand Down
6 changes: 3 additions & 3 deletions clang/docs/ThreadSafetyAnalysis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,7 @@ implementation.
THREAD_ANNOTATION_ATTRIBUTE__(capability(x))

#define SCOPED_CAPABILITY \
THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
THREAD_ANNOTATION_ATTRIBUTE__(scoped_capability)

#define GUARDED_BY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
Expand Down Expand Up @@ -843,7 +843,7 @@ implementation.
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))

#define EXCLUDES(...) \
THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
THREAD_ANNOTATION_ATTRIBUTE__(capabilities_excluded(__VA_ARGS__))

#define ASSERT_CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
Expand All @@ -852,7 +852,7 @@ implementation.
THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))

#define RETURN_CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
THREAD_ANNOTATION_ATTRIBUTE__(capability_returned(x))

#define NO_THREAD_SAFETY_ANALYSIS \
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Analysis/Analyses/ThreadSafetyCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ class SExprBuilder {
/// the appropriate mutex expression in the lexical context where the function
/// is called. PrevCtx holds the context in which the arguments themselves
/// should be evaluated; multiple calling contexts can be chained together
/// by the lock_returned attribute.
/// by the capability_returned attribute.
struct CallingContext {
// The previous context; or 0 if none.
CallingContext *Prev;
Expand Down
15 changes: 9 additions & 6 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -3583,8 +3583,9 @@ def Lockable : InheritableAttr {
let ASTNode = 0; // Replaced by Capability
}

def ScopedLockable : InheritableAttr {
let Spellings = [Clang<"scoped_lockable", 0>];
def ScopedCapability : InheritableAttr {
let Spellings = [Clang<"scoped_capability", 0>,
Clang<"scoped_lockable", 0>];
let Subjects = SubjectList<[Record]>;
let Documentation = [Undocumented];
let SimpleHandler = 1;
Expand Down Expand Up @@ -3779,8 +3780,9 @@ def SharedTrylockFunction : InheritableAttr {
let Documentation = [Undocumented];
}

def LockReturned : InheritableAttr {
let Spellings = [GNU<"lock_returned">];
def CapabilityReturned : InheritableAttr {
let Spellings = [GNU<"capability_returned">,
GNU<"lock_returned">];
let Args = [ExprArgument<"Arg">];
let LateParsed = LateAttrParseStandard;
let TemplateDependent = 1;
Expand All @@ -3789,8 +3791,9 @@ def LockReturned : InheritableAttr {
let Documentation = [Undocumented];
}

def LocksExcluded : InheritableAttr {
let Spellings = [GNU<"locks_excluded">];
def CapabilitiesExcluded : InheritableAttr {
let Spellings = [GNU<"capabilities_excluded">,
GNU<"locks_excluded">];
let Args = [VariadicExprArgument<"Args">];
let LateParsed = LateAttrParseStandard;
let TemplateDependent = 1;
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9364,13 +9364,13 @@ Expected<Attr *> ASTImporter::Import(const Attr *FromAttr) {
From->args_size());
break;
}
case attr::LockReturned: {
const auto *From = cast<LockReturnedAttr>(FromAttr);
case attr::CapabilityReturned: {
const auto *From = cast<CapabilityReturnedAttr>(FromAttr);
AI.importAttr(From, AI.importArg(From->getArg()).value());
break;
}
case attr::LocksExcluded: {
const auto *From = cast<LocksExcludedAttr>(FromAttr);
case attr::CapabilitiesExcluded: {
const auto *From = cast<CapabilitiesExcludedAttr>(FromAttr);
AI.importAttr(From,
AI.importArrayArg(From->args(), From->args_size()).value(),
From->args_size());
Expand Down
12 changes: 6 additions & 6 deletions clang/lib/Analysis/ThreadSafety.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,7 @@ class LockableFactEntry : public FactEntry {
}
};

class ScopedLockableFactEntry : public FactEntry {
class ScopedCapabilityFactEntry : public FactEntry {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other derived class is still called LockableFactEntry. We should either leave this or change both.

private:
enum UnderlyingCapabilityKind {
UCK_Acquired, ///< Any kind of acquired capability.
Expand All @@ -903,7 +903,7 @@ class ScopedLockableFactEntry : public FactEntry {
SmallVector<UnderlyingCapability, 2> UnderlyingMutexes;

public:
ScopedLockableFactEntry(const CapabilityExpr &CE, SourceLocation Loc)
ScopedCapabilityFactEntry(const CapabilityExpr &CE, SourceLocation Loc)
: FactEntry(CE, LK_Exclusive, Loc, Acquired) {}

void addLock(const CapabilityExpr &M) {
Expand Down Expand Up @@ -1812,7 +1812,7 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
assert(inserted.second && "Are we visiting the same expression again?");
if (isa<CXXConstructExpr>(Exp))
Self = Placeholder.first;
if (TagT->getDecl()->hasAttr<ScopedLockableAttr>())
if (TagT->getDecl()->hasAttr<ScopedCapabilityAttr>())
Scp = CapabilityExpr(Placeholder.first, Placeholder.second, false);
}

Expand Down Expand Up @@ -1896,8 +1896,8 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
break;
}

case attr::LocksExcluded: {
const auto *A = cast<LocksExcludedAttr>(At);
case attr::CapabilitiesExcluded: {
const auto *A = cast<CapabilitiesExcludedAttr>(At);
for (auto *Arg : A->args()) {
Analyzer->warnIfMutexHeld(FSet, D, Exp, Arg, Self, Loc);
// use for deferring a lock
Expand Down Expand Up @@ -1935,7 +1935,7 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,

if (!Scp.shouldIgnore()) {
// Add the managing object as a dummy mutex, mapped to the underlying mutex.
auto ScopedEntry = std::make_unique<ScopedLockableFactEntry>(Scp, Loc);
auto ScopedEntry = std::make_unique<ScopedCapabilityFactEntry>(Scp, Loc);
for (const auto &M : ExclusiveLocksToAdd)
ScopedEntry->addLock(M);
for (const auto &M : SharedLocksToAdd)
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Analysis/ThreadSafetyCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -420,10 +420,10 @@ til::SExpr *SExprBuilder::translateCallExpr(const CallExpr *CE,
CallingContext *Ctx,
const Expr *SelfE) {
if (CapabilityExprMode) {
// Handle LOCK_RETURNED
// Handle CAPABILITY_RETURNED
if (const FunctionDecl *FD = CE->getDirectCallee()) {
FD = FD->getMostRecentDecl();
if (LockReturnedAttr *At = FD->getAttr<LockReturnedAttr>()) {
if (CapabilityReturnedAttr *At = FD->getAttr<CapabilityReturnedAttr>()) {
CallingContext LRCallCtx(Ctx);
LRCallCtx.AttrDecl = CE->getDirectCallee();
LRCallCtx.SelfArg = SelfE;
Expand Down
20 changes: 11 additions & 9 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D,
const CXXRecordDecl *RD = MD->getParent();
// FIXME -- need to check this again on template instantiation
if (!checkRecordDeclForAttr<CapabilityAttr>(RD) &&
!checkRecordDeclForAttr<ScopedLockableAttr>(RD))
!checkRecordDeclForAttr<ScopedCapabilityAttr>(RD))
S.Diag(AL.getLoc(),
diag::warn_thread_attribute_not_on_capability_member)
<< AL << MD->getParent();
Expand Down Expand Up @@ -633,18 +633,20 @@ static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D,
S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size()));
}

static void handleLockReturnedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
static void handleCapabilityReturnedAttr(Sema &S, Decl *D,
const ParsedAttr &AL) {
// check that the argument is lockable object
SmallVector<Expr*, 1> Args;
checkAttrArgsAreCapabilityObjs(S, D, AL, Args);
unsigned Size = Args.size();
if (Size == 0)
return;

D->addAttr(::new (S.Context) LockReturnedAttr(S.Context, AL, Args[0]));
D->addAttr(::new (S.Context) CapabilityReturnedAttr(S.Context, AL, Args[0]));
}

static void handleLocksExcludedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
static void handleCapabilitiesExcludedAttr(Sema &S, Decl *D,
const ParsedAttr &AL) {
if (!AL.checkAtLeastNumArgs(S, 1))
return;

Expand All @@ -657,7 +659,7 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
Expr **StartArg = &Args[0];

D->addAttr(::new (S.Context)
LocksExcludedAttr(S.Context, AL, StartArg, Size));
CapabilitiesExcludedAttr(S.Context, AL, StartArg, Size));
}

static bool checkFunctionConditionAttr(Sema &S, Decl *D, const ParsedAttr &AL,
Expand Down Expand Up @@ -6927,11 +6929,11 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_ExclusiveTrylockFunction:
handleExclusiveTrylockFunctionAttr(S, D, AL);
break;
case ParsedAttr::AT_LockReturned:
handleLockReturnedAttr(S, D, AL);
case ParsedAttr::AT_CapabilityReturned:
handleCapabilityReturnedAttr(S, D, AL);
break;
case ParsedAttr::AT_LocksExcluded:
handleLocksExcludedAttr(S, D, AL);
case ParsedAttr::AT_CapabilitiesExcluded:
handleCapabilitiesExcludedAttr(S, D, AL);
break;
case ParsedAttr::AT_SharedTrylockFunction:
handleSharedTrylockFunctionAttr(S, D, AL);
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18792,9 +18792,9 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) {
} else if (const auto *STLF = dyn_cast<SharedTrylockFunctionAttr>(A)) {
Arg = STLF->getSuccessValue();
Args = llvm::ArrayRef(STLF->args_begin(), STLF->args_size());
} else if (const auto *LR = dyn_cast<LockReturnedAttr>(A))
} else if (const auto *LR = dyn_cast<CapabilityReturnedAttr>(A))
Arg = LR->getArg();
else if (const auto *LE = dyn_cast<LocksExcludedAttr>(A))
else if (const auto *LE = dyn_cast<CapabilitiesExcludedAttr>(A))
Args = llvm::ArrayRef(LE->args_begin(), LE->args_size());
else if (const auto *RC = dyn_cast<RequiresCapabilityAttr>(A))
Args = llvm::ArrayRef(RC->args_begin(), RC->args_size());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@
// CHECK-NEXT: ReturnsNonNull (SubjectMatchRule_objc_method, SubjectMatchRule_function)
// CHECK-NEXT: ReturnsTwice (SubjectMatchRule_function)
// CHECK-NEXT: SYCLSpecialClass (SubjectMatchRule_record)
// CHECK-NEXT: ScopedLockable (SubjectMatchRule_record)
// CHECK-NEXT: ScopedCapability (SubjectMatchRule_record)
// CHECK-NEXT: Section (SubjectMatchRule_function, SubjectMatchRule_variable_is_global, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property)
// CHECK-NEXT: SetTypestate (SubjectMatchRule_function_is_member)
// CHECK-NEXT: SpeculativeLoadHardening (SubjectMatchRule_function, SubjectMatchRule_objc_method)
Expand Down
4 changes: 4 additions & 0 deletions clang/test/Parser/cxx11-stmt-attributes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ void foo(int i) {
} catch (...) {
}

[[capability_returned]] try { // expected-warning {{unknown attribute 'capability_returned' ignored}}
} catch (...) {
}

[[weakref]] return; // expected-warning {{unknown attribute 'weakref' ignored}}

[[carries_dependency]] ; // expected-error {{'carries_dependency' attribute cannot be applied to a statement}}
Expand Down
9 changes: 6 additions & 3 deletions clang/test/SemaCXX/thread-safety-annotations.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
#define SHARED_TRYLOCK_FUNCTION(...) __attribute__((try_acquire_shared_capability(__VA_ARGS__)))
#define EXCLUSIVE_LOCKS_REQUIRED(...) __attribute__((requires_capability(__VA_ARGS__)))
#define SHARED_LOCKS_REQUIRED(...) __attribute__((requires_shared_capability(__VA_ARGS__)))
#define SCOPED_LOCKABLE __attribute__((scoped_capability))
#define LOCK_RETURNED(x) __attribute__((capability_returned(x)))
#define LOCKS_EXCLUDED(...) __attribute__((capabilities_excluded(__VA_ARGS__)))
#else
#define LOCKABLE __attribute__((lockable))
#define ASSERT_EXCLUSIVE_LOCK(...) __attribute__((assert_exclusive_lock(__VA_ARGS__)))
Expand All @@ -22,6 +25,9 @@
#define SHARED_TRYLOCK_FUNCTION(...) __attribute__((shared_trylock_function(__VA_ARGS__)))
#define EXCLUSIVE_LOCKS_REQUIRED(...) __attribute__((exclusive_locks_required(__VA_ARGS__)))
#define SHARED_LOCKS_REQUIRED(...) __attribute__((shared_locks_required(__VA_ARGS__)))
#define SCOPED_LOCKABLE __attribute__((scoped_lockable))
#define LOCK_RETURNED(x) __attribute__((lock_returned(x)))
#define LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__)))
#endif

// Lock semantics only
Expand All @@ -35,9 +41,6 @@
#define PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x)))

// Common
#define SCOPED_LOCKABLE __attribute__((scoped_lockable))
#define ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__)))
#define ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__)))
#define LOCK_RETURNED(x) __attribute__((lock_returned(x)))
#define LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__)))
#define NO_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis))
24 changes: 12 additions & 12 deletions clang/unittests/AST/ASTImporterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7819,10 +7819,10 @@ TEST_P(ImportAttributes, ImportPtGuardedVar) {
ToAttr);
}

TEST_P(ImportAttributes, ImportScopedLockable) {
ScopedLockableAttr *FromAttr, *ToAttr;
importAttr<CXXRecordDecl>("struct __attribute__((scoped_lockable)) test {};",
FromAttr, ToAttr);
TEST_P(ImportAttributes, ImportScopedCapability) {
ScopedCapabilityAttr *FromAttr, *ToAttr;
importAttr<CXXRecordDecl>(
"struct __attribute__((scoped_capability)) test {};", FromAttr, ToAttr);
}

TEST_P(ImportAttributes, ImportCapability) {
Expand Down Expand Up @@ -7965,19 +7965,19 @@ TEST_P(ImportAttributes, ImportSharedTrylockFunction) {
checkImportVariadicArg(FromAttr->args(), ToAttr->args());
}

TEST_P(ImportAttributes, ImportLockReturned) {
LockReturnedAttr *FromAttr, *ToAttr;
TEST_P(ImportAttributes, ImportCapabilityReturned) {
CapabilityReturnedAttr *FromAttr, *ToAttr;
importAttr<FunctionDecl>(
"void test(int A1) __attribute__((lock_returned(A1)));", FromAttr,
"void test(int A1) __attribute__((capability_returned(A1)));", FromAttr,
ToAttr);
checkImported(FromAttr->getArg(), ToAttr->getArg());
}

TEST_P(ImportAttributes, ImportLocksExcluded) {
LocksExcludedAttr *FromAttr, *ToAttr;
importAttr<FunctionDecl>(
"void test(int A1, int A2) __attribute__((locks_excluded(A1, A2)));",
FromAttr, ToAttr);
TEST_P(ImportAttributes, ImportCapabilitiesExcluded) {
CapabilitiesExcludedAttr *FromAttr, *ToAttr;
importAttr<FunctionDecl>("void test(int A1, int A2) "
"__attribute__((capabilities_excluded(A1, A2)));",
FromAttr, ToAttr);
checkImportVariadicArg(FromAttr->args(), ToAttr->args());
}

Expand Down