forked from OSchip/llvm-project
Thread safety analysis: the NO_THREAD_SAFETY_ANALYSIS attribute will now
disable checking of arguments to the function, which is done by -Wthread-safety-reference. llvm-svn: 246806
This commit is contained in:
parent
99d95328d6
commit
445a31cd4b
|
@ -1926,34 +1926,42 @@ void BuildLockset::VisitCallExpr(CallExpr *Exp) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (ExamineArgs) {
|
||||
if (FunctionDecl *FD = Exp->getDirectCallee()) {
|
||||
unsigned Fn = FD->getNumParams();
|
||||
unsigned Cn = Exp->getNumArgs();
|
||||
unsigned Skip = 0;
|
||||
|
||||
unsigned i = 0;
|
||||
if (OperatorFun) {
|
||||
if (isa<CXXMethodDecl>(FD)) {
|
||||
// First arg in operator call is implicit self argument,
|
||||
// and doesn't appear in the FunctionDecl.
|
||||
Skip = 1;
|
||||
Cn--;
|
||||
} else {
|
||||
// Ignore the first argument of operators; it's been checked above.
|
||||
i = 1;
|
||||
// NO_THREAD_SAFETY_ANALYSIS does double duty here. Normally it
|
||||
// only turns off checking within the body of a function, but we also
|
||||
// use it to turn off checking in arguments to the function. This
|
||||
// could result in some false negatives, but the alternative is to
|
||||
// create yet another attribute.
|
||||
//
|
||||
if (!FD->hasAttr<NoThreadSafetyAnalysisAttr>()) {
|
||||
unsigned Fn = FD->getNumParams();
|
||||
unsigned Cn = Exp->getNumArgs();
|
||||
unsigned Skip = 0;
|
||||
|
||||
unsigned i = 0;
|
||||
if (OperatorFun) {
|
||||
if (isa<CXXMethodDecl>(FD)) {
|
||||
// First arg in operator call is implicit self argument,
|
||||
// and doesn't appear in the FunctionDecl.
|
||||
Skip = 1;
|
||||
Cn--;
|
||||
} else {
|
||||
// Ignore the first argument of operators; it's been checked above.
|
||||
i = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ignore default arguments
|
||||
unsigned n = (Fn < Cn) ? Fn : Cn;
|
||||
// Ignore default arguments
|
||||
unsigned n = (Fn < Cn) ? Fn : Cn;
|
||||
|
||||
for (; i < n; ++i) {
|
||||
ParmVarDecl* Pvd = FD->getParamDecl(i);
|
||||
Expr* Arg = Exp->getArg(i+Skip);
|
||||
QualType Qt = Pvd->getType();
|
||||
if (Qt->isReferenceType())
|
||||
checkAccess(Arg, AK_Read, POK_PassByRef);
|
||||
for (; i < n; ++i) {
|
||||
ParmVarDecl* Pvd = FD->getParamDecl(i);
|
||||
Expr* Arg = Exp->getArg(i+Skip);
|
||||
QualType Qt = Pvd->getType();
|
||||
if (Qt->isReferenceType())
|
||||
checkAccess(Arg, AK_Read, POK_PassByRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5091,3 +5091,58 @@ class Foo {
|
|||
|
||||
} // end namespace ScopedAdoptTest
|
||||
|
||||
|
||||
namespace TestReferenceNoThreadSafetyAnalysis {
|
||||
|
||||
#define TS_UNCHECKED_READ(x) ts_unchecked_read(x)
|
||||
|
||||
// Takes a reference to a guarded data member, and returns an unguarded
|
||||
// reference.
|
||||
template <class T>
|
||||
inline const T& ts_unchecked_read(const T& v) NO_THREAD_SAFETY_ANALYSIS {
|
||||
return v;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T& ts_unchecked_read(T& v) NO_THREAD_SAFETY_ANALYSIS {
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
class Foo {
|
||||
public:
|
||||
Foo(): a(0) { }
|
||||
|
||||
int a;
|
||||
};
|
||||
|
||||
|
||||
class Bar {
|
||||
public:
|
||||
Bar() : a(0) { }
|
||||
|
||||
Mutex mu;
|
||||
int a GUARDED_BY(mu);
|
||||
Foo foo GUARDED_BY(mu);
|
||||
};
|
||||
|
||||
|
||||
void test() {
|
||||
Bar bar;
|
||||
const Bar cbar;
|
||||
|
||||
int a = TS_UNCHECKED_READ(bar.a); // nowarn
|
||||
TS_UNCHECKED_READ(bar.a) = 1; // nowarn
|
||||
|
||||
int b = TS_UNCHECKED_READ(bar.foo).a; // nowarn
|
||||
TS_UNCHECKED_READ(bar.foo).a = 1; // nowarn
|
||||
|
||||
int c = TS_UNCHECKED_READ(cbar.a); // nowarn
|
||||
}
|
||||
|
||||
#undef TS_UNCHECKED_READ
|
||||
|
||||
} // end namespace TestReferenceNoThreadSafetyAnalysis
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue