Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GMock doesn't support noexcept functions #2472

Closed
dotnetjunky opened this issue Sep 23, 2019 · 8 comments · Fixed by #2498
Closed

GMock doesn't support noexcept functions #2472

dotnetjunky opened this issue Sep 23, 2019 · 8 comments · Fixed by #2498

Comments

@dotnetjunky
Copy link

Hi,

What is the current plan for supporting mocking noexcept functions? From searching StackOverflow, I understand that it's currently not possible to mock noexcept functions. Is there a workaround?

Thanks

@kuzkry
Copy link
Contributor

kuzkry commented Sep 23, 2019

Hi! Does this address your issue?

@dotnetjunky
Copy link
Author

Is the MOCK_METHOD macro new in version 1.8? Our team is using 1.7 and I don't see the MOCK_METHOD macro. I only see the MOCK_METHODn macros. I'll try to update to 1.8 and give it a try.

@kuzkry
Copy link
Contributor

kuzkry commented Sep 25, 2019

The latest release is 1.8.1 and MOCK_METHOD was introduced after that had been published.

@thejcannon
Copy link
Contributor

thejcannon commented Oct 4, 2019

From skimming the MOCK_METHOD macros, it looks like noexcept expressions aren't supported.
Stuff like noexcept(false) or noexcept(noexcept(A+B))

@kuzkry
Copy link
Contributor

kuzkry commented Oct 5, 2019

@thejcannon, you aren't right, code with noexcept expressions compiles. Example:

struct Interface {
  virtual ~Interface() = default;

  virtual int foo1() const = 0;
  virtual int foo2() const = 0;
};

struct Mock : Interface {
  MOCK_METHOD(int, foo1, (), (const, override, noexcept(false)));
  MOCK_METHOD(int, foo2, (), (const, override, noexcept(noexcept(1 + 2))));
};

@thejcannon
Copy link
Contributor

Oh man, it's worse than expected. It compiles, but has the wrong side-effects.

struct Interface {
  virtual ~Interface() = default;
  virtual int foo1() const noexcept(false) = 0;
};

struct Mock : Interface {
  MOCK_METHOD(int, foo1, (), (const, override, noexcept(false)));
};

static_assert(
    !noexcept(std::declval<Mock>().foo1())
);
static_assert(
    !std::is_nothrow_invocable_v<std::remove_pointer_t<decltype(&Mock::foo1)>, Mock const*>
);

Both static assertions fail, which means foo1 is noexcept(true).

@thejcannon
Copy link
Contributor

If you do Scott Meyer's little "type-displayer" trick, you'll see the mock is being declared as noexcept (no condition). foo1 has type:
int (Mock::*)() const noexcept

Probably an issue with how the macro handles noexcept. You can see here that it either slaps noexcept on the generated mock or it doesn't. The preprocessor logic here essentially boils down to "if any of the spec arguments start with a noexcept". So noexcept, noexcept(true), noexcept(false), noexcept(noxcept(A+B)) will all evaluate to some truthy value, and line 109 will slap noexcept on those methods.

This comment seems to imply the authors know about this.

@kuzkry
Copy link
Contributor

kuzkry commented Oct 7, 2019

Oh my goodness! There's nothing like a lovely hidden bug, isn't it? ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants
@thejcannon @dotnetjunky @kuzkry and others