Skip to content

Commit 9c73eba

Browse files
authored
Merge similar Clang Thread Safety attributes (#135561)
Some of the old lock-based and new capability-based spellings behave basically in the same way, so merging them simplifies the code significantly. There are two minor functional changes: we only warn (instead of an error) when the try_acquire_capability attribute is used on something else than a function. The alternative would have been to produce an error for the old spelling, but we seem to only warn for all function attributes, so this is arguably more consistent. The second change is that we also check the first argument (which is the value returned for a successful try-acquire) for `this`. But from what I can tell, this code is defunct anyway at the moment (see #31414).
1 parent d30a5b4 commit 9c73eba

File tree

7 files changed

+21
-238
lines changed

7 files changed

+21
-238
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 11 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -3818,15 +3818,18 @@ def Capability : InheritableAttr {
38183818

38193819
def AssertCapability : InheritableAttr {
38203820
let Spellings = [Clang<"assert_capability", 0>,
3821-
Clang<"assert_shared_capability", 0>];
3821+
Clang<"assert_shared_capability", 0>,
3822+
GNU<"assert_exclusive_lock">,
3823+
GNU<"assert_shared_lock">];
38223824
let Subjects = SubjectList<[Function]>;
38233825
let LateParsed = LateAttrParseStandard;
38243826
let TemplateDependent = 1;
38253827
let ParseArgumentsAsUnevaluated = 1;
38263828
let InheritEvenIfAlreadyPresent = 1;
38273829
let Args = [VariadicExprArgument<"Args">];
38283830
let Accessors = [Accessor<"isShared",
3829-
[Clang<"assert_shared_capability", 0>]>];
3831+
[Clang<"assert_shared_capability", 0>,
3832+
GNU<"assert_shared_lock">]>];
38303833
let Documentation = [AssertCapabilityDocs];
38313834
}
38323835

@@ -3849,16 +3852,18 @@ def AcquireCapability : InheritableAttr {
38493852

38503853
def TryAcquireCapability : InheritableAttr {
38513854
let Spellings = [Clang<"try_acquire_capability", 0>,
3852-
Clang<"try_acquire_shared_capability", 0>];
3853-
let Subjects = SubjectList<[Function],
3854-
ErrorDiag>;
3855+
Clang<"try_acquire_shared_capability", 0>,
3856+
GNU<"exclusive_trylock_function">,
3857+
GNU<"shared_trylock_function">];
3858+
let Subjects = SubjectList<[Function]>;
38553859
let LateParsed = LateAttrParseStandard;
38563860
let TemplateDependent = 1;
38573861
let ParseArgumentsAsUnevaluated = 1;
38583862
let InheritEvenIfAlreadyPresent = 1;
38593863
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
38603864
let Accessors = [Accessor<"isShared",
3861-
[Clang<"try_acquire_shared_capability", 0>]>];
3865+
[Clang<"try_acquire_shared_capability", 0>,
3866+
GNU<"shared_trylock_function">]>];
38623867
let Documentation = [TryAcquireCapabilityDocs];
38633868
}
38643869

@@ -3948,54 +3953,6 @@ def AcquiredBefore : InheritableAttr {
39483953
let Documentation = [Undocumented];
39493954
}
39503955

3951-
def AssertExclusiveLock : InheritableAttr {
3952-
let Spellings = [GNU<"assert_exclusive_lock">];
3953-
let Args = [VariadicExprArgument<"Args">];
3954-
let LateParsed = LateAttrParseStandard;
3955-
let TemplateDependent = 1;
3956-
let ParseArgumentsAsUnevaluated = 1;
3957-
let InheritEvenIfAlreadyPresent = 1;
3958-
let Subjects = SubjectList<[Function]>;
3959-
let Documentation = [Undocumented];
3960-
}
3961-
3962-
def AssertSharedLock : InheritableAttr {
3963-
let Spellings = [GNU<"assert_shared_lock">];
3964-
let Args = [VariadicExprArgument<"Args">];
3965-
let LateParsed = LateAttrParseStandard;
3966-
let TemplateDependent = 1;
3967-
let ParseArgumentsAsUnevaluated = 1;
3968-
let InheritEvenIfAlreadyPresent = 1;
3969-
let Subjects = SubjectList<[Function]>;
3970-
let Documentation = [Undocumented];
3971-
}
3972-
3973-
// The first argument is an integer or boolean value specifying the return value
3974-
// of a successful lock acquisition.
3975-
def ExclusiveTrylockFunction : InheritableAttr {
3976-
let Spellings = [GNU<"exclusive_trylock_function">];
3977-
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
3978-
let LateParsed = LateAttrParseStandard;
3979-
let TemplateDependent = 1;
3980-
let ParseArgumentsAsUnevaluated = 1;
3981-
let InheritEvenIfAlreadyPresent = 1;
3982-
let Subjects = SubjectList<[Function]>;
3983-
let Documentation = [Undocumented];
3984-
}
3985-
3986-
// The first argument is an integer or boolean value specifying the return value
3987-
// of a successful lock acquisition.
3988-
def SharedTrylockFunction : InheritableAttr {
3989-
let Spellings = [GNU<"shared_trylock_function">];
3990-
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
3991-
let LateParsed = LateAttrParseStandard;
3992-
let TemplateDependent = 1;
3993-
let ParseArgumentsAsUnevaluated = 1;
3994-
let InheritEvenIfAlreadyPresent = 1;
3995-
let Subjects = SubjectList<[Function]>;
3996-
let Documentation = [Undocumented];
3997-
}
3998-
39993956
def LockReturned : InheritableAttr {
40003957
let Spellings = [GNU<"lock_returned">];
40013958
let Args = [ExprArgument<"Arg">];

clang/lib/AST/ASTImporter.cpp

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9425,34 +9425,6 @@ Expected<Attr *> ASTImporter::Import(const Attr *FromAttr) {
94259425
From->args_size());
94269426
break;
94279427
}
9428-
case attr::AssertExclusiveLock: {
9429-
const auto *From = cast<AssertExclusiveLockAttr>(FromAttr);
9430-
AI.importAttr(From,
9431-
AI.importArrayArg(From->args(), From->args_size()).value(),
9432-
From->args_size());
9433-
break;
9434-
}
9435-
case attr::AssertSharedLock: {
9436-
const auto *From = cast<AssertSharedLockAttr>(FromAttr);
9437-
AI.importAttr(From,
9438-
AI.importArrayArg(From->args(), From->args_size()).value(),
9439-
From->args_size());
9440-
break;
9441-
}
9442-
case attr::ExclusiveTrylockFunction: {
9443-
const auto *From = cast<ExclusiveTrylockFunctionAttr>(FromAttr);
9444-
AI.importAttr(From, AI.importArg(From->getSuccessValue()).value(),
9445-
AI.importArrayArg(From->args(), From->args_size()).value(),
9446-
From->args_size());
9447-
break;
9448-
}
9449-
case attr::SharedTrylockFunction: {
9450-
const auto *From = cast<SharedTrylockFunctionAttr>(FromAttr);
9451-
AI.importAttr(From, AI.importArg(From->getSuccessValue()).value(),
9452-
AI.importArrayArg(From->args(), From->args_size()).value(),
9453-
From->args_size());
9454-
break;
9455-
}
94569428
case attr::LockReturned: {
94579429
const auto *From = cast<LockReturnedAttr>(FromAttr);
94589430
AI.importAttr(From, AI.importArg(From->getArg()).value());

clang/lib/Analysis/ThreadSafety.cpp

Lines changed: 5 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,38 +1511,17 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result,
15111511
return;
15121512

15131513
auto *FunDecl = dyn_cast_or_null<NamedDecl>(Exp->getCalleeDecl());
1514-
if(!FunDecl || !FunDecl->hasAttrs())
1514+
if (!FunDecl || !FunDecl->hasAttr<TryAcquireCapabilityAttr>())
15151515
return;
15161516

15171517
CapExprSet ExclusiveLocksToAdd;
15181518
CapExprSet SharedLocksToAdd;
15191519

15201520
// If the condition is a call to a Trylock function, then grab the attributes
1521-
for (const auto *Attr : FunDecl->attrs()) {
1522-
switch (Attr->getKind()) {
1523-
case attr::TryAcquireCapability: {
1524-
auto *A = cast<TryAcquireCapabilityAttr>(Attr);
1525-
getMutexIDs(A->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, A,
1526-
Exp, FunDecl, PredBlock, CurrBlock, A->getSuccessValue(),
1527-
Negate);
1528-
break;
1529-
};
1530-
case attr::ExclusiveTrylockFunction: {
1531-
const auto *A = cast<ExclusiveTrylockFunctionAttr>(Attr);
1532-
getMutexIDs(ExclusiveLocksToAdd, A, Exp, FunDecl, PredBlock, CurrBlock,
1533-
A->getSuccessValue(), Negate);
1534-
break;
1535-
}
1536-
case attr::SharedTrylockFunction: {
1537-
const auto *A = cast<SharedTrylockFunctionAttr>(Attr);
1538-
getMutexIDs(SharedLocksToAdd, A, Exp, FunDecl, PredBlock, CurrBlock,
1539-
A->getSuccessValue(), Negate);
1540-
break;
1541-
}
1542-
default:
1543-
break;
1544-
}
1545-
}
1521+
for (const auto *Attr : FunDecl->specific_attrs<TryAcquireCapabilityAttr>())
1522+
getMutexIDs(Attr->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, Attr,
1523+
Exp, FunDecl, PredBlock, CurrBlock, Attr->getSuccessValue(),
1524+
Negate);
15461525

15471526
// Add and remove locks.
15481527
SourceLocation Loc = Exp->getExprLoc();
@@ -1882,29 +1861,6 @@ void BuildLockset::handleCall(const Expr *Exp, const NamedDecl *D,
18821861
// An assert will add a lock to the lockset, but will not generate
18831862
// a warning if it is already there, and will not generate a warning
18841863
// if it is not removed.
1885-
case attr::AssertExclusiveLock: {
1886-
const auto *A = cast<AssertExclusiveLockAttr>(At);
1887-
1888-
CapExprSet AssertLocks;
1889-
Analyzer->getMutexIDs(AssertLocks, A, Exp, D, Self);
1890-
for (const auto &AssertLock : AssertLocks)
1891-
Analyzer->addLock(
1892-
FSet, std::make_unique<LockableFactEntry>(
1893-
AssertLock, LK_Exclusive, Loc, FactEntry::Asserted));
1894-
break;
1895-
}
1896-
case attr::AssertSharedLock: {
1897-
const auto *A = cast<AssertSharedLockAttr>(At);
1898-
1899-
CapExprSet AssertLocks;
1900-
Analyzer->getMutexIDs(AssertLocks, A, Exp, D, Self);
1901-
for (const auto &AssertLock : AssertLocks)
1902-
Analyzer->addLock(
1903-
FSet, std::make_unique<LockableFactEntry>(
1904-
AssertLock, LK_Shared, Loc, FactEntry::Asserted));
1905-
break;
1906-
}
1907-
19081864
case attr::AssertCapability: {
19091865
const auto *A = cast<AssertCapabilityAttr>(At);
19101866
CapExprSet AssertLocks;
@@ -2499,12 +2455,6 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) {
24992455
getMutexIDs(A->isShared() ? SharedLocksAcquired
25002456
: ExclusiveLocksAcquired,
25012457
A, nullptr, D);
2502-
} else if (isa<ExclusiveTrylockFunctionAttr>(Attr)) {
2503-
// Don't try to check trylock functions for now.
2504-
return;
2505-
} else if (isa<SharedTrylockFunctionAttr>(Attr)) {
2506-
// Don't try to check trylock functions for now.
2507-
return;
25082458
} else if (isa<TryAcquireCapabilityAttr>(Attr)) {
25092459
// Don't try to check trylock functions for now.
25102460
return;

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -538,29 +538,6 @@ static bool checkLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
538538
return true;
539539
}
540540

541-
static void handleAssertSharedLockAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
542-
SmallVector<Expr *, 1> Args;
543-
if (!checkLockFunAttrCommon(S, D, AL, Args))
544-
return;
545-
546-
unsigned Size = Args.size();
547-
Expr **StartArg = Size == 0 ? nullptr : &Args[0];
548-
D->addAttr(::new (S.Context)
549-
AssertSharedLockAttr(S.Context, AL, StartArg, Size));
550-
}
551-
552-
static void handleAssertExclusiveLockAttr(Sema &S, Decl *D,
553-
const ParsedAttr &AL) {
554-
SmallVector<Expr *, 1> Args;
555-
if (!checkLockFunAttrCommon(S, D, AL, Args))
556-
return;
557-
558-
unsigned Size = Args.size();
559-
Expr **StartArg = Size == 0 ? nullptr : &Args[0];
560-
D->addAttr(::new (S.Context)
561-
AssertExclusiveLockAttr(S.Context, AL, StartArg, Size));
562-
}
563-
564541
/// Checks to be sure that the given parameter number is in bounds, and
565542
/// is an integral type. Will emit appropriate diagnostics if this returns
566543
/// false.
@@ -640,26 +617,6 @@ static bool checkTryLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
640617
return true;
641618
}
642619

643-
static void handleSharedTrylockFunctionAttr(Sema &S, Decl *D,
644-
const ParsedAttr &AL) {
645-
SmallVector<Expr*, 2> Args;
646-
if (!checkTryLockFunAttrCommon(S, D, AL, Args))
647-
return;
648-
649-
D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(
650-
S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size()));
651-
}
652-
653-
static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D,
654-
const ParsedAttr &AL) {
655-
SmallVector<Expr*, 2> Args;
656-
if (!checkTryLockFunAttrCommon(S, D, AL, Args))
657-
return;
658-
659-
D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(
660-
S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size()));
661-
}
662-
663620
static void handleLockReturnedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
664621
// check that the argument is lockable object
665622
SmallVector<Expr*, 1> Args;
@@ -7528,12 +7485,6 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
75287485
break;
75297486

75307487
// Thread safety attributes:
7531-
case ParsedAttr::AT_AssertExclusiveLock:
7532-
handleAssertExclusiveLockAttr(S, D, AL);
7533-
break;
7534-
case ParsedAttr::AT_AssertSharedLock:
7535-
handleAssertSharedLockAttr(S, D, AL);
7536-
break;
75377488
case ParsedAttr::AT_PtGuardedVar:
75387489
handlePtGuardedVarAttr(S, D, AL);
75397490
break;
@@ -7549,18 +7500,12 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
75497500
case ParsedAttr::AT_PtGuardedBy:
75507501
handlePtGuardedByAttr(S, D, AL);
75517502
break;
7552-
case ParsedAttr::AT_ExclusiveTrylockFunction:
7553-
handleExclusiveTrylockFunctionAttr(S, D, AL);
7554-
break;
75557503
case ParsedAttr::AT_LockReturned:
75567504
handleLockReturnedAttr(S, D, AL);
75577505
break;
75587506
case ParsedAttr::AT_LocksExcluded:
75597507
handleLocksExcludedAttr(S, D, AL);
75607508
break;
7561-
case ParsedAttr::AT_SharedTrylockFunction:
7562-
handleSharedTrylockFunctionAttr(S, D, AL);
7563-
break;
75647509
case ParsedAttr::AT_AcquiredBefore:
75657510
handleAcquiredBeforeAttr(S, D, AL);
75667511
break;

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19401,23 +19401,18 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) {
1940119401
Args = llvm::ArrayRef(AA->args_begin(), AA->args_size());
1940219402
else if (const auto *AB = dyn_cast<AcquiredBeforeAttr>(A))
1940319403
Args = llvm::ArrayRef(AB->args_begin(), AB->args_size());
19404-
else if (const auto *ETLF = dyn_cast<ExclusiveTrylockFunctionAttr>(A)) {
19405-
Arg = ETLF->getSuccessValue();
19406-
Args = llvm::ArrayRef(ETLF->args_begin(), ETLF->args_size());
19407-
} else if (const auto *STLF = dyn_cast<SharedTrylockFunctionAttr>(A)) {
19408-
Arg = STLF->getSuccessValue();
19409-
Args = llvm::ArrayRef(STLF->args_begin(), STLF->args_size());
19410-
} else if (const auto *LR = dyn_cast<LockReturnedAttr>(A))
19404+
else if (const auto *LR = dyn_cast<LockReturnedAttr>(A))
1941119405
Arg = LR->getArg();
1941219406
else if (const auto *LE = dyn_cast<LocksExcludedAttr>(A))
1941319407
Args = llvm::ArrayRef(LE->args_begin(), LE->args_size());
1941419408
else if (const auto *RC = dyn_cast<RequiresCapabilityAttr>(A))
1941519409
Args = llvm::ArrayRef(RC->args_begin(), RC->args_size());
1941619410
else if (const auto *AC = dyn_cast<AcquireCapabilityAttr>(A))
1941719411
Args = llvm::ArrayRef(AC->args_begin(), AC->args_size());
19418-
else if (const auto *AC = dyn_cast<TryAcquireCapabilityAttr>(A))
19412+
else if (const auto *AC = dyn_cast<TryAcquireCapabilityAttr>(A)) {
19413+
Arg = AC->getSuccessValue();
1941919414
Args = llvm::ArrayRef(AC->args_begin(), AC->args_size());
19420-
else if (const auto *RC = dyn_cast<ReleaseCapabilityAttr>(A))
19415+
} else if (const auto *RC = dyn_cast<ReleaseCapabilityAttr>(A))
1942119416
Args = llvm::ArrayRef(RC->args_begin(), RC->args_size());
1942219417

1942319418
if (Arg && !Finder.TraverseStmt(Arg))

clang/test/Sema/attr-capabilities.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ struct __attribute__((capability("custom"))) CustomName {};
1414
int Test1 __attribute__((capability("test1"))); // expected-error {{'capability' attribute only applies to structs, unions, classes, and typedefs}}
1515
int Test2 __attribute__((shared_capability("test2"))); // expected-error {{'shared_capability' attribute only applies to structs, unions, classes, and typedefs}}
1616
int Test3 __attribute__((acquire_capability("test3"))); // expected-warning {{'acquire_capability' attribute only applies to functions}}
17-
int Test4 __attribute__((try_acquire_capability("test4"))); // expected-error {{'try_acquire_capability' attribute only applies to functions}}
17+
int Test4 __attribute__((try_acquire_capability("test4"))); // expected-warning {{'try_acquire_capability' attribute only applies to functions}}
1818
int Test5 __attribute__((release_capability("test5"))); // expected-warning {{'release_capability' attribute only applies to functions}}
1919

2020
struct __attribute__((capability(12))) Test3 {}; // expected-error {{expected string literal as argument of 'capability' attribute}}

clang/unittests/AST/ASTImporterTest.cpp

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7977,42 +7977,6 @@ TEST_P(ImportAttributes, ImportAcquiredBefore) {
79777977
checkImportVariadicArg(FromAttr->args(), ToAttr->args());
79787978
}
79797979

7980-
TEST_P(ImportAttributes, ImportAssertExclusiveLock) {
7981-
AssertExclusiveLockAttr *FromAttr, *ToAttr;
7982-
importAttr<FunctionDecl>("void test(int A1, int A2) "
7983-
"__attribute__((assert_exclusive_lock(A1, A2)));",
7984-
FromAttr, ToAttr);
7985-
checkImportVariadicArg(FromAttr->args(), ToAttr->args());
7986-
}
7987-
7988-
TEST_P(ImportAttributes, ImportAssertSharedLock) {
7989-
AssertSharedLockAttr *FromAttr, *ToAttr;
7990-
importAttr<FunctionDecl>(
7991-
"void test(int A1, int A2) __attribute__((assert_shared_lock(A1, A2)));",
7992-
FromAttr, ToAttr);
7993-
checkImportVariadicArg(FromAttr->args(), ToAttr->args());
7994-
}
7995-
7996-
TEST_P(ImportAttributes, ImportExclusiveTrylockFunction) {
7997-
ExclusiveTrylockFunctionAttr *FromAttr, *ToAttr;
7998-
importAttr<FunctionDecl>(
7999-
"void test(int A1, int A2) __attribute__((exclusive_trylock_function(1, "
8000-
"A1, A2)));",
8001-
FromAttr, ToAttr);
8002-
checkImported(FromAttr->getSuccessValue(), ToAttr->getSuccessValue());
8003-
checkImportVariadicArg(FromAttr->args(), ToAttr->args());
8004-
}
8005-
8006-
TEST_P(ImportAttributes, ImportSharedTrylockFunction) {
8007-
SharedTrylockFunctionAttr *FromAttr, *ToAttr;
8008-
importAttr<FunctionDecl>(
8009-
"void test(int A1, int A2) __attribute__((shared_trylock_function(1, A1, "
8010-
"A2)));",
8011-
FromAttr, ToAttr);
8012-
checkImported(FromAttr->getSuccessValue(), ToAttr->getSuccessValue());
8013-
checkImportVariadicArg(FromAttr->args(), ToAttr->args());
8014-
}
8015-
80167980
TEST_P(ImportAttributes, ImportLockReturned) {
80177981
LockReturnedAttr *FromAttr, *ToAttr;
80187982
importAttr<FunctionDecl>(

0 commit comments

Comments
 (0)