Skip to content
Snippets Groups Projects
  • Nat Goodspeed's avatar
    322c4c6b
    DRTVWR-418: Fix -std=c++11 llinstancetracker_test crash. · 322c4c6b
    Nat Goodspeed authored
    LLInstanceTracker<T> performs validation in ~LLInstanceTracker(). Normally
    validation failure logs an error and terminates the program, which is fine. In
    the test executable, though, we want validation failure to throw an exception
    instead so we can catch it and continue testing other failure conditions. But
    since destructors in C++11 are implicitly noexcept(true), that exception never
    made it out of ~LLInstanceTracker(): it crashed the test program instead.
    Declaring ~LLInstanceTracker() noexcept(false) solves that, allowing the test
    program to catch the exception and continue.
    
    However, if we unconditionally declare that, then every destructor anywhere in
    the inheritance hierarchy for any LLInstanceTracker subclass must also be
    noexcept(false)! That's way too pervasive, especially for functionality we
    only need (or want) in a specific test executable.
    
    Instead, make the CMake macros LL_ADD_PROJECT_UNIT_TESTS() and
    LL_ADD_INTEGRATION_TEST() -- with which we define all viewer build-time tests
    -- define two new command-line macros: LL_TEST=testname and LL_TEST_testname.
    That way, preprocessor logic in a header file can detect whether it's being
    compiled for production code or for a test executable.
    
    (While at it, encapsulate in a new GET_OPT_SOURCE_FILE_PROPERTY() CMake macro
    an ugly repetitive pattern. The builtin GET_SOURCE_FILE_PROPERTY() sets the
    target variable to "NOTFOUND" -- rather than an empty string -- if the
    specified property wasn't set. Every call to GET_SOURCE_FILE_PROPERTY() in
    LL_ADD_PROJECT_UNIT_TESTS() was followed by a test for NOTFOUND and an
    assignment to "". Wrap all that in a macro whose 'unset' value is "".)
    
    Now llinstancetracker.h can detect when we're building the LLInstanceTracker
    unit test executable, and *only then* declare ~LLInstanceTracker() as
    noexcept(false). We #define LLINSTANCETRACKER_DTOR_NOEXCEPT to expand either
    empty or noexcept(false), also detecting clang in C++11 mode. (It all works
    fine without noexcept(false) until we turn on C++11 mode.)
    
    We also use that macro for the StatBase class in lltrace.h. Turns out some of
    the infrastructure headers required for tests in general, including the
    LLInstanceTracker test, use LLInstanceTracker. Fortunately that appears to be
    the only other class we must annotate this way for the LLInstanceTracker tests.
    322c4c6b
    History
    DRTVWR-418: Fix -std=c++11 llinstancetracker_test crash.
    Nat Goodspeed authored
    LLInstanceTracker<T> performs validation in ~LLInstanceTracker(). Normally
    validation failure logs an error and terminates the program, which is fine. In
    the test executable, though, we want validation failure to throw an exception
    instead so we can catch it and continue testing other failure conditions. But
    since destructors in C++11 are implicitly noexcept(true), that exception never
    made it out of ~LLInstanceTracker(): it crashed the test program instead.
    Declaring ~LLInstanceTracker() noexcept(false) solves that, allowing the test
    program to catch the exception and continue.
    
    However, if we unconditionally declare that, then every destructor anywhere in
    the inheritance hierarchy for any LLInstanceTracker subclass must also be
    noexcept(false)! That's way too pervasive, especially for functionality we
    only need (or want) in a specific test executable.
    
    Instead, make the CMake macros LL_ADD_PROJECT_UNIT_TESTS() and
    LL_ADD_INTEGRATION_TEST() -- with which we define all viewer build-time tests
    -- define two new command-line macros: LL_TEST=testname and LL_TEST_testname.
    That way, preprocessor logic in a header file can detect whether it's being
    compiled for production code or for a test executable.
    
    (While at it, encapsulate in a new GET_OPT_SOURCE_FILE_PROPERTY() CMake macro
    an ugly repetitive pattern. The builtin GET_SOURCE_FILE_PROPERTY() sets the
    target variable to "NOTFOUND" -- rather than an empty string -- if the
    specified property wasn't set. Every call to GET_SOURCE_FILE_PROPERTY() in
    LL_ADD_PROJECT_UNIT_TESTS() was followed by a test for NOTFOUND and an
    assignment to "". Wrap all that in a macro whose 'unset' value is "".)
    
    Now llinstancetracker.h can detect when we're building the LLInstanceTracker
    unit test executable, and *only then* declare ~LLInstanceTracker() as
    noexcept(false). We #define LLINSTANCETRACKER_DTOR_NOEXCEPT to expand either
    empty or noexcept(false), also detecting clang in C++11 mode. (It all works
    fine without noexcept(false) until we turn on C++11 mode.)
    
    We also use that macro for the StatBase class in lltrace.h. Turns out some of
    the infrastructure headers required for tests in general, including the
    LLInstanceTracker test, use LLInstanceTracker. Fortunately that appears to be
    the only other class we must annotate this way for the LLInstanceTracker tests.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.