https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91388

            Bug ID: 91388
           Summary: -Wreturn-type "no return statement" warning in
                    function that is already ill-formed
           Product: gcc
           Version: 9.1.1
            Status: UNCONFIRMED
          Keywords: diagnostic
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: redi at gcc dot gnu.org
  Target Milestone: ---

template<typename T> struct copyable;

template<typename T>
T func(const T& t)
{
  static_assert(copyable<T>::value);
  return t;
}

struct NoCopy {
  NoCopy() { }
  NoCopy(const NoCopy&) = delete;
};

template<> struct copyable<NoCopy> { static constexpr bool value = false; };

int main()
{
  NoCopy nc;
  func(nc);
}

This produces the following diagnostics:

nc.cc:20:10:   required from here
nc.cc:6:30: error: static assertion failed
    6 |   static_assert(copyable<T>::value);
      |                              ^~~~~
nc.cc:7:10: error: use of deleted function 'NoCopy::NoCopy(const NoCopy&)'
    7 |   return t;
      |          ^
nc.cc:12:3: note: declared here
   12 |   NoCopy(const NoCopy&) = delete;
      |   ^~~~~~

As the author of func<T> I have already added a static assertion to check if
the return statement will be well-formed, so the second error is redundant (and
I'd prefer for my users to not see it, the static assertion is for their
benefit).

So I try writing the function like this instead:

template<typename T>
T func(const T& t)
{
  static_assert(copyable<T>::value);

  if constexpr (copyable<T>::value)
    return t;
}

Now the compiler says:

nc.cc: In instantiation of 'T func(const T&) [with T = NoCopy]':
nc.cc:22:10:   required from here
nc.cc:6:30: error: static assertion failed
    6 |   static_assert(copyable<T>::value);
      |                              ^~~~~
nc.cc:10:1: warning: no return statement in function returning non-void
[-Wreturn-type]
   10 | }
      | ^

To suppress the warning I need to do:

template<typename T>
T func(const T& t)
{
  static_assert(copyable<T>::value);

  if constexpr (copyable<T>::value)
    return t;
  __builtin_unreachable();
}

I don't think it should be necessary to mark it unreachable. The fact the
static assertion failed means it's already guaranteed to be unreachable,
because it's not even compilable!

Could the -Wreturn-type warning be suppressed when the function is already
ill-formed?

I note that clang's -Wreturn-type diagnostic is phrased "warning: control
reaches end of non-void function" and isn't given for ill-formed functions.
That makes sense because control cannot reach the end of a function that cannot
possibly execute.

Reply via email to