Bug 1201314 - Make most of std:: non-memmovable for static analysis purposes. r=mystor r=ehsan

For simplicity, the exceptions are hard-coded in the plugin: currently
std::pair and std::atomic.
This commit is contained in:
Jed Davis 2015-10-14 18:13:00 +02:00
parent c6d2d4f8dd
commit f377ca14ea
3 changed files with 55 additions and 3 deletions

View File

@ -279,6 +279,8 @@ public:
CustomTypeAnnotation(const char *Spelling, const char *Pretty)
: Spelling(Spelling), Pretty(Pretty){};
virtual ~CustomTypeAnnotation() {}
// Checks if this custom annotation "effectively affects" the given type.
bool hasEffectiveAnnotation(QualType T) {
return directAnnotationReason(T).valid();
@ -299,6 +301,10 @@ public:
private:
bool hasLiteralAnnotation(QualType T) const;
AnnotationReason directAnnotationReason(QualType T);
protected:
// Allow subclasses to apply annotations to external code:
virtual bool hasFakeAnnotation(const TagDecl *D) const { return false; }
};
static CustomTypeAnnotation StackClass =
@ -313,8 +319,32 @@ static CustomTypeAnnotation NonTemporaryClass =
CustomTypeAnnotation("moz_non_temporary_class", "non-temporary");
static CustomTypeAnnotation MustUse =
CustomTypeAnnotation("moz_must_use", "must-use");
static CustomTypeAnnotation NonMemMovable =
CustomTypeAnnotation("moz_non_memmovable", "non-memmove()able");
class MemMoveAnnotation final : public CustomTypeAnnotation {
public:
MemMoveAnnotation()
: CustomTypeAnnotation("moz_non_memmovable", "non-memmove()able") {}
virtual ~MemMoveAnnotation() {}
protected:
bool hasFakeAnnotation(const TagDecl *D) const override {
// Annotate everything in ::std, with a few exceptions; see bug
// 1201314 for discussion.
if (getDeclarationNamespace(D) == "std") {
// This doesn't check that it's really ::std::pair and not
// ::std::something_else::pair, but should be good enough.
StringRef Name = D->getName();
if (Name == "pair" || Name == "atomic" || Name == "__atomic_base") {
return false;
}
return true;
}
return false;
}
};
static MemMoveAnnotation NonMemMovable = MemMoveAnnotation();
class MozChecker : public ASTConsumer, public RecursiveASTVisitor<MozChecker> {
DiagnosticsEngine &Diag;
@ -768,7 +798,7 @@ bool CustomTypeAnnotation::hasLiteralAnnotation(QualType T) const {
#else
if (const CXXRecordDecl *D = T->getAsCXXRecordDecl()) {
#endif
return MozChecker::hasCustomAnnotation(D, Spelling);
return hasFakeAnnotation(D) || MozChecker::hasCustomAnnotation(D, Spelling);
}
return false;
}

View File

@ -0,0 +1,21 @@
#define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type")))
template<class T>
class MOZ_NEEDS_MEMMOVABLE_TYPE Mover { T mForceInst; }; // expected-error-re 4 {{Cannot instantiate 'Mover<{{.*}}>' with non-memmovable template argument '{{.*}}'}}
namespace std {
// In theory defining things in std:: like this invokes undefined
// behavior, but in practice it's good enough for this test case.
template<class C> class basic_string { };
typedef basic_string<char> string;
template<class T, class U> class pair { T mT; U mU; }; // expected-note {{std::pair<bool, std::basic_string<char> >' is a non-memmove()able type because member 'mU' is a non-memmove()able type 'std::basic_string<char>'}}
class arbitrary_name { };
}
class HasString { std::string m; }; // expected-note {{'HasString' is a non-memmove()able type because member 'm' is a non-memmove()able type 'std::string' (aka 'basic_string<char>')}}
static Mover<std::string> bad; // expected-note {{instantiation of 'Mover<std::basic_string<char> >' requested here}}
static Mover<HasString> bad_mem; // expected-note {{instantiation of 'Mover<HasString>' requested here}}
static Mover<std::arbitrary_name> assumed_bad; // expected-note {{instantiation of 'Mover<std::arbitrary_name>' requested here}}
static Mover<std::pair<bool, int>> good;
static Mover<std::pair<bool, std::string>> not_good; // expected-note {{instantiation of 'Mover<std::pair<bool, std::basic_string<char> > >' requested here}}

View File

@ -24,6 +24,7 @@ SOURCES += [
'TestNoExplicitMoveConstructor.cpp',
'TestNonHeapClass.cpp',
'TestNonMemMovable.cpp',
'TestNonMemMovableStd.cpp',
'TestNonTemporaryClass.cpp',
'TestNoRefcountedInsideLambdas.cpp',
'TestRefCountedCopyConstructor.cpp',