Skip to content

Commit 372bfce

Browse files
committed
Merge similar Clang Thread Safety attributes
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 13faa81 commit 372bfce

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
@@ -3803,15 +3803,18 @@ def Capability : InheritableAttr {
38033803

38043804
def AssertCapability : InheritableAttr {
38053805
let Spellings = [Clang<"assert_capability", 0>,
3806-
Clang<"assert_shared_capability", 0>];
3806+
Clang<"assert_shared_capability", 0>,
3807+
GNU<"assert_exclusive_lock">,
3808+
GNU<"assert_shared_lock">];
38073809
let Subjects = SubjectList<[Function]>;
38083810
let LateParsed = LateAttrParseStandard;
38093811
let TemplateDependent = 1;
38103812
let ParseArgumentsAsUnevaluated = 1;
38113813
let InheritEvenIfAlreadyPresent = 1;
38123814
let Args = [VariadicExprArgument<"Args">];
38133815
let Accessors = [Accessor<"isShared",
3814-
[Clang<"assert_shared_capability", 0>]>];
3816+
[Clang<"assert_shared_capability", 0>,
3817+
GNU<"assert_shared_lock">]>];
38153818
let Documentation = [AssertCapabilityDocs];
38163819
}
38173820

@@ -3834,16 +3837,18 @@ def AcquireCapability : InheritableAttr {
38343837

38353838
def TryAcquireCapability : InheritableAttr {
38363839
let Spellings = [Clang<"try_acquire_capability", 0>,
3837-
Clang<"try_acquire_shared_capability", 0>];
3838-
let Subjects = SubjectList<[Function],
3839-
ErrorDiag>;
3840+
Clang<"try_acquire_shared_capability", 0>,
3841+
GNU<"exclusive_trylock_function">,
3842+
GNU<"shared_trylock_function">];
3843+
let Subjects = SubjectList<[Function]>;
38403844
let LateParsed = LateAttrParseStandard;
38413845
let TemplateDependent = 1;
38423846
let ParseArgumentsAsUnevaluated = 1;
38433847
let InheritEvenIfAlreadyPresent = 1;
38443848
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
38453849
let Accessors = [Accessor<"isShared",
3846-
[Clang<"try_acquire_shared_capability", 0>]>];
3850+
[Clang<"try_acquire_shared_capability", 0>,
3851+
GNU<"shared_trylock_function">]>];
38473852
let Documentation = [TryAcquireCapabilityDocs];
38483853
}
38493854

@@ -3933,54 +3938,6 @@ def AcquiredBefore : InheritableAttr {
39333938
let Documentation = [Undocumented];
39343939
}
39353940

3936-
def AssertExclusiveLock : InheritableAttr {
3937-
let Spellings = [GNU<"assert_exclusive_lock">];
3938-
let Args = [VariadicExprArgument<"Args">];
3939-
let LateParsed = LateAttrParseStandard;
3940-
let TemplateDependent = 1;
3941-
let ParseArgumentsAsUnevaluated = 1;
3942-
let InheritEvenIfAlreadyPresent = 1;
3943-
let Subjects = SubjectList<[Function]>;
3944-
let Documentation = [Undocumented];
3945-
}
3946-
3947-
def AssertSharedLock : InheritableAttr {
3948-
let Spellings = [GNU<"assert_shared_lock">];
3949-
let Args = [VariadicExprArgument<"Args">];
3950-
let LateParsed = LateAttrParseStandard;
3951-
let TemplateDependent = 1;
3952-
let ParseArgumentsAsUnevaluated = 1;
3953-
let InheritEvenIfAlreadyPresent = 1;
3954-
let Subjects = SubjectList<[Function]>;
3955-
let Documentation = [Undocumented];
3956-
}
3957-
3958-
// The first argument is an integer or boolean value specifying the return value
3959-
// of a successful lock acquisition.
3960-
def ExclusiveTrylockFunction : InheritableAttr {
3961-
let Spellings = [GNU<"exclusive_trylock_function">];
3962-
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
3963-
let LateParsed = LateAttrParseStandard;
3964-
let TemplateDependent = 1;
3965-
let ParseArgumentsAsUnevaluated = 1;
3966-
let InheritEvenIfAlreadyPresent = 1;
3967-
let Subjects = SubjectList<[Function]>;
3968-
let Documentation = [Undocumented];
3969-
}
3970-
3971-
// The first argument is an integer or boolean value specifying the return value
3972-
// of a successful lock acquisition.
3973-
def SharedTrylockFunction : InheritableAttr {
3974-
let Spellings = [GNU<"shared_trylock_function">];
3975-
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
3976-
let LateParsed = LateAttrParseStandard;
3977-
let TemplateDependent = 1;
3978-
let ParseArgumentsAsUnevaluated = 1;
3979-
let InheritEvenIfAlreadyPresent = 1;
3980-
let Subjects = SubjectList<[Function]>;
3981-
let Documentation = [Undocumented];
3982-
}
3983-
39843941
def LockReturned : InheritableAttr {
39853942
let Spellings = [GNU<"lock_returned">];
39863943
let Args = [ExprArgument<"Arg">];

clang/lib/AST/ASTImporter.cpp

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9420,34 +9420,6 @@ Expected<Attr *> ASTImporter::Import(const Attr *FromAttr) {
94209420
From->args_size());
94219421
break;
94229422
}
9423-
case attr::AssertExclusiveLock: {
9424-
const auto *From = cast<AssertExclusiveLockAttr>(FromAttr);
9425-
AI.importAttr(From,
9426-
AI.importArrayArg(From->args(), From->args_size()).value(),
9427-
From->args_size());
9428-
break;
9429-
}
9430-
case attr::AssertSharedLock: {
9431-
const auto *From = cast<AssertSharedLockAttr>(FromAttr);
9432-
AI.importAttr(From,
9433-
AI.importArrayArg(From->args(), From->args_size()).value(),
9434-
From->args_size());
9435-
break;
9436-
}
9437-
case attr::ExclusiveTrylockFunction: {
9438-
const auto *From = cast<ExclusiveTrylockFunctionAttr>(FromAttr);
9439-
AI.importAttr(From, AI.importArg(From->getSuccessValue()).value(),
9440-
AI.importArrayArg(From->args(), From->args_size()).value(),
9441-
From->args_size());
9442-
break;
9443-
}
9444-
case attr::SharedTrylockFunction: {
9445-
const auto *From = cast<SharedTrylockFunctionAttr>(FromAttr);
9446-
AI.importAttr(From, AI.importArg(From->getSuccessValue()).value(),
9447-
AI.importArrayArg(From->args(), From->args_size()).value(),
9448-
From->args_size());
9449-
break;
9450-
}
94519423
case attr::LockReturned: {
94529424
const auto *From = cast<LockReturnedAttr>(FromAttr);
94539425
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
@@ -536,29 +536,6 @@ static bool checkLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
536536
return true;
537537
}
538538

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

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

75377494
// Thread safety attributes:
7538-
case ParsedAttr::AT_AssertExclusiveLock:
7539-
handleAssertExclusiveLockAttr(S, D, AL);
7540-
break;
7541-
case ParsedAttr::AT_AssertSharedLock:
7542-
handleAssertSharedLockAttr(S, D, AL);
7543-
break;
75447495
case ParsedAttr::AT_PtGuardedVar:
75457496
handlePtGuardedVarAttr(S, D, AL);
75467497
break;
@@ -7556,18 +7507,12 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
75567507
case ParsedAttr::AT_PtGuardedBy:
75577508
handlePtGuardedByAttr(S, D, AL);
75587509
break;
7559-
case ParsedAttr::AT_ExclusiveTrylockFunction:
7560-
handleExclusiveTrylockFunctionAttr(S, D, AL);
7561-
break;
75627510
case ParsedAttr::AT_LockReturned:
75637511
handleLockReturnedAttr(S, D, AL);
75647512
break;
75657513
case ParsedAttr::AT_LocksExcluded:
75667514
handleLocksExcludedAttr(S, D, AL);
75677515
break;
7568-
case ParsedAttr::AT_SharedTrylockFunction:
7569-
handleSharedTrylockFunctionAttr(S, D, AL);
7570-
break;
75717516
case ParsedAttr::AT_AcquiredBefore:
75727517
handleAcquiredBeforeAttr(S, D, AL);
75737518
break;

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19060,23 +19060,18 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) {
1906019060
Args = llvm::ArrayRef(AA->args_begin(), AA->args_size());
1906119061
else if (const auto *AB = dyn_cast<AcquiredBeforeAttr>(A))
1906219062
Args = llvm::ArrayRef(AB->args_begin(), AB->args_size());
19063-
else if (const auto *ETLF = dyn_cast<ExclusiveTrylockFunctionAttr>(A)) {
19064-
Arg = ETLF->getSuccessValue();
19065-
Args = llvm::ArrayRef(ETLF->args_begin(), ETLF->args_size());
19066-
} else if (const auto *STLF = dyn_cast<SharedTrylockFunctionAttr>(A)) {
19067-
Arg = STLF->getSuccessValue();
19068-
Args = llvm::ArrayRef(STLF->args_begin(), STLF->args_size());
19069-
} else if (const auto *LR = dyn_cast<LockReturnedAttr>(A))
19063+
else if (const auto *LR = dyn_cast<LockReturnedAttr>(A))
1907019064
Arg = LR->getArg();
1907119065
else if (const auto *LE = dyn_cast<LocksExcludedAttr>(A))
1907219066
Args = llvm::ArrayRef(LE->args_begin(), LE->args_size());
1907319067
else if (const auto *RC = dyn_cast<RequiresCapabilityAttr>(A))
1907419068
Args = llvm::ArrayRef(RC->args_begin(), RC->args_size());
1907519069
else if (const auto *AC = dyn_cast<AcquireCapabilityAttr>(A))
1907619070
Args = llvm::ArrayRef(AC->args_begin(), AC->args_size());
19077-
else if (const auto *AC = dyn_cast<TryAcquireCapabilityAttr>(A))
19071+
else if (const auto *AC = dyn_cast<TryAcquireCapabilityAttr>(A)) {
19072+
Arg = AC->getSuccessValue();
1907819073
Args = llvm::ArrayRef(AC->args_begin(), AC->args_size());
19079-
else if (const auto *RC = dyn_cast<ReleaseCapabilityAttr>(A))
19074+
} else if (const auto *RC = dyn_cast<ReleaseCapabilityAttr>(A))
1908019075
Args = llvm::ArrayRef(RC->args_begin(), RC->args_size());
1908119076

1908219077
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)