diff options
Diffstat (limited to 'build/clang-plugin/tests')
50 files changed, 5423 insertions, 0 deletions
diff --git a/build/clang-plugin/tests/Makefile.in b/build/clang-plugin/tests/Makefile.in new file mode 100644 index 0000000000..318c9a0261 --- /dev/null +++ b/build/clang-plugin/tests/Makefile.in @@ -0,0 +1,19 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +include $(topsrcdir)/config/rules.mk + +$(OBJS): $(CLANG_PLUGIN) + +# Because building the objects doesn't actually build anything, create +# a stamp file to avoid re-running the tests unless the test files or +# the plugin changed. And since no objects are created, and not having +# the files around makes the rule always, we create dummy files here too. +tests-ok: $(OBJS) $(CSRCS) $(CPPSRCS) $(CLANG_PLUGIN) + touch $@ $(OBJS) + +target-objects: tests-ok + +# Don't actually build a library, since we don't actually build objects. +$(LIBRARY): EXPAND_LIBS_GEN=true diff --git a/build/clang-plugin/tests/NonParameterTestCases.h b/build/clang-plugin/tests/NonParameterTestCases.h new file mode 100644 index 0000000000..d38a14d944 --- /dev/null +++ b/build/clang-plugin/tests/NonParameterTestCases.h @@ -0,0 +1,61 @@ +MAYBE_STATIC void raw(Param x) {} + +MAYBE_STATIC void raw(NonParam x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void raw(NonParamUnion x) {} //expected-error {{Type 'NonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void raw(NonParamClass x) {} //expected-error {{Type 'NonParamClass' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void raw(NonParamEnum x) {} //expected-error {{Type 'NonParamEnum' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void raw(NonParamEnumClass x) {} //expected-error {{Type 'NonParamEnumClass' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void raw(HasNonParamStruct x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void raw(HasNonParamUnion x) {} //expected-error {{Type 'HasNonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void raw(HasNonParamStructUnion x) {} //expected-error {{Type 'HasNonParamStructUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + +MAYBE_STATIC void const_(const NonParam x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void const_(const NonParamUnion x) {} //expected-error {{Type 'NonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void const_(const NonParamClass x) {} //expected-error {{Type 'NonParamClass' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void const_(const NonParamEnum x) {} //expected-error {{Type 'NonParamEnum' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void const_(const NonParamEnumClass x) {} //expected-error {{Type 'NonParamEnumClass' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void const_(const HasNonParamStruct x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void const_(const HasNonParamUnion x) {} //expected-error {{Type 'HasNonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC void const_(const HasNonParamStructUnion x) {} //expected-error {{Type 'HasNonParamStructUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + +MAYBE_STATIC void array(NonParam x[]) {} +MAYBE_STATIC void array(NonParamUnion x[]) {} +MAYBE_STATIC void array(NonParamClass x[]) {} +MAYBE_STATIC void array(NonParamEnum x[]) {} +MAYBE_STATIC void array(NonParamEnumClass x[]) {} +MAYBE_STATIC void array(HasNonParamStruct x[]) {} +MAYBE_STATIC void array(HasNonParamUnion x[]) {} +MAYBE_STATIC void array(HasNonParamStructUnion x[]) {} + +MAYBE_STATIC void ptr(NonParam* x) {} +MAYBE_STATIC void ptr(NonParamUnion* x) {} +MAYBE_STATIC void ptr(NonParamClass* x) {} +MAYBE_STATIC void ptr(NonParamEnum* x) {} +MAYBE_STATIC void ptr(NonParamEnumClass* x) {} +MAYBE_STATIC void ptr(HasNonParamStruct* x) {} +MAYBE_STATIC void ptr(HasNonParamUnion* x) {} +MAYBE_STATIC void ptr(HasNonParamStructUnion* x) {} + +MAYBE_STATIC void ref(NonParam& x) {} +MAYBE_STATIC void ref(NonParamUnion& x) {} +MAYBE_STATIC void ref(NonParamClass& x) {} +MAYBE_STATIC void ref(NonParamEnum& x) {} +MAYBE_STATIC void ref(NonParamEnumClass& x) {} +MAYBE_STATIC void ref(HasNonParamStruct& x) {} +MAYBE_STATIC void ref(HasNonParamUnion& x) {} +MAYBE_STATIC void ref(HasNonParamStructUnion& x) {} + +MAYBE_STATIC void constRef(const NonParam& x) {} +MAYBE_STATIC void constRef(const NonParamUnion& x) {} +MAYBE_STATIC void constRef(const NonParamClass& x) {} +MAYBE_STATIC void constRef(const NonParamEnum& x) {} +MAYBE_STATIC void constRef(const NonParamEnumClass& x) {} +MAYBE_STATIC void constRef(const HasNonParamStruct& x) {} +MAYBE_STATIC void constRef(const HasNonParamUnion& x) {} +MAYBE_STATIC void constRef(const HasNonParamStructUnion& x) {} + +MAYBE_STATIC inline void inlineRaw(NonParam x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC inline void inlineRaw(NonParamUnion x) {} //expected-error {{Type 'NonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC inline void inlineRaw(NonParamClass x) {} //expected-error {{Type 'NonParamClass' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC inline void inlineRaw(NonParamEnum x) {} //expected-error {{Type 'NonParamEnum' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +MAYBE_STATIC inline void inlineRaw(NonParamEnumClass x) {} //expected-error {{Type 'NonParamEnumClass' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} diff --git a/build/clang-plugin/tests/TestAssertWithAssignment.cpp b/build/clang-plugin/tests/TestAssertWithAssignment.cpp new file mode 100644 index 0000000000..f0f049e4a3 --- /dev/null +++ b/build/clang-plugin/tests/TestAssertWithAssignment.cpp @@ -0,0 +1,68 @@ +#include "mozilla/MacroArgs.h" + +static __attribute__((always_inline)) bool MOZ_AssertAssignmentTest(bool expr) { + return expr; +} + +#define MOZ_UNLIKELY(x) (__builtin_expect(!!(x), 0)) +#define MOZ_CRASH() do { } while(0) +#define MOZ_CHECK_ASSERT_ASSIGNMENT(expr) MOZ_AssertAssignmentTest(!!(expr)) + +#define MOZ_ASSERT_HELPER1(expr) \ + do { \ + if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \ + MOZ_CRASH();\ + } \ + } while(0) \ + +/* Now the two-argument form. */ +#define MOZ_ASSERT_HELPER2(expr, explain) \ + do { \ + if (MOZ_UNLIKELY(!MOZ_CHECK_ASSERT_ASSIGNMENT(expr))) { \ + MOZ_CRASH();\ + } \ + } while(0) \ + +#define MOZ_RELEASE_ASSERT_GLUE(a, b) a b +#define MOZ_RELEASE_ASSERT(...) \ + MOZ_RELEASE_ASSERT_GLUE( \ + MOZ_PASTE_PREFIX_AND_ARG_COUNT(MOZ_ASSERT_HELPER, __VA_ARGS__), \ + (__VA_ARGS__)) + +#define MOZ_ASSERT(...) MOZ_RELEASE_ASSERT(__VA_ARGS__) + +void FunctionTest(int p) { + MOZ_ASSERT(p = 1); // expected-error {{Forbidden assignment in assert expression}} +} + +void FunctionTest2(int p) { + MOZ_ASSERT(((p = 1))); // expected-error {{Forbidden assignment in assert expression}} +} + +void FunctionTest3(int p) { + MOZ_ASSERT(p != 3); +} + +class TestOverloading { + int value; +public: + explicit TestOverloading(int _val) : value(_val) {} + // different operators + explicit operator bool() const { return true; } + TestOverloading& operator=(const int _val) { value = _val; return *this; } + + int& GetInt() {return value;} +}; + +void TestOverloadingFunc() { + TestOverloading p(2); + int f; + + MOZ_ASSERT(p); + MOZ_ASSERT(p = 3); // expected-error {{Forbidden assignment in assert expression}} + MOZ_ASSERT(p, "p is not valid"); + MOZ_ASSERT(p = 3, "p different than 3"); // expected-error {{Forbidden assignment in assert expression}} + MOZ_ASSERT(p.GetInt() = 2); // expected-error {{Forbidden assignment in assert expression}} + MOZ_ASSERT(p.GetInt() == 2); + MOZ_ASSERT(p.GetInt() == 2, f = 3); +} diff --git a/build/clang-plugin/tests/TestBadImplicitConversionCtor.cpp b/build/clang-plugin/tests/TestBadImplicitConversionCtor.cpp new file mode 100644 index 0000000000..ca2472582e --- /dev/null +++ b/build/clang-plugin/tests/TestBadImplicitConversionCtor.cpp @@ -0,0 +1,50 @@ +#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) + +struct Foo { + Foo(int); // expected-error {{bad implicit conversion constructor for 'Foo'}} expected-note {{consider adding the explicit keyword to the constructor}} + Foo(int, char=0); // expected-error {{bad implicit conversion constructor for 'Foo'}} expected-note {{consider adding the explicit keyword to the constructor}} + Foo(...); // expected-error {{bad implicit conversion constructor for 'Foo'}} expected-note {{consider adding the explicit keyword to the constructor}} + template<class T> + Foo(float); // expected-error {{bad implicit conversion constructor for 'Foo'}} expected-note {{consider adding the explicit keyword to the constructor}} + Foo(int, unsigned); + Foo(Foo&); + Foo(const Foo&); + Foo(volatile Foo&); + Foo(const volatile Foo&); + Foo(Foo&&); + Foo(const Foo&&); + Foo(volatile Foo&&); + Foo(const volatile Foo&&); +}; + +struct Bar { + explicit Bar(int); + explicit Bar(int, char=0); + explicit Bar(...); +}; + +struct Baz { + MOZ_IMPLICIT Baz(int); + MOZ_IMPLICIT Baz(int, char=0); + MOZ_IMPLICIT Baz(...); +}; + +struct Barn { + Barn(int) = delete; + Barn(int, char=0) = delete; + Barn(...) = delete; +}; + +struct Abstract { + Abstract(int); + Abstract(int, char=0); + Abstract(...); + virtual void f() = 0; +}; + +template<class T> +struct Template { + Template(int); // expected-error {{bad implicit conversion constructor for 'Template'}} expected-note {{consider adding the explicit keyword to the constructor}} + template<class U> + Template(float); // expected-error {{bad implicit conversion constructor for 'Template'}} expected-note {{consider adding the explicit keyword to the constructor}} +}; diff --git a/build/clang-plugin/tests/TestCanRunScript.cpp b/build/clang-plugin/tests/TestCanRunScript.cpp new file mode 100644 index 0000000000..28795a31bf --- /dev/null +++ b/build/clang-plugin/tests/TestCanRunScript.cpp @@ -0,0 +1,881 @@ +#include <mozilla/RefPtr.h> +#include <mozilla/Maybe.h> + +#define MOZ_CAN_RUN_SCRIPT __attribute__((annotate("moz_can_run_script"))) +#define MOZ_CAN_RUN_SCRIPT_BOUNDARY __attribute__((annotate("moz_can_run_script_boundary"))) + +MOZ_CAN_RUN_SCRIPT void test() { + +} + +void test_parent() { // expected-note {{caller function declared here}} + test(); // expected-error {{functions marked as MOZ_CAN_RUN_SCRIPT can only be called from functions also marked as MOZ_CAN_RUN_SCRIPT}} +} + +MOZ_CAN_RUN_SCRIPT void test_parent2() { + test(); +} + +struct RefCountedBase; +MOZ_CAN_RUN_SCRIPT void test2(RefCountedBase* param) { + +} + +struct RefCountedBase { + void AddRef(); + void Release(); + + MOZ_CAN_RUN_SCRIPT void method_test() { + test(); + } + + MOZ_CAN_RUN_SCRIPT void method_test2() { + test2(this); + } + + virtual void method_test3() { // expected-note {{caller function declared here}} + test(); // expected-error {{functions marked as MOZ_CAN_RUN_SCRIPT can only be called from functions also marked as MOZ_CAN_RUN_SCRIPT}} + } + + MOZ_CAN_RUN_SCRIPT void method_test4() { + method_test(); + } + + MOZ_CAN_RUN_SCRIPT void method_test5() { + this->method_test(); + } +}; + +MOZ_CAN_RUN_SCRIPT void testLambda() { + auto doIt = []() MOZ_CAN_RUN_SCRIPT { + test(); + }; + + auto doItWrong = []() { // expected-note {{caller function declared here}} + test(); // expected-error {{functions marked as MOZ_CAN_RUN_SCRIPT can only be called from functions also marked as MOZ_CAN_RUN_SCRIPT}} + }; + + doIt(); + doItWrong(); +} + +void test2_parent() { // expected-note {{caller function declared here}} + test2(new RefCountedBase); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'new RefCountedBase' is neither.}} \ + // expected-error {{functions marked as MOZ_CAN_RUN_SCRIPT can only be called from functions also marked as MOZ_CAN_RUN_SCRIPT}} +} + +MOZ_CAN_RUN_SCRIPT void test2_parent2() { + test2(new RefCountedBase); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'new RefCountedBase' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test2_parent3(RefCountedBase* param) { + test2(param); + + RefCountedBase*& paramRef = param; + test2(paramRef); +} + +MOZ_CAN_RUN_SCRIPT void test2_parent4() { + RefPtr<RefCountedBase> refptr = new RefCountedBase; + test2(refptr); + RefPtr<RefCountedBase>& refptrRef = refptr; + test2(refptrRef); + const RefPtr<RefCountedBase>& refptrConstRef = refptr; + test2(refptrConstRef); + + RefPtr<RefCountedBase> refptrOther = refptr; + RefPtr<RefCountedBase>& refptrRef2 = refptr ? refptr : refptrOther; + test2(refptrRef2); + + RefPtr<RefCountedBase>* refPtrInHeap = new RefPtr<RefCountedBase>; + RefPtr<RefCountedBase>& refptrRefUnsafe1 = *refPtrInHeap; + test2(refptrRefUnsafe1); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refptrRefUnsafe1' is neither.}} + + RefPtr<RefCountedBase>& refptrRefUnsafe2 = refPtrInHeap ? *refPtrInHeap : refptr; + test2(refptrRefUnsafe2); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refptrRefUnsafe2' is neither.}} + + RefPtr<RefCountedBase>& refptrRefUnsafe3 = refPtrInHeap ? refptr : *refPtrInHeap; + test2(refptrRefUnsafe3); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refptrRefUnsafe3' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test2_parent5() { + test2(MOZ_KnownLive(new RefCountedBase)); +} + +MOZ_CAN_RUN_SCRIPT void test2_parent6() { + RefPtr<RefCountedBase> refptr = new RefCountedBase; + refptr->method_test(); + refptr->method_test2(); + RefPtr<RefCountedBase>& refptrRef = refptr; + refptrRef->method_test(); + refptrRef->method_test2(); + + RefPtr<RefCountedBase> refptrOther = refptr; + RefPtr<RefCountedBase>& refptrRef2 = refptr ? refptr : refptrOther; + refptrRef2->method_test(); + refptrRef2->method_test2(); + + RefPtr<RefCountedBase>* refPtrInHeap = new RefPtr<RefCountedBase>; + RefPtr<RefCountedBase>& refptrRefUnsafe1 = *refPtrInHeap; + refptrRefUnsafe1->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refptrRefUnsafe1->' is neither.}} + refptrRefUnsafe1->method_test2(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refptrRefUnsafe1->' is neither.}} + + RefPtr<RefCountedBase>& refptrRefUnsafe2 = refPtrInHeap ? *refPtrInHeap : refptr; + refptrRefUnsafe2->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refptrRefUnsafe2->' is neither.}} + refptrRefUnsafe2->method_test2(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refptrRefUnsafe2->' is neither.}} + + RefPtr<RefCountedBase>& refptrRefUnsafe3 = refPtrInHeap ? refptr : *refPtrInHeap; + refptrRefUnsafe3->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refptrRefUnsafe3->' is neither.}} + refptrRefUnsafe3->method_test2(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refptrRefUnsafe3->' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test2_parent7() { + RefCountedBase* t = new RefCountedBase; + t->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 't' is neither.}} + t->method_test2(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 't' is neither.}} + + RefCountedBase*& tRef = t; + tRef->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'tRef' is neither.}} + tRef->method_test2(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'tRef' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test2_parent8() { + test2(nullptr); +} + +MOZ_CAN_RUN_SCRIPT void test3(int* param) {} + +MOZ_CAN_RUN_SCRIPT void test3_parent() { + test3(new int); +} + +struct RefCountedChild : public RefCountedBase { + virtual void method_test3() override; // expected-note {{overridden function declared here}} expected-note {{overridden function declared here}} expected-note {{caller function declared here}} +}; + +void RefCountedChild::method_test3() { + test(); // expected-error {{functions marked as MOZ_CAN_RUN_SCRIPT can only be called from functions also marked as MOZ_CAN_RUN_SCRIPT}} +} + +struct RefCountedSubChild : public RefCountedChild { + MOZ_CAN_RUN_SCRIPT void method_test3() override; // expected-error {{functions marked as MOZ_CAN_RUN_SCRIPT cannot override functions that are not marked MOZ_CAN_RUN_SCRIPT}} +}; + +void RefCountedSubChild::method_test3() { // expected-error {{functions marked as MOZ_CAN_RUN_SCRIPT cannot override functions that are not marked MOZ_CAN_RUN_SCRIPT}} + test(); +} + +MOZ_CAN_RUN_SCRIPT void test4() { + RefPtr<RefCountedBase> refptr1 = new RefCountedChild; + refptr1->method_test3(); + + RefPtr<RefCountedBase> refptr2 = new RefCountedSubChild; + refptr2->method_test3(); + + RefPtr<RefCountedChild> refptr3 = new RefCountedSubChild; + refptr3->method_test3(); + + RefPtr<RefCountedSubChild> refptr4 = new RefCountedSubChild; + refptr4->method_test3(); +} + +MOZ_CAN_RUN_SCRIPT_BOUNDARY void test5() { + RefPtr<RefCountedBase> refptr1 = new RefCountedChild; + refptr1->method_test3(); + + RefPtr<RefCountedBase> refptr2 = new RefCountedSubChild; + refptr2->method_test3(); + + RefPtr<RefCountedChild> refptr3 = new RefCountedSubChild; + refptr3->method_test3(); + + RefPtr<RefCountedSubChild> refptr4 = new RefCountedSubChild; + refptr4->method_test3(); +} + +// We should be able to call test5 from a non-can_run_script function. +void test5_b() { + test5(); +} + +MOZ_CAN_RUN_SCRIPT void test6() { + void* x = new RefCountedBase(); + test2((RefCountedBase*)x); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'x' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_ref(const RefCountedBase&) { + +} + +MOZ_CAN_RUN_SCRIPT void test_ref_1() { + RefCountedBase* t = new RefCountedBase; + test_ref(*t); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*t' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_ref_2() { + RefCountedBase* t = new RefCountedBase; + (*t).method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*t' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_ref_3() { + RefCountedBase* t = new RefCountedBase; + auto& ref = *t; + test_ref(ref); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'ref' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_ref_4() { + RefCountedBase* t = new RefCountedBase; + auto& ref = *t; + ref.method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'ref' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_ref_5() { + RefPtr<RefCountedBase> t = new RefCountedBase; + test_ref(*t); +} + +MOZ_CAN_RUN_SCRIPT void test_ref_6() { + RefPtr<RefCountedBase> t = new RefCountedBase; + (*t).method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ref_7() { + RefPtr<RefCountedBase> t = new RefCountedBase; + auto& ref = *t; + MOZ_KnownLive(ref).method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ref_8() { + RefPtr<RefCountedBase> t = new RefCountedBase; + auto& ref = *t; + test_ref(MOZ_KnownLive(ref)); +} + +MOZ_CAN_RUN_SCRIPT void test_ref_9() { + void* x = new RefCountedBase(); + test_ref(*(RefCountedBase*)x); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*(RefCountedBase*)x' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_maybe() { + mozilla::Maybe<RefCountedBase*> unsafe; + unsafe.emplace(new RefCountedBase); + (*unsafe)->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*unsafe' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_maybe_2() { + // FIXME(bz): This should not generate an error! + mozilla::Maybe<RefPtr<RefCountedBase>> safe; + safe.emplace(new RefCountedBase); + (*safe)->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '(*safe){{(->)?}}' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_defaults_helper_1(RefCountedBase* arg = nullptr) { +} + +MOZ_CAN_RUN_SCRIPT void test_defaults_1() { + test_defaults_helper_1(); +} + +MOZ_CAN_RUN_SCRIPT void test_defaults_2() { + RefCountedBase* t = new RefCountedBase; + test_defaults_helper_1(t); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 't' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_defaults_3() { + RefPtr<RefCountedBase> t = new RefCountedBase; + test_defaults_helper_1(t); +} + +MOZ_CAN_RUN_SCRIPT void test_defaults_helper_2(RefCountedBase* arg = new RefCountedBase()) { // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'new RefCountedBase()' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_defaults_4() { + test_defaults_helper_2(); +} + +MOZ_CAN_RUN_SCRIPT void test_defaults_5() { + RefCountedBase* t = new RefCountedBase; + test_defaults_helper_2(t); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 't' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_defaults_6() { + RefPtr<RefCountedBase> t = new RefCountedBase; + test_defaults_helper_2(t); +} + +MOZ_CAN_RUN_SCRIPT void test_arg_deref_helper(RefCountedBase&) { +} + +MOZ_CAN_RUN_SCRIPT void test_arg_deref(RefCountedBase* arg) { + test_arg_deref_helper(*arg); +} + +struct RefCountedDerefTester : public RefCountedBase { + MOZ_CAN_RUN_SCRIPT void foo() { + test_arg_deref_helper(*this); + } +}; + +struct DisallowMemberArgs { + RefPtr<RefCountedBase> mRefCounted; + MOZ_CAN_RUN_SCRIPT void foo() { + mRefCounted->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mRefCounted{{(->)?}}' is neither.}} + + RefPtr<RefCountedBase>& unsafeMemberRef = mRefCounted; + unsafeMemberRef->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'unsafeMemberRef{{(->)?}}' is neither.}} + + RefPtr<RefCountedBase> safeRefCounted = mRefCounted; + RefPtr<RefCountedBase>& maybeUnsafeMemberRef1 = mRefCounted ? mRefCounted : safeRefCounted; + maybeUnsafeMemberRef1->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'maybeUnsafeMemberRef1{{(->)?}}' is neither.}} + RefPtr<RefCountedBase>& maybeUnsafeMemberRef2 = safeRefCounted ? safeRefCounted : mRefCounted; + maybeUnsafeMemberRef2->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'maybeUnsafeMemberRef2{{(->)?}}' is neither.}} + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(mRefCounted); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mRefCounted' is neither.}} + + RefPtr<RefCountedBase>& unsafeMemberRef = mRefCounted; + test2(unsafeMemberRef); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'unsafeMemberRef' is neither.}} + + RefPtr<RefCountedBase> safeRefCounted = mRefCounted; + RefPtr<RefCountedBase>& maybeUnsafeMemberRef1 = mRefCounted ? mRefCounted : safeRefCounted; + test2(maybeUnsafeMemberRef1); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'maybeUnsafeMemberRef1' is neither.}} + RefPtr<RefCountedBase>& maybeUnsafeMemberRef2 = safeRefCounted ? safeRefCounted : mRefCounted; + test2(maybeUnsafeMemberRef2); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'maybeUnsafeMemberRef2' is neither.}} + } +}; + +struct DisallowMemberArgsWithGet { + RefPtr<RefCountedBase> mRefCounted; + MOZ_CAN_RUN_SCRIPT void foo() { + mRefCounted.get()->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mRefCounted.get()' is neither.}} + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(mRefCounted.get()); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mRefCounted.get()' is neither.}} + } +}; + +struct AllowKnownLiveMemberArgs { + RefPtr<RefCountedBase> mRefCounted; + MOZ_CAN_RUN_SCRIPT void foo() { + MOZ_KnownLive(mRefCounted)->method_test(); + + RefPtr<RefCountedBase>& unsafeMemberRef = mRefCounted; + MOZ_KnownLive(unsafeMemberRef)->method_test(); + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(MOZ_KnownLive(mRefCounted)); + + RefPtr<RefCountedBase>& unsafeMemberRef = mRefCounted; + test2(MOZ_KnownLive(unsafeMemberRef)); + } +}; + +struct WeakPtrReturner : public RefCountedBase { + RefCountedBase* getWeakPtr() { return new RefCountedBase(); } +}; + +struct DisallowMemberCallsOnRandomKnownLive { + RefPtr<WeakPtrReturner> mWeakPtrReturner1; + WeakPtrReturner* mWeakPtrReturner2; + + MOZ_CAN_RUN_SCRIPT void test_refptr_method() { + MOZ_KnownLive(mWeakPtrReturner1)->getWeakPtr()->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'MOZ_KnownLive(mWeakPtrReturner1)->getWeakPtr()' is neither.}} + } + + MOZ_CAN_RUN_SCRIPT void test_refptr_function() { + test2(MOZ_KnownLive(mWeakPtrReturner1)->getWeakPtr()); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'MOZ_KnownLive(mWeakPtrReturner1)->getWeakPtr()' is neither.}} + } + + MOZ_CAN_RUN_SCRIPT void test_raw_method() { + MOZ_KnownLive(mWeakPtrReturner2)->getWeakPtr()->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'MOZ_KnownLive(mWeakPtrReturner2)->getWeakPtr()' is neither.}} + } + + MOZ_CAN_RUN_SCRIPT void test_raw_function() { + test2(MOZ_KnownLive(mWeakPtrReturner2)->getWeakPtr()); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'MOZ_KnownLive(mWeakPtrReturner2)->getWeakPtr()' is neither.}} + } +}; + +struct AllowConstMemberArgs { + const RefPtr<RefCountedBase> mRefCounted; + MOZ_CAN_RUN_SCRIPT void foo() { + mRefCounted->method_test(); + + const RefPtr<RefCountedBase>& safeMemberRef1 = mRefCounted; + safeMemberRef1->method_test(); + + const RefPtr<RefCountedBase> safeRefCounted = new RefCountedBase; + const RefPtr<RefCountedBase>& safeMemberRef2 = safeRefCounted ? safeRefCounted : mRefCounted; + safeMemberRef2->method_test(); + const RefPtr<RefCountedBase>& safeMemberRef3 = mRefCounted ? mRefCounted : safeRefCounted; + safeMemberRef3->method_test(); + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(mRefCounted); + + const RefPtr<RefCountedBase>& safeMemberRef1 = mRefCounted; + test2(safeMemberRef1); + + const RefPtr<RefCountedBase> safeRefCounted = new RefCountedBase; + const RefPtr<RefCountedBase>& safeMemberRef2 = safeRefCounted ? safeRefCounted : mRefCounted; + test2(safeMemberRef2); + const RefPtr<RefCountedBase>& safeMemberRef3 = mRefCounted ? mRefCounted : safeRefCounted; + test2(safeMemberRef3); + } +}; + +struct AllowConstMemberArgsWithExplicitThis { + const RefPtr<RefCountedBase> mRefCounted; + MOZ_CAN_RUN_SCRIPT void foo() { + this->mRefCounted->method_test(); + + const RefPtr<RefCountedBase>& safeMemberRef1 = this->mRefCounted; + safeMemberRef1->method_test(); + + const RefPtr<RefCountedBase> safeRefCounted = new RefCountedBase; + const RefPtr<RefCountedBase>& safeMemberRef2 = safeRefCounted ? safeRefCounted : this->mRefCounted; + safeMemberRef2->method_test(); + const RefPtr<RefCountedBase>& safeMemberRef3 = this->mRefCounted ? this->mRefCounted : safeRefCounted; + safeMemberRef3->method_test(); + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(this->mRefCounted); + + const RefPtr<RefCountedBase>& safeMemberRef1 = this->mRefCounted; + test2(safeMemberRef1); + + const RefPtr<RefCountedBase> safeRefCounted = new RefCountedBase; + const RefPtr<RefCountedBase>& safeMemberRef2 = safeRefCounted ? safeRefCounted : this->mRefCounted; + test2(safeMemberRef2); + const RefPtr<RefCountedBase>& safeMemberRef3 = this->mRefCounted ? this->mRefCounted : safeRefCounted; + test2(safeMemberRef3); + } +}; + +struct DisallowConstMemberArgsOfMembers { + RefPtr<AllowConstMemberArgs> mMember; + MOZ_CAN_RUN_SCRIPT void foo() { + mMember->mRefCounted->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mMember->mRefCounted{{(->)?}}' is neither.}} + + const RefPtr<RefCountedBase>& unsafeMemberRef = mMember->mRefCounted; + unsafeMemberRef->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'unsafeMemberRef{{(->)?}}' is neither.}} + + const RefPtr<RefCountedBase> safeRefCounted = new RefCountedBase; + const RefPtr<RefCountedBase>& maybeUnsafeMemberRef1 = safeRefCounted ? safeRefCounted : mMember->mRefCounted; + maybeUnsafeMemberRef1->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'maybeUnsafeMemberRef1{{(->)?}}' is neither.}} + const RefPtr<RefCountedBase>& maybeUnsafeMemberRef2 = mMember->mRefCounted ? mMember->mRefCounted : safeRefCounted; + maybeUnsafeMemberRef2->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'maybeUnsafeMemberRef2{{(->)?}}' is neither.}} + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(mMember->mRefCounted); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mMember->mRefCounted' is neither.}} + + const RefPtr<RefCountedBase>& unsafeMemberRef = mMember->mRefCounted; + test2(unsafeMemberRef); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'unsafeMemberRef' is neither.}} + + const RefPtr<RefCountedBase> safeRefCounted = new RefCountedBase; + const RefPtr<RefCountedBase>& maybeUnsafeMemberRef1 = safeRefCounted ? safeRefCounted : mMember->mRefCounted; + test2(maybeUnsafeMemberRef1); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'maybeUnsafeMemberRef1' is neither.}} + const RefPtr<RefCountedBase>& maybeUnsafeMemberRef2 = mMember->mRefCounted ? mMember->mRefCounted : safeRefCounted; + test2(maybeUnsafeMemberRef2); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'maybeUnsafeMemberRef2' is neither.}} + } +}; + +struct DisallowConstNonRefPtrMemberArgs { + RefCountedBase* const mRefCounted; + MOZ_CAN_RUN_SCRIPT void foo() { + mRefCounted->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mRefCounted' is neither.}} + + RefCountedBase* const& unsafeMemberRefCounted = mRefCounted; + unsafeMemberRefCounted->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'unsafeMemberRefCounted' is neither.}} + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(mRefCounted); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mRefCounted' is neither.}} + + RefCountedBase* const& unsafeMemberRefCounted = mRefCounted; + test2(unsafeMemberRefCounted); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'unsafeMemberRefCounted' is neither.}} + } +}; + +MOZ_CAN_RUN_SCRIPT void test_temporary_1() { +#ifdef MOZ_CLANG_PLUGIN_ALPHA + RefPtr<RefCountedBase>(new RefCountedBase())->method_test(); // expected-warning {{performance issue: temporary 'RefPtr<RefCountedBase>' is only dereferenced here once which involves short-lived AddRef/Release calls}} +#else + RefPtr<RefCountedBase>(new RefCountedBase())->method_test(); +#endif +} + +MOZ_CAN_RUN_SCRIPT void test_temporary_2() { + test_ref(*RefPtr<RefCountedBase>(new RefCountedBase())); +} + +struct WeakSmartPtr { + RefCountedBase* member; + + explicit WeakSmartPtr(RefCountedBase* arg) : member(arg) {} + + RefCountedBase* operator->() const { + return member; + } + + RefCountedBase& operator*() const { + return *member; + } + + operator RefCountedBase*() const { + return member; + } +}; + +MOZ_CAN_RUN_SCRIPT void test_temporary_3() { + WeakSmartPtr(new RefCountedBase())->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'WeakSmartPtr(new RefCountedBase()){{(->)?}}' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_temporary_4() { + test_ref(*WeakSmartPtr(new RefCountedBase())); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*WeakSmartPtr(new RefCountedBase())' is neither.}} +} + +MOZ_CAN_RUN_SCRIPT void test_temporary_5() { + test2(WeakSmartPtr(new RefCountedBase())); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'WeakSmartPtr(new RefCountedBase())' is neither.}} +} + + +template<typename T> +struct TArray { + TArray() { + mArray[0] = new RefCountedBase(); + } + T& operator[](unsigned int index) { return mArray[index]; } + T mArray[1]; +}; + +struct DisallowRawTArrayElement { + TArray<RefCountedBase*> mArray; + MOZ_CAN_RUN_SCRIPT void foo() { + mArray[0]->method_test(); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mArray[0]' is neither.}} + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(mArray[0]); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mArray[0]' is neither.}} + } +}; + +struct DisallowRefPtrTArrayElement { + TArray<RefPtr<RefCountedBase>> mArray; + MOZ_CAN_RUN_SCRIPT void foo() { + mArray[0]->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mArray[0]{{(->)?}}' is neither.}} + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(mArray[0]); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mArray[0]' is neither.}} + } +}; + +struct AllowConstexprMembers { + static constexpr RefCountedBase* mRefCounted = nullptr; + static constexpr RefCountedBase* mRefCounted2 = nullptr; + MOZ_CAN_RUN_SCRIPT void foo() { + mRefCounted->method_test(); + } + MOZ_CAN_RUN_SCRIPT void bar() { + test2(mRefCounted); + } + MOZ_CAN_RUN_SCRIPT void baz() { + test_ref(*mRefCounted); + } +}; + +MOZ_CAN_RUN_SCRIPT void test_constexpr_1() { + AllowConstexprMembers::mRefCounted->method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_constexpr_2() { + test2(AllowConstexprMembers::mRefCounted); +} + +MOZ_CAN_RUN_SCRIPT void test_constexpr_3() { + test_ref(*AllowConstexprMembers::mRefCounted); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_1(RefCountedBase* arg1, RefCountedBase* arg2) { + (arg1 ? arg1 : arg2)->method_test(); + RefCountedBase*& safeArg = arg1 ? arg1 : arg2; + safeArg->method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_2(RefCountedBase* arg1, RefCountedBase* arg2) { + test2(arg1 ? arg1 : arg2); + RefCountedBase*& safeArg = arg1 ? arg1 : arg2; + test2(safeArg); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_3(RefCountedBase* arg1, RefCountedBase& arg2) { + (arg1 ? *arg1 : arg2).method_test(); + RefCountedBase& safeArg = arg1 ? *arg1 : arg2; + safeArg.method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_4(RefCountedBase* arg1, RefCountedBase& arg2) { + test_ref(arg1 ? *arg1 : arg2); + RefCountedBase& safeArg = arg1 ? *arg1 : arg2; + test_ref(safeArg); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_5(RefCountedBase* arg) { + RefPtr<RefCountedBase> local = new RefCountedBase(); + (arg ? arg : local.get())->method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_6(RefCountedBase* arg) { + RefPtr<RefCountedBase> local = new RefCountedBase(); + test2(arg ? arg : local.get()); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_7(RefCountedBase* arg) { + RefPtr<RefCountedBase> local = new RefCountedBase(); + (arg ? *arg : *local).method_test(); + RefCountedBase& safeArgOrLocal = arg ? *arg : *local; + safeArgOrLocal.method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_8(RefCountedBase* arg) { + RefPtr<RefCountedBase> local = new RefCountedBase(); + test_ref(arg ? *arg : *local); + RefCountedBase& safeArgOrLocal = arg ? *arg : *local; + test_ref(safeArgOrLocal); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_9(RefCountedBase* arg) { + (arg ? arg : AllowConstexprMembers::mRefCounted)->method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_10(RefCountedBase* arg) { + test2(arg ? arg : AllowConstexprMembers::mRefCounted); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_11(RefCountedBase* arg) { + (arg ? *arg : *AllowConstexprMembers::mRefCounted).method_test(); + RefCountedBase& safeArgOrMember = arg ? *arg : *AllowConstexprMembers::mRefCounted; + safeArgOrMember.method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_12(RefCountedBase* arg) { + test_ref(arg ? *arg : *AllowConstexprMembers::mRefCounted); + RefCountedBase& safeArgOrMember = arg ? *arg : *AllowConstexprMembers::mRefCounted; + test_ref(safeArgOrMember); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_13(RefCountedBase* arg1, RefCountedBase& arg2) { + (arg1 ? arg1 : &arg2)->method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_44(RefCountedBase* arg1, RefCountedBase& arg2) { + test2(arg1 ? arg1 : &arg2); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_13(bool arg) { + (arg ? + AllowConstexprMembers::mRefCounted : + AllowConstexprMembers::mRefCounted2)->method_test(); + RefCountedBase* const& safeConstexprMember = arg ? AllowConstexprMembers::mRefCounted : AllowConstexprMembers::mRefCounted2; + safeConstexprMember->method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_14(bool arg) { + test2(arg ? + AllowConstexprMembers::mRefCounted : + AllowConstexprMembers::mRefCounted2); + RefCountedBase* const& safeConstexprMember = arg ? AllowConstexprMembers::mRefCounted : AllowConstexprMembers::mRefCounted2; + test2(safeConstexprMember); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_15(bool arg) { + (arg ? + *AllowConstexprMembers::mRefCounted : + *AllowConstexprMembers::mRefCounted2).method_test(); + RefCountedBase& safeConstexprMember = arg ? *AllowConstexprMembers::mRefCounted : *AllowConstexprMembers::mRefCounted2; + safeConstexprMember.method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_ternary_16(bool arg) { + test_ref(arg ? + *AllowConstexprMembers::mRefCounted : + *AllowConstexprMembers::mRefCounted2); + RefCountedBase& safeConstexprMember = arg ? *AllowConstexprMembers::mRefCounted : *AllowConstexprMembers::mRefCounted2; + test_ref(safeConstexprMember); +} + +MOZ_CAN_RUN_SCRIPT void test_pointer_to_ref_1(RefCountedBase& arg) { + (&arg)->method_test(); +} + +MOZ_CAN_RUN_SCRIPT void test_pointer_to_ref_2(RefCountedBase& arg) { + test2(&arg); +} + +struct DisallowMemberArgsViaReferenceAlias { + RefPtr<RefCountedBase> mRefCounted; + MOZ_CAN_RUN_SCRIPT void foo() { + RefPtr<RefCountedBase>& bogus = mRefCounted; + bogus->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'bogus{{(->)?}}' is neither.}} + } + MOZ_CAN_RUN_SCRIPT void bar() { + RefPtr<RefCountedBase>& bogus = mRefCounted; + test2(bogus); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'bogus' is neither.}} + } +}; + +struct DisallowMemberArgsViaReferenceAlias2 { + RefPtr<RefCountedBase> mRefCountedArr[2]; + MOZ_CAN_RUN_SCRIPT void foo1() { + for (RefPtr<RefCountedBase>& item : mRefCountedArr) { + item->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'item{{(->)?}}' is neither.}} + } + } + MOZ_CAN_RUN_SCRIPT void foo2() { + for (auto& item : mRefCountedArr) { + item->method_test(); // expected-error-re {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'item{{(->)?}}' is neither.}} + } + } + MOZ_CAN_RUN_SCRIPT void foo3() { + for (RefPtr<RefCountedBase> item : mRefCountedArr) { + item->method_test(); + } + } + MOZ_CAN_RUN_SCRIPT void foo4() { + for (auto item : mRefCountedArr) { + item->method_test(); + } + } + MOZ_CAN_RUN_SCRIPT void bar1() { + for (RefPtr<RefCountedBase>& item : mRefCountedArr) { + test2(item); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'item' is neither.}} + } + } + MOZ_CAN_RUN_SCRIPT void bar2() { + for (auto& item : mRefCountedArr) { + test2(item); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'item' is neither.}} + } + } + MOZ_CAN_RUN_SCRIPT void bar3() { + for (RefPtr<RefCountedBase> item : mRefCountedArr) { + test2(item); + } + } + MOZ_CAN_RUN_SCRIPT void bar4() { + for (auto item : mRefCountedArr) { + test2(item); + } + } +}; + +struct AllowMozKnownLiveMember { +public: + MOZ_KNOWN_LIVE RefCountedBase* mWhatever; + MOZ_KNOWN_LIVE RefPtr<RefCountedBase> mRefCountedWhatever; + MOZ_CAN_RUN_SCRIPT void fooPtr(RefCountedBase* aWhatever) {} + MOZ_CAN_RUN_SCRIPT void fooRef(RefCountedBase& aWhatever) {} + MOZ_CAN_RUN_SCRIPT void bar() { + fooPtr(mWhatever); + fooRef(*mWhatever); + fooPtr(mRefCountedWhatever); + fooRef(*mRefCountedWhatever); + + RefCountedBase*& whateverRef = mWhatever; + fooPtr(whateverRef); + fooRef(*whateverRef); + RefPtr<RefCountedBase>& refCountedWhateverRef = mRefCountedWhatever; + fooPtr(refCountedWhateverRef); + fooRef(*refCountedWhateverRef); + } +}; + +struct AllowMozKnownLiveMemberParent : AllowMozKnownLiveMember { + MOZ_CAN_RUN_SCRIPT void baz() { + fooPtr(mWhatever); + fooRef(*mWhatever); + fooPtr(mRefCountedWhatever); + fooRef(*mRefCountedWhatever); + + RefCountedBase*& whateverRef = mWhatever; + fooPtr(whateverRef); + fooRef(*whateverRef); + RefPtr<RefCountedBase>& refCountedWhateverRef = mRefCountedWhatever; + fooPtr(refCountedWhateverRef); + fooRef(*refCountedWhateverRef); + } +}; + +struct AllowMozKnownLiveParamMember { +public: + MOZ_CAN_RUN_SCRIPT void foo(AllowMozKnownLiveMember& aAllow) { + aAllow.fooPtr(aAllow.mWhatever); + aAllow.fooRef(*aAllow.mWhatever); + aAllow.fooPtr(aAllow.mRefCountedWhatever); + aAllow.fooRef(*aAllow.mRefCountedWhatever); + + RefCountedBase*& whateverRef = aAllow.mWhatever; + aAllow.fooPtr(whateverRef); + aAllow.fooRef(*whateverRef); + RefPtr<RefCountedBase>& refCountedWhateverRef = aAllow.mRefCountedWhatever; + aAllow.fooPtr(refCountedWhateverRef); + aAllow.fooRef(*refCountedWhateverRef); + } + MOZ_CAN_RUN_SCRIPT void bar(AllowMozKnownLiveMemberParent& aAllowParent) { + aAllowParent.fooPtr(aAllowParent.mWhatever); + aAllowParent.fooRef(*aAllowParent.mWhatever); + aAllowParent.fooPtr(aAllowParent.mRefCountedWhatever); + aAllowParent.fooRef(*aAllowParent.mRefCountedWhatever); + + RefCountedBase*& whateverRef = aAllowParent.mWhatever; + aAllowParent.fooPtr(whateverRef); + aAllowParent.fooRef(*whateverRef); + RefPtr<RefCountedBase>& refCountedWhateverRef = aAllowParent.mRefCountedWhatever; + aAllowParent.fooPtr(refCountedWhateverRef); + aAllowParent.fooRef(*refCountedWhateverRef); + } +}; + +MOZ_CAN_RUN_SCRIPT void AllowMozKnownLiveMemberInAutoStorage() { + AllowMozKnownLiveMember inStack; + AllowMozKnownLiveMember* inHeap = new AllowMozKnownLiveMember(); + inStack.fooPtr(inStack.mWhatever); + inStack.fooRef(*inStack.mWhatever); + inStack.fooPtr(inStack.mRefCountedWhatever); + inStack.fooRef(*inStack.mRefCountedWhatever); + RefCountedBase*& whateverRefInStack = inStack.mWhatever; + inStack.fooPtr(whateverRefInStack); + inStack.fooRef(*whateverRefInStack); + RefPtr<RefCountedBase>& refCountedWhateverRefInStack = inStack.mRefCountedWhatever; + inStack.fooPtr(refCountedWhateverRefInStack); + inStack.fooRef(*refCountedWhateverRefInStack); + + inStack.fooPtr(inHeap->mWhatever); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'inHeap->mWhatever' is neither.}} + inStack.fooRef(*inHeap->mWhatever); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*inHeap->mWhatever' is neither.}} + inStack.fooPtr(inHeap->mRefCountedWhatever); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'inHeap->mRefCountedWhatever' is neither.}} + inStack.fooRef(*inHeap->mRefCountedWhatever); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*inHeap->mRefCountedWhatever' is neither.}} + RefCountedBase*& whateverRefInHeap = inHeap->mWhatever; + inStack.fooPtr(whateverRefInHeap); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'whateverRefInHeap' is neither.}} + inStack.fooRef(*whateverRefInHeap); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*whateverRefInHeap' is neither.}} + RefPtr<RefCountedBase>& refCountedWhateverRefInHeap = inHeap->mRefCountedWhatever; + inStack.fooPtr(refCountedWhateverRefInHeap); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refCountedWhateverRefInHeap' is neither.}} + inStack.fooRef(*refCountedWhateverRefInHeap); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*refCountedWhateverRefInHeap' is neither.}} +} + +struct DisallowMozKnownLiveMemberNotFromKnownLive { + AllowMozKnownLiveMember* mMember; + MOZ_CAN_RUN_SCRIPT void fooPtr(RefCountedBase* aWhatever) {} + MOZ_CAN_RUN_SCRIPT void fooRef(RefCountedBase& aWhatever) {} + MOZ_CAN_RUN_SCRIPT void bar() { + fooPtr(mMember->mWhatever); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mMember->mWhatever' is neither.}} + fooRef(*mMember->mWhatever); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*mMember->mWhatever' is neither.}} + fooPtr(mMember->mRefCountedWhatever); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'mMember->mRefCountedWhatever' is neither.}} + fooRef(*mMember->mRefCountedWhatever); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*mMember->mRefCountedWhatever' is neither.}} + RefCountedBase*& whateverRef = mMember->mWhatever; + fooPtr(whateverRef); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'whateverRef' is neither.}} + fooRef(*whateverRef); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*whateverRef' is neither.}} + RefPtr<RefCountedBase>& refCountedWhateverRef = mMember->mRefCountedWhatever; + fooPtr(refCountedWhateverRef); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). 'refCountedWhateverRef' is neither.}} + fooRef(*refCountedWhateverRef); // expected-error {{arguments must all be strong refs or caller's parameters when calling a function marked as MOZ_CAN_RUN_SCRIPT (including the implicit object argument). '*refCountedWhateverRef' is neither.}} + } +}; + +void IncorrectlyUnmarkedEarlyDeclaration(); // expected-note {{The first declaration exists here}} + +MOZ_CAN_RUN_SCRIPT void IncorrectlyUnmarkedEarlyDeclaration() {}; // expected-error {{MOZ_CAN_RUN_SCRIPT must be put in front of the declaration, not the definition}} diff --git a/build/clang-plugin/tests/TestCustomHeap.cpp b/build/clang-plugin/tests/TestCustomHeap.cpp new file mode 100644 index 0000000000..c1e82f2fa7 --- /dev/null +++ b/build/clang-plugin/tests/TestCustomHeap.cpp @@ -0,0 +1,29 @@ +#define MOZ_NONHEAP_CLASS __attribute__((annotate("moz_nonheap_class"))) +#ifndef MOZ_HEAP_ALLOCATOR +#define MOZ_HEAP_ALLOCATOR \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((annotate("moz_heap_allocator"))) \ + _Pragma("GCC diagnostic pop") +#endif + +#include <stdlib.h> +#include <memory> + +struct MOZ_NONHEAP_CLASS X { +}; + +void *operator new(size_t x, int qual) MOZ_HEAP_ALLOCATOR { + return ::operator new(x); +} + +template <typename T> +T *customAlloc() MOZ_HEAP_ALLOCATOR { + T *arg = static_cast<T*>(malloc(sizeof(T))); + return new (arg) T(); +} + +void misuseX() { + X *foo = customAlloc<X>(); // expected-error {{variable of type 'X' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} + X *foo2 = new (100) X(); // expected-error {{variable of type 'X' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} +} diff --git a/build/clang-plugin/tests/TestDanglingOnTemporary.cpp b/build/clang-plugin/tests/TestDanglingOnTemporary.cpp new file mode 100644 index 0000000000..62a7755ece --- /dev/null +++ b/build/clang-plugin/tests/TestDanglingOnTemporary.cpp @@ -0,0 +1,45 @@ +#define MOZ_NO_DANGLING_ON_TEMPORARIES \ + __attribute__((annotate("moz_no_dangling_on_temporaries"))) + +class AnnotateConflict { + MOZ_NO_DANGLING_ON_TEMPORARIES int *get() && { return nullptr; } // expected-error {{methods annotated with MOZ_NO_DANGLING_ON_TEMPORARIES cannot be && ref-qualified}} + MOZ_NO_DANGLING_ON_TEMPORARIES int test() { return 0; } // expected-error {{methods annotated with MOZ_NO_DANGLING_ON_TEMPORARIES must return a pointer}} +}; + +class NS_ConvertUTF8toUTF16 { +public: + MOZ_NO_DANGLING_ON_TEMPORARIES int *get() { return nullptr; } + operator int*() + { + return get(); // This should be ignored because the call is implcitly on this + } +}; + +NS_ConvertUTF8toUTF16 TemporaryFunction() { return NS_ConvertUTF8toUTF16(); } + +void UndefinedFunction(int* test); + +void NoEscapeFunction(int *test) {} + +int *glob; // expected-note {{through the variable declared here}} +void EscapeFunction1(int *test) { glob = test; } // expected-note {{the raw pointer escapes the function scope here}} + +void EscapeFunction2(int *test, int *&escape) { escape = test; } // expected-note {{the raw pointer escapes the function scope here}} \ + expected-note {{through the parameter declared here}} + +int *EscapeFunction3(int *test) { return test; } // expected-note {{the raw pointer escapes the function scope here}} \ + expected-note {{through the return value of the function declared here}} + +int main() { + int *test = TemporaryFunction().get(); // expected-error {{calling `get` on a temporary, potentially allowing use after free of the raw pointer}} + int *test2 = NS_ConvertUTF8toUTF16().get(); // expected-error {{calling `get` on a temporary, potentially allowing use after free of the raw pointer}} + + UndefinedFunction(NS_ConvertUTF8toUTF16().get()); + + NoEscapeFunction(TemporaryFunction().get()); + EscapeFunction1(TemporaryFunction().get()); // expected-error {{calling `get` on a temporary, potentially allowing use after free of the raw pointer}} + + int *escape; + EscapeFunction2(TemporaryFunction().get(), escape); // expected-error {{calling `get` on a temporary, potentially allowing use after free of the raw pointer}} + int *escape2 = EscapeFunction3(TemporaryFunction().get()); // expected-error {{calling `get` on a temporary, potentially allowing use after free of the raw pointer}} +} diff --git a/build/clang-plugin/tests/TestExplicitOperatorBool.cpp b/build/clang-plugin/tests/TestExplicitOperatorBool.cpp new file mode 100644 index 0000000000..bc4b43a7d0 --- /dev/null +++ b/build/clang-plugin/tests/TestExplicitOperatorBool.cpp @@ -0,0 +1,11 @@ +#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) + +struct Bad { + operator bool(); // expected-error {{bad implicit conversion operator for 'Bad'}} expected-note {{consider adding the explicit keyword to 'operator bool'}} +}; +struct Good { + explicit operator bool(); +}; +struct Okay { + MOZ_IMPLICIT operator bool(); +}; diff --git a/build/clang-plugin/tests/TestFopenUsage.cpp b/build/clang-plugin/tests/TestFopenUsage.cpp new file mode 100644 index 0000000000..19a89f88c9 --- /dev/null +++ b/build/clang-plugin/tests/TestFopenUsage.cpp @@ -0,0 +1,50 @@ +#include <stdio.h> +#include <io.h> +#include <fcntl.h> +#include <fstream> +#include <windows.h> + +void func_fopen() { + FILE *f1 = fopen("dummy.txt", "rt"); // expected-warning {{Usage of ASCII file functions (here fopen) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + FILE *f2; + fopen_s(&f2, "dummy.txt", "rt"); // expected-warning {{Usage of ASCII file functions (here fopen_s) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + + int fh1 = _open("dummy.txt", _O_RDONLY); // expected-warning {{Usage of ASCII file functions (here _open) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + int fh2 = open("dummy.txt", _O_RDONLY); // expected-warning {{Usage of ASCII file functions (here open) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + int fh3 = _sopen("dummy.txt", _O_RDONLY, _SH_DENYRW); // expected-warning {{Usage of ASCII file functions (here _sopen) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + int fd4; + errno_t err = _sopen_s(&fd4, "dummy.txt", _O_RDONLY, _SH_DENYRW, 0); // expected-warning {{Usage of ASCII file functions (here _sopen_s) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + + std::fstream fs1; + fs1.open("dummy.txt"); // expected-warning {{Usage of ASCII file functions (here open) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + std::ifstream ifs1; + ifs1.open("dummy.txt"); // expected-warning {{Usage of ASCII file functions (here open) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + std::ofstream ofs1; + ofs1.open("dummy.txt"); // expected-warning {{Usage of ASCII file functions (here open) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} +#ifdef _MSC_VER + std::fstream fs2; + fs2.open(L"dummy.txt"); + std::ifstream ifs2; + ifs2.open(L"dummy.txt"); + std::ofstream ofs2; + ofs2.open(L"dummy.txt"); +#endif + + LPOFSTRUCT buffer; + HFILE hFile1 = OpenFile("dummy.txt", buffer, OF_READ); // expected-warning {{Usage of ASCII file functions (here OpenFile) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + +#ifndef UNICODE + // CreateFile is just an alias of CreateFileA + LPCSTR buffer2; + HANDLE hFile2 = CreateFile(buffer2, GENERIC_WRITE, 0, NULL, CREATE_NEW, // expected-warning {{Usage of ASCII file functions (here CreateFileA) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + FILE_ATTRIBUTE_NORMAL, NULL); +#else + // CreateFile is just an alias of CreateFileW and should not be matched + LPCWSTR buffer2; + HANDLE hFile2 = CreateFile(buffer2, GENERIC_WRITE, 0, NULL, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, NULL); +#endif + LPCSTR buffer3; + HANDLE hFile3 = CreateFileA(buffer3, GENERIC_WRITE, 0, NULL, CREATE_NEW, // expected-warning {{Usage of ASCII file functions (here CreateFileA) is forbidden on Windows.}} expected-note {{On Windows executed functions: fopen, fopen_s, open, _open, _sopen, _sopen_s, OpenFile, CreateFileA should never be used due to lossy conversion from UTF8 to ANSI.}} + FILE_ATTRIBUTE_NORMAL, NULL); +} diff --git a/build/clang-plugin/tests/TestGlobalClass.cpp b/build/clang-plugin/tests/TestGlobalClass.cpp new file mode 100644 index 0000000000..7ce9c8d463 --- /dev/null +++ b/build/clang-plugin/tests/TestGlobalClass.cpp @@ -0,0 +1,52 @@ +#define MOZ_GLOBAL_CLASS __attribute__((annotate("moz_global_class"))) +#include <stddef.h> + +struct MOZ_GLOBAL_CLASS Global { + int i; + void *operator new(size_t x) throw() { return 0; } + void *operator new(size_t blah, char *buffer) { return buffer; } +}; + +template <class T> +struct MOZ_GLOBAL_CLASS TemplateClass { + T i; +}; + +void gobble(void *) { } + +void misuseGlobalClass(int len) { + Global notValid; // expected-error {{variable of type 'Global' only valid as global}} expected-note {{value incorrectly allocated in an automatic variable}} + Global alsoNotValid[2]; // expected-error-re {{variable of type 'Global{{ ?}}[2]' only valid as global}} expected-note-re {{'Global{{ ?}}[2]' is a global type because it is an array of global type 'Global'}} expected-note {{value incorrectly allocated in an automatic variable}} + static Global valid; + static Global alsoValid[2]; + + gobble(¬Valid); + gobble(&valid); + gobble(&alsoValid[0]); + + gobble(new Global); // expected-error {{variable of type 'Global' only valid as global}} expected-note {{value incorrectly allocated on the heap}} + gobble(new Global[10]); // expected-error {{variable of type 'Global' only valid as global}} expected-note {{value incorrectly allocated on the heap}} + gobble(new TemplateClass<int>); // expected-error {{variable of type 'TemplateClass<int>' only valid as global}} expected-note {{value incorrectly allocated on the heap}} + gobble(len <= 5 ? &valid : new Global); // expected-error {{variable of type 'Global' only valid as global}} expected-note {{value incorrectly allocated on the heap}} + + char buffer[sizeof(Global)]; + gobble(new (buffer) Global); +} + +Global valid; +struct RandomClass { + Global nonstaticMember; // expected-note {{'RandomClass' is a global type because member 'nonstaticMember' is a global type 'Global'}} + static Global staticMember; +}; +struct MOZ_GLOBAL_CLASS RandomGlobalClass { + Global nonstaticMember; + static Global staticMember; +}; + +struct BadInherit : Global {}; // expected-note {{'BadInherit' is a global type because it inherits from a global type 'Global'}} +struct MOZ_GLOBAL_CLASS GoodInherit : Global {}; + +void misuseGlobalClassEvenMore(int len) { + BadInherit moreInvalid; // expected-error {{variable of type 'BadInherit' only valid as global}} expected-note {{value incorrectly allocated in an automatic variable}} + RandomClass evenMoreInvalid; // expected-error {{variable of type 'RandomClass' only valid as global}} expected-note {{value incorrectly allocated in an automatic variable}} +} diff --git a/build/clang-plugin/tests/TestHeapClass.cpp b/build/clang-plugin/tests/TestHeapClass.cpp new file mode 100644 index 0000000000..0cdd939250 --- /dev/null +++ b/build/clang-plugin/tests/TestHeapClass.cpp @@ -0,0 +1,64 @@ +#define MOZ_HEAP_CLASS __attribute__((annotate("moz_heap_class"))) +#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) + +#include <stddef.h> + +struct MOZ_HEAP_CLASS Heap { + int i; + Heap() {} + MOZ_IMPLICIT Heap(int a) {} + Heap(int a, int b) {} + void *operator new(size_t x) throw() { return 0; } + void *operator new(size_t blah, char *buffer) { return buffer; } +}; + +template <class T> +struct MOZ_HEAP_CLASS TemplateClass { + T i; +}; + +void gobble(void *) { } + +void gobbleref(const Heap&) { } + +void misuseHeapClass(int len) { + Heap invalid; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}} + Heap alsoInvalid[2]; // expected-error-re {{variable of type 'Heap{{ ?}}[2]' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}} expected-note-re {{'Heap{{ ?}}[2]' is a heap type because it is an array of heap type 'Heap'}} + static Heap invalidStatic; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}} + static Heap alsoInvalidStatic[2]; // expected-error-re {{variable of type 'Heap{{ ?}}[2]' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}} expected-note-re {{'Heap{{ ?}}[2]' is a heap type because it is an array of heap type 'Heap'}} + + gobble(&invalid); + gobble(&invalidStatic); + gobble(&alsoInvalid[0]); + + gobbleref(Heap()); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}} + gobbleref(Heap(10, 20)); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}} + gobbleref(Heap(10)); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}} + gobbleref(10); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}} + + gobble(new Heap); + gobble(new Heap[10]); + gobble(new TemplateClass<int>); + gobble(len <= 5 ? &invalid : new Heap); + + char buffer[sizeof(Heap)]; + gobble(new (buffer) Heap); +} + +Heap invalidStatic; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}} +struct RandomClass { + Heap nonstaticMember; // expected-note {{'RandomClass' is a heap type because member 'nonstaticMember' is a heap type 'Heap'}} + static Heap staticMember; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}} +}; +struct MOZ_HEAP_CLASS RandomHeapClass { + Heap nonstaticMember; + static Heap staticMember; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}} +}; + +struct BadInherit : Heap {}; // expected-note {{'BadInherit' is a heap type because it inherits from a heap type 'Heap'}} +struct MOZ_HEAP_CLASS GoodInherit : Heap {}; + +void useStuffWrongly() { + BadInherit i; // expected-error {{variable of type 'BadInherit' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}} + RandomClass r; // expected-error {{variable of type 'RandomClass' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}} +} diff --git a/build/clang-plugin/tests/TestInheritTypeAnnotationsFromTemplateArgs.cpp b/build/clang-plugin/tests/TestInheritTypeAnnotationsFromTemplateArgs.cpp new file mode 100644 index 0000000000..0c04c3b2bd --- /dev/null +++ b/build/clang-plugin/tests/TestInheritTypeAnnotationsFromTemplateArgs.cpp @@ -0,0 +1,46 @@ +#define MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS \ + __attribute__((annotate("moz_inherit_type_annotations_from_template_args"))) +#define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class"))) +#define MOZ_NON_MEMMOVABLE __attribute__((annotate("moz_non_memmovable"))) +#define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type"))) + +class Normal {}; +class MOZ_STACK_CLASS Stack {}; +class IndirectStack : Stack {}; // expected-note {{'IndirectStack' is a stack type because it inherits from a stack type 'Stack'}} +class ContainsStack { Stack m; }; // expected-note {{'ContainsStack' is a stack type because member 'm' is a stack type 'Stack'}} +class MOZ_NON_MEMMOVABLE Pointery {}; +class IndirectPointery : Pointery {}; // expected-note {{'IndirectPointery' is a non-memmove()able type because it inherits from a non-memmove()able type 'Pointery'}} +class ContainsPointery { Pointery m; }; // expected-note {{'ContainsPointery' is a non-memmove()able type because member 'm' is a non-memmove()able type 'Pointery'}} + +template<class T> +class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Template {}; // expected-note-re 5 {{'Template<{{.*}}>' is a stack type because it has a template argument stack type '{{.*}}'}} expected-note-re 5 {{'Template<{{.*}}>' is a non-memmove()able type because it has a template argument non-memmove()able type '{{.*}}'}} +class IndirectTemplate : Template<Stack> {}; // expected-note {{'IndirectTemplate' is a stack type because it inherits from a stack type 'Template<Stack>'}} +class ContainsTemplate { Template<Stack> m; }; // expected-note {{'ContainsTemplate' is a stack type because member 'm' is a stack type 'Template<Stack>'}} + +static Template<Stack> a; // expected-error {{variable of type 'Template<Stack>' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +static Template<IndirectStack> b; // expected-error {{variable of type 'Template<IndirectStack>' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +static Template<ContainsStack> c; // expected-error {{variable of type 'Template<ContainsStack>' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +static IndirectTemplate d; // expected-error {{variable of type 'IndirectTemplate' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +static ContainsTemplate e; // expected-error {{variable of type 'ContainsTemplate' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +static Template<Normal> f; + +template<class T> +class MOZ_NEEDS_MEMMOVABLE_TYPE Mover { // expected-error-re 8 {{Cannot instantiate 'Mover<{{.*}}>' with non-memmovable template argument '{{.*}}'}} + char mForceInstantiation[sizeof(T)]; +}; +class IndirectTemplatePointery : Template<Pointery> {}; // expected-note {{'IndirectTemplatePointery' is a non-memmove()able type because it inherits from a non-memmove()able type 'Template<Pointery>'}} +class ContainsTemplatePointery { Template<Pointery> m; }; // expected-note {{'ContainsTemplatePointery' is a non-memmove()able type because member 'm' is a non-memmove()able type 'Template<Pointery>'}} + +static Mover<Template<Pointery>> n; // expected-note-re {{instantiation of 'Mover<Template<Pointery>{{ ?}}>' requested here}} +static Mover<Template<IndirectPointery>> o; // expected-note-re {{instantiation of 'Mover<Template<IndirectPointery>{{ ?}}>' requested here}} +static Mover<Template<ContainsPointery>> p; // expected-note-re {{instantiation of 'Mover<Template<ContainsPointery>{{ ?}}>' requested here}} +static Mover<IndirectTemplatePointery> q; // expected-note {{instantiation of 'Mover<IndirectTemplatePointery>' requested here}} +static Mover<ContainsTemplatePointery> r; // expected-note {{instantiation of 'Mover<ContainsTemplatePointery>' requested here}} +static Mover<Template<Normal>> s; + +template<class T, class... Ts> +class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS ManyTs {}; // expected-note-re 3 {{'ManyTs<{{.*}}>' is a non-memmove()able type because it has a template argument non-memmove()able type '{{.*}}'}} + +static Mover<ManyTs<Pointery>> t; // expected-note-re {{instantiation of 'Mover<ManyTs<Pointery>{{ ?}}>' requested here}} +static Mover<ManyTs<Normal, Pointery>> u; // expected-note-re {{instantiation of 'Mover<ManyTs<Normal, Pointery>{{ ?}}>' requested here}} +static Mover<ManyTs<Normal, Normal, Pointery>> v; // expected-note-re {{instantiation of 'Mover<ManyTs<Normal, Normal, Pointery>{{ ?}}>' requested here}} diff --git a/build/clang-plugin/tests/TestJSHandleRootedTypedef.cpp b/build/clang-plugin/tests/TestJSHandleRootedTypedef.cpp new file mode 100644 index 0000000000..a0489e09ef --- /dev/null +++ b/build/clang-plugin/tests/TestJSHandleRootedTypedef.cpp @@ -0,0 +1,168 @@ +#include "js/TypeDecls.h" +#include "js/Value.h" +#include "js/GCVector.h" +#include "js/Id.h" + +class Foo { + void HandleFunction(JS::HandleFunction){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleId(JS::HandleId){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleObject(JS::HandleObject){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleScript(JS::HandleScript){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleString(JS::HandleString){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleSymbol(JS::HandleSymbol){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleBigInt(JS::HandleBigInt){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleValue(JS::HandleValue){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleValueVector(JS::HandleValueVector){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleObjectVector(JS::HandleObjectVector){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void HandleIdVector(JS::HandleIdVector){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + + void MutableHandleFunction(JS::MutableHandleFunction){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleId(JS::MutableHandleId){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleObject(JS::MutableHandleObject){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleScript(JS::MutableHandleScript){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleString(JS::MutableHandleString){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleSymbol(JS::MutableHandleSymbol){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleBigInt(JS::MutableHandleBigInt){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleValue(JS::MutableHandleValue){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleValueVector(JS::MutableHandleValueVector){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleObjectVector(JS::MutableHandleObjectVector){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + void MutableHandleIdVector(JS::MutableHandleIdVector){}; // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + + // Examples of preferred forms + void FullHandleFunction(JS::Handle<JSFunction*>){}; + void FullHandleId(JS::Handle<JS::PropertyKey>){}; + void FullHandleObject(JS::Handle<JSObject*>){}; + void FullHandleScript(JS::Handle<JSScript*>){}; + void FullHandleString(JS::Handle<JSString*>){}; + void FullHandleSymbol(JS::Handle<JS::Symbol*>){}; + void FullHandleBigInt(JS::Handle<JS::BigInt*>){}; + void FullHandleValue(JS::Handle<JS::Value>){}; + void FullHandleValueVector(JS::Handle<JS::StackGCVector<JS::Value>>){}; + void FullHandleObjectVector(JS::Handle<JS::StackGCVector<JSObject*>>){}; + void FullHandleIdVector(JS::HandleVector<JS::PropertyKey>){}; + void FullHandleValueVectorShorter(JS::HandleVector<JS::Value>){}; + void FullHandleObjectVectorShorter(JS::HandleVector<JSObject*>){}; + void FullHandleIdVectorShorter(JS::HandleVector<JS::PropertyKey>){}; + + void FullMutableHandleFunction(JS::MutableHandle<JSFunction*>){}; + void FullMutableHandleId(JS::MutableHandle<JS::PropertyKey>){}; + void FullMutableHandleObject(JS::MutableHandle<JSObject*>){}; + void FullMutableHandleScript(JS::MutableHandle<JSScript*>){}; + void FullMutableHandleString(JS::MutableHandle<JSString*>){}; + void FullMutableHandleSymbol(JS::MutableHandle<JS::Symbol*>){}; + void FullMutableHandleBigInt(JS::MutableHandle<JS::BigInt*>){}; + void FullMutableHandleValue(JS::MutableHandle<JS::Value*>){}; + void FullMutableHandleValueVector(JS::MutableHandle<JS::StackGCVector<JS::Value>>){}; + void FullMutableHandleObjectVector(JS::MutableHandle<JS::StackGCVector<JSObject*>>){}; + void FullMutableHandleIdVector(JS::MutableHandle<JS::StackGCVector<JS::PropertyKey>>){}; + void FullMutableHandleValueVectorShorter(JS::MutableHandleVector<JS::Value>){}; + void FullMutableHandleObjectVectorShorter(JS::MutableHandleVector<JSObject*>){}; + void FullMutableHandleIdVectorShorter(JS::MutableHandleVector<JS::PropertyKey>){}; +}; + +static void Bar(JSContext *aCx) { + JS::RootedObject RootedObject(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::RootedFunction RootedFunction(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::RootedScript RootedScript(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::RootedString RootedString(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::RootedSymbol RootedSymbol(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::RootedBigInt RootedBigInt(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::RootedId RootedId(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::RootedValue RootedValue(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + + JS::RootedValueVector RootedValueVector(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::RootedObjectVector RootedObjectVector(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::RootedIdVector RootedIdVector(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + + JS::PersistentRootedFunction PersistentRootedFunction(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::PersistentRootedId PersistentRootedId(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::PersistentRootedObject PersistentRootedObject(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::PersistentRootedScript PersistentRootedScript(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::PersistentRootedString PersistentRootedString(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::PersistentRootedSymbol PersistentRootedSymbol(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::PersistentRootedBigInt PersistentRootedBigInt(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::PersistentRootedValue PersistentRootedValue(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + + JS::PersistentRootedIdVector PersistentRootedIdVector(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::PersistentRootedObjectVector PersistentRootedObjectVector(aCx); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + + JS::HandleFunction HandleFunction(RootedFunction); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleId HandleId(RootedId); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleObject HandleObject(RootedObject); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleScript HandleScript(RootedScript); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleString HandleString(RootedString); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleSymbol HandleSymbol(RootedSymbol); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleBigInt HandleBigInt(RootedBigInt); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleValue HandleValue(RootedValue); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleValueVector HandleValueVector(RootedValueVector); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleObjectVector HandleObjectVector(RootedObjectVector); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::HandleIdVector HandleIdVector(RootedIdVector); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + + JS::MutableHandleFunction MutableHandleFunction(&RootedFunction); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleId MutableHandleId(&RootedId); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleObject MutableHandleObject(&RootedObject); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleScript MutableHandleScript(&RootedScript); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleString MutableHandleString(&RootedString); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleSymbol MutableHandleSymbol(&RootedSymbol); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleBigInt MutableHandleBigInt(&RootedBigInt); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleValue MutableHandleValue(&RootedValue); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleValueVector MutableHandleValueVector(&RootedValueVector); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleObjectVector MutableHandleObjectVector(&RootedObjectVector); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + JS::MutableHandleIdVector MutableHandleIdVector(&RootedIdVector); // expected-error {{The fully qualified types are preferred over the shorthand typedefs for JS::Handle/JS::Rooted types outside SpiderMonkey.}} + + // Examples of preferred forms + JS::Rooted<JSObject*> FullRootedObject(aCx); + JS::Rooted<JSFunction*> FullRootedFunction(aCx); + JS::Rooted<JSScript*> FullRootedScript(aCx); + JS::Rooted<JSString*> FullRootedString(aCx); + JS::Rooted<JS::Symbol*> FullRootedSymbol(aCx); + JS::Rooted<JS::BigInt*> FullRootedBigInt(aCx); + JS::Rooted<JS::PropertyKey> FullRootedId(aCx); + JS::Rooted<JS::Value> FullRootedValue(aCx); + + JS::RootedVector<JS::Value> FullRootedValueVector(aCx); + JS::RootedVector<JSObject*> FullRootedObjectVector(aCx); + JS::RootedVector<JS::PropertyKey> FullRootedIdVector(aCx); + + JS::PersistentRooted<JSFunction*> FullPersistentRootedFunction(aCx); + JS::PersistentRooted<JS::PropertyKey> FullPersistentRootedId(aCx); + JS::PersistentRooted<JSObject*> FullPersistentRootedObject(aCx); + JS::PersistentRooted<JSScript*> FullPersistentRootedScript(aCx); + JS::PersistentRooted<JSString*> FullPersistentRootedString(aCx); + JS::PersistentRooted<JS::Symbol*> FullPersistentRootedSymbol(aCx); + JS::PersistentRooted<JS::BigInt*> FullPersistentRootedBigInt(aCx); + JS::PersistentRooted<JS::Value> FullPersistentRootedValue(aCx); + + JS::PersistentRootedVector<JS::PropertyKey> FullPersistentRootedIdVector(aCx); + JS::PersistentRootedVector<JSObject*> FullPersistentRootedObjectVector(aCx); + + JS::Handle<JSFunction*> FullHandleFunction(FullRootedFunction); + JS::Handle<JS::PropertyKey> FullHandleId(FullRootedId); + JS::Handle<JSObject*> FullHandleObject(FullRootedObject); + JS::Handle<JSScript*> FullHandleScript(FullRootedScript); + JS::Handle<JSString*> FullHandleString(FullRootedString); + JS::Handle<JS::Symbol*> FullHandleSymbol(FullRootedSymbol); + JS::Handle<JS::BigInt*> FullHandleBigInt(FullRootedBigInt); + JS::Handle<JS::Value> FullHandleValue(FullRootedValue); + JS::Handle<JS::StackGCVector<JS::Value>> FullHandleValueVector(FullRootedValueVector); + JS::Handle<JS::StackGCVector<JSObject*>> FullHandleObjectVector(FullRootedObjectVector); + JS::Handle<JS::StackGCVector<JS::PropertyKey>> FullHandleIdVector(FullRootedIdVector); + JS::HandleVector<JS::Value> FullHandleValueVectorShorter(FullRootedValueVector); + JS::HandleVector<JSObject*> FullHandleObjectVectorShorter(FullRootedObjectVector); + JS::HandleVector<JS::PropertyKey> FullHandleIdVectorShorter(FullRootedIdVector); + + JS::MutableHandle<JSFunction*> FullMutableHandleFunction(&FullRootedFunction); + JS::MutableHandle<JS::PropertyKey> FullMutableHandleId(&FullRootedId); + JS::MutableHandle<JSObject*> FullMutableHandleObject(&FullRootedObject); + JS::MutableHandle<JSScript*> FullMutableHandleScript(&FullRootedScript); + JS::MutableHandle<JSString*> FullMutableHandleString(&FullRootedString); + JS::MutableHandle<JS::Symbol*> FullMutableHandleSymbol(&FullRootedSymbol); + JS::MutableHandle<JS::BigInt*> FullMutableHandleBigInt(&FullRootedBigInt); + JS::MutableHandle<JS::Value> FullMutableHandleValue(&FullRootedValue); + JS::MutableHandle<JS::StackGCVector<JS::Value>> FullMutableHandleValueVector(&FullRootedValueVector); + JS::MutableHandle<JS::StackGCVector<JSObject*>> FullMutableHandleObjectVector(&FullRootedObjectVector); + JS::MutableHandle<JS::StackGCVector<JS::PropertyKey>> FullMutableHandleIdVector(&FullRootedIdVector); + JS::MutableHandleVector<JS::Value> FullMutableHandleValueVectorShorter(&FullRootedValueVector); + JS::MutableHandleVector<JSObject*> FullMutableHandleObjectVectorShorter(&FullRootedObjectVector); + JS::MutableHandleVector<JS::PropertyKey> FullMutableHandleIdVectorShorter(&FullRootedIdVector); +} diff --git a/build/clang-plugin/tests/TestKnownLive.cpp b/build/clang-plugin/tests/TestKnownLive.cpp new file mode 100644 index 0000000000..8d01160d1d --- /dev/null +++ b/build/clang-plugin/tests/TestKnownLive.cpp @@ -0,0 +1,33 @@ +#include <mozilla/RefPtr.h> + +#define MOZ_KNOWN_LIVE __attribute__((annotate("moz_known_live"))) + +class Foo { + // dummy refcounting +public: + uint32_t AddRef() { return 0; } + uint32_t Release() { return 0; } + +private: + ~Foo() = default; +}; + +class Bar { + MOZ_KNOWN_LIVE RefPtr<Foo> mFoo; + Bar() : mFoo(new Foo()) {} + ~Bar() { mFoo = nullptr; } + + void Baz() { + mFoo = nullptr; // expected-error {{MOZ_KNOWN_LIVE members can only be modified by constructors and destructors}} + } +}; + +class Bar2 { + MOZ_KNOWN_LIVE Foo *mFoo; + Bar2() : mFoo(new Foo()) {} + ~Bar2() { mFoo = nullptr; } + + void Baz() { + mFoo = nullptr; // expected-error {{MOZ_KNOWN_LIVE members can only be modified by constructors and destructors}} + } +}; diff --git a/build/clang-plugin/tests/TestKungFuDeathGrip.cpp b/build/clang-plugin/tests/TestKungFuDeathGrip.cpp new file mode 100644 index 0000000000..0218015807 --- /dev/null +++ b/build/clang-plugin/tests/TestKungFuDeathGrip.cpp @@ -0,0 +1,142 @@ +#include <utility> + +#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) + +template <typename T> +class already_AddRefed { +public: + already_AddRefed(); + T* mPtr; +}; + +template <typename T> +class RefPtr { +public: + RefPtr(); + MOZ_IMPLICIT RefPtr(T* aIn); + MOZ_IMPLICIT RefPtr(already_AddRefed<T> aIn); + + RefPtr(const RefPtr<T>& aOther) = default; + RefPtr& operator=(const RefPtr<T>&) = default; + + // We must define non-defaulted move operations as in the real RefPtr to make + // the type non-trivially-copyable. + RefPtr(RefPtr<T>&&); + RefPtr& operator=(RefPtr<T>&&); + + void swap(RefPtr<T>& aOther); + + ~RefPtr(); + T* mPtr; +}; + +template <typename T> +class nsCOMPtr { +public: + nsCOMPtr(); + MOZ_IMPLICIT nsCOMPtr(T* aIn); + MOZ_IMPLICIT nsCOMPtr(already_AddRefed<T> aIn); + ~nsCOMPtr(); + T* mPtr; +}; + +class Type { +public: + static nsCOMPtr<Type> someStaticCOMPtr; + + void f(nsCOMPtr<Type> ignoredArgument, Type *param) { + nsCOMPtr<Type> never_referenced; + nsCOMPtr<Type> kfdg_t1(this); + nsCOMPtr<Type> kfdg_t2 = this; + nsCOMPtr<Type> kfdg_t3 = (this); + + nsCOMPtr<Type> kfdg_m1(p); // expected-error {{Unused "kungFuDeathGrip" 'nsCOMPtr<Type>' objects constructed from members are prohibited}} expected-note {{Please switch all accesses to this member to go through 'kfdg_m1', or explicitly pass 'kfdg_m1' to `mozilla::Unused`}} + nsCOMPtr<Type> kfdg_m2 = p; // expected-error {{Unused "kungFuDeathGrip" 'nsCOMPtr<Type>' objects constructed from members are prohibited}} expected-note {{Please switch all accesses to this member to go through 'kfdg_m2', or explicitly pass 'kfdg_m2' to `mozilla::Unused`}} + nsCOMPtr<Type> kfdg_m3(p); + kfdg_m3.mPtr->f(nullptr, nullptr); + nsCOMPtr<Type> kfdg_m4 = p; + kfdg_m4.mPtr->f(nullptr, nullptr); + + nsCOMPtr<Type> kfdg_a1((already_AddRefed<Type>())); + nsCOMPtr<Type> kfdg_a2 = already_AddRefed<Type>(); + + nsCOMPtr<Type> kfdg_p1(param); + nsCOMPtr<Type> kfdg_p2 = param; + + + RefPtr<Type> never_referenced2; + RefPtr<Type> kfdg_t4(this); + RefPtr<Type> kfdg_t5 = this; + RefPtr<Type> kfdg_t6 = (this); + + RefPtr<Type> kfdg_m5(p); // expected-error {{Unused "kungFuDeathGrip" 'RefPtr<Type>' objects constructed from members are prohibited}} expected-note {{Please switch all accesses to this member to go through 'kfdg_m5', or explicitly pass 'kfdg_m5' to `mozilla::Unused`}} + RefPtr<Type> kfdg_m6 = p; // expected-error {{Unused "kungFuDeathGrip" 'RefPtr<Type>' objects constructed from members are prohibited}} expected-note {{Please switch all accesses to this member to go through 'kfdg_m6', or explicitly pass 'kfdg_m6' to `mozilla::Unused`}} + RefPtr<Type> kfdg_m7(p); + kfdg_m7.mPtr->f(nullptr, nullptr); + RefPtr<Type> kfdg_m8 = p; + kfdg_m8.mPtr->f(nullptr, nullptr); + + RefPtr<Type> kfdg_a3((already_AddRefed<Type>())); + RefPtr<Type> kfdg_a4 = already_AddRefed<Type>(); + + RefPtr<Type> kfdg_p3(param); + RefPtr<Type> kfdg_p4 = param; + } + + Type *p; +}; + +struct Type2 { + void f() { + mWeakRef->f(nullptr, nullptr); + } + + void g() { + RefPtr<Type> kfdg; + kfdg.swap(mStrongRef); + f(); + } + + void h() { + RefPtr<Type> kfdg = std::move(mStrongRef); + f(); + } + + RefPtr<Type> mStrongRef; + Type* mWeakRef; +}; + +void f(nsCOMPtr<Type> ignoredArgument, Type *param) { + nsCOMPtr<Type> never_referenced; + Type t; + // Type *p = nullptr; + nsCOMPtr<Type> kfdg_m1(t.p); // expected-error {{Unused "kungFuDeathGrip" 'nsCOMPtr<Type>' objects constructed from members are prohibited}} expected-note {{Please switch all accesses to this member to go through 'kfdg_m1', or explicitly pass 'kfdg_m1' to `mozilla::Unused`}} + nsCOMPtr<Type> kfdg_m2 = t.p; // expected-error {{Unused "kungFuDeathGrip" 'nsCOMPtr<Type>' objects constructed from members are prohibited}} expected-note {{Please switch all accesses to this member to go through 'kfdg_m2', or explicitly pass 'kfdg_m2' to `mozilla::Unused`}} + nsCOMPtr<Type> kfdg_m3(t.p); + kfdg_m3.mPtr->f(nullptr, nullptr); + nsCOMPtr<Type> kfdg_m4 = t.p; + kfdg_m4.mPtr->f(nullptr, nullptr); + + nsCOMPtr<Type> kfdg_a1((already_AddRefed<Type>())); + nsCOMPtr<Type> kfdg_a2 = already_AddRefed<Type>(); + + nsCOMPtr<Type> kfdg_p1(param); + nsCOMPtr<Type> kfdg_p2 = param; + + + RefPtr<Type> never_referenced2; + RefPtr<Type> kfdg_m5(t.p); // expected-error {{Unused "kungFuDeathGrip" 'RefPtr<Type>' objects constructed from members are prohibited}} expected-note {{Please switch all accesses to this member to go through 'kfdg_m5', or explicitly pass 'kfdg_m5' to `mozilla::Unused`}} + RefPtr<Type> kfdg_m6 = t.p; // expected-error {{Unused "kungFuDeathGrip" 'RefPtr<Type>' objects constructed from members are prohibited}} expected-note {{Please switch all accesses to this member to go through 'kfdg_m6', or explicitly pass 'kfdg_m6' to `mozilla::Unused`}} + RefPtr<Type> kfdg_m7(t.p); + kfdg_m7.mPtr->f(nullptr, nullptr); + RefPtr<Type> kfdg_m8 = t.p; + kfdg_m8.mPtr->f(nullptr, nullptr); + + RefPtr<Type> kfdg_a3((already_AddRefed<Type>())); + RefPtr<Type> kfdg_a4 = already_AddRefed<Type>(); + + RefPtr<Type> kfdg_p3(param); + RefPtr<Type> kfdg_p4 = param; +} + +nsCOMPtr<Type> Type::someStaticCOMPtr(nullptr); diff --git a/build/clang-plugin/tests/TestLoadLibraryUsage.cpp b/build/clang-plugin/tests/TestLoadLibraryUsage.cpp new file mode 100644 index 0000000000..319c9d6b2a --- /dev/null +++ b/build/clang-plugin/tests/TestLoadLibraryUsage.cpp @@ -0,0 +1,20 @@ +#include <windows.h> +#include "prlink.h" + +void Func() { + auto h1 = PR_LoadLibrary(nullptr); // expected-error {{Usage of ASCII file functions (such as PR_LoadLibrary) is forbidden.}} + auto h2 = PR_LoadLibrary("C:\\Some\\Path"); + auto h3 = LoadLibraryA(nullptr); // expected-error {{Usage of ASCII file functions (such as LoadLibraryA) is forbidden.}} + auto h4 = LoadLibraryA("C:\\Some\\Path"); + auto h5 = LoadLibraryExA(nullptr, nullptr, 0); // expected-error {{Usage of ASCII file functions (such as LoadLibraryExA) is forbidden.}} + auto h6 = LoadLibraryExA("C:\\Some\\Path", nullptr, 0); + +#ifndef UNICODE + // LoadLibrary is a defnine for LoadLibraryA + auto h7 = LoadLibrary(nullptr); // expected-error {{Usage of ASCII file functions (such as LoadLibraryA) is forbidden.}} + auto h8 = LoadLibrary("C:\\Some\\Path"); + // LoadLibraryEx is a define for LoadLibraryExA + auto h9 = LoadLibraryEx(nullptr, nullptr, 0); // expected-error {{Usage of ASCII file functions (such as LoadLibraryExA) is forbidden.}} + auto h10 = LoadLibraryEx("C:\\Some\\Path", nullptr, 0); +#endif +} diff --git a/build/clang-plugin/tests/TestMultipleAnnotations.cpp b/build/clang-plugin/tests/TestMultipleAnnotations.cpp new file mode 100644 index 0000000000..034367a58e --- /dev/null +++ b/build/clang-plugin/tests/TestMultipleAnnotations.cpp @@ -0,0 +1,19 @@ +#define MOZ_NON_TEMPORARY_CLASS __attribute__((annotate("moz_non_temporary_class"))) +#define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class"))) + +class MOZ_NON_TEMPORARY_CLASS MOZ_STACK_CLASS TestClass {}; + +TestClass foo; // expected-error {{variable of type 'TestClass' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} + +TestClass f() +{ + TestClass bar; + return bar; +} + +void gobbleref(const TestClass&) { } + +void g() +{ + gobbleref(f()); // expected-error {{variable of type 'TestClass' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}} +} diff --git a/build/clang-plugin/tests/TestMustOverride.cpp b/build/clang-plugin/tests/TestMustOverride.cpp new file mode 100644 index 0000000000..8e053f6c23 --- /dev/null +++ b/build/clang-plugin/tests/TestMustOverride.cpp @@ -0,0 +1,63 @@ +#define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override"))) +// Ignore warnings not related to static analysis here +#pragma GCC diagnostic ignored "-Woverloaded-virtual" + +struct S { + virtual void f() MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} + virtual void g() MOZ_MUST_OVERRIDE; + virtual void h() MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} +}; +struct C : S { // expected-error {{'C' must override 'f'}} expected-error {{'C' must override 'h'}} + virtual void g() MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} + virtual void h(int); + void q() MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} +}; +struct D : C { // expected-error {{'D' must override 'g'}} expected-error {{'D' must override 'q'}} + virtual void f(); +}; + +struct Base { + virtual void VirtMethod() MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} + void NonVirtMethod() MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} + static void StaticMethod() MOZ_MUST_OVERRIDE; +}; + +struct DoesNotPropagate : Base { + virtual void VirtMethod(); + void NonVirtMethod(); + static void StaticMethod(); +}; + +struct Final : DoesNotPropagate { }; + +struct Propagates : Base { + virtual void VirtMethod() MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} + void NonVirtMethod() MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} + static void StaticMethod() MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} +}; + +struct FailsFinal : Propagates { }; // expected-error {{'FailsFinal' must override 'VirtMethod'}} expected-error {{'FailsFinal' must override 'NonVirtMethod'}} expected-error {{'FailsFinal' must override 'StaticMethod'}} + +struct WrongOverload : Base { // expected-error {{'WrongOverload' must override 'VirtMethod'}} expected-error {{'WrongOverload' must override 'NonVirtMethod'}} + virtual void VirtMethod() const; + void NonVirtMethod(int param); + static void StaticMethod(); +}; + +namespace A { namespace B { namespace C { + struct Param {}; + struct Base { + void f(Param p) MOZ_MUST_OVERRIDE; // expected-note {{function to override is here}} + }; +}}} + +struct Param {}; + +struct Derived : A::B::C::Base { + typedef A::B::C::Param Typedef; + void f(Typedef t); +}; + +struct BadDerived : A::B::C::Base { // expected-error {{'BadDerived' must override 'f'}} + void f(Param p); +}; diff --git a/build/clang-plugin/tests/TestMustReturnFromCaller.cpp b/build/clang-plugin/tests/TestMustReturnFromCaller.cpp new file mode 100644 index 0000000000..c935be3cf8 --- /dev/null +++ b/build/clang-plugin/tests/TestMustReturnFromCaller.cpp @@ -0,0 +1,270 @@ +#include <cstddef> +#include <utility> + +#define MOZ_MUST_RETURN_FROM_CALLER_IF_THIS_IS_ARG __attribute__((annotate("moz_must_return_from_caller_if_this_is_arg"))) +#define MOZ_MAY_CALL_AFTER_MUST_RETURN __attribute__((annotate("moz_may_call_after_must_return"))) + +struct Thrower { + void MOZ_MUST_RETURN_FROM_CALLER_IF_THIS_IS_ARG Throw() {} +}; + +void DoAnythingElse(); +int MakeAnInt(); +int MOZ_MAY_CALL_AFTER_MUST_RETURN SafeMakeInt(); +bool Condition(); + +// It might be nicer to #include "mozilla/ScopeExit.h" and use that here -- but +// doing so also will #define the two attribute-macros defined above, running a +// risk of redefinition errors. Just stick to the normal clang-plugin test +// style and use as little external code as possible. + +template<typename Func> +class ScopeExit { + Func exitFunction; + bool callOnDestruction; +public: + explicit ScopeExit(Func&& func) + : exitFunction(std::move(func)) + , callOnDestruction(true) + {} + + ~ScopeExit() { + if (callOnDestruction) { + exitFunction(); + } + } + + void release() { callOnDestruction = false; } +}; + +template<typename ExitFunction> +ScopeExit<ExitFunction> +MakeScopeExit(ExitFunction&& func) +{ + return ScopeExit<ExitFunction>(std::move(func)); +} + +class Foo { +public: + __attribute__((annotate("moz_implicit"))) Foo(std::nullptr_t); + Foo(); +}; + +void a1(Thrower& thrower) { + thrower.Throw(); +} + +int a2(Thrower& thrower) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + return MakeAnInt(); +} + +int a3(Thrower& thrower) { + // RAII operations happening after a must-immediately-return are fine. + auto atExit = MakeScopeExit([] { DoAnythingElse(); }); + thrower.Throw(); + return 5; +} + +int a4(Thrower& thrower) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + return Condition() ? MakeAnInt() : MakeAnInt(); +} + +void a5(Thrower& thrower) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + DoAnythingElse(); +} + +int a6(Thrower& thrower) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + DoAnythingElse(); + return MakeAnInt(); +} + +int a7(Thrower& thrower) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + DoAnythingElse(); + return Condition() ? MakeAnInt() : MakeAnInt(); +} + +int a8(Thrower& thrower) { + thrower.Throw(); + return SafeMakeInt(); +} + +int a9(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + } + return SafeMakeInt(); +} + +int a10(Thrower& thrower) { + auto atExit = MakeScopeExit([] { DoAnythingElse(); }); + + if (Condition()) { + thrower.Throw(); + return SafeMakeInt(); + } + + atExit.release(); + DoAnythingElse(); + return 5; +} + +void b1(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + } +} + +int b2(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + } + return MakeAnInt(); +} + +int b3(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + } + return 5; +} + +// Explicit test in orer to also verify the `UnaryOperator` node in the `CFG` +int b3a(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + } + return -1; +} + +float b3b(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + } + return 1.0f; +} + +bool b3c(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + } + return false; +} + +int b4(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + } + return Condition() ? MakeAnInt() : MakeAnInt(); +} + +void b5(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + } + DoAnythingElse(); +} + +void b6(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + DoAnythingElse(); + } +} + +void b7(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + return; + } + DoAnythingElse(); +} + +void b8(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + DoAnythingElse(); + return; + } + DoAnythingElse(); +} + +void b9(Thrower& thrower) { + while (Condition()) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + } +} + +void b10(Thrower& thrower) { + while (Condition()) { + thrower.Throw(); + return; + } +} + +void b11(Thrower& thrower) { + thrower.Throw(); // expected-error {{You must immediately return after calling this function}} + if (Condition()) { + return; + } else { + return; + } +} + +void b12(Thrower& thrower) { + switch (MakeAnInt()) { + case 1: + break; + default: + thrower.Throw(); + return; + } +} + +void b13(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + } + return; +} + +Foo b14(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + return nullptr; + } + return nullptr; +} + +Foo b15(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + } + return nullptr; +} + +Foo b16(Thrower& thrower) { + if (Condition()) { + thrower.Throw(); + } + return Foo(); +} + +void c1() { + Thrower thrower; + thrower.Throw(); + DoAnythingElse(); // Should be allowed, since our thrower is not an arg +} + +class TestRet { + TestRet *b13(Thrower &thrower) { + if (Condition()) { + thrower.Throw(); + } + return this; + } +}; diff --git a/build/clang-plugin/tests/TestNANTestingExpr.cpp b/build/clang-plugin/tests/TestNANTestingExpr.cpp new file mode 100644 index 0000000000..9aac46d036 --- /dev/null +++ b/build/clang-plugin/tests/TestNANTestingExpr.cpp @@ -0,0 +1,24 @@ +#line 1 "tests/SkScalar.h" +// This checks that the whitelist accounts for #line directives and such. If you +// remove SkScalar from the whitelist, please change the filename here instead +// of adding expected diagnostics. +inline int headerSays(double x) { + return x != x; +} +#line 9 "TestNANTestingExpr.cpp" +void test(bool x); +void foo() { + float f, f2; + typedef double mydouble; + mydouble d; + double d2; + test(f == f); // expected-error{{comparing a floating point value to itself for NaN checking can lead to incorrect results}} expected-note{{consider using std::isnan instead}} + test(d == d); // expected-error{{comparing a floating point value to itself for NaN checking can lead to incorrect results}} expected-note{{consider using std::isnan instead}} + test(f != f); // expected-error{{comparing a floating point value to itself for NaN checking can lead to incorrect results}} expected-note{{consider using std::isnan instead}} + test(d != d); // expected-error{{comparing a floating point value to itself for NaN checking can lead to incorrect results}} expected-note{{consider using std::isnan instead}} + test(f != d); + test(d == (d - f)); + test(f == f2); + test(d == d2); + test(d + 1 == d); +} diff --git a/build/clang-plugin/tests/TestNANTestingExprC.c b/build/clang-plugin/tests/TestNANTestingExprC.c new file mode 100644 index 0000000000..ab2fead22a --- /dev/null +++ b/build/clang-plugin/tests/TestNANTestingExprC.c @@ -0,0 +1,17 @@ +/* expected-no-diagnostics */ +void test(int x); +void foo() { + float f, f2; + typedef double mydouble; + mydouble d; + double d2; + test(f == f); + test(d == d); + test(f != f); + test(d != d); + test(f != d); + test(d == (d - f)); + test(f == f2); + test(d == d2); + test(d + 1 == d); +} diff --git a/build/clang-plugin/tests/TestNeedsNoVTableType.cpp b/build/clang-plugin/tests/TestNeedsNoVTableType.cpp new file mode 100644 index 0000000000..9b7c405d80 --- /dev/null +++ b/build/clang-plugin/tests/TestNeedsNoVTableType.cpp @@ -0,0 +1,94 @@ +#define MOZ_NEEDS_NO_VTABLE_TYPE __attribute__((annotate("moz_needs_no_vtable_type"))) + +template <class T> +struct MOZ_NEEDS_NO_VTABLE_TYPE PickyConsumer { // expected-error {{'PickyConsumer<B>' cannot be instantiated because 'B' has a VTable}} expected-error {{'PickyConsumer<E>' cannot be instantiated because 'E' has a VTable}} expected-error {{'PickyConsumer<F>' cannot be instantiated because 'F' has a VTable}} expected-error {{'PickyConsumer<G>' cannot be instantiated because 'G' has a VTable}} + T *m; +}; + +template <class T> +struct MOZ_NEEDS_NO_VTABLE_TYPE PickyConsumer_A { // expected-error {{'PickyConsumer_A<B>' cannot be instantiated because 'B' has a VTable}} expected-error {{'PickyConsumer_A<E>' cannot be instantiated because 'E' has a VTable}} expected-error {{'PickyConsumer_A<F>' cannot be instantiated because 'F' has a VTable}} expected-error {{'PickyConsumer_A<G>' cannot be instantiated because 'G' has a VTable}} + T *m; +}; +template <class T> +struct PickyConsumerWrapper { + PickyConsumer_A<T> m; // expected-note {{bad instantiation of 'PickyConsumer_A<B>' requested here}} expected-note {{bad instantiation of 'PickyConsumer_A<E>' requested here}} expected-note {{bad instantiation of 'PickyConsumer_A<F>' requested here}} expected-note {{bad instantiation of 'PickyConsumer_A<G>' requested here}} +}; + +template <class T> +struct MOZ_NEEDS_NO_VTABLE_TYPE PickyConsumer_B { // expected-error {{'PickyConsumer_B<B>' cannot be instantiated because 'B' has a VTable}} expected-error {{'PickyConsumer_B<E>' cannot be instantiated because 'E' has a VTable}} expected-error {{'PickyConsumer_B<F>' cannot be instantiated because 'F' has a VTable}} expected-error {{'PickyConsumer_B<G>' cannot be instantiated because 'G' has a VTable}} + T *m; +}; +template <class T> +struct PickyConsumerSubclass : PickyConsumer_B<T> {}; // expected-note {{bad instantiation of 'PickyConsumer_B<B>' requested here}} expected-note {{bad instantiation of 'PickyConsumer_B<E>' requested here}} expected-note {{bad instantiation of 'PickyConsumer_B<F>' requested here}} expected-note {{bad instantiation of 'PickyConsumer_B<G>' requested here}} + +template <class T> +struct NonPickyConsumer { + T *m; +}; + +struct A {}; +struct B : virtual A {}; +struct C : A {}; +struct D { + void d(); +}; +struct E { + virtual void e(); +}; +struct F : E { + void e() final; +}; +struct G { + virtual void e() = 0; +}; + +void f() { + { + PickyConsumer<A> a1; + PickyConsumerWrapper<A> a2; + PickyConsumerSubclass<A> a3; + NonPickyConsumer<A> a4; + } + + { + PickyConsumer<B> a1; // expected-note {{bad instantiation of 'PickyConsumer<B>' requested here}} + PickyConsumerWrapper<B> a2; + PickyConsumerSubclass<B> a3; + NonPickyConsumer<B> a4; + } + + { + PickyConsumer<C> a1; + PickyConsumerWrapper<C> a2; + PickyConsumerSubclass<C> a3; + NonPickyConsumer<C> a4; + } + + { + PickyConsumer<D> a1; + PickyConsumerWrapper<D> a2; + PickyConsumerSubclass<D> a3; + NonPickyConsumer<D> a4; + } + + { + PickyConsumer<E> a1; // expected-note {{bad instantiation of 'PickyConsumer<E>' requested here}} + PickyConsumerWrapper<E> a2; + PickyConsumerSubclass<E> a3; + NonPickyConsumer<E> a4; + } + + { + PickyConsumer<F> a1; // expected-note {{bad instantiation of 'PickyConsumer<F>' requested here}} + PickyConsumerWrapper<F> a2; + PickyConsumerSubclass<F> a3; + NonPickyConsumer<F> a4; + } + + { + PickyConsumer<G> a1; // expected-note {{bad instantiation of 'PickyConsumer<G>' requested here}} + PickyConsumerWrapper<G> a2; + PickyConsumerSubclass<G> a3; + NonPickyConsumer<G> a4; + } +} diff --git a/build/clang-plugin/tests/TestNoAddRefReleaseOnReturn.cpp b/build/clang-plugin/tests/TestNoAddRefReleaseOnReturn.cpp new file mode 100644 index 0000000000..5db514f7ab --- /dev/null +++ b/build/clang-plugin/tests/TestNoAddRefReleaseOnReturn.cpp @@ -0,0 +1,110 @@ +#define MOZ_NO_ADDREF_RELEASE_ON_RETURN __attribute__((annotate("moz_no_addref_release_on_return"))) + +struct Test { + void AddRef(); + void Release(); + void foo(); +}; + +struct TestD : Test {}; + +struct S { + Test* f() MOZ_NO_ADDREF_RELEASE_ON_RETURN; + Test& g() MOZ_NO_ADDREF_RELEASE_ON_RETURN; + Test h() MOZ_NO_ADDREF_RELEASE_ON_RETURN; +}; + +struct SD { + TestD* f() MOZ_NO_ADDREF_RELEASE_ON_RETURN; + TestD& g() MOZ_NO_ADDREF_RELEASE_ON_RETURN; + TestD h() MOZ_NO_ADDREF_RELEASE_ON_RETURN; +}; + +template<class T> +struct X { + T* f() MOZ_NO_ADDREF_RELEASE_ON_RETURN; + T& g() MOZ_NO_ADDREF_RELEASE_ON_RETURN; + T h() MOZ_NO_ADDREF_RELEASE_ON_RETURN; +}; + +template<class T> +struct SP { + T* operator->() MOZ_NO_ADDREF_RELEASE_ON_RETURN; +}; + +Test* f() MOZ_NO_ADDREF_RELEASE_ON_RETURN; +Test& g() MOZ_NO_ADDREF_RELEASE_ON_RETURN; +Test h() MOZ_NO_ADDREF_RELEASE_ON_RETURN; + +TestD* fd() MOZ_NO_ADDREF_RELEASE_ON_RETURN; +TestD& gd() MOZ_NO_ADDREF_RELEASE_ON_RETURN; +TestD hd() MOZ_NO_ADDREF_RELEASE_ON_RETURN; + +void test() { + S s; + s.f()->AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'S::f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + s.f()->Release(); // expected-error{{'Release' must not be called on the return value of 'S::f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + s.f()->foo(); + s.g().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'S::g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + s.g().Release(); // expected-error{{'Release' must not be called on the return value of 'S::g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + s.g().foo(); + s.h().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'S::h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + s.h().Release(); // expected-error{{'Release' must not be called on the return value of 'S::h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + s.h().foo(); + SD sd; + sd.f()->AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'SD::f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + sd.f()->Release(); // expected-error{{'Release' must not be called on the return value of 'SD::f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + sd.f()->foo(); + sd.g().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'SD::g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + sd.g().Release(); // expected-error{{'Release' must not be called on the return value of 'SD::g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + sd.g().foo(); + sd.h().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'SD::h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + sd.h().Release(); // expected-error{{'Release' must not be called on the return value of 'SD::h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + sd.h().foo(); + X<Test> x; + x.f()->AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'X<Test>::f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + x.f()->Release(); // expected-error{{'Release' must not be called on the return value of 'X<Test>::f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + x.f()->foo(); + x.g().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'X<Test>::g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + x.g().Release(); // expected-error{{'Release' must not be called on the return value of 'X<Test>::g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + x.g().foo(); + x.h().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'X<Test>::h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + x.h().Release(); // expected-error{{'Release' must not be called on the return value of 'X<Test>::h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + x.h().foo(); + X<TestD> xd; + xd.f()->AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'X<TestD>::f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + xd.f()->Release(); // expected-error{{'Release' must not be called on the return value of 'X<TestD>::f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + xd.f()->foo(); + xd.g().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'X<TestD>::g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + xd.g().Release(); // expected-error{{'Release' must not be called on the return value of 'X<TestD>::g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + xd.g().foo(); + xd.h().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'X<TestD>::h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + xd.h().Release(); // expected-error{{'Release' must not be called on the return value of 'X<TestD>::h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + xd.h().foo(); + SP<Test> sp; + sp->AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'SP<Test>::operator->' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + sp->Release(); // expected-error{{'Release' must not be called on the return value of 'SP<Test>::operator->' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + sp->foo(); + SP<TestD> spd; + spd->AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'SP<TestD>::operator->' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + spd->Release(); // expected-error{{'Release' must not be called on the return value of 'SP<TestD>::operator->' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + spd->foo(); + f()->AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + f()->Release(); // expected-error{{'Release' must not be called on the return value of 'f' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + f()->foo(); + g().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + g().Release(); // expected-error{{'Release' must not be called on the return value of 'g' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + g().foo(); + h().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + h().Release(); // expected-error{{'Release' must not be called on the return value of 'h' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + h().foo(); + fd()->AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'fd' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + fd()->Release(); // expected-error{{'Release' must not be called on the return value of 'fd' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + fd()->foo(); + gd().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'gd' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + gd().Release(); // expected-error{{'Release' must not be called on the return value of 'gd' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + gd().foo(); + hd().AddRef(); // expected-error{{'AddRef' must not be called on the return value of 'hd' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + hd().Release(); // expected-error{{'Release' must not be called on the return value of 'hd' which is marked with MOZ_NO_ADDREF_RELEASE_ON_RETURN}} + hd().foo(); +} diff --git a/build/clang-plugin/tests/TestNoArithmeticExprInArgument.cpp b/build/clang-plugin/tests/TestNoArithmeticExprInArgument.cpp new file mode 100644 index 0000000000..d147b17012 --- /dev/null +++ b/build/clang-plugin/tests/TestNoArithmeticExprInArgument.cpp @@ -0,0 +1,32 @@ +#define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT __attribute__((annotate("moz_no_arith_expr_in_arg"))) + +struct X { + explicit X(int) MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT; + void baz(int) MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT; +}; + +int operator+(int, X); +int operator+(X, int); +int operator++(X); + +void badArithmeticsInArgs() { + int a = 1; + typedef int myint; + myint b = 2; + X goodObj1(a); + goodObj1.baz(b); + X badObj1(a + b); // expected-error{{cannot pass an arithmetic expression of built-in types to 'X'}} + X badObj2 = X(a ? 0 : ++a); // expected-error{{cannot pass an arithmetic expression of built-in types to 'X'}} + X badObj3(~a); // expected-error{{cannot pass an arithmetic expression of built-in types to 'X'}} + badObj1.baz(a - 1 - b); // expected-error{{cannot pass an arithmetic expression of built-in types to 'baz'}} + badObj1.baz(++a); // expected-error{{cannot pass an arithmetic expression of built-in types to 'baz'}} + badObj1.baz(a++); // expected-error{{cannot pass an arithmetic expression of built-in types to 'baz'}} + badObj1.baz(a || b); + badObj1.baz(a + goodObj1); + badObj1.baz(goodObj1 + a); + badObj1.baz(++goodObj1); + badObj1.baz(-1); + badObj1.baz(-1.0); + badObj1.baz(1 + 2); + badObj1.baz(1 << (sizeof(int)/2)); +} diff --git a/build/clang-plugin/tests/TestNoAutoType.cpp b/build/clang-plugin/tests/TestNoAutoType.cpp new file mode 100644 index 0000000000..6c6e65f243 --- /dev/null +++ b/build/clang-plugin/tests/TestNoAutoType.cpp @@ -0,0 +1,41 @@ +#define MOZ_NON_AUTOABLE __attribute__((annotate("moz_non_autoable"))) + +template<class T> +struct MOZ_NON_AUTOABLE ExplicitTypeTemplate {}; +struct MOZ_NON_AUTOABLE ExplicitType {}; +struct NonExplicitType {}; + +void f() { + { + ExplicitType a; + auto b = a; // expected-error {{Cannot use auto to declare a variable of type 'ExplicitType'}} expected-note {{Please write out this type explicitly}} + auto &br = a; // expected-error {{Cannot use auto to declare a variable of type 'ExplicitType &'}} expected-note {{Please write out this type explicitly}} + const auto &brc = a; // expected-error {{Cannot use auto to declare a variable of type 'const ExplicitType &'}} expected-note {{Please write out this type explicitly}} + auto *bp = &a; // expected-error {{Cannot use auto to declare a variable of type 'ExplicitType *'}} expected-note {{Please write out this type explicitly}} + const auto *bpc = &a; // expected-error {{Cannot use auto to declare a variable of type 'const ExplicitType *'}} expected-note {{Please write out this type explicitly}} + } + + { + ExplicitTypeTemplate<int> a; + auto b = a; // expected-error {{Cannot use auto to declare a variable of type 'ExplicitTypeTemplate<int>'}} expected-note {{Please write out this type explicitly}} + auto &br = a; // expected-error {{Cannot use auto to declare a variable of type 'ExplicitTypeTemplate<int> &'}} expected-note {{Please write out this type explicitly}} + const auto &brc = a; // expected-error {{Cannot use auto to declare a variable of type 'const ExplicitTypeTemplate<int> &'}} expected-note {{Please write out this type explicitly}} + auto *bp = &a; // expected-error {{Cannot use auto to declare a variable of type 'ExplicitTypeTemplate<int> *'}} expected-note {{Please write out this type explicitly}} + const auto *bpc = &a; // expected-error {{Cannot use auto to declare a variable of type 'const ExplicitTypeTemplate<int> *'}} expected-note {{Please write out this type explicitly}} + } + + { + NonExplicitType c; + auto d = c; + auto &dr = c; + const auto &drc = c; + auto *dp = &c; + const auto *dpc = &c; + } +} + +ExplicitType A; +auto B = A; // expected-error {{Cannot use auto to declare a variable of type 'ExplicitType'}} expected-note {{Please write out this type explicitly}} + +NonExplicitType C; +auto D = C; diff --git a/build/clang-plugin/tests/TestNoDuplicateRefCntMember.cpp b/build/clang-plugin/tests/TestNoDuplicateRefCntMember.cpp new file mode 100644 index 0000000000..ff68e4fc7c --- /dev/null +++ b/build/clang-plugin/tests/TestNoDuplicateRefCntMember.cpp @@ -0,0 +1,49 @@ +class C1 {}; + +class RC1 { +public: + virtual void AddRef(); + virtual void Release(); + +private: + int mRefCnt; // expected-note 2 {{Superclass 'RC1' also has an mRefCnt member}} expected-note 3 {{Superclass 'RC1' has an mRefCnt member}} +}; + +class RC2 : public RC1 { // expected-error {{Refcounted record 'RC2' has multiple mRefCnt members}} +public: + virtual void AddRef(); + virtual void Release(); + +private: + int mRefCnt; // expected-note {{Consider using the _INHERITED macros for AddRef and Release here}} +}; + +class C2 : public RC1 {}; + +class RC3 : public RC1 {}; + +class RC4 : public RC3, public C2 {}; // expected-error {{Refcounted record 'RC4' has multiple superclasses with mRefCnt members}} + +class RC5 : public RC1 {}; + +class RC6 : public C1, public RC5 { // expected-error {{Refcounted record 'RC6' has multiple mRefCnt members}} +public: + virtual void AddRef(); + virtual void Release(); + +private: + int mRefCnt; // expected-note {{Consider using the _INHERITED macros for AddRef and Release here}} +}; + +class Predecl; + +class OtherRC { +public: + virtual void AddRef(); + virtual void Release(); + +private: + int mRefCnt; // expected-note {{Superclass 'OtherRC' has an mRefCnt member}} +}; + +class MultRCSuper : public RC1, public OtherRC {}; // expected-error {{Refcounted record 'MultRCSuper' has multiple superclasses with mRefCnt members}} diff --git a/build/clang-plugin/tests/TestNoExplicitMoveConstructor.cpp b/build/clang-plugin/tests/TestNoExplicitMoveConstructor.cpp new file mode 100644 index 0000000000..5aea6b1a7f --- /dev/null +++ b/build/clang-plugin/tests/TestNoExplicitMoveConstructor.cpp @@ -0,0 +1,25 @@ +class Foo { + Foo(Foo&& f); +}; + +class Bar { + explicit Bar(Bar&& f); // expected-error {{Move constructors may not be marked explicit}} +}; + +class Baz { + template<typename T> + explicit Baz(T&& f) {}; +}; + +class Quxx { + Quxx(); + Quxx(Quxx& q) = delete; + template<typename T> + explicit Quxx(T&& f) {}; +}; + +void f() { + // Move a quxx into a quxx! (This speciailizes Quxx's constructor to look like + // a move constructor - to make sure it doesn't trigger) + Quxx(Quxx()); +} diff --git a/build/clang-plugin/tests/TestNoNewThreadsChecker.cpp b/build/clang-plugin/tests/TestNoNewThreadsChecker.cpp new file mode 100644 index 0000000000..c10277c1c4 --- /dev/null +++ b/build/clang-plugin/tests/TestNoNewThreadsChecker.cpp @@ -0,0 +1,9 @@ +// Dummy NS_NewNamedThread. +void NS_NewNamedThread(const char *aName) {} + +void func_threads() { + // Test to see if the checker recognizes a bad name, and if it recognizes a + // name from the ThreadAllows.txt. + NS_NewNamedThread("A bad name"); // expected-error {{Thread name not recognized. Please use the background thread pool.}} expected-note {{NS_NewNamedThread has been deprecated in favor of background task dispatch via NS_DispatchBackgroundTask and NS_CreateBackgroundTaskQueue. If you must create a new ad-hoc thread, have your thread name added to ThreadAllows.txt.}} + NS_NewNamedThread("Checker Test"); +} diff --git a/build/clang-plugin/tests/TestNoPrincipalGetUri.cpp b/build/clang-plugin/tests/TestNoPrincipalGetUri.cpp new file mode 100644 index 0000000000..c94a2add8a --- /dev/null +++ b/build/clang-plugin/tests/TestNoPrincipalGetUri.cpp @@ -0,0 +1,31 @@ +class nsIPrincipal { +public: + void GetURI(int foo){}; +}; + +class SomePrincipal : public nsIPrincipal { +public: + void GetURI(int foo) {} +}; + +class NullPrincipal : public SomePrincipal {}; + +class SomeURI { +public: + void GetURI(int foo) {} +}; + +void f() { + nsIPrincipal *a = new SomePrincipal(); + a->GetURI(0); // expected-error {{Principal->GetURI is deprecated and will be removed soon. Please consider using the new helper functions of nsIPrincipal}} + + ::nsIPrincipal *b = new NullPrincipal(); + b->GetURI(0); // expected-error {{Principal->GetURI is deprecated and will be removed soon. Please consider using the new helper functions of nsIPrincipal}} + + SomeURI *c = new SomeURI(); + c->GetURI(0); + + SomePrincipal *d = new SomePrincipal(); + d->GetURI(0); + +} diff --git a/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp b/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp new file mode 100644 index 0000000000..aedc5af096 --- /dev/null +++ b/build/clang-plugin/tests/TestNoRefcountedInsideLambdas.cpp @@ -0,0 +1,682 @@ +#include <mozilla/StaticAnalysisFunctions.h> + +#include <functional> +#define MOZ_STRONG_REF +#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) + +// Ensure that warnings about returning stack addresses of local variables are +// errors, so our `expected-error` annotations below work correctly. +#pragma GCC diagnostic error "-Wreturn-stack-address" + +struct RefCountedBase { + void AddRef(); + void Release(); +}; + +template <class T> +struct SmartPtr { + SmartPtr(); + MOZ_IMPLICIT SmartPtr(T*); + T* MOZ_STRONG_REF t; + T* operator->() const; +}; + +struct R : RefCountedBase { + void method(); +private: + void privateMethod(); +}; + +void take(...); +void foo() { + R* ptr; + SmartPtr<R> sp; + take([&](R* argptr) { + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); + take([&](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + take([&](R* argptr) { + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); + take([&](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + take(sp); + take(argsp); + take(localsp); + }); + take([=](R* argptr) { + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); + take([=](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + take([=](R* argptr) { + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); + take([=](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + take(sp); + take(argsp); + take(localsp); + }); + take([ptr](R* argptr) { + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); + take([sp](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + take([ptr](R* argptr) { + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); + take([sp](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + take(sp); + take(argsp); + take(localsp); + }); + take([&ptr](R* argptr) { + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); + take([&sp](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + take([&ptr](R* argptr) { + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); + take([&sp](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + take(sp); + take(argsp); + take(localsp); + }); +} + +void b() { + R* ptr; + SmartPtr<R> sp; + std::function<void(R*)>([&](R* argptr) { + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); + std::function<void(SmartPtr<R>)>([&](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + std::function<void(R*)>([&](R* argptr) { + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); + std::function<void(SmartPtr<R>)>([&](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + take(sp); + take(argsp); + take(localsp); + }); + std::function<void(R*)>([=](R* argptr) { + R* localptr; + ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + argptr->method(); + localptr->method(); + }); + std::function<void(SmartPtr<R>)>([=](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + std::function<void(R*)>([=](R* argptr) { + R* localptr; + take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + take(argptr); + take(localptr); + }); + std::function<void(SmartPtr<R>)>([=](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + take(sp); + take(argsp); + take(localsp); + }); + std::function<void(R*)>([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); + std::function<void(SmartPtr<R>)>([sp](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + std::function<void(R*)>([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); + std::function<void(SmartPtr<R>)>([sp](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + take(sp); + take(argsp); + take(localsp); + }); + std::function<void(R*)>([&ptr](R* argptr) { + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); + std::function<void(SmartPtr<R>)>([&sp](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + std::function<void(R*)>([&ptr](R* argptr) { + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); + std::function<void(SmartPtr<R>)>([&sp](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + take(sp); + take(argsp); + take(localsp); + }); +} + +// These tests would check c++14 deduced return types, if they were supported in +// our codebase. They are being kept here for convenience in the future if we do +// add support for c++14 deduced return types +#if 0 +auto d1() { + R* ptr; + SmartPtr<R> sp; + return ([&](R* argptr) { + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); +} +auto d2() { + R* ptr; + SmartPtr<R> sp; + return ([&](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); +} +auto d3() { + R* ptr; + SmartPtr<R> sp; + return ([&](R* argptr) { + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); +} +auto d4() { + R* ptr; + SmartPtr<R> sp; + return ([&](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + take(sp); + take(argsp); + take(localsp); + }); +} +auto d5() { + R* ptr; + SmartPtr<R> sp; + return ([=](R* argptr) { + R* localptr; + ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + argptr->method(); + localptr->method(); + }); +} +auto d6() { + R* ptr; + SmartPtr<R> sp; + return ([=](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); +} +auto d8() { + R* ptr; + SmartPtr<R> sp; + return ([=](R* argptr) { + R* localptr; + take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + take(argptr); + take(localptr); + }); +} +auto d9() { + R* ptr; + SmartPtr<R> sp; + return ([=](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + take(sp); + take(argsp); + take(localsp); + }); +} +auto d10() { + R* ptr; + SmartPtr<R> sp; + return ([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); +} +auto d11() { + R* ptr; + SmartPtr<R> sp; + return ([sp](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); +} +auto d12() { + R* ptr; + SmartPtr<R> sp; + return ([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); +} +auto d13() { + R* ptr; + SmartPtr<R> sp; + return ([sp](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + take(sp); + take(argsp); + take(localsp); + }); +} +auto d14() { + R* ptr; + SmartPtr<R> sp; + return ([&ptr](R* argptr) { + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); +} +auto d15() { + R* ptr; + SmartPtr<R> sp; + return ([&sp](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); +} +auto d16() { + R* ptr; + SmartPtr<R> sp; + return ([&ptr](R* argptr) { + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); +} +auto d17() { + R* ptr; + SmartPtr<R> sp; + return ([&sp](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + take(sp); + take(argsp); + take(localsp); + }); +} +#endif + +void e() { + auto e1 = []() { + R* ptr; + SmartPtr<R> sp; + return ([&](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} + R* localptr; +#if __clang_major__ >= 12 + ptr->method(); // expected-note{{implicitly captured by reference due to use here}} +#else + ptr->method(); +#endif + argptr->method(); + localptr->method(); + }); + }; + auto e2 = []() { + R* ptr; + SmartPtr<R> sp; + return ([&](SmartPtr<R> argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} + SmartPtr<R> localsp; +#if __clang_major__ >= 12 + sp->method(); // expected-note{{implicitly captured by reference due to use here}} +#else + sp->method(); +#endif + argsp->method(); + localsp->method(); + }); + }; + auto e3 = []() { + R* ptr; + SmartPtr<R> sp; + return ([&](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} + R* localptr; +#if __clang_major__ >= 12 + take(ptr); // expected-note{{implicitly captured by reference due to use here}} +#else + take(ptr); +#endif + take(argptr); + take(localptr); + }); + }; + auto e4 = []() { + R* ptr; + SmartPtr<R> sp; + return ([&](SmartPtr<R> argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} + SmartPtr<R> localsp; +#if __clang_major__ >= 12 + take(sp); // expected-note{{implicitly captured by reference due to use here}} +#else + take(sp); +#endif + take(argsp); + take(localsp); + }); + }; + auto e5 = []() { + R* ptr; + SmartPtr<R> sp; + return ([=](R* argptr) { + R* localptr; + ptr->method(); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + argptr->method(); + localptr->method(); + }); + }; + auto e6 = []() { + R* ptr; + SmartPtr<R> sp; + return ([=](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + }; + auto e8 = []() { + R* ptr; + SmartPtr<R> sp; + return ([=](R* argptr) { + R* localptr; + take(ptr); // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + take(argptr); + take(localptr); + }); + }; + auto e9 = []() { + R* ptr; + SmartPtr<R> sp; + return ([=](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + take(sp); + take(argsp); + take(localsp); + }); + }; + auto e10 = []() { + R* ptr; + SmartPtr<R> sp; + return ([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); + }; + auto e11 = []() { + R* ptr; + SmartPtr<R> sp; + return ([sp](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); + }; + auto e12 = []() { + R* ptr; + SmartPtr<R> sp; + return ([ptr](R* argptr) { // expected-error{{Refcounted variable 'ptr' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); + }; + auto e13 = []() { + R* ptr; + SmartPtr<R> sp; + return ([sp](SmartPtr<R> argsp) { + SmartPtr<R> localsp; + take(sp); + take(argsp); + take(localsp); + }); + }; + auto e14 = []() { + R* ptr; + SmartPtr<R> sp; +#if __clang_major__ >= 12 + return ([&ptr](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} expected-note{{captured by reference here}} + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); +#else + return ([&ptr](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} + R* localptr; + ptr->method(); + argptr->method(); + localptr->method(); + }); +#endif + }; + auto e15 = []() { + R* ptr; + SmartPtr<R> sp; +#if __clang_major__ >= 12 + return ([&sp](SmartPtr<R> argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} expected-note{{captured by reference here}} + SmartPtr<R> localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); +#else + return ([&sp](SmartPtr<R> argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} + SmartPtr<R> localsp; + sp->method(); + argsp->method(); + localsp->method(); + }); +#endif + }; + auto e16 = []() { + R* ptr; + SmartPtr<R> sp; +#if __clang_major__ >= 12 + return ([&ptr](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} expected-note{{captured by reference here}} + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); +#else + return ([&ptr](R* argptr) { // expected-error{{address of stack memory associated with local variable 'ptr' returned}} + R* localptr; + take(ptr); + take(argptr); + take(localptr); + }); +#endif + }; + auto e17 = []() { + R* ptr; + SmartPtr<R> sp; +#if __clang_major__ >= 12 + return ([&sp](SmartPtr<R> argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} expected-note{{captured by reference here}} + SmartPtr<R> localsp; + take(sp); + take(argsp); + take(localsp); + }); +#else + return ([&sp](SmartPtr<R> argsp) { // expected-error{{address of stack memory associated with local variable 'sp' returned}} + SmartPtr<R> localsp; + take(sp); + take(argsp); + take(localsp); + }); +#endif + }; +} + +void +R::privateMethod() { + SmartPtr<R> self = this; + std::function<void()>([&]() { + self->method(); + }); + std::function<void()>([&]() { + self->privateMethod(); + }); + std::function<void()>([&]() { + this->method(); + }); + std::function<void()>([&]() { + this->privateMethod(); + }); + std::function<void()>([=]() { + self->method(); + }); + std::function<void()>([=]() { + self->privateMethod(); + }); + std::function<void()>([=]() { + this->method(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + }); + std::function<void()>([=]() { + this->privateMethod(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + }); + std::function<void()>([self]() { + self->method(); + }); + std::function<void()>([self]() { + self->privateMethod(); + }); + std::function<void()>([this]() { + this->method(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + }); + std::function<void()>([this]() { + this->privateMethod(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + }); + std::function<void()>([this]() { + method(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + }); + std::function<void()>([this]() { + privateMethod(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + }); + std::function<void()>([=]() { + method(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + }); + std::function<void()>([=]() { + privateMethod(); // expected-error{{Refcounted variable 'this' of type 'R' cannot be captured by a lambda}} expected-note{{Please consider using a smart pointer}} + }); + std::function<void()>([&]() { + method(); + }); + std::function<void()>([&]() { + privateMethod(); + }); + + std::function<void()>( + [instance = MOZ_KnownLive(this)]() { instance->privateMethod(); }); + + // It should be OK to go through `this` if we have captured a reference to it. + std::function<void()>([this, self]() { + this->method(); + this->privateMethod(); + method(); + privateMethod(); + }); +} diff --git a/build/clang-plugin/tests/TestNoUsingNamespaceMozillaJava.cpp b/build/clang-plugin/tests/TestNoUsingNamespaceMozillaJava.cpp new file mode 100644 index 0000000000..70cfbe1827 --- /dev/null +++ b/build/clang-plugin/tests/TestNoUsingNamespaceMozillaJava.cpp @@ -0,0 +1,29 @@ +namespace mozilla { +namespace java { +namespace sdk { +} // namespace sdk + +namespace future { +} // namespace future +} // namespace java +} // namespace mozilla + +namespace mozilla { + using namespace java; // expected-error{{using namespace mozilla::java is forbidden}} + using namespace java::future; // expected-error{{using namespace mozilla::java::future is forbidden}} +} + +using namespace mozilla::java::sdk; // expected-error{{using namespace mozilla::java::sdk is forbidden}} + +namespace shouldPass { + namespace java { + } + + using namespace java; +} + +using namespace shouldPass::java; + + +void test() { +} diff --git a/build/clang-plugin/tests/TestNonHeapClass.cpp b/build/clang-plugin/tests/TestNonHeapClass.cpp new file mode 100644 index 0000000000..26fe6404e0 --- /dev/null +++ b/build/clang-plugin/tests/TestNonHeapClass.cpp @@ -0,0 +1,62 @@ +#define MOZ_NONHEAP_CLASS __attribute__((annotate("moz_nonheap_class"))) +#define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class"))) +#include <stddef.h> + +struct MOZ_NONHEAP_CLASS NonHeap { + int i; + void *operator new(size_t x) throw() { return 0; } + void *operator new(size_t blah, char *buffer) { return buffer; } +}; + +template <class T> +struct MOZ_NONHEAP_CLASS TemplateClass { + T i; +}; + +void gobble(void *) { } + +void misuseNonHeapClass(int len) { + NonHeap valid; + NonHeap alsoValid[2]; + static NonHeap validStatic; + static NonHeap alsoValidStatic[2]; + + gobble(&valid); + gobble(&validStatic); + gobble(&alsoValid[0]); + + gobble(new NonHeap); // expected-error {{variable of type 'NonHeap' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} + gobble(new NonHeap[10]); // expected-error {{variable of type 'NonHeap' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} + gobble(new TemplateClass<int>); // expected-error {{variable of type 'TemplateClass<int>' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} + gobble(len <= 5 ? &valid : new NonHeap); // expected-error {{variable of type 'NonHeap' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} + + char buffer[sizeof(NonHeap)]; + gobble(new (buffer) NonHeap); +} + +NonHeap validStatic; +struct RandomClass { + NonHeap nonstaticMember; // expected-note {{'RandomClass' is a non-heap type because member 'nonstaticMember' is a non-heap type 'NonHeap'}} + static NonHeap staticMember; +}; +struct MOZ_NONHEAP_CLASS RandomNonHeapClass { + NonHeap nonstaticMember; + static NonHeap staticMember; +}; + +struct BadInherit : NonHeap {}; // expected-note {{'BadInherit' is a non-heap type because it inherits from a non-heap type 'NonHeap'}} +struct MOZ_NONHEAP_CLASS GoodInherit : NonHeap {}; + +void useStuffWrongly() { + gobble(new BadInherit); // expected-error {{variable of type 'BadInherit' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} + gobble(new RandomClass); // expected-error {{variable of type 'RandomClass' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} +} + +// Stack class overrides non-heap typees. +struct MOZ_STACK_CLASS StackClass {}; +struct MOZ_NONHEAP_CLASS InferredStackClass : GoodInherit { + NonHeap nonstaticMember; + StackClass stackClass; // expected-note {{'InferredStackClass' is a stack type because member 'stackClass' is a stack type 'StackClass'}} +}; + +InferredStackClass global; // expected-error {{variable of type 'InferredStackClass' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} diff --git a/build/clang-plugin/tests/TestNonMemMovable.cpp b/build/clang-plugin/tests/TestNonMemMovable.cpp new file mode 100644 index 0000000000..dfbb5a6c65 --- /dev/null +++ b/build/clang-plugin/tests/TestNonMemMovable.cpp @@ -0,0 +1,830 @@ +#define MOZ_NON_MEMMOVABLE __attribute__((annotate("moz_non_memmovable"))) +#define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type"))) +#define MOZ_NEEDS_MEMMOVABLE_MEMBERS __attribute__((annotate("moz_needs_memmovable_members"))) + +/* + These are a bunch of structs with variable levels of memmovability. + They will be used as template parameters to the various NeedyTemplates +*/ +struct MOZ_NON_MEMMOVABLE NonMovable {}; +struct Movable {}; + +// Subclasses +struct S_NonMovable : NonMovable {}; // expected-note 51 {{'S_NonMovable' is a non-memmove()able type because it inherits from a non-memmove()able type 'NonMovable'}} +struct S_Movable : Movable {}; + +// Members +struct W_NonMovable { + NonMovable m; // expected-note 34 {{'W_NonMovable' is a non-memmove()able type because member 'm' is a non-memmove()able type 'NonMovable'}} +}; +struct W_Movable { + Movable m; +}; + +// Wrapped Subclasses +struct WS_NonMovable { + S_NonMovable m; // expected-note 34 {{'WS_NonMovable' is a non-memmove()able type because member 'm' is a non-memmove()able type 'S_NonMovable'}} +}; +struct WS_Movable { + S_Movable m; +}; + +// Combinations of the above +struct SW_NonMovable : W_NonMovable {}; // expected-note 17 {{'SW_NonMovable' is a non-memmove()able type because it inherits from a non-memmove()able type 'W_NonMovable'}} +struct SW_Movable : W_Movable {}; + +struct SWS_NonMovable : WS_NonMovable {}; // expected-note 17 {{'SWS_NonMovable' is a non-memmove()able type because it inherits from a non-memmove()able type 'WS_NonMovable'}} +struct SWS_Movable : WS_Movable {}; + +// Basic templated wrapper +template <class T> +struct Template_Inline { + T m; // expected-note-re 56 {{'Template_Inline<{{.*}}>' is a non-memmove()able type because member 'm' is a non-memmove()able type '{{.*}}'}} +}; + +template <class T> +struct Template_Ref { + T* m; +}; + +template <class T> +struct Template_Unused {}; + +template <class T> +struct MOZ_NON_MEMMOVABLE Template_NonMovable {}; + +/* + These tests take the following form: + DECLARATIONS => Declarations of the templates which are either marked with MOZ_NEEDS_MEMMOVABLE_TYPE + or which instantiate a MOZ_NEEDS_MEMMOVABLE_TYPE through some mechanism. + BAD N => Instantiations of the wrapper template with each of the non-memmovable types. + The prefix S_ means subclass, W_ means wrapped. Each of these rows should produce an error + on the NeedyTemplate in question, and a note at the instantiation location of that template. + Unfortunately, on every case more complicated than bad1, the instantiation location is + within another template. Thus, the notes are expected on the template in question which + actually instantiates the MOZ_NEEDS_MEMMOVABLE_TYPE template. + GOOD N => Instantiations of the wrapper template with each of the memmovable types. + This is meant as a sanity check to ensure that we don't reject valid instantiations of + templates. + + + Note 1: Each set uses it's own types to ensure that they don't re-use each-other's template specializations. + If they did, then some of the error messages would not be emitted (as error messages are emitted for template + specializations, rather than for variable declarations) + + Note 2: Every instance of NeedyTemplate contains a member of type T. This is to ensure that T is actually + instantiated (if T is a template) by clang. If T isn't instantiated, then we can't actually tell if it is + NON_MEMMOVABLE. (This is OK in practice, as you cannot memmove a type which you don't know the size of). + + Note 3: There are a set of tests for specializations of NeedyTemplate at the bottom. For each set of tests, + these tests contribute two expected errors to the templates. +*/ + +// +// 1 - Unwrapped MOZ_NEEDS_MEMMOVABLE_TYPE +// + +template <class T> +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate1 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate1<{{.*}}>' with non-memmovable template argument '{{.*}}'}} + +void bad1() { + NeedyTemplate1<NonMovable> a1; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<S_NonMovable> a2; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<W_NonMovable> a3; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<WS_NonMovable> a4; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<SW_NonMovable> a5; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<SWS_NonMovable> a6; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + + NeedyTemplate1<Template_Inline<NonMovable> > b1; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<Template_Inline<S_NonMovable> > b2; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<Template_Inline<W_NonMovable> > b3; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<Template_Inline<WS_NonMovable> > b4; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<Template_Inline<SW_NonMovable> > b5; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<Template_Inline<SWS_NonMovable> > b6; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + + NeedyTemplate1<Template_NonMovable<NonMovable> > c1; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<Template_NonMovable<S_NonMovable> > c2; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<Template_NonMovable<W_NonMovable> > c3; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<Template_NonMovable<WS_NonMovable> > c4; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<Template_NonMovable<SW_NonMovable> > c5; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<Template_NonMovable<SWS_NonMovable> > c6; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<Template_NonMovable<Movable> > c7; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<Template_NonMovable<S_Movable> > c8; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<Template_NonMovable<W_Movable> > c9; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<Template_NonMovable<WS_Movable> > c10; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<Template_NonMovable<SW_Movable> > c11; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} + NeedyTemplate1<Template_NonMovable<SWS_Movable> > c12; // expected-note-re {{instantiation of 'NeedyTemplate1<{{.*}}>' requested here}} +} + +void good1() { + NeedyTemplate1<Movable> a1; + NeedyTemplate1<S_Movable> a2; + NeedyTemplate1<W_Movable> a3; + NeedyTemplate1<WS_Movable> a4; + NeedyTemplate1<SW_Movable> a5; + NeedyTemplate1<SWS_Movable> a6; + + NeedyTemplate1<Template_Inline<Movable> > b1; + NeedyTemplate1<Template_Inline<S_Movable> > b2; + NeedyTemplate1<Template_Inline<W_Movable> > b3; + NeedyTemplate1<Template_Inline<WS_Movable> > b4; + NeedyTemplate1<Template_Inline<SW_Movable> > b5; + NeedyTemplate1<Template_Inline<SWS_Movable> > b6; + + NeedyTemplate1<Template_Unused<Movable> > c1; + NeedyTemplate1<Template_Unused<S_Movable> > c2; + NeedyTemplate1<Template_Unused<W_Movable> > c3; + NeedyTemplate1<Template_Unused<WS_Movable> > c4; + NeedyTemplate1<Template_Unused<SW_Movable> > c5; + NeedyTemplate1<Template_Unused<SWS_Movable> > c6; + NeedyTemplate1<Template_Unused<NonMovable> > c7; + NeedyTemplate1<Template_Unused<S_NonMovable> > c8; + NeedyTemplate1<Template_Unused<W_NonMovable> > c9; + NeedyTemplate1<Template_Unused<WS_NonMovable> > c10; + NeedyTemplate1<Template_Unused<SW_NonMovable> > c11; + NeedyTemplate1<Template_Unused<SWS_NonMovable> > c12; + + NeedyTemplate1<Template_Ref<Movable> > d1; + NeedyTemplate1<Template_Ref<S_Movable> > d2; + NeedyTemplate1<Template_Ref<W_Movable> > d3; + NeedyTemplate1<Template_Ref<WS_Movable> > d4; + NeedyTemplate1<Template_Ref<SW_Movable> > d5; + NeedyTemplate1<Template_Ref<SWS_Movable> > d6; + NeedyTemplate1<Template_Ref<NonMovable> > d7; + NeedyTemplate1<Template_Ref<S_NonMovable> > d8; + NeedyTemplate1<Template_Ref<W_NonMovable> > d9; + NeedyTemplate1<Template_Ref<WS_NonMovable> > d10; + NeedyTemplate1<Template_Ref<SW_NonMovable> > d11; + NeedyTemplate1<Template_Ref<SWS_NonMovable> > d12; +} + +// +// 2 - Subclassed MOZ_NEEDS_MEMMOVABLE_TYPE +// + +template <class T> +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate2 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate2<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template <class T> +struct S_NeedyTemplate2 : NeedyTemplate2<T> {}; // expected-note-re 26 {{instantiation of 'NeedyTemplate2<{{.*}}>' requested here}} + +void bad2() { + S_NeedyTemplate2<NonMovable> a1; + S_NeedyTemplate2<S_NonMovable> a2; + S_NeedyTemplate2<W_NonMovable> a3; + S_NeedyTemplate2<WS_NonMovable> a4; + S_NeedyTemplate2<SW_NonMovable> a5; + S_NeedyTemplate2<SWS_NonMovable> a6; + + S_NeedyTemplate2<Template_Inline<NonMovable> > b1; + S_NeedyTemplate2<Template_Inline<S_NonMovable> > b2; + S_NeedyTemplate2<Template_Inline<W_NonMovable> > b3; + S_NeedyTemplate2<Template_Inline<WS_NonMovable> > b4; + S_NeedyTemplate2<Template_Inline<SW_NonMovable> > b5; + S_NeedyTemplate2<Template_Inline<SWS_NonMovable> > b6; + + S_NeedyTemplate2<Template_NonMovable<NonMovable> > c1; + S_NeedyTemplate2<Template_NonMovable<S_NonMovable> > c2; + S_NeedyTemplate2<Template_NonMovable<W_NonMovable> > c3; + S_NeedyTemplate2<Template_NonMovable<WS_NonMovable> > c4; + S_NeedyTemplate2<Template_NonMovable<SW_NonMovable> > c5; + S_NeedyTemplate2<Template_NonMovable<SWS_NonMovable> > c6; + S_NeedyTemplate2<Template_NonMovable<Movable> > c7; + S_NeedyTemplate2<Template_NonMovable<S_Movable> > c8; + S_NeedyTemplate2<Template_NonMovable<W_Movable> > c9; + S_NeedyTemplate2<Template_NonMovable<WS_Movable> > c10; + S_NeedyTemplate2<Template_NonMovable<SW_Movable> > c11; + S_NeedyTemplate2<Template_NonMovable<SWS_Movable> > c12; +} + +void good2() { + S_NeedyTemplate2<Movable> a1; + S_NeedyTemplate2<S_Movable> a2; + S_NeedyTemplate2<W_Movable> a3; + S_NeedyTemplate2<WS_Movable> a4; + S_NeedyTemplate2<SW_Movable> a5; + S_NeedyTemplate2<SWS_Movable> a6; + + S_NeedyTemplate2<Template_Inline<Movable> > b1; + S_NeedyTemplate2<Template_Inline<S_Movable> > b2; + S_NeedyTemplate2<Template_Inline<W_Movable> > b3; + S_NeedyTemplate2<Template_Inline<WS_Movable> > b4; + S_NeedyTemplate2<Template_Inline<SW_Movable> > b5; + S_NeedyTemplate2<Template_Inline<SWS_Movable> > b6; + + S_NeedyTemplate2<Template_Unused<Movable> > c1; + S_NeedyTemplate2<Template_Unused<S_Movable> > c2; + S_NeedyTemplate2<Template_Unused<W_Movable> > c3; + S_NeedyTemplate2<Template_Unused<WS_Movable> > c4; + S_NeedyTemplate2<Template_Unused<SW_Movable> > c5; + S_NeedyTemplate2<Template_Unused<SWS_Movable> > c6; + S_NeedyTemplate2<Template_Unused<NonMovable> > c7; + S_NeedyTemplate2<Template_Unused<S_NonMovable> > c8; + S_NeedyTemplate2<Template_Unused<W_NonMovable> > c9; + S_NeedyTemplate2<Template_Unused<WS_NonMovable> > c10; + S_NeedyTemplate2<Template_Unused<SW_NonMovable> > c11; + S_NeedyTemplate2<Template_Unused<SWS_NonMovable> > c12; + + S_NeedyTemplate2<Template_Ref<Movable> > d1; + S_NeedyTemplate2<Template_Ref<S_Movable> > d2; + S_NeedyTemplate2<Template_Ref<W_Movable> > d3; + S_NeedyTemplate2<Template_Ref<WS_Movable> > d4; + S_NeedyTemplate2<Template_Ref<SW_Movable> > d5; + S_NeedyTemplate2<Template_Ref<SWS_Movable> > d6; + S_NeedyTemplate2<Template_Ref<NonMovable> > d7; + S_NeedyTemplate2<Template_Ref<S_NonMovable> > d8; + S_NeedyTemplate2<Template_Ref<W_NonMovable> > d9; + S_NeedyTemplate2<Template_Ref<WS_NonMovable> > d10; + S_NeedyTemplate2<Template_Ref<SW_NonMovable> > d11; + S_NeedyTemplate2<Template_Ref<SWS_NonMovable> > d12; +} + +// +// 3 - Wrapped MOZ_NEEDS_MEMMOVABLE_TYPE +// + +template <class T> +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate3 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate3<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template <class T> +struct W_NeedyTemplate3 { + NeedyTemplate3<T> m; // expected-note-re 26 {{instantiation of 'NeedyTemplate3<{{.*}}>' requested here}} +}; +void bad3() { + W_NeedyTemplate3<NonMovable> a1; + W_NeedyTemplate3<S_NonMovable> a2; + W_NeedyTemplate3<W_NonMovable> a3; + W_NeedyTemplate3<WS_NonMovable> a4; + W_NeedyTemplate3<SW_NonMovable> a5; + W_NeedyTemplate3<SWS_NonMovable> a6; + + W_NeedyTemplate3<Template_Inline<NonMovable> > b1; + W_NeedyTemplate3<Template_Inline<S_NonMovable> > b2; + W_NeedyTemplate3<Template_Inline<W_NonMovable> > b3; + W_NeedyTemplate3<Template_Inline<WS_NonMovable> > b4; + W_NeedyTemplate3<Template_Inline<SW_NonMovable> > b5; + W_NeedyTemplate3<Template_Inline<SWS_NonMovable> > b6; + + W_NeedyTemplate3<Template_NonMovable<NonMovable> > c1; + W_NeedyTemplate3<Template_NonMovable<S_NonMovable> > c2; + W_NeedyTemplate3<Template_NonMovable<W_NonMovable> > c3; + W_NeedyTemplate3<Template_NonMovable<WS_NonMovable> > c4; + W_NeedyTemplate3<Template_NonMovable<SW_NonMovable> > c5; + W_NeedyTemplate3<Template_NonMovable<SWS_NonMovable> > c6; + W_NeedyTemplate3<Template_NonMovable<Movable> > c7; + W_NeedyTemplate3<Template_NonMovable<S_Movable> > c8; + W_NeedyTemplate3<Template_NonMovable<W_Movable> > c9; + W_NeedyTemplate3<Template_NonMovable<WS_Movable> > c10; + W_NeedyTemplate3<Template_NonMovable<SW_Movable> > c11; + W_NeedyTemplate3<Template_NonMovable<SWS_Movable> > c12; +} + +void good3() { + W_NeedyTemplate3<Movable> a1; + W_NeedyTemplate3<S_Movable> a2; + W_NeedyTemplate3<W_Movable> a3; + W_NeedyTemplate3<WS_Movable> a4; + W_NeedyTemplate3<SW_Movable> a5; + W_NeedyTemplate3<SWS_Movable> a6; + + W_NeedyTemplate3<Template_Inline<Movable> > b1; + W_NeedyTemplate3<Template_Inline<S_Movable> > b2; + W_NeedyTemplate3<Template_Inline<W_Movable> > b3; + W_NeedyTemplate3<Template_Inline<WS_Movable> > b4; + W_NeedyTemplate3<Template_Inline<SW_Movable> > b5; + W_NeedyTemplate3<Template_Inline<SWS_Movable> > b6; + + W_NeedyTemplate3<Template_Unused<Movable> > c1; + W_NeedyTemplate3<Template_Unused<S_Movable> > c2; + W_NeedyTemplate3<Template_Unused<W_Movable> > c3; + W_NeedyTemplate3<Template_Unused<WS_Movable> > c4; + W_NeedyTemplate3<Template_Unused<SW_Movable> > c5; + W_NeedyTemplate3<Template_Unused<SWS_Movable> > c6; + W_NeedyTemplate3<Template_Unused<NonMovable> > c7; + W_NeedyTemplate3<Template_Unused<S_NonMovable> > c8; + W_NeedyTemplate3<Template_Unused<W_NonMovable> > c9; + W_NeedyTemplate3<Template_Unused<WS_NonMovable> > c10; + W_NeedyTemplate3<Template_Unused<SW_NonMovable> > c11; + W_NeedyTemplate3<Template_Unused<SWS_NonMovable> > c12; + + W_NeedyTemplate3<Template_Ref<Movable> > d1; + W_NeedyTemplate3<Template_Ref<S_Movable> > d2; + W_NeedyTemplate3<Template_Ref<W_Movable> > d3; + W_NeedyTemplate3<Template_Ref<WS_Movable> > d4; + W_NeedyTemplate3<Template_Ref<SW_Movable> > d5; + W_NeedyTemplate3<Template_Ref<SWS_Movable> > d6; + W_NeedyTemplate3<Template_Ref<NonMovable> > d7; + W_NeedyTemplate3<Template_Ref<S_NonMovable> > d8; + W_NeedyTemplate3<Template_Ref<W_NonMovable> > d9; + W_NeedyTemplate3<Template_Ref<WS_NonMovable> > d10; + W_NeedyTemplate3<Template_Ref<SW_NonMovable> > d11; + W_NeedyTemplate3<Template_Ref<SWS_NonMovable> > d12; +} + +// +// 4 - Wrapped Subclassed MOZ_NEEDS_MEMMOVABLE_TYPE +// + +template <class T> +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate4 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate4<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template <class T> +struct S_NeedyTemplate4 : NeedyTemplate4<T> {}; // expected-note-re 26 {{instantiation of 'NeedyTemplate4<{{.*}}>' requested here}} +template <class T> +struct WS_NeedyTemplate4 { + S_NeedyTemplate4<T> m; +}; +void bad4() { + WS_NeedyTemplate4<NonMovable> a1; + WS_NeedyTemplate4<S_NonMovable> a2; + WS_NeedyTemplate4<W_NonMovable> a3; + WS_NeedyTemplate4<WS_NonMovable> a4; + WS_NeedyTemplate4<SW_NonMovable> a5; + WS_NeedyTemplate4<SWS_NonMovable> a6; + + WS_NeedyTemplate4<Template_Inline<NonMovable> > b1; + WS_NeedyTemplate4<Template_Inline<S_NonMovable> > b2; + WS_NeedyTemplate4<Template_Inline<W_NonMovable> > b3; + WS_NeedyTemplate4<Template_Inline<WS_NonMovable> > b4; + WS_NeedyTemplate4<Template_Inline<SW_NonMovable> > b5; + WS_NeedyTemplate4<Template_Inline<SWS_NonMovable> > b6; + + WS_NeedyTemplate4<Template_NonMovable<NonMovable> > c1; + WS_NeedyTemplate4<Template_NonMovable<S_NonMovable> > c2; + WS_NeedyTemplate4<Template_NonMovable<W_NonMovable> > c3; + WS_NeedyTemplate4<Template_NonMovable<WS_NonMovable> > c4; + WS_NeedyTemplate4<Template_NonMovable<SW_NonMovable> > c5; + WS_NeedyTemplate4<Template_NonMovable<SWS_NonMovable> > c6; + WS_NeedyTemplate4<Template_NonMovable<Movable> > c7; + WS_NeedyTemplate4<Template_NonMovable<S_Movable> > c8; + WS_NeedyTemplate4<Template_NonMovable<W_Movable> > c9; + WS_NeedyTemplate4<Template_NonMovable<WS_Movable> > c10; + WS_NeedyTemplate4<Template_NonMovable<SW_Movable> > c11; + WS_NeedyTemplate4<Template_NonMovable<SWS_Movable> > c12; +} + +void good4() { + WS_NeedyTemplate4<Movable> a1; + WS_NeedyTemplate4<S_Movable> a2; + WS_NeedyTemplate4<W_Movable> a3; + WS_NeedyTemplate4<WS_Movable> a4; + WS_NeedyTemplate4<SW_Movable> a5; + WS_NeedyTemplate4<SWS_Movable> a6; + + WS_NeedyTemplate4<Template_Inline<Movable> > b1; + WS_NeedyTemplate4<Template_Inline<S_Movable> > b2; + WS_NeedyTemplate4<Template_Inline<W_Movable> > b3; + WS_NeedyTemplate4<Template_Inline<WS_Movable> > b4; + WS_NeedyTemplate4<Template_Inline<SW_Movable> > b5; + WS_NeedyTemplate4<Template_Inline<SWS_Movable> > b6; + + WS_NeedyTemplate4<Template_Unused<Movable> > c1; + WS_NeedyTemplate4<Template_Unused<S_Movable> > c2; + WS_NeedyTemplate4<Template_Unused<W_Movable> > c3; + WS_NeedyTemplate4<Template_Unused<WS_Movable> > c4; + WS_NeedyTemplate4<Template_Unused<SW_Movable> > c5; + WS_NeedyTemplate4<Template_Unused<SWS_Movable> > c6; + WS_NeedyTemplate4<Template_Unused<NonMovable> > c7; + WS_NeedyTemplate4<Template_Unused<S_NonMovable> > c8; + WS_NeedyTemplate4<Template_Unused<W_NonMovable> > c9; + WS_NeedyTemplate4<Template_Unused<WS_NonMovable> > c10; + WS_NeedyTemplate4<Template_Unused<SW_NonMovable> > c11; + WS_NeedyTemplate4<Template_Unused<SWS_NonMovable> > c12; + + WS_NeedyTemplate4<Template_Ref<Movable> > d1; + WS_NeedyTemplate4<Template_Ref<S_Movable> > d2; + WS_NeedyTemplate4<Template_Ref<W_Movable> > d3; + WS_NeedyTemplate4<Template_Ref<WS_Movable> > d4; + WS_NeedyTemplate4<Template_Ref<SW_Movable> > d5; + WS_NeedyTemplate4<Template_Ref<SWS_Movable> > d6; + WS_NeedyTemplate4<Template_Ref<NonMovable> > d7; + WS_NeedyTemplate4<Template_Ref<S_NonMovable> > d8; + WS_NeedyTemplate4<Template_Ref<W_NonMovable> > d9; + WS_NeedyTemplate4<Template_Ref<WS_NonMovable> > d10; + WS_NeedyTemplate4<Template_Ref<SW_NonMovable> > d11; + WS_NeedyTemplate4<Template_Ref<SWS_NonMovable> > d12; +} + +// +// 5 - Subclassed Wrapped MOZ_NEEDS_MEMMOVABLE_TYPE +// + +template <class T> +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate5 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate5<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template <class T> +struct W_NeedyTemplate5 { + NeedyTemplate5<T> m; // expected-note-re 26 {{instantiation of 'NeedyTemplate5<{{.*}}>' requested here}} +}; +template <class T> +struct SW_NeedyTemplate5 : W_NeedyTemplate5<T> {}; +void bad5() { + SW_NeedyTemplate5<NonMovable> a1; + SW_NeedyTemplate5<S_NonMovable> a2; + SW_NeedyTemplate5<W_NonMovable> a3; + SW_NeedyTemplate5<WS_NonMovable> a4; + SW_NeedyTemplate5<SW_NonMovable> a5; + SW_NeedyTemplate5<SWS_NonMovable> a6; + + SW_NeedyTemplate5<Template_Inline<NonMovable> > b1; + SW_NeedyTemplate5<Template_Inline<S_NonMovable> > b2; + SW_NeedyTemplate5<Template_Inline<W_NonMovable> > b3; + SW_NeedyTemplate5<Template_Inline<WS_NonMovable> > b4; + SW_NeedyTemplate5<Template_Inline<SW_NonMovable> > b5; + SW_NeedyTemplate5<Template_Inline<SWS_NonMovable> > b6; + + SW_NeedyTemplate5<Template_NonMovable<NonMovable> > c1; + SW_NeedyTemplate5<Template_NonMovable<S_NonMovable> > c2; + SW_NeedyTemplate5<Template_NonMovable<W_NonMovable> > c3; + SW_NeedyTemplate5<Template_NonMovable<WS_NonMovable> > c4; + SW_NeedyTemplate5<Template_NonMovable<SW_NonMovable> > c5; + SW_NeedyTemplate5<Template_NonMovable<SWS_NonMovable> > c6; + SW_NeedyTemplate5<Template_NonMovable<Movable> > c7; + SW_NeedyTemplate5<Template_NonMovable<S_Movable> > c8; + SW_NeedyTemplate5<Template_NonMovable<W_Movable> > c9; + SW_NeedyTemplate5<Template_NonMovable<WS_Movable> > c10; + SW_NeedyTemplate5<Template_NonMovable<SW_Movable> > c11; + SW_NeedyTemplate5<Template_NonMovable<SWS_Movable> > c12; +} + +void good5() { + SW_NeedyTemplate5<Movable> a1; + SW_NeedyTemplate5<S_Movable> a2; + SW_NeedyTemplate5<W_Movable> a3; + SW_NeedyTemplate5<WS_Movable> a4; + SW_NeedyTemplate5<SW_Movable> a5; + SW_NeedyTemplate5<SWS_Movable> a6; + + SW_NeedyTemplate5<Template_Inline<Movable> > b1; + SW_NeedyTemplate5<Template_Inline<S_Movable> > b2; + SW_NeedyTemplate5<Template_Inline<W_Movable> > b3; + SW_NeedyTemplate5<Template_Inline<WS_Movable> > b4; + SW_NeedyTemplate5<Template_Inline<SW_Movable> > b5; + SW_NeedyTemplate5<Template_Inline<SWS_Movable> > b6; + + SW_NeedyTemplate5<Template_Unused<Movable> > c1; + SW_NeedyTemplate5<Template_Unused<S_Movable> > c2; + SW_NeedyTemplate5<Template_Unused<W_Movable> > c3; + SW_NeedyTemplate5<Template_Unused<WS_Movable> > c4; + SW_NeedyTemplate5<Template_Unused<SW_Movable> > c5; + SW_NeedyTemplate5<Template_Unused<SWS_Movable> > c6; + SW_NeedyTemplate5<Template_Unused<NonMovable> > c7; + SW_NeedyTemplate5<Template_Unused<S_NonMovable> > c8; + SW_NeedyTemplate5<Template_Unused<W_NonMovable> > c9; + SW_NeedyTemplate5<Template_Unused<WS_NonMovable> > c10; + SW_NeedyTemplate5<Template_Unused<SW_NonMovable> > c11; + SW_NeedyTemplate5<Template_Unused<SWS_NonMovable> > c12; + + SW_NeedyTemplate5<Template_Ref<Movable> > d1; + SW_NeedyTemplate5<Template_Ref<S_Movable> > d2; + SW_NeedyTemplate5<Template_Ref<W_Movable> > d3; + SW_NeedyTemplate5<Template_Ref<WS_Movable> > d4; + SW_NeedyTemplate5<Template_Ref<SW_Movable> > d5; + SW_NeedyTemplate5<Template_Ref<SWS_Movable> > d6; + SW_NeedyTemplate5<Template_Ref<NonMovable> > d7; + SW_NeedyTemplate5<Template_Ref<S_NonMovable> > d8; + SW_NeedyTemplate5<Template_Ref<W_NonMovable> > d9; + SW_NeedyTemplate5<Template_Ref<WS_NonMovable> > d10; + SW_NeedyTemplate5<Template_Ref<SW_NonMovable> > d11; + SW_NeedyTemplate5<Template_Ref<SWS_NonMovable> > d12; +} + +// +// 6 - MOZ_NEEDS_MEMMOVABLE_TYPE instantiated with default template argument +// +// Note: This has an extra error, because it also includes a test with the default template argument. +// + +template <class T> +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate6 {T m;}; // expected-error-re 27 {{Cannot instantiate 'NeedyTemplate6<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template <class T> +struct W_NeedyTemplate6 { + NeedyTemplate6<T> m; // expected-note-re 27 {{instantiation of 'NeedyTemplate6<{{.*}}>' requested here}} +}; +template <class T> +struct SW_NeedyTemplate6 : W_NeedyTemplate6<T> {}; +// We create a different NonMovable type here, as NeedyTemplate6 will already be instantiated with NonMovable +struct MOZ_NON_MEMMOVABLE NonMovable2 {}; +template <class T = NonMovable2> +struct Defaulted_SW_NeedyTemplate6 { + SW_NeedyTemplate6<T> m; +}; +void bad6() { + Defaulted_SW_NeedyTemplate6<NonMovable> a1; + Defaulted_SW_NeedyTemplate6<S_NonMovable> a2; + Defaulted_SW_NeedyTemplate6<W_NonMovable> a3; + Defaulted_SW_NeedyTemplate6<WS_NonMovable> a4; + Defaulted_SW_NeedyTemplate6<SW_NonMovable> a5; + Defaulted_SW_NeedyTemplate6<SWS_NonMovable> a6; + + Defaulted_SW_NeedyTemplate6<Template_Inline<NonMovable> > b1; + Defaulted_SW_NeedyTemplate6<Template_Inline<S_NonMovable> > b2; + Defaulted_SW_NeedyTemplate6<Template_Inline<W_NonMovable> > b3; + Defaulted_SW_NeedyTemplate6<Template_Inline<WS_NonMovable> > b4; + Defaulted_SW_NeedyTemplate6<Template_Inline<SW_NonMovable> > b5; + Defaulted_SW_NeedyTemplate6<Template_Inline<SWS_NonMovable> > b6; + + Defaulted_SW_NeedyTemplate6<Template_NonMovable<NonMovable> > c1; + Defaulted_SW_NeedyTemplate6<Template_NonMovable<S_NonMovable> > c2; + Defaulted_SW_NeedyTemplate6<Template_NonMovable<W_NonMovable> > c3; + Defaulted_SW_NeedyTemplate6<Template_NonMovable<WS_NonMovable> > c4; + Defaulted_SW_NeedyTemplate6<Template_NonMovable<SW_NonMovable> > c5; + Defaulted_SW_NeedyTemplate6<Template_NonMovable<SWS_NonMovable> > c6; + Defaulted_SW_NeedyTemplate6<Template_NonMovable<Movable> > c7; + Defaulted_SW_NeedyTemplate6<Template_NonMovable<S_Movable> > c8; + Defaulted_SW_NeedyTemplate6<Template_NonMovable<W_Movable> > c9; + Defaulted_SW_NeedyTemplate6<Template_NonMovable<WS_Movable> > c10; + Defaulted_SW_NeedyTemplate6<Template_NonMovable<SW_Movable> > c11; + Defaulted_SW_NeedyTemplate6<Template_NonMovable<SWS_Movable> > c12; + + Defaulted_SW_NeedyTemplate6<> c13; +} + +void good6() { + Defaulted_SW_NeedyTemplate6<Movable> a1; + Defaulted_SW_NeedyTemplate6<S_Movable> a2; + Defaulted_SW_NeedyTemplate6<W_Movable> a3; + Defaulted_SW_NeedyTemplate6<WS_Movable> a4; + Defaulted_SW_NeedyTemplate6<SW_Movable> a5; + Defaulted_SW_NeedyTemplate6<SWS_Movable> a6; + + Defaulted_SW_NeedyTemplate6<Template_Inline<Movable> > b1; + Defaulted_SW_NeedyTemplate6<Template_Inline<S_Movable> > b2; + Defaulted_SW_NeedyTemplate6<Template_Inline<W_Movable> > b3; + Defaulted_SW_NeedyTemplate6<Template_Inline<WS_Movable> > b4; + Defaulted_SW_NeedyTemplate6<Template_Inline<SW_Movable> > b5; + Defaulted_SW_NeedyTemplate6<Template_Inline<SWS_Movable> > b6; + + Defaulted_SW_NeedyTemplate6<Template_Unused<Movable> > c1; + Defaulted_SW_NeedyTemplate6<Template_Unused<S_Movable> > c2; + Defaulted_SW_NeedyTemplate6<Template_Unused<W_Movable> > c3; + Defaulted_SW_NeedyTemplate6<Template_Unused<WS_Movable> > c4; + Defaulted_SW_NeedyTemplate6<Template_Unused<SW_Movable> > c5; + Defaulted_SW_NeedyTemplate6<Template_Unused<SWS_Movable> > c6; + Defaulted_SW_NeedyTemplate6<Template_Unused<NonMovable> > c7; + Defaulted_SW_NeedyTemplate6<Template_Unused<S_NonMovable> > c8; + Defaulted_SW_NeedyTemplate6<Template_Unused<W_NonMovable> > c9; + Defaulted_SW_NeedyTemplate6<Template_Unused<WS_NonMovable> > c10; + Defaulted_SW_NeedyTemplate6<Template_Unused<SW_NonMovable> > c11; + Defaulted_SW_NeedyTemplate6<Template_Unused<SWS_NonMovable> > c12; + + Defaulted_SW_NeedyTemplate6<Template_Ref<Movable> > d1; + Defaulted_SW_NeedyTemplate6<Template_Ref<S_Movable> > d2; + Defaulted_SW_NeedyTemplate6<Template_Ref<W_Movable> > d3; + Defaulted_SW_NeedyTemplate6<Template_Ref<WS_Movable> > d4; + Defaulted_SW_NeedyTemplate6<Template_Ref<SW_Movable> > d5; + Defaulted_SW_NeedyTemplate6<Template_Ref<SWS_Movable> > d6; + Defaulted_SW_NeedyTemplate6<Template_Ref<NonMovable> > d7; + Defaulted_SW_NeedyTemplate6<Template_Ref<S_NonMovable> > d8; + Defaulted_SW_NeedyTemplate6<Template_Ref<W_NonMovable> > d9; + Defaulted_SW_NeedyTemplate6<Template_Ref<WS_NonMovable> > d10; + Defaulted_SW_NeedyTemplate6<Template_Ref<SW_NonMovable> > d11; + Defaulted_SW_NeedyTemplate6<Template_Ref<SWS_NonMovable> > d12; +} + +// +// 7 - MOZ_NEEDS_MEMMOVABLE_TYPE instantiated as default template argument +// + +template <class T> +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate7 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate7<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template <class T, class Q = NeedyTemplate7<T> > +struct Defaulted_Templated_NeedyTemplate7 {Q m;}; // expected-note-re 26 {{instantiation of 'NeedyTemplate7<{{.*}}>' requested here}} +void bad7() { + Defaulted_Templated_NeedyTemplate7<NonMovable> a1; + Defaulted_Templated_NeedyTemplate7<S_NonMovable> a2; + Defaulted_Templated_NeedyTemplate7<W_NonMovable> a3; + Defaulted_Templated_NeedyTemplate7<WS_NonMovable> a4; + Defaulted_Templated_NeedyTemplate7<SW_NonMovable> a5; + Defaulted_Templated_NeedyTemplate7<SWS_NonMovable> a6; + + Defaulted_Templated_NeedyTemplate7<Template_Inline<NonMovable> > b1; + Defaulted_Templated_NeedyTemplate7<Template_Inline<S_NonMovable> > b2; + Defaulted_Templated_NeedyTemplate7<Template_Inline<W_NonMovable> > b3; + Defaulted_Templated_NeedyTemplate7<Template_Inline<WS_NonMovable> > b4; + Defaulted_Templated_NeedyTemplate7<Template_Inline<SW_NonMovable> > b5; + Defaulted_Templated_NeedyTemplate7<Template_Inline<SWS_NonMovable> > b6; + + Defaulted_Templated_NeedyTemplate7<Template_NonMovable<NonMovable> > c1; + Defaulted_Templated_NeedyTemplate7<Template_NonMovable<S_NonMovable> > c2; + Defaulted_Templated_NeedyTemplate7<Template_NonMovable<W_NonMovable> > c3; + Defaulted_Templated_NeedyTemplate7<Template_NonMovable<WS_NonMovable> > c4; + Defaulted_Templated_NeedyTemplate7<Template_NonMovable<SW_NonMovable> > c5; + Defaulted_Templated_NeedyTemplate7<Template_NonMovable<SWS_NonMovable> > c6; + Defaulted_Templated_NeedyTemplate7<Template_NonMovable<Movable> > c7; + Defaulted_Templated_NeedyTemplate7<Template_NonMovable<S_Movable> > c8; + Defaulted_Templated_NeedyTemplate7<Template_NonMovable<W_Movable> > c9; + Defaulted_Templated_NeedyTemplate7<Template_NonMovable<WS_Movable> > c10; + Defaulted_Templated_NeedyTemplate7<Template_NonMovable<SW_Movable> > c11; + Defaulted_Templated_NeedyTemplate7<Template_NonMovable<SWS_Movable> > c12; +} + +void good7() { + Defaulted_Templated_NeedyTemplate7<Movable> a1; + Defaulted_Templated_NeedyTemplate7<S_Movable> a2; + Defaulted_Templated_NeedyTemplate7<W_Movable> a3; + Defaulted_Templated_NeedyTemplate7<WS_Movable> a4; + Defaulted_Templated_NeedyTemplate7<SW_Movable> a5; + Defaulted_Templated_NeedyTemplate7<SWS_Movable> a6; + + Defaulted_Templated_NeedyTemplate7<Template_Inline<Movable> > b1; + Defaulted_Templated_NeedyTemplate7<Template_Inline<S_Movable> > b2; + Defaulted_Templated_NeedyTemplate7<Template_Inline<W_Movable> > b3; + Defaulted_Templated_NeedyTemplate7<Template_Inline<WS_Movable> > b4; + Defaulted_Templated_NeedyTemplate7<Template_Inline<SW_Movable> > b5; + Defaulted_Templated_NeedyTemplate7<Template_Inline<SWS_Movable> > b6; + + Defaulted_Templated_NeedyTemplate7<Template_Unused<Movable> > c1; + Defaulted_Templated_NeedyTemplate7<Template_Unused<S_Movable> > c2; + Defaulted_Templated_NeedyTemplate7<Template_Unused<W_Movable> > c3; + Defaulted_Templated_NeedyTemplate7<Template_Unused<WS_Movable> > c4; + Defaulted_Templated_NeedyTemplate7<Template_Unused<SW_Movable> > c5; + Defaulted_Templated_NeedyTemplate7<Template_Unused<SWS_Movable> > c6; + Defaulted_Templated_NeedyTemplate7<Template_Unused<NonMovable> > c7; + Defaulted_Templated_NeedyTemplate7<Template_Unused<S_NonMovable> > c8; + Defaulted_Templated_NeedyTemplate7<Template_Unused<W_NonMovable> > c9; + Defaulted_Templated_NeedyTemplate7<Template_Unused<WS_NonMovable> > c10; + Defaulted_Templated_NeedyTemplate7<Template_Unused<SW_NonMovable> > c11; + Defaulted_Templated_NeedyTemplate7<Template_Unused<SWS_NonMovable> > c12; + + Defaulted_Templated_NeedyTemplate7<Template_Ref<Movable> > d1; + Defaulted_Templated_NeedyTemplate7<Template_Ref<S_Movable> > d2; + Defaulted_Templated_NeedyTemplate7<Template_Ref<W_Movable> > d3; + Defaulted_Templated_NeedyTemplate7<Template_Ref<WS_Movable> > d4; + Defaulted_Templated_NeedyTemplate7<Template_Ref<SW_Movable> > d5; + Defaulted_Templated_NeedyTemplate7<Template_Ref<SWS_Movable> > d6; + Defaulted_Templated_NeedyTemplate7<Template_Ref<NonMovable> > d7; + Defaulted_Templated_NeedyTemplate7<Template_Ref<S_NonMovable> > d8; + Defaulted_Templated_NeedyTemplate7<Template_Ref<W_NonMovable> > d9; + Defaulted_Templated_NeedyTemplate7<Template_Ref<WS_NonMovable> > d10; + Defaulted_Templated_NeedyTemplate7<Template_Ref<SW_NonMovable> > d11; + Defaulted_Templated_NeedyTemplate7<Template_Ref<SWS_NonMovable> > d12; +} + +// +// 8 - Wrapped MOZ_NEEDS_MEMMOVABLE_TYPE instantiated as default template argument +// + +template <class T> +struct MOZ_NEEDS_MEMMOVABLE_TYPE NeedyTemplate8 {T m;}; // expected-error-re 26 {{Cannot instantiate 'NeedyTemplate8<{{.*}}>' with non-memmovable template argument '{{.*}}'}} +template <class T, class Q = NeedyTemplate8<T> > +struct Defaulted_Templated_NeedyTemplate8 {Q m;}; // expected-note-re 26 {{instantiation of 'NeedyTemplate8<{{.*}}>' requested here}} +template <class T> +struct W_Defaulted_Templated_NeedyTemplate8 { + Defaulted_Templated_NeedyTemplate8<T> m; +}; +void bad8() { + W_Defaulted_Templated_NeedyTemplate8<NonMovable> a1; + W_Defaulted_Templated_NeedyTemplate8<S_NonMovable> a2; + W_Defaulted_Templated_NeedyTemplate8<W_NonMovable> a3; + W_Defaulted_Templated_NeedyTemplate8<WS_NonMovable> a4; + W_Defaulted_Templated_NeedyTemplate8<SW_NonMovable> a5; + W_Defaulted_Templated_NeedyTemplate8<SWS_NonMovable> a6; + + W_Defaulted_Templated_NeedyTemplate8<Template_Inline<NonMovable> > b1; + W_Defaulted_Templated_NeedyTemplate8<Template_Inline<S_NonMovable> > b2; + W_Defaulted_Templated_NeedyTemplate8<Template_Inline<W_NonMovable> > b3; + W_Defaulted_Templated_NeedyTemplate8<Template_Inline<WS_NonMovable> > b4; + W_Defaulted_Templated_NeedyTemplate8<Template_Inline<SW_NonMovable> > b5; + W_Defaulted_Templated_NeedyTemplate8<Template_Inline<SWS_NonMovable> > b6; + + W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<NonMovable> > c1; + W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<S_NonMovable> > c2; + W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<W_NonMovable> > c3; + W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<WS_NonMovable> > c4; + W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<SW_NonMovable> > c5; + W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<SWS_NonMovable> > c6; + W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<Movable> > c7; + W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<S_Movable> > c8; + W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<W_Movable> > c9; + W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<WS_Movable> > c10; + W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<SW_Movable> > c11; + W_Defaulted_Templated_NeedyTemplate8<Template_NonMovable<SWS_Movable> > c12; +} + +void good8() { + W_Defaulted_Templated_NeedyTemplate8<Movable> a1; + W_Defaulted_Templated_NeedyTemplate8<S_Movable> a2; + W_Defaulted_Templated_NeedyTemplate8<W_Movable> a3; + W_Defaulted_Templated_NeedyTemplate8<WS_Movable> a4; + W_Defaulted_Templated_NeedyTemplate8<SW_Movable> a5; + W_Defaulted_Templated_NeedyTemplate8<SWS_Movable> a6; + + W_Defaulted_Templated_NeedyTemplate8<Template_Inline<Movable> > b1; + W_Defaulted_Templated_NeedyTemplate8<Template_Inline<S_Movable> > b2; + W_Defaulted_Templated_NeedyTemplate8<Template_Inline<W_Movable> > b3; + W_Defaulted_Templated_NeedyTemplate8<Template_Inline<WS_Movable> > b4; + W_Defaulted_Templated_NeedyTemplate8<Template_Inline<SW_Movable> > b5; + W_Defaulted_Templated_NeedyTemplate8<Template_Inline<SWS_Movable> > b6; + + W_Defaulted_Templated_NeedyTemplate8<Template_Unused<Movable> > c1; + W_Defaulted_Templated_NeedyTemplate8<Template_Unused<S_Movable> > c2; + W_Defaulted_Templated_NeedyTemplate8<Template_Unused<W_Movable> > c3; + W_Defaulted_Templated_NeedyTemplate8<Template_Unused<WS_Movable> > c4; + W_Defaulted_Templated_NeedyTemplate8<Template_Unused<SW_Movable> > c5; + W_Defaulted_Templated_NeedyTemplate8<Template_Unused<SWS_Movable> > c6; + W_Defaulted_Templated_NeedyTemplate8<Template_Unused<NonMovable> > c7; + W_Defaulted_Templated_NeedyTemplate8<Template_Unused<S_NonMovable> > c8; + W_Defaulted_Templated_NeedyTemplate8<Template_Unused<W_NonMovable> > c9; + W_Defaulted_Templated_NeedyTemplate8<Template_Unused<WS_NonMovable> > c10; + W_Defaulted_Templated_NeedyTemplate8<Template_Unused<SW_NonMovable> > c11; + W_Defaulted_Templated_NeedyTemplate8<Template_Unused<SWS_NonMovable> > c12; + + W_Defaulted_Templated_NeedyTemplate8<Template_Ref<Movable> > d1; + W_Defaulted_Templated_NeedyTemplate8<Template_Ref<S_Movable> > d2; + W_Defaulted_Templated_NeedyTemplate8<Template_Ref<W_Movable> > d3; + W_Defaulted_Templated_NeedyTemplate8<Template_Ref<WS_Movable> > d4; + W_Defaulted_Templated_NeedyTemplate8<Template_Ref<SW_Movable> > d5; + W_Defaulted_Templated_NeedyTemplate8<Template_Ref<SWS_Movable> > d6; + W_Defaulted_Templated_NeedyTemplate8<Template_Ref<NonMovable> > d7; + W_Defaulted_Templated_NeedyTemplate8<Template_Ref<S_NonMovable> > d8; + W_Defaulted_Templated_NeedyTemplate8<Template_Ref<W_NonMovable> > d9; + W_Defaulted_Templated_NeedyTemplate8<Template_Ref<WS_NonMovable> > d10; + W_Defaulted_Templated_NeedyTemplate8<Template_Ref<SW_NonMovable> > d11; + W_Defaulted_Templated_NeedyTemplate8<Template_Ref<SWS_NonMovable> > d12; +} + +/* + SpecializedNonMovable is a non-movable class which has an explicit specialization of NeedyTemplate + for it. Instantiations of NeedyTemplateN<SpecializedNonMovable> should be legal as the explicit + specialization isn't annotated with MOZ_NEEDS_MEMMOVABLE_TYPE. + + However, as it is MOZ_NON_MEMMOVABLE, derived classes and members shouldn't be able to be used to + instantiate NeedyTemplate. +*/ + +struct MOZ_NON_MEMMOVABLE SpecializedNonMovable {}; +struct S_SpecializedNonMovable : SpecializedNonMovable {}; // expected-note 8 {{'S_SpecializedNonMovable' is a non-memmove()able type because it inherits from a non-memmove()able type 'SpecializedNonMovable'}} + +// Specialize all of the NeedyTemplates with SpecializedNonMovable. +template <> +struct NeedyTemplate1<SpecializedNonMovable> {}; +template <> +struct NeedyTemplate2<SpecializedNonMovable> {}; +template <> +struct NeedyTemplate3<SpecializedNonMovable> {}; +template <> +struct NeedyTemplate4<SpecializedNonMovable> {}; +template <> +struct NeedyTemplate5<SpecializedNonMovable> {}; +template <> +struct NeedyTemplate6<SpecializedNonMovable> {}; +template <> +struct NeedyTemplate7<SpecializedNonMovable> {}; +template <> +struct NeedyTemplate8<SpecializedNonMovable> {}; + +void specialization() { + /* + SpecializedNonMovable has a specialization for every variant of NeedyTemplate, + so these templates are valid, even though SpecializedNonMovable isn't + memmovable + */ + NeedyTemplate1<SpecializedNonMovable> a1; + S_NeedyTemplate2<SpecializedNonMovable> a2; + W_NeedyTemplate3<SpecializedNonMovable> a3; + WS_NeedyTemplate4<SpecializedNonMovable> a4; + SW_NeedyTemplate5<SpecializedNonMovable> a5; + Defaulted_SW_NeedyTemplate6<SpecializedNonMovable> a6; + Defaulted_Templated_NeedyTemplate7<SpecializedNonMovable> a7; + W_Defaulted_Templated_NeedyTemplate8<SpecializedNonMovable> a8; + + /* + These entries contain an element which is SpecializedNonMovable, and are non-movable + as there is no valid specialization, and their member is non-memmovable + */ + NeedyTemplate1<Template_Inline<SpecializedNonMovable> > b1; // expected-note-re {{instantiation of 'NeedyTemplate1<Template_Inline<SpecializedNonMovable>{{ ?}}>' requested here}} + S_NeedyTemplate2<Template_Inline<SpecializedNonMovable> > b2; + W_NeedyTemplate3<Template_Inline<SpecializedNonMovable> > b3; + WS_NeedyTemplate4<Template_Inline<SpecializedNonMovable> > b4; + SW_NeedyTemplate5<Template_Inline<SpecializedNonMovable> > b5; + Defaulted_SW_NeedyTemplate6<Template_Inline<SpecializedNonMovable> > b6; + Defaulted_Templated_NeedyTemplate7<Template_Inline<SpecializedNonMovable> > b7; + W_Defaulted_Templated_NeedyTemplate8<Template_Inline<SpecializedNonMovable> > b8; + + /* + The subclass of SpecializedNonMovable, is also non-memmovable, + as there is no valid specialization. + */ + NeedyTemplate1<S_SpecializedNonMovable> c1; // expected-note {{instantiation of 'NeedyTemplate1<S_SpecializedNonMovable>' requested here}} + S_NeedyTemplate2<S_SpecializedNonMovable> c2; + W_NeedyTemplate3<S_SpecializedNonMovable> c3; + WS_NeedyTemplate4<S_SpecializedNonMovable> c4; + SW_NeedyTemplate5<S_SpecializedNonMovable> c5; + Defaulted_SW_NeedyTemplate6<S_SpecializedNonMovable> c6; + Defaulted_Templated_NeedyTemplate7<S_SpecializedNonMovable> c7; + W_Defaulted_Templated_NeedyTemplate8<S_SpecializedNonMovable> c8; +} + +class MOZ_NEEDS_MEMMOVABLE_MEMBERS NeedsMemMovableMembers { + Movable m1; + NonMovable m2; // expected-error {{class 'NeedsMemMovableMembers' cannot have non-memmovable member 'm2' of type 'NonMovable'}} + S_Movable sm1; + S_NonMovable sm2; // expected-error {{class 'NeedsMemMovableMembers' cannot have non-memmovable member 'sm2' of type 'S_NonMovable'}} + W_Movable wm1; + W_NonMovable wm2; // expected-error {{class 'NeedsMemMovableMembers' cannot have non-memmovable member 'wm2' of type 'W_NonMovable'}} + SW_Movable swm1; + SW_NonMovable swm2; // expected-error {{class 'NeedsMemMovableMembers' cannot have non-memmovable member 'swm2' of type 'SW_NonMovable'}} + WS_Movable wsm1; + WS_NonMovable wsm2; // expected-error {{class 'NeedsMemMovableMembers' cannot have non-memmovable member 'wsm2' of type 'WS_NonMovable'}} + SWS_Movable swsm1; + SWS_NonMovable swsm2; // expected-error {{class 'NeedsMemMovableMembers' cannot have non-memmovable member 'swsm2' of type 'SWS_NonMovable'}} +}; + +class NeedsMemMovableMembersDerived : public NeedsMemMovableMembers {}; diff --git a/build/clang-plugin/tests/TestNonMemMovableStd.cpp b/build/clang-plugin/tests/TestNonMemMovableStd.cpp new file mode 100644 index 0000000000..b380d07186 --- /dev/null +++ b/build/clang-plugin/tests/TestNonMemMovableStd.cpp @@ -0,0 +1,70 @@ +#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 9 {{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 { // expected-note 2 {{'std::basic_string<char>' is a non-memmove()able type because it is an stl-provided type not guaranteed to be memmove-able}} expected-note {{'std::string' (aka 'basic_string<char>') is a non-memmove()able type because it is an stl-provided type not guaranteed to be memmove-able}} + public: + basic_string(); + basic_string(const basic_string&); + basic_string(basic_string&&); + basic_string& operator=(const basic_string&); + basic_string& operator=(basic_string&&); + ~basic_string(); +}; +typedef basic_string<char> string; +template<class T, class U> class pair { T mT; U mU; }; // expected-note-re 4 {{'std::pair<bool, {{.*}}>' is a non-memmove()able type because it has a template argument non-memmove()able type '{{.*}}'}} + +struct has_nontrivial_dtor { // expected-note 2 {{'std::has_nontrivial_dtor' is a non-memmove()able type because it is an stl-provided type not guaranteed to be memmove-able}} + has_nontrivial_dtor() = default; + ~has_nontrivial_dtor(); +}; +struct has_nontrivial_copy { // expected-note 2 {{'std::has_nontrivial_copy' is a non-memmove()able type because it is an stl-provided type not guaranteed to be memmove-able}} + has_nontrivial_copy() = default; + has_nontrivial_copy(const has_nontrivial_copy&); + has_nontrivial_copy& operator=(const has_nontrivial_copy&); +}; +struct has_nontrivial_move { // expected-note 2 {{'std::has_nontrivial_move' is a non-memmove()able type because it is an stl-provided type not guaranteed to be memmove-able}} + has_nontrivial_move() = default; + has_nontrivial_move(const has_nontrivial_move&); + has_nontrivial_move& operator=(const has_nontrivial_move&); +}; +struct has_trivial_dtor { + has_trivial_dtor() = default; + ~has_trivial_dtor() = default; +}; +struct has_trivial_copy { + has_trivial_copy() = default; + has_trivial_copy(const has_trivial_copy&) = default; + has_trivial_copy& operator=(const has_trivial_copy&) = default; +}; +struct has_trivial_move { + has_trivial_move() = default; + has_trivial_move(const has_trivial_move&) = default; + has_trivial_move& operator=(const has_trivial_move&) = default; +}; +} + +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-re {{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::pair<bool, int>> good; +static Mover<std::pair<bool, std::string>> not_good; // expected-note-re {{instantiation of 'Mover<std::pair<bool, std::basic_string<char>{{ ?}}>{{ ?}}>' requested here}} + +static Mover<std::has_nontrivial_dtor> nontrivial_dtor; // expected-note {{instantiation of 'Mover<std::has_nontrivial_dtor>' requested here}} +static Mover<std::has_nontrivial_copy> nontrivial_copy; // expected-note {{instantiation of 'Mover<std::has_nontrivial_copy>' requested here}} +static Mover<std::has_nontrivial_move> nontrivial_move; // expected-note {{instantiation of 'Mover<std::has_nontrivial_move>' requested here}} +static Mover<std::has_trivial_dtor> trivial_dtor; +static Mover<std::has_trivial_copy> trivial_copy; +static Mover<std::has_trivial_move> trivial_move; + +static Mover<std::pair<bool, std::has_nontrivial_dtor>> pair_nontrivial_dtor; // expected-note {{instantiation of 'Mover<std::pair<bool, std::has_nontrivial_dtor>>' requested here}} +static Mover<std::pair<bool, std::has_nontrivial_copy>> pair_nontrivial_copy; // expected-note {{instantiation of 'Mover<std::pair<bool, std::has_nontrivial_copy>>' requested here}} +static Mover<std::pair<bool, std::has_nontrivial_move>> pair_nontrivial_move; // expected-note {{instantiation of 'Mover<std::pair<bool, std::has_nontrivial_move>>' requested here}} +static Mover<std::pair<bool, std::has_trivial_dtor>> pair_trivial_dtor; +static Mover<std::pair<bool, std::has_trivial_copy>> pair_trivial_copy; +static Mover<std::pair<bool, std::has_trivial_move>> pair_trivial_move; diff --git a/build/clang-plugin/tests/TestNonMemMovableStdAtomic.cpp b/build/clang-plugin/tests/TestNonMemMovableStdAtomic.cpp new file mode 100644 index 0000000000..b8aef2eacd --- /dev/null +++ b/build/clang-plugin/tests/TestNonMemMovableStdAtomic.cpp @@ -0,0 +1,30 @@ +// expected-no-diagnostics + +#define MOZ_NEEDS_MEMMOVABLE_TYPE __attribute__((annotate("moz_needs_memmovable_type"))) + +template<class T> +class MOZ_NEEDS_MEMMOVABLE_TYPE Mover { T mForceInst; }; + +#include <atomic> +#include <cstdint> +struct CustomType{}; +static struct { + Mover<std::atomic<CustomType>> m1; + Mover<std::atomic<bool>> m2; + Mover<std::atomic<char>> m3; + Mover<std::atomic<signed char>> m4; + Mover<std::atomic<unsigned char>> m5; + Mover<std::atomic<char16_t>> m6; + Mover<std::atomic<char32_t>> m7; + Mover<std::atomic<wchar_t>> m8; + Mover<std::atomic<short>> m9; + Mover<std::atomic<unsigned short>> m10; + Mover<std::atomic<int>> m11; + Mover<std::atomic<unsigned int>> m12; + Mover<std::atomic<long>> m13; + Mover<std::atomic<unsigned long>> m14; + Mover<std::atomic<long long>> m15; + Mover<std::atomic<unsigned long long>> m16; + Mover<std::atomic<void*>> m17; + Mover<std::atomic<CustomType*>> m18; +} good; diff --git a/build/clang-plugin/tests/TestNonParameterChecker.cpp b/build/clang-plugin/tests/TestNonParameterChecker.cpp new file mode 100644 index 0000000000..291ef949f6 --- /dev/null +++ b/build/clang-plugin/tests/TestNonParameterChecker.cpp @@ -0,0 +1,187 @@ +#define MOZ_NON_PARAM __attribute__((annotate("moz_non_param"))) + +struct Param {}; +struct MOZ_NON_PARAM NonParam {}; +union MOZ_NON_PARAM NonParamUnion {}; +class MOZ_NON_PARAM NonParamClass {}; +enum MOZ_NON_PARAM NonParamEnum { X, Y, Z }; +enum class MOZ_NON_PARAM NonParamEnumClass { X, Y, Z }; + +struct HasNonParamStruct { NonParam x; int y; }; // expected-note 14 {{'HasNonParamStruct' is a non-param type because member 'x' is a non-param type 'NonParam'}} +union HasNonParamUnion { NonParam x; int y; }; // expected-note 18 {{'HasNonParamUnion' is a non-param type because member 'x' is a non-param type 'NonParam'}} +struct HasNonParamStructUnion { HasNonParamUnion z; }; // expected-note 9 {{'HasNonParamStructUnion' is a non-param type because member 'z' is a non-param type 'HasNonParamUnion'}} + +#define MAYBE_STATIC +#include "NonParameterTestCases.h" +#undef MAYBE_STATIC + +// Do not check typedef and using. +typedef void (*funcTypeParam)(Param x); +typedef void (*funcTypeNonParam)(NonParam x); + +using usingFuncTypeParam = void (*)(Param x); +using usingFuncTypeNonParam = void (*)(NonParam x); + +class class_ +{ + explicit class_(Param x) {} + explicit class_(NonParam x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + explicit class_(HasNonParamStruct x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + explicit class_(HasNonParamUnion x) {} //expected-error {{Type 'HasNonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + explicit class_(HasNonParamStructUnion x) {} //expected-error {{Type 'HasNonParamStructUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + +#define MAYBE_STATIC +#include "NonParameterTestCases.h" +#undef MAYBE_STATIC +}; + +class classWithStatic +{ +#define MAYBE_STATIC static +#include "NonParameterTestCases.h" +#undef MAYBE_STATIC +}; + +template <typename T> +class tmplClassForParam +{ +public: + void raw(T x) {} + void rawDefault(T x = T()) {} + void const_(const T x) {} + void ptr(T* x) {} + void ref(T& x) {} + void constRef(const T& x) {} + + void notCalled(T x) {} +}; + +template <typename T> +class tmplClassForNonParam +{ +public: + void raw(T x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + void rawDefault(T x = T()) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + void const_(const T x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + void ptr(T* x) {} + void ref(T& x) {} + void constRef(const T& x) {} + + void notCalled(T x) {} +}; + +template <typename T> +class tmplClassForHasNonParamStruct +{ +public: + void raw(T x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + void rawDefault(T x = T()) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + void const_(const T x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + void ptr(T* x) {} + void ref(T& x) {} + void constRef(const T& x) {} + + void notCalled(T x) {} +}; + +void testTemplateClass() +{ + tmplClassForParam<Param> paramClass; + Param param; + paramClass.raw(param); + paramClass.rawDefault(); + paramClass.const_(param); + paramClass.ptr(¶m); + paramClass.ref(param); + paramClass.constRef(param); + + tmplClassForNonParam<NonParam> nonParamClass; //expected-note 3 {{The bad argument was passed to 'tmplClassForNonParam' here}} + NonParam nonParam; + nonParamClass.raw(nonParam); + nonParamClass.rawDefault(); + nonParamClass.const_(nonParam); + nonParamClass.ptr(&nonParam); + nonParamClass.ref(nonParam); + nonParamClass.constRef(nonParam); + + tmplClassForHasNonParamStruct<HasNonParamStruct> hasNonParamStructClass;//expected-note 3 {{The bad argument was passed to 'tmplClassForHasNonParamStruct' here}} + HasNonParamStruct hasNonParamStruct; + hasNonParamStructClass.raw(hasNonParamStruct); + hasNonParamStructClass.rawDefault(); + hasNonParamStructClass.const_(hasNonParamStruct); + hasNonParamStructClass.ptr(&hasNonParamStruct); + hasNonParamStructClass.ref(hasNonParamStruct); + hasNonParamStructClass.constRef(hasNonParamStruct); +} + +template <typename T> +class NestedTemplateInner +{ +public: + void raw(T x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +}; + +template <typename T> +class nestedTemplateOuter +{ +public: + void constRef(const T& x) { + NestedTemplateInner<T> inner; //expected-note {{The bad argument was passed to 'NestedTemplateInner' here}} + inner.raw(x); + } +}; + +void testNestedTemplateClass() +{ + nestedTemplateOuter<NonParam> outer; + NonParam nonParam; + outer.constRef(nonParam); // FIXME: this line needs note "The bad argument was passed to 'constRef' here" +} + +template <typename T> +void tmplFuncForParam(T x) {} +template <typename T> +void tmplFuncForNonParam(T x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +template <typename T> +void tmplFuncForNonParamImplicit(T x) {} //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +template <typename T> +void tmplFuncForHasNonParamStruct(T x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +template <typename T> +void tmplFuncForHasNonParamStructImplicit(T x) {} //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + +void testTemplateFunc() +{ + Param param; + tmplFuncForParam<Param>(param); + + NonParam nonParam; + tmplFuncForNonParam<NonParam>(nonParam); // FIXME: this line needs note "The bad argument was passed to 'tmplFuncForNonParam' here" + tmplFuncForNonParamImplicit(nonParam); // FIXME: this line needs note "The bad argument was passed to 'tmplFuncForNonParamImplicit' here" + + HasNonParamStruct hasNonParamStruct; + tmplFuncForHasNonParamStruct<HasNonParamStruct>(hasNonParamStruct); // FIXME: this line needs note "The bad argument was passed to 'tmplFuncForHasNonParamStruct' here" + tmplFuncForHasNonParamStructImplicit(hasNonParamStruct); // FIXME: this line needs note "The bad argument was passed to 'tmplFuncForHasNonParamStructImplicit' here" +} + +void testLambda() +{ + auto paramLambda = [](Param x) -> void {}; + auto nonParamLambda = [](NonParam x) -> void {}; //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + auto nonParamStructLambda = [](HasNonParamStruct x) -> void {}; //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + auto nonParamUnionLambda = [](HasNonParamUnion x) -> void {}; //expected-error {{Type 'HasNonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + auto nonParamStructUnionLambda = [](HasNonParamStructUnion x) -> void {}; //expected-error {{Type 'HasNonParamStructUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + + (void)[](Param x) -> void {}; + (void)[](NonParam x) -> void {}; //expected-error {{Type 'NonParam' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + (void)[](HasNonParamStruct x) -> void {}; //expected-error {{Type 'HasNonParamStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + (void)[](HasNonParamUnion x) -> void {}; //expected-error {{Type 'HasNonParamUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} + (void)[](HasNonParamStructUnion x) -> void {}; //expected-error {{Type 'HasNonParamStructUnion' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +} + +struct alignas(16) AlignasStruct { char a; ~AlignasStruct(); }; // expected-note {{'AlignasStruct' is a non-param type because it has an explicit alignment of '16'}} +void takesAlignasStruct(AlignasStruct x) { } // expected-error {{Type 'AlignasStruct' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +void takesAlignasStructByRef(const AlignasStruct& x) { } + +struct AlignasMember { alignas(16) char a; ~AlignasMember(); }; // expected-note {{'AlignasMember' is a non-param type because member 'a' has an explicit alignment of '16'}} +void takesAlignasMember(AlignasMember x) { } // expected-error {{Type 'AlignasMember' must not be used as parameter}} expected-note {{Please consider passing a const reference instead}} +void takesAlignasMemberByRef(const AlignasMember& x) { } diff --git a/build/clang-plugin/tests/TestNonTemporaryClass.cpp b/build/clang-plugin/tests/TestNonTemporaryClass.cpp new file mode 100644 index 0000000000..682c8ad530 --- /dev/null +++ b/build/clang-plugin/tests/TestNonTemporaryClass.cpp @@ -0,0 +1,70 @@ +#define MOZ_NON_TEMPORARY_CLASS __attribute__((annotate("moz_non_temporary_class"))) +#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) + +#include <stddef.h> + +struct MOZ_NON_TEMPORARY_CLASS NonTemporary { + int i; + NonTemporary() {} + MOZ_IMPLICIT NonTemporary(int a) {} + NonTemporary(int a, int b) {} + void *operator new(size_t x) throw() { return 0; } + void *operator new(size_t blah, char *buffer) { return buffer; } +}; + +template <class T> +struct MOZ_NON_TEMPORARY_CLASS TemplateClass { + T i; +}; + +void gobble(void *) { } + +void gobbleref(const NonTemporary&) { } + +template <class T> +void gobbleanyref(const T&) { } + +void misuseNonTemporaryClass(int len) { + NonTemporary invalid; + NonTemporary alsoInvalid[2]; + static NonTemporary invalidStatic; + static NonTemporary alsoInvalidStatic[2]; + + gobble(&invalid); + gobble(&invalidStatic); + gobble(&alsoInvalid[0]); + + gobbleref(NonTemporary()); // expected-error {{variable of type 'NonTemporary' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}} + gobbleref(NonTemporary(10, 20)); // expected-error {{variable of type 'NonTemporary' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}} + gobbleref(NonTemporary(10)); // expected-error {{variable of type 'NonTemporary' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}} + gobbleref(10); // expected-error {{variable of type 'NonTemporary' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}} + gobbleanyref(TemplateClass<int>()); // expected-error {{variable of type 'TemplateClass<int>' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}} + + gobble(new NonTemporary); + gobble(new NonTemporary[10]); + gobble(new TemplateClass<int>); + gobble(len <= 5 ? &invalid : new NonTemporary); + + char buffer[sizeof(NonTemporary)]; + gobble(new (buffer) NonTemporary); +} + +void defaultArg(const NonTemporary& arg = NonTemporary()) { +} + +NonTemporary invalidStatic; +struct RandomClass { + NonTemporary nonstaticMember; // expected-note {{'RandomClass' is a non-temporary type because member 'nonstaticMember' is a non-temporary type 'NonTemporary'}} + static NonTemporary staticMember; +}; +struct MOZ_NON_TEMPORARY_CLASS RandomNonTemporaryClass { + NonTemporary nonstaticMember; + static NonTemporary staticMember; +}; + +struct BadInherit : NonTemporary {}; // expected-note {{'BadInherit' is a non-temporary type because it inherits from a non-temporary type 'NonTemporary'}} + +void useStuffWrongly() { + gobbleanyref(BadInherit()); // expected-error {{variable of type 'BadInherit' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}} + gobbleanyref(RandomClass()); // expected-error {{variable of type 'RandomClass' is not valid in a temporary}} expected-note {{value incorrectly allocated in a temporary}} +} diff --git a/build/clang-plugin/tests/TestNonTrivialTypeInFfi.cpp b/build/clang-plugin/tests/TestNonTrivialTypeInFfi.cpp new file mode 100644 index 0000000000..e491122b99 --- /dev/null +++ b/build/clang-plugin/tests/TestNonTrivialTypeInFfi.cpp @@ -0,0 +1,65 @@ +// clang warns for some of these on its own, but we're not testing that, plus +// some of them (TrivialT<int>) is a false positive (clang doesn't realize the +// type is fully specialized below). +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wreturn-type-c-linkage" + +struct Opaque; +struct Trivial { + int foo; + char bar; + Opaque* baz; +}; + +template <typename T> +struct TrivialT { + int foo; + char bar; + T* baz; +}; + +struct NonTrivial { + ~NonTrivial() { + } + + Opaque* ptr; +}; + +template <typename T> +struct NonTrivialT { + ~NonTrivialT() { + delete ptr; + } + + T* ptr; +}; + +struct TransitivelyNonTrivial { + NonTrivial nontrivial; +}; + +extern "C" void Foo(); +extern "C" Trivial Foo1(); +extern "C" NonTrivial Foo2(); // expected-error {{Type 'NonTrivial' must not be used as return type of extern "C" function}} expected-note {{Please consider using a pointer or reference instead}} +extern "C" NonTrivialT<int> Foo3(); // expected-error {{Type 'NonTrivialT<int>' must not be used as return type of extern "C" function}} expected-note {{Please consider using a pointer or reference, or explicitly instantiating the template instead}} +extern "C" NonTrivialT<float> Foo4(); // expected-error {{Type 'NonTrivialT<float>' must not be used as return type of extern "C" function}} expected-note {{Please consider using a pointer or reference, or explicitly instantiating the template instead}} + +extern "C" NonTrivial* Foo5(); + +extern "C" TrivialT<int> Foo6(); +extern "C" TrivialT<float> Foo7(); // expected-error {{Type 'TrivialT<float>' must not be used as return type of extern "C" function}} expected-note {{Please consider using a pointer or reference, or explicitly instantiating the template instead}} +extern "C" Trivial* Foo8(); + +extern "C" void Foo9(Trivial); +extern "C" void Foo10(NonTrivial); // expected-error {{Type 'NonTrivial' must not be used as parameter to extern "C" function}} expected-note {{Please consider using a pointer or reference instead}} +extern "C" void Foo11(NonTrivial*); +extern "C" void Foo12(NonTrivialT<int>); // expected-error {{Type 'NonTrivialT<int>' must not be used as parameter to extern "C" function}} expected-note {{Please consider using a pointer or reference, or explicitly instantiating the template instead}} +extern "C" void Foo13(TrivialT<int>); +extern "C" void Foo14(TrivialT<float>); // expected-error {{Type 'TrivialT<float>' must not be used as parameter to extern "C" function}} expected-note {{Please consider using a pointer or reference, or explicitly instantiating the template instead}} + +extern "C" TransitivelyNonTrivial Foo15(); // expected-error {{Type 'TransitivelyNonTrivial' must not be used as return type of extern "C" function}} expected-note {{Please consider using a pointer or reference instead}} +extern "C" void Foo16(TransitivelyNonTrivial); // expected-error {{Type 'TransitivelyNonTrivial' must not be used as parameter to extern "C" function}} expected-note {{Please consider using a pointer or reference instead}} + +template struct TrivialT<int>; + +#pragma GCC diagnostic pop diff --git a/build/clang-plugin/tests/TestOverrideBaseCall.cpp b/build/clang-plugin/tests/TestOverrideBaseCall.cpp new file mode 100644 index 0000000000..6fdaaad04e --- /dev/null +++ b/build/clang-plugin/tests/TestOverrideBaseCall.cpp @@ -0,0 +1,175 @@ +#define MOZ_REQUIRED_BASE_METHOD __attribute__((annotate("moz_required_base_method"))) + +class Base { +public: + virtual void fo() MOZ_REQUIRED_BASE_METHOD { + } + + virtual int foRet() MOZ_REQUIRED_BASE_METHOD { + return 0; + } +}; + +class BaseOne : public Base { +public: + virtual void fo() MOZ_REQUIRED_BASE_METHOD { + Base::fo(); + } +}; + +class BaseSecond : public Base { +public: + virtual void fo() MOZ_REQUIRED_BASE_METHOD { + Base::fo(); + } +}; + +class Deriv : public BaseOne, public BaseSecond { +public: + void func() { + } + + void fo() { + func(); + BaseSecond::fo(); + BaseOne::fo(); + } +}; + +class DerivSimple : public Base { +public: + void fo() { // expected-error {{Method Base::fo must be called in all overrides, but is not called in this override defined for class DerivSimple}} + } +}; + +class BaseVirtualOne : public virtual Base { +}; + +class BaseVirtualSecond: public virtual Base { +}; + +class DerivVirtual : public BaseVirtualOne, public BaseVirtualSecond { +public: + void fo() { + Base::fo(); + } +}; + +class DerivIf : public Base { +public: + void fo() { + if (true) { + Base::fo(); + } + } +}; + +class DerivIfElse : public Base { +public: + void fo() { + if (true) { + Base::fo(); + } else { + Base::fo(); + } + } +}; + +class DerivFor : public Base { +public: + void fo() { + for (int i = 0; i < 10; i++) { + Base::fo(); + } + } +}; + +class DerivDoWhile : public Base { +public: + void fo() { + do { + Base::fo(); + } while(false); + } +}; + +class DerivWhile : public Base { +public: + void fo() { + while (true) { + Base::fo(); + break; + } + } +}; + +class DerivAssignment : public Base { +public: + int foRet() { + return foRet(); + } +}; + +class BaseOperator { +private: + int value; +public: + BaseOperator() : value(0) { + } + virtual BaseOperator& operator++() MOZ_REQUIRED_BASE_METHOD { + value++; + return *this; + } +}; + +class DerivOperatorErr : public BaseOperator { +private: + int value; +public: + DerivOperatorErr() : value(0) { + } + DerivOperatorErr& operator++() { // expected-error {{Method BaseOperator::operator++ must be called in all overrides, but is not called in this override defined for class DerivOperatorErr}} + value++; + return *this; + } +}; + +class DerivOperator : public BaseOperator { +private: + int value; +public: + DerivOperator() : value(0) { + } + DerivOperator& operator++() { + BaseOperator::operator++(); + value++; + return *this; + } +}; + +class DerivPrime : public Base { +public: + void fo() { + Base::fo(); + } +}; + +class DerivSecondErr : public DerivPrime { +public: + void fo() { // expected-error {{Method Base::fo must be called in all overrides, but is not called in this override defined for class DerivSecondErr}} + } +}; + +class DerivSecond : public DerivPrime { +public: + void fo() { + Base::fo(); + } +}; + +class DerivSecondIndirect : public DerivPrime { +public: + void fo() { + DerivPrime::fo(); + } +}; diff --git a/build/clang-plugin/tests/TestOverrideBaseCallAnnotation.cpp b/build/clang-plugin/tests/TestOverrideBaseCallAnnotation.cpp new file mode 100644 index 0000000000..e268122c69 --- /dev/null +++ b/build/clang-plugin/tests/TestOverrideBaseCallAnnotation.cpp @@ -0,0 +1,47 @@ +#define MOZ_REQUIRED_BASE_METHOD __attribute__((annotate("moz_required_base_method"))) + +class Base { +public: + virtual void fo() MOZ_REQUIRED_BASE_METHOD { + } +}; + +class BaseNonVirtual { +public: + void fo() MOZ_REQUIRED_BASE_METHOD { // expected-error {{MOZ_REQUIRED_BASE_METHOD can be used only on virtual methods}} + } +}; + +class Deriv : public BaseNonVirtual { +public: + virtual void fo() MOZ_REQUIRED_BASE_METHOD { + } +}; + +class DerivVirtual : public Base { +public: + void fo() MOZ_REQUIRED_BASE_METHOD { + Base::fo(); + } +}; + +class BaseOperator { +public: + BaseOperator& operator++() MOZ_REQUIRED_BASE_METHOD { // expected-error {{MOZ_REQUIRED_BASE_METHOD can be used only on virtual methods}} + return *this; + } +}; + +class DerivOperator : public BaseOperator { +public: + virtual DerivOperator& operator++() { + return *this; + } +}; + +class DerivPrimeOperator : public DerivOperator { +public: + DerivPrimeOperator& operator++() { + return *this; + } +}; diff --git a/build/clang-plugin/tests/TestParamTraitsEnum.cpp b/build/clang-plugin/tests/TestParamTraitsEnum.cpp new file mode 100644 index 0000000000..a250250bfe --- /dev/null +++ b/build/clang-plugin/tests/TestParamTraitsEnum.cpp @@ -0,0 +1,94 @@ +typedef enum { + BadFirst, + BadSecond, + BadThird +} BadEnum; + +typedef enum { + NestedFirst, + NestedSecond +} NestedBadEnum; + +typedef enum { + GoodFirst, + GoodSecond, + GoodLast +} GoodEnum; + +enum RawEnum { + RawFirst, + RawLast +}; + +enum class ClassEnum { + ClassFirst, + ClassLast +}; + +template <class P> struct ParamTraits; + +// Simplified EnumSerializer etc. from IPCMessageUtils.h +template <typename E, typename EnumValidator> +struct EnumSerializer { + typedef E paramType; +}; + +template <typename E, + E MinLegal, + E HighBound> +class ContiguousEnumValidator +{}; + +template <typename E, + E MinLegal, + E HighBound> +struct ContiguousEnumSerializer + : EnumSerializer<E, + ContiguousEnumValidator<E, MinLegal, HighBound>> +{}; + +// Typical ParamTraits implementation that should be avoided +template<> +struct ParamTraits<ClassEnum> // expected-error {{Custom ParamTraits implementation for an enum type}} expected-note {{Please use a helper class for example ContiguousEnumSerializer}} +{ + typedef ClassEnum paramType; +}; + +template<> +struct ParamTraits<enum RawEnum> // expected-error {{Custom ParamTraits implementation for an enum type}} expected-note {{Please use a helper class for example ContiguousEnumSerializer}} +{ + typedef enum RawEnum paramType; +}; + +template<> +struct ParamTraits<BadEnum> // expected-error {{Custom ParamTraits implementation for an enum type}} expected-note {{Please use a helper class for example ContiguousEnumSerializer}} +{ + typedef BadEnum paramType; +}; + +// Make sure the analysis catches nested typedefs +typedef NestedBadEnum NestedDefLevel1; +typedef NestedDefLevel1 NestedDefLevel2; + +template<> +struct ParamTraits<NestedDefLevel2> // expected-error {{Custom ParamTraits implementation for an enum type}} expected-note {{Please use a helper class for example ContiguousEnumSerializer}} +{ + typedef NestedDefLevel2 paramType; +}; + +// Make sure a non enum typedef is not accidentally flagged +typedef int IntTypedef; + +template<> +struct ParamTraits<IntTypedef> +{ + typedef IntTypedef paramType; +}; + +// Make sure ParamTraits using helper classes are not flagged +template<> +struct ParamTraits<GoodEnum> +: public ContiguousEnumSerializer<GoodEnum, + GoodEnum::GoodFirst, + GoodEnum::GoodLast> +{}; diff --git a/build/clang-plugin/tests/TestRefCountedCopyConstructor.cpp b/build/clang-plugin/tests/TestRefCountedCopyConstructor.cpp new file mode 100644 index 0000000000..d3bd73084c --- /dev/null +++ b/build/clang-plugin/tests/TestRefCountedCopyConstructor.cpp @@ -0,0 +1,25 @@ +// Implicit copy construct which is unused +class RC1 { + void AddRef(); + void Release(); + int mRefCnt; +}; + +// Explicit copy constructor which is used +class RC2 { +public: + RC2(); + RC2(const RC2&); +private: + void AddRef(); + void Release(); + int mRefCnt; +}; + +void f() { + RC1* r1 = new RC1(); + RC1* r1p = new RC1(*r1); // expected-error {{Invalid use of compiler-provided copy constructor on refcounted type}} expected-note {{The default copy constructor also copies the default mRefCnt property, leading to reference count imbalance issues. Please provide your own copy constructor which only copies the fields which need to be copied}} + + RC2* r2 = new RC2(); + RC2* r2p = new RC2(*r2); +} diff --git a/build/clang-plugin/tests/TestRefCountedThisInsideConstructor.cpp b/build/clang-plugin/tests/TestRefCountedThisInsideConstructor.cpp new file mode 100644 index 0000000000..a6684e3812 --- /dev/null +++ b/build/clang-plugin/tests/TestRefCountedThisInsideConstructor.cpp @@ -0,0 +1,76 @@ +#include <functional> + +#include <mozilla/RefPtr.h> + +struct RefCountedBase { + void AddRef(); + void Release(); +}; + +struct Bar; + +struct Foo : RefCountedBase { + void foo(); +}; + +struct Bar : RefCountedBase { + Bar() { + RefPtr<Bar> self = this; // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + auto self2 = RefPtr(this); // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + auto self3 = RefPtr{this}; // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + RefPtr<Bar> self4(this); // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + RefPtr<Bar> self5{this}; // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + [self=RefPtr{this}]{}(); // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + refptr(RefPtr{this}); // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + refptr(this); // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + } + + explicit Bar(float f) { + // Does not match member expressions with `this` + RefPtr<Foo> foo = this->mFoo; + foo->foo(); + auto foo2 = RefPtr(this->mFoo); + foo2->foo(); + auto foo3 = RefPtr{this->mFoo}; + foo3->foo(); + } + + explicit Bar(short i); + + explicit Bar(int i): mBar(this) {} // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + explicit Bar(int i, int i2): mBar(RefPtr(this)) {} // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + + void Init() { + // Does not match outside the constructor + RefPtr<Bar> self = this; + auto self2 = RefPtr(this); + auto self3 = RefPtr{this}; + } + + void refptr(const RefPtr<Bar>& aBar) {} + + RefPtr<Foo> mFoo; + RefPtr<Bar> mBar; +}; + +// Test case for non-inline constructor +Bar::Bar(short i) { + RefPtr<Bar> self = this; // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + auto self2 = RefPtr(this); // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + auto self3 = RefPtr{this}; // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} +} + +// Same goes for any class with MOZ_IS_REFPTR (not including nsCOMPtr because SM +// doesn't have it) +template <typename T> class MOZ_IS_REFPTR MyRefPtr { +public: + MOZ_IMPLICIT MyRefPtr(T *aPtr) : mPtr(aPtr) {} + T *mPtr; +}; + +class Baz : RefCountedBase { + Baz() { + MyRefPtr<Baz> self = this; // expected-error {{Refcounting `this` inside the constructor is a footgun, `this` may be destructed at the end of the constructor unless there's another strong reference. Consider adding a separate Create function and do the work there.}} + (void)self; + } +}; diff --git a/build/clang-plugin/tests/TestSprintfLiteral.cpp b/build/clang-plugin/tests/TestSprintfLiteral.cpp new file mode 100644 index 0000000000..3c54ce004f --- /dev/null +++ b/build/clang-plugin/tests/TestSprintfLiteral.cpp @@ -0,0 +1,41 @@ +#include <cstdio> + +void bad() { + char x[100]; + snprintf(x, sizeof(x), "bar"); // expected-error {{Use SprintfLiteral instead of snprintf when writing into a character array.}} expected-note {{This will prevent passing in the wrong size to snprintf accidentally.}} + snprintf(x, 100, "bar"); // expected-error {{Use SprintfLiteral instead of snprintf when writing into a character array.}} expected-note {{This will prevent passing in the wrong size to snprintf accidentally.}} + const int hundred = 100; + snprintf(x, hundred, "bar"); // expected-error {{Use SprintfLiteral instead of snprintf when writing into a character array.}} expected-note {{This will prevent passing in the wrong size to snprintf accidentally.}} +} + +void ok() { + char x[100]; + int y; + snprintf(x, sizeof(y), "foo"); + + snprintf(x, 50, "foo"); + + int nothundred = 100; + nothundred = 99; + snprintf(x, nothundred, "foo"); +} + +void vargs_bad(va_list args) { + char x[100]; + vsnprintf(x, sizeof(x), "bar", args); // expected-error {{Use VsprintfLiteral instead of vsnprintf when writing into a character array.}} expected-note {{This will prevent passing in the wrong size to vsnprintf accidentally.}} + vsnprintf(x, 100, "bar", args); // expected-error {{Use VsprintfLiteral instead of vsnprintf when writing into a character array.}} expected-note {{This will prevent passing in the wrong size to vsnprintf accidentally.}} + const int hundred = 100; + vsnprintf(x, hundred, "bar", args); // expected-error {{Use VsprintfLiteral instead of vsnprintf when writing into a character array.}} expected-note {{This will prevent passing in the wrong size to vsnprintf accidentally.}} +} + +void vargs_good(va_list args) { + char x[100]; + int y; + vsnprintf(x, sizeof(y), "foo", args); + + vsnprintf(x, 50, "foo", args); + + int nothundred = 100; + nothundred = 99; + vsnprintf(x, nothundred, "foo", args); +} diff --git a/build/clang-plugin/tests/TestStackClass.cpp b/build/clang-plugin/tests/TestStackClass.cpp new file mode 100644 index 0000000000..3289abef1b --- /dev/null +++ b/build/clang-plugin/tests/TestStackClass.cpp @@ -0,0 +1,50 @@ +#define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class"))) +#include <stddef.h> + +struct MOZ_STACK_CLASS Stack { + int i; + void *operator new(size_t x) throw() { return 0; } + void *operator new(size_t blah, char *buffer) { return buffer; } +}; + +template <class T> +struct MOZ_STACK_CLASS TemplateClass { + T i; +}; + +void gobble(void *) { } + +void misuseStackClass(int len) { + Stack valid; + Stack alsoValid[2]; + static Stack notValid; // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} + static Stack alsoNotValid[2]; // expected-error-re {{variable of type 'Stack{{ ?}}[2]' only valid on the stack}} expected-note-re {{'Stack{{ ?}}[2]' is a stack type because it is an array of stack type 'Stack'}} expected-note {{value incorrectly allocated in a global variable}} + + gobble(&valid); + gobble(¬Valid); + gobble(&alsoValid[0]); + + gobble(new Stack); // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated on the heap}} + gobble(new Stack[10]); // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated on the heap}} + gobble(new TemplateClass<int>); // expected-error {{variable of type 'TemplateClass<int>' only valid on the stack}} expected-note {{value incorrectly allocated on the heap}} + gobble(len <= 5 ? &valid : new Stack); // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated on the heap}} + + char buffer[sizeof(Stack)]; + gobble(new (buffer) Stack); +} + +Stack notValid; // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +struct RandomClass { + Stack nonstaticMember; // expected-note {{'RandomClass' is a stack type because member 'nonstaticMember' is a stack type 'Stack'}} + static Stack staticMember; // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +}; +struct MOZ_STACK_CLASS RandomStackClass { + Stack nonstaticMember; + static Stack staticMember; // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +}; + +struct BadInherit : Stack {}; // expected-note {{'BadInherit' is a stack type because it inherits from a stack type 'Stack'}} +struct MOZ_STACK_CLASS GoodInherit : Stack {}; + +BadInherit moreInvalid; // expected-error {{variable of type 'BadInherit' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +RandomClass evenMoreInvalid; // expected-error {{variable of type 'RandomClass' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} diff --git a/build/clang-plugin/tests/TestStaticLocalClass.cpp b/build/clang-plugin/tests/TestStaticLocalClass.cpp new file mode 100644 index 0000000000..c3b0d8645a --- /dev/null +++ b/build/clang-plugin/tests/TestStaticLocalClass.cpp @@ -0,0 +1,54 @@ +#define MOZ_STATIC_LOCAL_CLASS __attribute__((annotate("moz_static_local_class"))) +#include <stddef.h> + +struct MOZ_STATIC_LOCAL_CLASS StaticLocal { + int i; + void *operator new(size_t x) throw() { return 0; } + void *operator new(size_t blah, char *buffer) { return buffer; } +}; + +template <class T> +struct MOZ_STATIC_LOCAL_CLASS TemplateClass { + T i; +}; + +void gobble(void *) { } + +void misuseStaticLocalClass(int len) { + StaticLocal notValid; // expected-error {{variable of type 'StaticLocal' is only valid as a static local}} expected-note {{value incorrectly allocated in an automatic variable}} + StaticLocal alsoNotValid[2]; // expected-error-re {{variable of type 'StaticLocal{{ ?}}[2]' is only valid as a static local}} expected-note-re {{'StaticLocal{{ ?}}[2]' is a static-local type because it is an array of static-local type 'StaticLocal'}} expected-note {{value incorrectly allocated in an automatic variable}} + static StaticLocal valid; + static StaticLocal alsoValid[2]; + + gobble(¬Valid); + gobble(&valid); + gobble(&alsoValid[0]); + + gobble(new StaticLocal); // expected-error {{variable of type 'StaticLocal' is only valid as a static local}} expected-note {{value incorrectly allocated on the heap}} + gobble(new StaticLocal[10]); // expected-error {{variable of type 'StaticLocal' is only valid as a static local}} expected-note {{value incorrectly allocated on the heap}} + gobble(new TemplateClass<int>); // expected-error {{variable of type 'TemplateClass<int>' is only valid as a static local}} expected-note {{value incorrectly allocated on the heap}} + gobble(len <= 5 ? &valid : new StaticLocal); // expected-error {{variable of type 'StaticLocal' is only valid as a static local}} expected-note {{value incorrectly allocated on the heap}} + + char buffer[sizeof(StaticLocal)]; + gobble(new (buffer) StaticLocal); +} + +StaticLocal notValid; // expected-error {{variable of type 'StaticLocal' is only valid as a static local}} expected-note {{value incorrectly allocated in a global variable}} + +struct RandomClass { + StaticLocal nonstaticMember; // expected-note {{'RandomClass' is a static-local type because member 'nonstaticMember' is a static-local type 'StaticLocal'}} + static StaticLocal staticMember; // expected-error {{variable of type 'StaticLocal' is only valid as a static local}} expected-note {{value incorrectly allocated in a global variable}} +}; + +struct MOZ_STATIC_LOCAL_CLASS RandomStaticLocalClass { + StaticLocal nonstaticMember; + static StaticLocal staticMember; // expected-error {{variable of type 'StaticLocal' is only valid as a static local}} expected-note {{value incorrectly allocated in a global variable}} +}; + +struct BadInherit : StaticLocal {}; // expected-note {{'BadInherit' is a static-local type because it inherits from a static-local type 'StaticLocal'}} +struct MOZ_STATIC_LOCAL_CLASS GoodInherit : StaticLocal {}; + +void misuseStaticLocalClassEvenMore(int len) { + BadInherit moreInvalid; // expected-error {{variable of type 'BadInherit' is only valid as a static local}} expected-note {{value incorrectly allocated in an automatic variable}} + RandomClass evenMoreInvalid; // expected-error {{variable of type 'RandomClass' is only valid as a static local}} expected-note {{value incorrectly allocated in an automatic variable}} +} diff --git a/build/clang-plugin/tests/TestTemporaryClass.cpp b/build/clang-plugin/tests/TestTemporaryClass.cpp new file mode 100644 index 0000000000..f00acf0d7a --- /dev/null +++ b/build/clang-plugin/tests/TestTemporaryClass.cpp @@ -0,0 +1,72 @@ +#define MOZ_TEMPORARY_CLASS __attribute__((annotate("moz_temporary_class"))) +#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) + +#include <stddef.h> + +struct MOZ_TEMPORARY_CLASS Temporary { + int i; + Temporary() {} + MOZ_IMPLICIT Temporary(int a) {} + Temporary(int a, int b) {} + void *operator new(size_t x) throw() { return 0; } + void *operator new(size_t blah, char *buffer) { return buffer; } +}; + +template <class T> +struct MOZ_TEMPORARY_CLASS TemplateClass { + T i; +}; + +void gobble(void *) { } + +void gobbleref(const Temporary&) { } + +template <class T> +void gobbleanyref(const T&) { } + +void misuseNonTemporaryClass(int len) { + // All of these should error. + Temporary invalid; // expected-error {{variable of type 'Temporary' is only valid as a temporary}} expected-note {{value incorrectly allocated in an automatic variable}} + Temporary alsoInvalid[2]; // expected-error-re {{variable of type 'Temporary{{ ?}}[2]' is only valid as a temporary}} expected-note {{value incorrectly allocated in an automatic variable}} expected-note-re {{'Temporary{{ ?}}[2]' is a temporary type because it is an array of temporary type 'Temporary'}} + static Temporary invalidStatic; // expected-error {{variable of type 'Temporary' is only valid as a temporary}} expected-note {{value incorrectly allocated in a global variable}} + static Temporary alsoInvalidStatic[2]; // expected-error-re {{variable of type 'Temporary{{ ?}}[2]' is only valid as a temporary}} expected-note {{value incorrectly allocated in a global variable}} expected-note-re {{'Temporary{{ ?}}[2]' is a temporary type because it is an array of temporary type 'Temporary'}} + + gobble(&invalid); + gobble(&invalidStatic); + gobble(&alsoInvalid[0]); + + // All of these should be fine. + gobbleref(Temporary()); + gobbleref(Temporary(10, 20)); + gobbleref(Temporary(10)); + gobbleref(10); + gobbleanyref(TemplateClass<int>()); + + // All of these should error. + gobble(new Temporary); // expected-error {{variable of type 'Temporary' is only valid as a temporary}} expected-note {{value incorrectly allocated on the heap}} + gobble(new Temporary[10]); // expected-error {{variable of type 'Temporary' is only valid as a temporary}} expected-note {{value incorrectly allocated on the heap}} + gobble(new TemplateClass<int>); // expected-error {{variable of type 'TemplateClass<int>' is only valid as a temporary}} expected-note {{value incorrectly allocated on the heap}} + gobble(len <= 5 ? &invalid : new Temporary); // expected-error {{variable of type 'Temporary' is only valid as a temporary}} expected-note {{value incorrectly allocated on the heap}} + + // Placement new is odd, but okay. + char buffer[sizeof(Temporary)]; + gobble(new (buffer) Temporary); +} + +void defaultArg(const Temporary& arg = Temporary()) { // expected-error {{variable of type 'Temporary' is only valid as a temporary}} expected-note {{value incorrectly allocated in an automatic variable}} +} + +// Can't be a global, this should error. +Temporary invalidStatic; // expected-error {{variable of type 'Temporary' is only valid as a temporary}} expected-note {{value incorrectly allocated in a global variable}} + +struct RandomClass { + Temporary nonstaticMember; // This is okay if RandomClass is only used as a temporary. + static Temporary staticMember; // expected-error {{variable of type 'Temporary' is only valid as a temporary}} expected-note {{value incorrectly allocated in a global variable}} +}; + +struct BadInherit : Temporary {}; + +void useStuffWrongly() { + gobbleanyref(BadInherit()); + gobbleanyref(RandomClass()); +} diff --git a/build/clang-plugin/tests/TestTrivialCtorDtor.cpp b/build/clang-plugin/tests/TestTrivialCtorDtor.cpp new file mode 100644 index 0000000000..a1038b6e63 --- /dev/null +++ b/build/clang-plugin/tests/TestTrivialCtorDtor.cpp @@ -0,0 +1,88 @@ +#define MOZ_TRIVIAL_CTOR_DTOR __attribute__((annotate("moz_trivial_ctor_dtor"))) + +struct MOZ_TRIVIAL_CTOR_DTOR EmptyClass{}; + +template <class T> +struct MOZ_TRIVIAL_CTOR_DTOR TemplateEmptyClass{}; + +struct MOZ_TRIVIAL_CTOR_DTOR NonEmptyClass { + void *m; +}; + +template <class T> +struct MOZ_TRIVIAL_CTOR_DTOR TemplateNonEmptyClass { + T* m; +}; + +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 OkVirtualMember { + 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 OkVirtualMemberInMember { + VirtualMember m; +}; + +struct MOZ_TRIVIAL_CTOR_DTOR OkConstExprConstructor { + constexpr OkConstExprConstructor() {} +}; + +struct MOZ_TRIVIAL_CTOR_DTOR OkConstExprConstructorInMember { + OkConstExprConstructor m; +}; + +#if __cplusplus >= 202002L +struct +#else +// XXX: This error is unfortunate, but is unlikely to come up in real code. +// In this situation, it should be possible to define a constexpr constructor +// which explicitly initializes the members. +struct // expected-error {{class 'BadUnfortunateError' must have trivial constructors and destructors}} +#endif +MOZ_TRIVIAL_CTOR_DTOR BadUnfortunateError { + OkConstExprConstructor m; + void *n; +}; diff --git a/build/clang-plugin/tests/TestTrivialDtor.cpp b/build/clang-plugin/tests/TestTrivialDtor.cpp new file mode 100644 index 0000000000..f86d41b238 --- /dev/null +++ b/build/clang-plugin/tests/TestTrivialDtor.cpp @@ -0,0 +1,52 @@ +#define MOZ_TRIVIAL_DTOR __attribute__((annotate("moz_trivial_dtor"))) + +struct MOZ_TRIVIAL_DTOR EmptyClass{}; + +template <class T> +struct MOZ_TRIVIAL_DTOR TemplateEmptyClass{}; + +struct MOZ_TRIVIAL_DTOR NonEmptyClass { + void *m; +}; + +template <class T> +struct MOZ_TRIVIAL_DTOR TemplateNonEmptyClass { + T* m; +}; + +struct MOZ_TRIVIAL_DTOR BadUserDefinedDtor { // expected-error {{class 'BadUserDefinedDtor' must have a trivial destructor}} + ~BadUserDefinedDtor() {} +}; + +struct MOZ_TRIVIAL_DTOR BadVirtualDtor { // expected-error {{class 'BadVirtualDtor' must have a trivial destructor}} + virtual ~BadVirtualDtor() {} +}; + +struct MOZ_TRIVIAL_DTOR OkVirtualMember { + virtual void f(); +}; + +void foo(); +struct MOZ_TRIVIAL_DTOR BadNonEmptyCtorDtor { // expected-error {{class 'BadNonEmptyCtorDtor' must have a trivial destructor}} + BadNonEmptyCtorDtor() { foo(); } + ~BadNonEmptyCtorDtor() { foo(); } +}; + +struct NonTrivialDtor { + ~NonTrivialDtor() { foo(); } +}; + +struct VirtualMember { + virtual void f(); +}; + +struct MOZ_TRIVIAL_DTOR BadNonTrivialDtorInBase : NonTrivialDtor { // expected-error {{class 'BadNonTrivialDtorInBase' must have a trivial destructor}} +}; + +struct MOZ_TRIVIAL_DTOR BadNonTrivialDtorInMember { // expected-error {{class 'BadNonTrivialDtorInMember' must have a trivial destructor}} + NonTrivialDtor m; +}; + +struct MOZ_TRIVIAL_DTOR OkVirtualMemberInMember { + VirtualMember m; +}; diff --git a/build/clang-plugin/tests/moz.build b/build/clang-plugin/tests/moz.build new file mode 100644 index 0000000000..45f416be44 --- /dev/null +++ b/build/clang-plugin/tests/moz.build @@ -0,0 +1,101 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# dummy library name to avoid skipping building the sources here. +Library("clang-plugin-tests") + +SOURCES += [ + "TestAssertWithAssignment.cpp", + "TestBadImplicitConversionCtor.cpp", + "TestCanRunScript.cpp", + "TestCustomHeap.cpp", + "TestDanglingOnTemporary.cpp", + "TestExplicitOperatorBool.cpp", + "TestGlobalClass.cpp", + "TestHeapClass.cpp", + "TestInheritTypeAnnotationsFromTemplateArgs.cpp", + "TestJSHandleRootedTypedef.cpp", + "TestKnownLive.cpp", + "TestKungFuDeathGrip.cpp", + "TestMultipleAnnotations.cpp", + "TestMustOverride.cpp", + "TestMustReturnFromCaller.cpp", + "TestNANTestingExpr.cpp", + "TestNANTestingExprC.c", + "TestNeedsNoVTableType.cpp", + "TestNoAddRefReleaseOnReturn.cpp", + "TestNoArithmeticExprInArgument.cpp", + "TestNoAutoType.cpp", + "TestNoDuplicateRefCntMember.cpp", + "TestNoExplicitMoveConstructor.cpp", + "TestNoNewThreadsChecker.cpp", + "TestNonHeapClass.cpp", + "TestNonMemMovable.cpp", + "TestNonMemMovableStd.cpp", + "TestNonMemMovableStdAtomic.cpp", + "TestNonParameterChecker.cpp", + "TestNonTemporaryClass.cpp", + "TestNonTrivialTypeInFfi.cpp", + "TestNoPrincipalGetUri.cpp", + "TestNoRefcountedInsideLambdas.cpp", + "TestNoUsingNamespaceMozillaJava.cpp", + "TestOverrideBaseCall.cpp", + "TestOverrideBaseCallAnnotation.cpp", + "TestParamTraitsEnum.cpp", + "TestRefCountedCopyConstructor.cpp", + "TestRefCountedThisInsideConstructor.cpp", + "TestSprintfLiteral.cpp", + "TestStackClass.cpp", + "TestStaticLocalClass.cpp", + "TestTemporaryClass.cpp", + "TestTrivialCtorDtor.cpp", + "TestTrivialDtor.cpp", +] + +if CONFIG["OS_ARCH"] == "WINNT": + SOURCES += [ + "TestFopenUsage.cpp", + "TestLoadLibraryUsage.cpp", + ] + +include("../external/tests/sources.mozbuild") + +if CONFIG["ENABLE_CLANG_PLUGIN_ALPHA"]: + DEFINES["MOZ_CLANG_PLUGIN_ALPHA"] = "1" + include("../alpha/tests/sources.mozbuild") + +DisableStlWrapping() +NoVisibilityFlags() + +# Build without any warning flags, and with clang verify flag for a +# syntax-only build (no codegen), without a limit on the number of errors. +COMPILE_FLAGS["OS_CXXFLAGS"] = [ + f for f in COMPILE_FLAGS.get("OS_CXXFLAGS", []) if not f.startswith("-W") +] + [ + "-fsyntax-only", + "-Xclang", + "-verify", + "-ferror-limit=0", + "-Wno-invalid-noreturn", + # For SpiderMonkey headers in TestJSHandleRootedTypedef.cpp + "-Wno-attributes", + "-Wno-invalid-offsetof", +] +COMPILE_FLAGS["OS_CFLAGS"] = [ + f for f in COMPILE_FLAGS.get("OS_CFLAGS", []) if not f.startswith("-W") +] + [ + "-fsyntax-only", + "-Xclang", + "-verify", + "-ferror-limit=0", + "-Xclang", + "-std=c11", + "-Wno-invalid-noreturn", +] + +# Don't reflect WARNINGS_CFLAGS into CFLAGS, as the warnings flags should be +# as specified in OS_CFLAGS above. +DisableCompilerWarnings() |