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

Jason Merrill <jason at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jason at gcc dot gnu.org,
                   |                            |ville.voutilainen at gmail dot 
com

--- Comment #4 from Jason Merrill <jason at gcc dot gnu.org> ---
(In reply to Allan Jensen from comment #0)
> I seems to me when it warns about a previous failure to complete SFINAE, it
> should tell where that was by default and not instruct us to compile again
> with the warning set to report more false positives.

The issue is that failure to complete is not a problem in itself; it's OK to
have incomplete classes.  By default the warning only checks whether such a
type is later completed.  Ideally rather than suggest running the compiler
again with another flag we would store away the full context of the previous
use for the delayed diagnostic, but that's impractical.

With your testcase I need to specify -Wsystem-headers along with
-Wsfinae-incomplete=2 to get the interesting output, because the incompleteness
in SFINAE context happens in std::data, in the standard library.

At that point the QAnyStringView warnings point to these lines:
   
static_assert(QtPrivate::IsContainerCompatibleWithQStringView<QAnyStringView>::value
== false);
static_assert(QtPrivate::IsContainerCompatibleWithQUtf8StringView<QAnyStringView>::value
== false);

which are within the body of QAnyStringView.  One of the full diagnostics looks
like 

wa.ii: In substitution of ‘template<class _Container> constexpr decltype
(__cont.data()) std::data(const _Container&) [with _Container =
QAnyStringView]’:
wa.ii:97042:52:   required by substitution of ‘template<class T> struct
QtPrivate::IsContainerCompatibleWithQStringView<T, typename
std::enable_if<conjunction_v<QtPrivate::IsCompatiblePointer<decltype
(std::data(declval<const T&>()))>, std::is_convertible<decltype
(std::size(declval<const T&>())), long long int>,
QtPrivate::IsCompatibleCharType<typename std::iterator_traits<decltype
(std::begin(declval<const T&>()))>::value_type>, std::is_convertible<decltype
((std::begin(declval<const T&>()) != std::end(declval<const T&>()))), bool>,
std::negation<std::is_same<typename std::decay<_Tp>::type, QString> >,
std::negation<std::is_same<typename std::decay<_Tp>::type, QStringView> > >,
void>::type> [with T = QAnyStringView]’
97042 |             IsCompatiblePointer<decltype( std::data(std::declval<const
T &>()) )>,
      |                                          
~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
wa.ii:98178:82:   required from here
98178 |    
static_assert(QtPrivate::IsContainerCompatibleWithQStringView<QAnyStringView>::value
== false);
      |                                                                        
         ^~
wa.ii:50528:24: warning: failed to complete ‘QAnyStringView’ in SFINAE context
[-Wsfinae-incomplete=]
50528 |     -> decltype(__cont.data())
      |                 ~~~~~~~^~~~

This reduces roughly to

template <class T> auto data (const T& t) -> decltype (t.data());
template <class T> concept Data = requires (const T& t) { data(t); };
struct A {
  void data() const;
  static_assert (!Data<A>); // data(A()) ill-formed here
};
static_assert (Data<A>); // data(A()) well-formed here

At the static_assert in the class body, instantiating data<A> is ill-formed
because A isn't complete yet, so Data<A> is not satisfied.  After the class
body, it's well-formed, so Data<A> is satisfied.  This change of satisfaction
is IFNDR, and GCC complains about it with a "satisfaction changed" error.

-Wsfinae-incomplete warns about this situation sooner, at the point of
completing the definition of A, that something was previously affected by its
incompleteness.

The warning for the Qt code is a true positive; they should probably just move
the static_asserts out of the class body.

Reply via email to