0

Background

I'm helping debug a code base. I can't give exact details about it, but such details should be out of scope of an SO question anyway, my actual question is how I actually diagnose why an arbitrary noexcept defaulted function gets deleted anyway, not solve my codebase specific debugging issue.

The (scrubbed) version of the error I get is the following:

/.../bin/cmake --build /.../cmake-build-debug --target [current_project] -- -j 3
...
Scanning dependencies of target [other_module]
...
Scanning dependencies of target [current_project]
...

#[first instance of any error or warning that has to do with 'other_module']
/.../[current_project]/foo.cpp: In member function ‘void util::Foo::update_size(int32_t, int32_t)’:
/.../[current_project]/foo.cpp:159:70: error: use of deleted function ‘[other_module]::Bar& [other_module]::Bar::operator=([other_module]::Bar&&)’
     m_Bar = createBar(number_generator, width, height);

In file included from /.../[current_project]/foo.h:11,
                 from /.../[current_project]/foo.cpp:6:
/.../[current_project]/external/[other_module]/include/Bar.h:69:27: note: ‘[other_module]::Bar& [other_module]::Bar::operator=([other_module]::Bar&&) noexcept’ is implicitly deleted because its exception-specification does not match the implicit exception-specification ‘’
   Bar& operator=(Bar&& r) noexcept = default;
#[No other instances afterwards 'other_module']
...
gmake[3]: *** [CMakeFiles/[current_project].dir/build.make:278: CMakeFiles/[current_project].dir/foo.cpp.o] Error 1
gmake[2]: *** [CMakeFiles/Makefile2:455: CMakeFiles/[current_project].dir/all] Error 2
gmake[1]: *** [CMakeFiles/Makefile2:462: CMakeFiles/[current_project].dir/rule] Error 2
gmake: *** [Makefile:184: [current_project]] Error 2

Note that createBar has the following scrubbed signature:

Bar createTracker(NumberGenerator number_generator, int width, int height);

I assume is implicitly deleted because its exception-specification does not match the implicit exception-specification means that there is something that isn't/can't be noexcept, either in the inheritance chain of Bar or in the member variables' move assignment operators that causes this to be an issue.

Note that the other_module is configured as it's own target, and compiling said target does not show any warnings or errors on its own.

However I can't get clang tools or GCC to tell me where that problem is. I know it is the noexcept causing the issue, because if I remove it, the program compiles. A scrubbed version of Bar.

class Bar : public Baz{
public:

Bar(NumberGenerator number_generator,
        int width, int height);

Bar(const Bar&) noexcept = default;

Bar(Bar&&) noexcept = default;

Bar& operator=(const Bar& r) noexcept = default;
//offending declaration
Bar& operator=(Bar&& r) noexcept = default;
//working declaration
//Bar& operator=(Bar&& r) = default;

private:
    static bool s_value;

    Bax m_bax;
    Qux m_qux;
    std::vector<Quux> m_quux_list;

    std::vector<Corge> m_corge_list;
};

I thought that maybe if I manually implemented the definition, it would help me isolate where the violation came from, even though this should have been the information GCC gave me in the first place. Upon implementing it manually however, I found... it just compiled. no issues.

//no longer defaulted:
Bar& operator=(Bar&& r) noexcept;
//definition:
Bar &
Bar::operator=(Bar &&r) noexcept {
    m_bax = std::move(r.m_bax);
    m_qux = std::move(r.m_qux);
    m_quux_list = std::move(r.m_quux_list);
    m_corge_list = std::move(r.m_corge_list);
    return *this;
}

Question

What can I actually do (ie compiler args, manual code testing, etc...) to figure out where an arbitrary "noexcept" conflict like this is happening?

Krupip
  • 4,404
  • 2
  • 32
  • 54
  • What about the members of `Baz` you aren't moving in your custom implementation? – clcto Feb 22 '21 at 20:28
  • @cicto that's a good point, though in this case, Baz has no members, and is just an abstract class – Krupip Feb 22 '21 at 20:33
  • What version of C++ are you using? Untill C++17, `std::vector::operator=(vector&&)` was not `noexcept` – NathanOliver Feb 22 '21 at 20:35
  • @NathanOliver I'm using C++17, but the other library (which is causing this issue) is explicitly C++14, Is that the issue then? By definition it shouldn't be noexcept because it's defined not to be? – Krupip Feb 22 '21 at 20:38
  • @whn That sounds like it could be the issue. FWIW, using `Bar& operator=(Bar&& r) = default;` will make the operator `noexcept` if all of the members have a `noexcept` move assignment operator. Otherwise it will not be `noexcept`. You really shouldn't need to specify `noexcpt` for defaulted constructors/special member functions. – NathanOliver Feb 22 '21 at 20:40
  • @NathanOliver Does this only apply to the move assignment operator? or does this apply to all of the operators and constructors that can be defaulted? – Krupip Feb 22 '21 at 20:49
  • It applies to all defaulted constructors and assignment operators. – NathanOliver Feb 22 '21 at 20:51

0 Answers0