Michael Jung
Michael Jung

Reputation: 380

What is the meaning of “noexcept-expression evaluates to ‘false’ because of a call to…”?

Consider the following example:

#include <chrono>

using T = std::chrono::system_clock::time_point;

struct A
{
  A() = default;
  explicit A(T time) : time{time}
  {
  }

  T time{};
};

A foo()
{
  return A{};
}

When I compile this code with GCC 9.2.0, it will generate the following warning:

$ g++ -c noexcept.cpp -o noexcept.cpp.o --std=c++17 -Wnoexcept
noexcept.cpp:18:12: warning: noexcept-expression evaluates to ‘false’ because of a call to ‘constexpr std::chrono::time_point<_Clock, _Dur>::time_point() [with _Clock = std::chrono::_V2::system_clock; _Dur = std::chrono::duration<long int, std::ratio<1, 1000000000> >]’ [-Wnoexcept]
   18 |   return A{};
      |            ^

I do not understand the meaning of this warning. It is only generated when the second constructor is in place (even though it is never called).

The warning talks about a noexcept-expression that is being evaluated. As I don’t see any such expression, I suppose there is something like an implicit noexcept-expression in the first constructor. I don’t understand why something like that should lead to a warning, though. And why does it make a difference if the second constructor is there?

Could you please shed some light onto this and explain what the problem with this code is?

Upvotes: 6

Views: 1485

Answers (2)

eerorika
eerorika

Reputation: 238281

This looks like a false positive diagnostic to me. Because there indeed doesn't appear to be any noexcept-expression that would evaluate to false because of that function.

P.S. The behaviour doesn't reproduce if I remove the default member initialiser from A::time. As far as I know, this has no semantic difference in the example program.

Upvotes: 1

Brian Bi
Brian Bi

Reputation: 119034

It seems you explicitly opted into -Wnoexcept. The meaning of the flag is explained here: https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Dialect-Options.html

Warn when a noexcept-expression evaluates to false because of a call to a function that does not have a non-throwing exception specification (i.e. throw() or noexcept) but is known by the compiler to never throw an exception.

In this case, I would have to guess that the compiler is implicitly evaluating a noexcept-expression involving T{} in order to determine whether the defaulted default constructor of A should be implicitly declared noexcept. The warning arises because the compiler can determine that the default constructor of time_point never throws, yet said default constructor is not declared noexcept. See here for definition.

There is no issue with your code. The root cause of the warning is that time_point doesn't have the appropriate noexcept declaration. However, this is true for many standard library constructors, and it will take a long time to fix all of them. So, in the meantime, this warning seems to mostly add noise. If you still want to compile with this flag, you could define A::A() yourself as A() noexcept {}. (In this case you wouldn't be giving up triviality, since T::T() isn't trivial anyway.)

Upvotes: 6

Related Questions