return QT->isBooleanType() || QT->isIntegerType();
}
+
+// Check to see if the type is a smart pointer of some kind. We assume
+// it's a smart pointer if it defines both operator-> and operator*.
+static bool threadSafetyCheckIsSmartPointer(Sema &S, const QualType QT) {
+ if (const RecordType *RT = QT->getAs<RecordType>()) {
+ DeclContextLookupConstResult Res1 = RT->getDecl()->lookup(
+ S.Context.DeclarationNames.getCXXOperatorName(OO_Star));
+ if (Res1.first == Res1.second)
+ return false;
+
+ DeclContextLookupConstResult Res2 = RT->getDecl()->lookup(
+ S.Context.DeclarationNames.getCXXOperatorName(OO_Arrow));
+ if (Res2.first != Res2.second)
+ return true;
+ }
+ return false;
+}
+
///
/// \brief Check if passed in Decl is a pointer type.
/// Note that this function may produce an error message.
QualType QT = vd->getType();
if (QT->isAnyPointerType())
return true;
+
+ if (threadSafetyCheckIsSmartPointer(S, QT))
+ return true;
+
S.Diag(Attr.getLoc(), diag::warn_thread_attribute_decl_not_pointer)
<< Attr.getName()->getName() << QT;
} else {
namespace PointerToMemberTest {
+// Empty string should be ignored.
+int testEmptyAttribute GUARDED_BY("");
+void testEmptyAttributeFunction() EXCLUSIVE_LOCKS_REQUIRED("");
+
class Graph {
public:
Mu mu_;
}
+
+namespace SmartPointerTest {
+
+template<class T>
+class smart_ptr {
+ public:
+ smart_ptr(T* p) : ptr_(p) { };
+
+ T* operator->() { return ptr_; }
+ T& operator*() { return ptr_; }
+
+ private:
+ T* ptr_;
+};
+
+
+class MyClass {
+public:
+ Mu mu_;
+
+ smart_ptr<int> a PT_GUARDED_BY(mu_);
+};
+
+}
+
+
} // end namespace TestMultiDecl