This is an archive of the discontinued LLVM Phabricator instance.

[Clang] Fix member lookup so that we don't ignore ambiguous lookups in some cases
ClosedPublic

Authored by shafik on Jul 15 2023, 10:04 PM.

Details

Summary

There are some cases during member lookup we are aggressively suppressing diagnostics when we should just be suppressing access control diagnostic.

In this PR I add the ability to simply suppress access diagnostics while not suppressing ambiguous lookup diagnostics.

Fixes: https://github.com/llvm/llvm-project/issues/22413
https://github.com/llvm/llvm-project/issues/29942
https://github.com/llvm/llvm-project/issues/35574
https://github.com/llvm/llvm-project/issues/27224

Diff Detail

Event Timeline

shafik created this revision.Jul 15 2023, 10:04 PM
Herald added a project: Restricted Project. · View Herald TranscriptJul 15 2023, 10:04 PM
shafik requested review of this revision.Jul 15 2023, 10:04 PM

It looks like the paragraphs in class.member.lookup have changed a lot and so the tests don't totally match in that directory. Fixing that seems like a big piece of work but maybe worth doing.

clang/include/clang/Sema/Lookup.h
152

Note sure about this, alternatively I could set it to what DiagnoseAccess is set to as well.

clang/lib/Sema/SemaOverload.cpp
14986

I was a bit conservative where I changed this but maybe we should do this everywhere.

cor3ntin added inline comments.Jul 16 2023, 6:17 AM
clang/include/clang/Sema/Lookup.h
197–200

these std::move are a bit superfluous :)

228–230

Does anything break if you remove these two lines? they don't appear useful

rsmith added inline comments.Jul 16 2023, 10:07 AM
clang/include/clang/Sema/Lookup.h
228–230

I think these make sense: if we move a lookup result into this one, then the other lookup result shouldn't issue diagnostics any more. (Otherwise we could see the same diagnostics twice.)

clang/lib/Sema/SemaOverload.cpp
14986

Most of the other calls in this file all look wrong. DiagnoseTwoPhaseLookup and BuildRecoveryCallExpr are doing error recovery and I think it's appropriate for them to suppress all diagnostics, but the rest are doing standard-mandated searches, and so should diagnose lookup ambiguity.

cor3ntin added inline comments.Jul 16 2023, 10:49 AM
clang/include/clang/Sema/Lookup.h
228–230

The reason I'm asking is that we don't seem consistent about resetting the state of the moved-from lookup, so i don;t know if moved from lookup are ever reused. and if they are, should we use std::exchange or something along those lines?

rsmith added inline comments.Jul 16 2023, 1:16 PM
clang/include/clang/Sema/Lookup.h
228–230

I don't think moved-from LookupResults are ever reused, and I don't think it's the intent for this function to leave a moved-from result in a state suitable for use in further lookups. (If you assign over a moved-from lookup result, that'd presumably work fine, though I doubt we ever do that.) The point here, I think, is just to leave the source of the move in a state where the destructor doesn't have side-effects any more.

shafik added inline comments.Jul 16 2023, 2:54 PM
clang/lib/Sema/SemaOverload.cpp
14986

So it looks like BuildOverloadedArrowExpr catches the ambiguous lookup when calling CandidateSet.BestViableFunction(...) while BuildCallToObjectOfClassType(...) does not. So if I change the suppressDiagnostics() call in BuildOverloadedArrowExpr we get double diagnostic. I am not seeing why we have the inconsistency here.

shafik added inline comments.Jul 16 2023, 10:58 PM
clang/lib/Sema/SemaOverload.cpp
14986

Correction, there are not duplicate diagnostics, one is for ambiguous overload and the other is for ambiguous name lookup. Maybe we should suppress the ambiguous overload if we have an ambiguous name lookup though.

shafik updated this revision to Diff 540866.Jul 16 2023, 11:03 PM
  • Adjusted more place to use suppressAccessDiagnostics
shafik marked an inline comment as done.Jul 17 2023, 4:06 PM
shafik added inline comments.
clang/include/clang/Sema/Lookup.h
197–200

Yeah, I was just keeping consistent. I don't think they are doing any harm in this case.

shafik added inline comments.Jul 19 2023, 12:23 PM
clang/lib/Sema/SemaOverload.cpp
15265

@rsmith if R.isAmbiguous() should we even check the overload candidates?

Right now in clang/test/SemaCXX/arrow-operator.cpp we are getting both an ambiguous name lookup and overload diagnostic.

shafik added a reviewer: Restricted Project.Jul 20 2023, 1:18 PM
rsmith added inline comments.Jul 21 2023, 3:04 PM
clang/lib/Sema/SemaOverload.cpp
15265

Hm, I think perhaps the ideal thing to do is: if BestViableFunction returns OR_Ambiguous, the lookup was ambiguous, and we found viable functions in multiple different base classes, then don't produce any further diagnostics. That way, we still get good error recovery in the case where the overloading is unambiguous despite the lookup being ambiguous, or when the overloading is ambiguous for some reason unrelated to the ambiguous lookup.

(We'd want to do this in all the overloaded operator lookups in this file, not just for operator->.)

shafik updated this revision to Diff 544960.Jul 27 2023, 3:33 PM
shafik marked an inline comment as done.
  • Updated so that we ignore ambiguous overload candidate if the name lookup was also ambiguous.
shafik marked 4 inline comments as done.Jul 27 2023, 3:35 PM
shafik added inline comments.
clang/lib/Sema/SemaOverload.cpp
15265

I only found one other location that matched this pattern if you meant a larger change let me know.

rsmith accepted this revision.Jul 28 2023, 1:40 PM

This looks good to me. I think we can further refine the handling of duplicate diagnostics but I don't think that needs to be done as part of this bugfix.

clang/lib/Sema/SemaOverload.cpp
953

Can we get duplicate diagnostics here if this lookup fails due to ambiguity? I think we'll perform the same lookup again when looking for candidates if the original operator was !=.

(I wonder if we can fix that by avoiding the duplicate lookup, rather than by suppressing ambiguity diagnostics.)

964

There can't be any access diagnostics here because this is a namespace-scope lookup. You can just drop this call entirly.

15083–15089

I think we should also check whether the ambiguous viable functions were all first declared in the same base class here. If so, then it still makes sense to NoteCandidates, because the ambiguous lookup had nothing to do with the ambiguous overload resolution.

15265

Ideally, we should make AddMemberOperatorCandidates (and LookupOverloadedBinOp) inform its three callers whether its lookup was ambiguous, so that they can also suppress the duplicate ambiguity diagnostics, for unary operators, binary operators, and subscripting.

15293–15298

(Likewise here.)

This revision is now accepted and ready to land.Jul 28 2023, 1:40 PM
shafik edited the summary of this revision. (Show Details)Jul 28 2023, 2:33 PM
shafik updated this revision to Diff 545283.Jul 28 2023, 2:49 PM

Add release note.

This revision was landed with ongoing or failed builds.Jul 28 2023, 3:24 PM
This revision was automatically updated to reflect the committed changes.
Herald added a project: Restricted Project. · View Herald TranscriptJul 28 2023, 3:24 PM
hctim added a subscriber: hctim.Aug 3 2023, 7:57 AM

Hi folks,

I found an issue with building Android using this patch. I've reduced it down to the following problem where the evaluation of the std::visit is believed to be non-exhaustive, but it seems like it is? Would you mind taking a look? Admittedly, my knowledge in this area of the cxx stdlib is not so great.

Thanks.

$ cat /tmp/variant.cpp
#include <utility>
#include <variant>

struct A {};
struct B {};

using MyVariant = std::variant<A, B>;

// Helper to std::visit with lambdas.
template <typename... V>
struct Visitor : V... {};
// explicit deduction guide (not needed as of C++20)
template <typename... V>
Visitor(V...) -> Visitor<V...>;

const char* toString(const MyVariant& args) {
    Visitor toStringVisitor{
            [&](const A&) { return "A"; },
            [&](const B&) { return "B"; },
    };
    return std::visit(toStringVisitor, args);
}
$ ~/llvm-build/opt/bin/clang++ /tmp/variant.cpp -c -o /tmp/variant.o -std=c++17 -stdlib=libc++
In file included from /tmp/variant.cpp:2:
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:680:19: error: static assertion failed due to requirement 'is_invocable_v<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &, const A &>': `std::visit` requires the visitor to be exhaustive.
  680 |     static_assert(is_invocable_v<_Visitor, _Values...>,
      |                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:689:7: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__variant::__std_visit_exhaustive_visitor_check<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &, const A &>' requested here
  689 |       __std_visit_exhaustive_visitor_check<
      |       ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/__type_traits/invoke.h:337:10: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &>::operator()<const std::__variant_detail::__alt<0, A> &>' requested here
  337 | decltype(std::declval<_Fp>()(std::declval<_Args>()...))
      |          ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:572:16: note: while substituting deduced template arguments into function template '__invoke' [with _Fp = std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &>, _Args = <const __alt<0UL, A> &>]
  572 |         return _VSTD::__invoke(
      |                ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/__config:805:17: note: expanded from macro '_VSTD'
  805 | #  define _VSTD std
      |                 ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:581:43: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__dispatcher<0>::__dispatch<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &> &&, const std::__variant_detail::__base<std::__variant_detail::_Trait::_TriviallyAvailable, A, B> &>' requested here
  581 |     return __dispatcher<_Is...>::template __dispatch<_Fp, _Vs...>;
      |                                           ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:608:12: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__make_dispatch<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &> &&, const std::__variant_detail::__base<std::__variant_detail::_Trait::_TriviallyAvailable, A, B> &, 0UL>' requested here
  608 |     return __make_dispatch<_Fp, _Vs...>(__is);
      |            ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:616:34: note: (skipping 2 contexts in backtrace; use -ftemplate-backtrace-limit=0 to see all)
  616 |     return __base::__make_farray(__make_fmatrix_impl<_Fp, _Vs...>(
      |                                  ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:533:9: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__make_fmatrix<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &> &&, const std::__variant_detail::__base<std::__variant_detail::_Trait::_TriviallyAvailable, A, B> &>' requested here
  533 |         __make_fmatrix<_Visitor&&,
      |         ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:642:20: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__visit_alt<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &>, const std::__variant_detail::__impl<A, B> &>' requested here
  642 |     return __base::__visit_alt(
      |                    ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:661:12: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__variant::__visit_alt<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &>, const std::variant<A, B> &>' requested here
  661 |     return __visit_alt(
      |            ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:1759:21: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__variant::__visit_value<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &, const std::variant<A, B> &>' requested here
 1759 |   return __variant::__visit_value(_VSTD::forward<_Visitor>(__visitor),
      |                     ^
/tmp/variant.cpp:21:17: note: in instantiation of function template specialization 'std::visit<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &, const std::variant<A, B> &, void>' requested here
   21 |     return std::visit(toStringVisitor, args);
      |                 ^
In file included from /tmp/variant.cpp:2:
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:692:14: error: attempt to use a deleted function
  692 |       return _VSTD::__invoke(_VSTD::forward<_Visitor>(__visitor),
      |              ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/__config:805:17: note: expanded from macro '_VSTD'
  805 | #  define _VSTD std
      |                 ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/__type_traits/invoke.h:337:10: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &>::operator()<const std::__variant_detail::__alt<0, A> &>' requested here
  337 | decltype(std::declval<_Fp>()(std::declval<_Args>()...))
      |          ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:572:16: note: while substituting deduced template arguments into function template '__invoke' [with _Fp = std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &>, _Args = <const __alt<0UL, A> &>]
  572 |         return _VSTD::__invoke(
      |                ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/__config:805:17: note: expanded from macro '_VSTD'
  805 | #  define _VSTD std
      |                 ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:581:43: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__dispatcher<0>::__dispatch<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &> &&, const std::__variant_detail::__base<std::__variant_detail::_Trait::_TriviallyAvailable, A, B> &>' requested here
  581 |     return __dispatcher<_Is...>::template __dispatch<_Fp, _Vs...>;
      |                                           ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:608:12: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__make_dispatch<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &> &&, const std::__variant_detail::__base<std::__variant_detail::_Trait::_TriviallyAvailable, A, B> &, 0UL>' requested here
  608 |     return __make_dispatch<_Fp, _Vs...>(__is);
      |            ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:616:34: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__make_fmatrix_impl<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &> &&, const std::__variant_detail::__base<std::__variant_detail::_Trait::_TriviallyAvailable, A, B> &, 0UL>' requested here
  616 |     return __base::__make_farray(__make_fmatrix_impl<_Fp, _Vs...>(
      |                                  ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:623:12: note: (skipping 1 context in backtrace; use -ftemplate-backtrace-limit=0 to see all)
  623 |     return __make_fmatrix_impl<_Fp, _Vs...>(
      |            ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:533:9: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__make_fmatrix<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &> &&, const std::__variant_detail::__base<std::__variant_detail::_Trait::_TriviallyAvailable, A, B> &>' requested here
  533 |         __make_fmatrix<_Visitor&&,
      |         ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:642:20: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__visit_alt<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &>, const std::__variant_detail::__impl<A, B> &>' requested here
  642 |     return __base::__visit_alt(
      |                    ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:661:12: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__variant::__visit_alt<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &>, const std::variant<A, B> &>' requested here
  661 |     return __visit_alt(
      |            ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:1759:21: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__variant::__visit_value<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &, const std::variant<A, B> &>' requested here
 1759 |   return __variant::__visit_value(_VSTD::forward<_Visitor>(__visitor),
      |                     ^
/tmp/variant.cpp:21:17: note: in instantiation of function template specialization 'std::visit<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &, const std::variant<A, B> &, void>' requested here
   21 |     return std::visit(toStringVisitor, args);
      |                 ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/__type_traits/nat.h:25:3: note: '~__nat' has been explicitly marked deleted here
   25 |   ~__nat()                       = delete;
      |   ^
In file included from /tmp/variant.cpp:2:
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:572:16: error: attempt to use a deleted function
  572 |         return _VSTD::__invoke(
      |                ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/__config:805:17: note: expanded from macro '_VSTD'
  805 | #  define _VSTD std
      |                 ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:581:43: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__dispatcher<0>::__dispatch<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &> &&, const std::__variant_detail::__base<std::__variant_detail::_Trait::_TriviallyAvailable, A, B> &>' requested here
  581 |     return __dispatcher<_Is...>::template __dispatch<_Fp, _Vs...>;
      |                                           ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:608:12: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__make_dispatch<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &> &&, const std::__variant_detail::__base<std::__variant_detail::_Trait::_TriviallyAvailable, A, B> &, 0UL>' requested here
  608 |     return __make_dispatch<_Fp, _Vs...>(__is);
      |            ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:616:34: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__make_fmatrix_impl<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &> &&, const std::__variant_detail::__base<std::__variant_detail::_Trait::_TriviallyAvailable, A, B> &, 0UL>' requested here
  616 |     return __base::__make_farray(__make_fmatrix_impl<_Fp, _Vs...>(
      |                                  ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:623:12: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__make_fmatrix_impl<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &> &&, const std::__variant_detail::__base<std::__variant_detail::_Trait::_TriviallyAvailable, A, B> &, 0UL, 1UL>' requested here
  623 |     return __make_fmatrix_impl<_Fp, _Vs...>(
      |            ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:533:9: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__make_fmatrix<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &> &&, const std::__variant_detail::__base<std::__variant_detail::_Trait::_TriviallyAvailable, A, B> &>' requested here
  533 |         __make_fmatrix<_Visitor&&,
      |         ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:642:20: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__visit_alt<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &>, const std::__variant_detail::__impl<A, B> &>' requested here
  642 |     return __base::__visit_alt(
      |                    ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:661:12: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__variant::__visit_alt<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &>, const std::variant<A, B> &>' requested here
  661 |     return __visit_alt(
      |            ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:1759:21: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__variant::__visit_value<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &, const std::variant<A, B> &>' requested here
 1759 |   return __variant::__visit_value(_VSTD::forward<_Visitor>(__visitor),
      |                     ^
/tmp/variant.cpp:21:17: note: in instantiation of function template specialization 'std::visit<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &, const std::variant<A, B> &, void>' requested here
   21 |     return std::visit(toStringVisitor, args);
      |                 ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/__type_traits/nat.h:25:3: note: '~__nat' has been explicitly marked deleted here
   25 |   ~__nat()                       = delete;
      |   ^
In file included from /tmp/variant.cpp:2:
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:581:12: error: cannot deduce return type 'auto' from returned value of type '<overloaded function type>'
  581 |     return __dispatcher<_Is...>::template __dispatch<_Fp, _Vs...>;
      |            ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:608:12: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__make_dispatch<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &> &&, const std::__variant_detail::__base<std::__variant_detail::_Trait::_TriviallyAvailable, A, B> &, 0UL>' requested here
  608 |     return __make_dispatch<_Fp, _Vs...>(__is);
      |            ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:616:34: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__make_fmatrix_impl<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &> &&, const std::__variant_detail::__base<std::__variant_detail::_Trait::_TriviallyAvailable, A, B> &, 0UL>' requested here
  616 |     return __base::__make_farray(__make_fmatrix_impl<_Fp, _Vs...>(
      |                                  ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:623:12: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__make_fmatrix_impl<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &> &&, const std::__variant_detail::__base<std::__variant_detail::_Trait::_TriviallyAvailable, A, B> &, 0UL, 1UL>' requested here
  623 |     return __make_fmatrix_impl<_Fp, _Vs...>(
      |            ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:533:9: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__make_fmatrix<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &> &&, const std::__variant_detail::__base<std::__variant_detail::_Trait::_TriviallyAvailable, A, B> &>' requested here
  533 |         __make_fmatrix<_Visitor&&,
      |         ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:642:20: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__base::__visit_alt<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &>, const std::__variant_detail::__impl<A, B> &>' requested here
  642 |     return __base::__visit_alt(
      |                    ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:661:12: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__variant::__visit_alt<std::__variant_detail::__visitation::__variant::__value_visitor<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &>, const std::variant<A, B> &>' requested here
  661 |     return __visit_alt(
      |            ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:1759:21: note: in instantiation of function template specialization 'std::__variant_detail::__visitation::__variant::__visit_value<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &, const std::variant<A, B> &>' requested here
 1759 |   return __variant::__visit_value(_VSTD::forward<_Visitor>(__visitor),
      |                     ^
/tmp/variant.cpp:21:17: note: in instantiation of function template specialization 'std::visit<Visitor<(lambda at /tmp/variant.cpp:18:13), (lambda at /tmp/variant.cpp:19:13)> &, const std::variant<A, B> &, void>' requested here
   21 |     return std::visit(toStringVisitor, args);
      |                 ^
/usr/local/google/home/mitchp/llvm-build/opt/bin/../include/c++/v1/variant:571:37: note: candidate template ignored: failed template argument deduction
  571 |     static constexpr decltype(auto) __dispatch(_Fp __f, _Vs... __vs) {
      |                                     ^
4 errors generated.

I found an issue with building Android using this patch. I've reduced it down to the following problem where the evaluation of the std::visit is believed to be non-exhaustive, but it seems like it is? Would you mind taking a look? Admittedly, my knowledge in this area of the cxx stdlib is not so great.

Your example code is invalid, and Clang is now correctly diagnosing that. You can fix the problem by adding using V::operator()...; inside struct Visitor.

This change seems to expose a bug in Clang in C++20 see godbolt.
I believe following code should compile, but it does not:

struct X {
  virtual ~X();
  virtual bool operator ==(X);
  bool operator !=(X);
};

struct Y {
  virtual ~Y();
  virtual bool operator ==(Y);
  bool operator !=(Y);
};

struct Z : X, Y {
  virtual bool operator==(Z);
  bool operator==(X) override;
  bool operator==(Y) override;
};

int main() {
  bool b = Z() == Z(); // Clang errors saying `lookup for operator != is ambiguous`
  (void)b;
}

The operator != is coming from checking if we need to add a reversed candidates.
I believe this should compile as according to (over.match.oper)p4:

A non-template function or function template F named operator== is a rewrite target with first operand o unless a search for the name operator!= in the scope S from the instantiation context of the operator expression finds a function …

And 'search' is defined without any checks for ambiguous bases in (basic.lookup.general)p3

A single search in a scope S for a name N from a program point P finds all declarations that precede P to which any name that is the same as N ([basic.pre]) is bound in S. If any such declaration is a using-declarator whose terminal name ([expr.prim.id.unqual]) is not dependent ([temp.dep.type]), it is replaced by the declarations named by the using-declarator ([namespace.udecl]).

Clang does a full lookup instead, therefore exposing the errors that it should not diagnose.

We actually hit this on real code and found this during integration.

I have sent a fix for review in D157708.

I believe this should compile as according to (over.match.oper)p4:

A non-template function or function template F named operator== is a rewrite target with first operand o unless a search for the name operator!= in the scope S from the instantiation context of the operator expression finds a function …

And 'search' is defined without any checks for ambiguous bases in (basic.lookup.general)p3

A single search in a scope S for a name N from a program point P finds all declarations that precede P to which any name that is the same as N ([basic.pre]) is bound in S. If any such declaration is a using-declarator whose terminal name ([expr.prim.id.unqual]) is not dependent ([temp.dep.type]), it is replaced by the declarations named by the using-declarator ([namespace.udecl]).

Clang does a full lookup instead, therefore exposing the errors that it should not diagnose.

A search of a class scope is ill-formed if it finds an ambiguous result, see http://eel.is/c++draft/basic.lookup#class.member.lookup-6.sentence-2 -- that's the rule that we're now enforcing more broadly, and it applies to all searches of class scopes. So I think Clang is correct to reject your testcase, even though the ambiguity seems much less relevant in this case and the rejection is surprising. The fix / workaround is to add using X::operator!=; using Y::operator!=; to the derived class.

dewen added a subscriber: dewen.Sep 5 2023, 6:21 AM
dewen added inline comments.Sep 5 2023, 6:31 AM
clang/test/CXX/class.derived/class.member.lookup/p11.cpp
15
bool correctness{true};
struct A {
    bool operator==(A const&oth) const {
	return true;
    }
};

struct B {
    bool operator==(B const&oth) const {
	return false;
    }
};

struct C {
    bool operator==(C const&oth) const {
	correctness=false;
	return false;
    }
};

typedef std::tuple<A,B,C> tuple_t ;

int test_it (void) {
    tuple_t x,y;
    return ( !(x==y) ) && correctness ;
}

This test case does not report an error in GCC11 and later versions. The tuple class overloads the operator==() method. Different structs also overload the operator==() method. Due to the introduction of the patch, the llvm18 reports an error when compiling the test case. Is this reasonable?