diff --git a/build/clang-plugin/clang-plugin.cpp b/build/clang-plugin/clang-plugin.cpp index a5399caa965b..75e4931146a8 100644 --- a/build/clang-plugin/clang-plugin.cpp +++ b/build/clang-plugin/clang-plugin.cpp @@ -64,10 +64,16 @@ private: virtual void run(const MatchFinder::MatchResult &Result); }; + class TrivialCtorDtorChecker : public MatchFinder::MatchCallback { + public: + virtual void run(const MatchFinder::MatchResult &Result); + }; + ScopeChecker stackClassChecker; ScopeChecker globalClassChecker; NonHeapClassChecker nonheapClassChecker; ArithmeticArgChecker arithmeticArgChecker; + TrivialCtorDtorChecker trivialCtorDtorChecker; MatchFinder astMatcher; }; @@ -368,6 +374,12 @@ AST_MATCHER(Decl, noArithmeticExprInArgs) { return MozChecker::hasCustomAnnotation(&Node, "moz_no_arith_expr_in_arg"); } +/// This matcher will match any C++ class that is marked as having a trivial +/// constructor and destructor. +AST_MATCHER(CXXRecordDecl, hasTrivialCtorDtor) { + return MozChecker::hasCustomAnnotation(&Node, "moz_trivial_ctor_dtor"); +} + /// This matcher will match all arithmetic binary operators. AST_MATCHER(BinaryOperator, binaryArithmeticOperator) { BinaryOperatorKind opcode = Node.getOpcode(); @@ -484,6 +496,9 @@ DiagnosticsMatcher::DiagnosticsMatcher() ) )).bind("call"), &arithmeticArgChecker); + + astMatcher.addMatcher(recordDecl(hasTrivialCtorDtor()).bind("node"), + &trivialCtorDtorChecker); } void DiagnosticsMatcher::ScopeChecker::run( @@ -620,6 +635,19 @@ void DiagnosticsMatcher::ArithmeticArgChecker::run( } } +void DiagnosticsMatcher::TrivialCtorDtorChecker::run( + const MatchFinder::MatchResult &Result) { + DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); + unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID( + DiagnosticIDs::Error, "class %0 must have trivial constructors and destructors"); + const CXXRecordDecl *node = Result.Nodes.getNodeAs("node"); + + bool badCtor = !node->hasTrivialDefaultConstructor(); + bool badDtor = !node->hasTrivialDestructor(); + if (badCtor || badDtor) + Diag.Report(node->getLocStart(), errorID) << node; +} + class MozCheckAction : public PluginASTAction { public: ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI, StringRef fileName) override { diff --git a/build/clang-plugin/tests/TestTrivialCtorDtor.cpp b/build/clang-plugin/tests/TestTrivialCtorDtor.cpp new file mode 100644 index 000000000000..81604c190e23 --- /dev/null +++ b/build/clang-plugin/tests/TestTrivialCtorDtor.cpp @@ -0,0 +1,58 @@ +#define MOZ_TRIVIAL_CTOR_DTOR __attribute__((annotate("moz_trivial_ctor_dtor"))) + +struct MOZ_TRIVIAL_CTOR_DTOR EmptyClass{}; + +template +struct MOZ_TRIVIAL_CTOR_DTOR TemplateEmptyClass{}; + +struct MOZ_TRIVIAL_CTOR_DTOR BadUserDefinedCtor { // expected-error {{class 'BadUserDefinedCtor' must have trivial constructors and destructors}} + BadUserDefinedCtor() {} +}; + +struct MOZ_TRIVIAL_CTOR_DTOR BadUserDefinedDtor { // expected-error {{class 'BadUserDefinedDtor' must have trivial constructors and destructors}} + ~BadUserDefinedDtor() {} +}; + +struct MOZ_TRIVIAL_CTOR_DTOR BadVirtualDtor { // expected-error {{class 'BadVirtualDtor' must have trivial constructors and destructors}} + virtual ~BadVirtualDtor() {} +}; + +struct MOZ_TRIVIAL_CTOR_DTOR BadVirtualMember { // expected-error {{class 'BadVirtualMember' must have trivial constructors and destructors}} + virtual void f(); +}; + +void foo(); +struct MOZ_TRIVIAL_CTOR_DTOR BadNonEmptyCtorDtor { // expected-error {{class 'BadNonEmptyCtorDtor' must have trivial constructors and destructors}} + BadNonEmptyCtorDtor() { foo(); } + ~BadNonEmptyCtorDtor() { foo(); } +}; + +struct NonTrivialCtor { + NonTrivialCtor() { foo(); } +}; + +struct NonTrivialDtor { + ~NonTrivialDtor() { foo(); } +}; + +struct VirtualMember { + virtual void f(); +}; + +struct MOZ_TRIVIAL_CTOR_DTOR BadNonTrivialCtorInBase : NonTrivialCtor { // expected-error {{class 'BadNonTrivialCtorInBase' must have trivial constructors and destructors}} +}; + +struct MOZ_TRIVIAL_CTOR_DTOR BadNonTrivialDtorInBase : NonTrivialDtor { // expected-error {{class 'BadNonTrivialDtorInBase' must have trivial constructors and destructors}} +}; + +struct MOZ_TRIVIAL_CTOR_DTOR BadNonTrivialCtorInMember { // expected-error {{class 'BadNonTrivialCtorInMember' must have trivial constructors and destructors}} + NonTrivialCtor m; +}; + +struct MOZ_TRIVIAL_CTOR_DTOR BadNonTrivialDtorInMember { // expected-error {{class 'BadNonTrivialDtorInMember' must have trivial constructors and destructors}} + NonTrivialDtor m; +}; + +struct MOZ_TRIVIAL_CTOR_DTOR BadVirtualMemberInMember { // expected-error {{class 'BadVirtualMemberInMember' must have trivial constructors and destructors}} + VirtualMember m; +}; diff --git a/build/clang-plugin/tests/moz.build b/build/clang-plugin/tests/moz.build index 1e41422c7481..41d8dc0a682c 100644 --- a/build/clang-plugin/tests/moz.build +++ b/build/clang-plugin/tests/moz.build @@ -12,6 +12,7 @@ SOURCES += [ 'TestNoArithmeticExprInArgument.cpp', 'TestNonHeapClass.cpp', 'TestStackClass.cpp', + 'TestTrivialCtorDtor.cpp', ] DISABLE_STL_WRAPPING = True