As reported in https://bugs.freebsd.org/245530, compiling ceph-master with recent clang results in: can't implicitly cast lvalue to rvalue with this cast kind UNREACHABLE executed at /usr/srcs/head/src/contrib/llvm-project/clang/lib/Sema/Sema.cpp:538! Stack dump: 0. Program arguments: /usr/bin/c++ -Wall -fno-strict-aliasing -fsigned-char -Wtype-limits -Wignored-qualifiers -Wpointer-arith -Werror=format-security -Winit-self -Wno-unknown-pragmas -Wno-unused-function -Wno-unused-local-typedef -Wno-varargs -Wno-gnu-designator -Wno-missing-braces -Wno-parentheses -Wno-deprecated-register -Wno-unknown-pragmas -Wno-non-virtual-dtor -Wno-ignored-qualifiers -ftemplate-depth-1024 -Wpessimizing-move -Wredundant-move -Wno-inconsistent-missing-override -Wno-mismatched-tags -Wno-unused-private-field -Wno-address-of-packed-member -fdiagnostics-color=auto -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free -O0 -g -fPIC -std=c++17 -DCEPH_DATADIR="/usr/local/share/ceph" -DCEPH_LIBDIR="/usr/local/lib" -DCEPH_PKGLIBDIR="/usr/local/lib/ceph" -D_FILE_OFFSET_BITS=64 -I/home/jenkins/workspace/ceph-master/build/src/include -I/home/jenkins/workspace/ceph-master/src -isystem /usr/local/include -isystem /home/jenkins/workspace/ceph-master/build/include -isystem /home/jenkins/workspace/ceph-master/src/xxHash -isystem /home/jenkins/workspace/ceph-master/src/rapidjson/include -isystem /home/jenkins/workspace/ceph-master/src/fmt/include -DCEPH_DEBUG_MUTEX -D_GLIBCXX_ASSERTIONS -DHAVE_CONFIG_H -D__CEPH__ -D_REENTRANT -D_THREAD_SAFE -D__STDC_FORMAT_MACROS -c -o CMakeFiles/common-common-objs.dir/config.cc.o /home/jenkins/workspace/ceph-master/src/common/config.cc 1. <eof> parser at end of file 2. /usr/local/include/boost/variant/detail/apply_visitor_unary.hpp:66:1: instantiating function definition 'boost::apply_visitor<(anonymous namespace)::assign_visitor<ConfigValues>, boost::variant<long ConfigValues::*, unsigned long ConfigValues::*, std::__1::basic_string<char> ConfigValues::*, double ConfigValues::*, bool ConfigValues::*, entity_addr_t ConfigValues::*, entity_addrvec_t ConfigValues::*, uuid_d ConfigValues::*> &>' 3. /usr/local/include/boost/variant/variant.hpp:2384:5: instantiating function definition 'boost::variant<long ConfigValues::*, unsigned long ConfigValues::*, std::__1::basic_string<char> ConfigValues::*, double ConfigValues::*, bool ConfigValues::*, entity_addr_t ConfigValues::*, entity_addrvec_t ConfigValues::*, uuid_d ConfigValues::*>::apply_visitor<const (anonymous namespace)::assign_visitor<ConfigValues> >' 4. /usr/local/include/boost/variant/variant.hpp:2344:5: instantiating function definition 'boost::variant<long ConfigValues::*, unsigned long ConfigValues::*, std::__1::basic_string<char> ConfigValues::*, double ConfigValues::*, bool ConfigValues::*, entity_addr_t ConfigValues::*, entity_addrvec_t ConfigValues::*, uuid_d ConfigValues::*>::internal_apply_visitor<boost::detail::variant::invoke_visitor<const (anonymous namespace)::assign_visitor<ConfigValues>, false> >' 5. /usr/local/include/boost/variant/variant.hpp:2319:5: instantiating function definition 'boost::variant<long ConfigValues::*, unsigned long ConfigValues::*, std::__1::basic_string<char> ConfigValues::*, double ConfigValues::*, bool ConfigValues::*, entity_addr_t ConfigValues::*, entity_addrvec_t ConfigValues::*, uuid_d ConfigValues::*>::internal_apply_visitor_impl<boost::detail::variant::invoke_visitor<const (anonymous namespace)::assign_visitor<ConfigValues>, false>, void *>' 6. /usr/local/include/boost/variant/detail/visitation_impl.hpp:194:1: instantiating function definition 'boost::detail::variant::visitation_impl<mpl_::int_<0>, boost::detail::variant::visitation_impl_step<boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<8>, long ConfigValues::*, boost::mpl::l_item<mpl_::long_<7>, unsigned long ConfigValues::*, boost::mpl::l_item<mpl_::long_<6>, std::__1::basic_string<char> ConfigValues::*, boost::mpl::l_item<mpl_::long_<5>, double ConfigValues::*, boost::mpl::l_item<mpl_::long_<4>, bool ConfigValues::*, boost::mpl::l_item<mpl_::long_<3>, entity_addr_t ConfigValues::*, boost::mpl::l_item<mpl_::long_<2>, entity_addrvec_t ConfigValues::*, boost::mpl::l_item<mpl_::long_<1>, uuid_d ConfigValues::*, boost::mpl::l_end> > > > > > > > >, boost::mpl::l_iter<boost::mpl::l_end> >, boost::detail::variant::invoke_visitor<const (anonymous namespace)::assign_visitor<ConfigValues>, false>, void *, boost::variant<long ConfigValues::*, unsigned long ConfigValues::*, std::__1::basic_string<char> ConfigValues::*, double ConfigValues::*, bool ConfigValues::*, entity_addr_t ConfigValues::*, entity_addrvec_t ConfigValues::*, uuid_d ConfigValues::*>::has_fallback_type_>' 7. /usr/local/include/boost/variant/detail/visitation_impl.hpp:138:1: instantiating function definition 'boost::detail::variant::visitation_impl_invoke<boost::detail::variant::invoke_visitor<const (anonymous namespace)::assign_visitor<ConfigValues>, false>, void *, long ConfigValues::*, boost::variant<long ConfigValues::*, unsigned long ConfigValues::*, std::__1::basic_string<char> ConfigValues::*, double ConfigValues::*, bool ConfigValues::*, entity_addr_t ConfigValues::*, entity_addrvec_t ConfigValues::*, uuid_d ConfigValues::*>::has_fallback_type_>' 8. /usr/local/include/boost/variant/detail/visitation_impl.hpp:105:1: instantiating function definition 'boost::detail::variant::visitation_impl_invoke_impl<boost::detail::variant::invoke_visitor<const (anonymous namespace)::assign_visitor<ConfigValues>, false>, void *, long ConfigValues::*>' 9. /usr/local/include/boost/variant/variant.hpp:1026:85: instantiating function definition 'boost::detail::variant::invoke_visitor<const (anonymous namespace)::assign_visitor<ConfigValues>, false>::internal_visit<long ConfigValues::*&>' 10. /home/jenkins/workspace/ceph-master/src/common/config.cc:1496:8: instantiating function definition '(anonymous namespace)::assign_visitor<ConfigValues>::operator()' #0 0x0000000003e068fe PrintStackTrace /usr/srcs/head/src/contrib/llvm-project/llvm/lib/Support/Unix/Signals.inc:564:13 #1 0x0000000003e04a85 RunSignalHandlers /usr/srcs/head/src/contrib/llvm-project/llvm/lib/Support/Signals.cpp:69:18 #2 0x0000000003e08a0e HandleCrash /usr/srcs/head/src/contrib/llvm-project/llvm/lib/Support/CrashRecoveryContext.cpp:77:5 #3 0x0000000003e08b91 CrashRecoverySignalHandler /usr/srcs/head/src/contrib/llvm-project/llvm/lib/Support/CrashRecoveryContext.cpp:0:51 #4 0x000000080502e990 handle_signal /usr/srcs/head/src/lib/libthr/thread/thr_sig.c:0:3 Reduced test case: // clang -cc1 -triple x86_64-- -S -std=c++17 config-min.cpp template <class a> struct b { typedef a c; }; template <class a> struct B { typedef a const &d; }; template <class a> struct e : b<B<a>>::c { e(typename B<a>::d); }; template <class a> void ab(e<a> const &); template <typename> struct f; template <typename g> struct h { typedef typename g::al ao; typedef typename f<ao>::template m<g>::c c; }; template <typename a> struct n { typedef int al; typedef n; typedef a ar; }; template <typename as> struct o { typedef typename as::ar c; }; template <> struct f<int> { template <typename au> struct m { typedef o<au> c; }; }; template <typename av, typename> struct p : n<av> {}; namespace bf { template <typename... a> struct q { typedef p<a...> c; }; template <typename bi> struct r { typedef typename bi::c c; }; template <typename bk, typename bl, typename a> void bm(bk bn, bl, a *) { a bo; bn.i(bo, 0); } template <typename bk, typename bl, typename a, typename j> void bp(bk bn, bl br, a k, j) { bm(bn, 0, k); } template <typename bs, typename bt, typename bk, typename bl, typename j> void bu(bk bn, bl br, j bv, bs, bt *) { bp(bn, 0, static_cast<typename bt::c *>(0), 0); } } // namespace bf template <typename bk, typename by> void bz(bk bn, by) { by().bz(bn); } namespace bf { template <typename bk> struct ca { bk cb; ca(bk bn) : cb(bn) {} template <typename a> void i(a cc, int) { cb(cc); } }; } // namespace bf template <typename cd, typename... ce> struct s { template <typename bk, typename bl> void ck(bk bn, bl br) { bu(bn, 0, 0, 0, static_cast<bf::r<typename h<typename bf::q<cd, ce...>::c>::c> *>(0)); } template <typename bk> void cl(bk bn) { ck(bn, 0); } template <typename bk> void bz(bk bn) { bf::ca invoker(bn); cl(invoker); } }; struct co; template <class cp> struct cq { cq(cp *, int); template <typename a> void operator()(a cp::*cr) { ab<const a cp::*>(cr); } }; void cs(co &ct, s<int co::*, int> cu) { int l; bz(cq(&ct, 0), cu); }
Bisecting shows this regressed with https://reviews.llvm.org/rGf041e9ad706aee7987c5299427c33424fcabbd0d ("CWG2352: Allow qualification conversions during reference binding").
So what appears to happen is that Sema::ImpCastExprToType() gets called with the Kind parameter set to CK_NoOp, and that triggers the llvm_unreachable, but only in case assertions are enabled: 534 ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, 535 CastKind Kind, ExprValueKind VK, 536 const CXXCastPath *BasePath, 537 CheckedConversionKind CCK) { 538 #ifndef NDEBUG 539 if (VK == VK_RValue && !E->isRValue()) { 540 switch (Kind) { 541 default: 542 llvm_unreachable("can't implicitly cast lvalue to rvalue with this cast " 543 "kind"); 544 case CK_Dependent: 545 case CK_LValueToRValue: 546 case CK_ArrayToPointerDecay: 547 case CK_FunctionToPointerDecay: 548 case CK_ToVoid: 549 case CK_NonAtomicToAtomic: 550 break; 551 } 552 } This is called from Sema::PerformImplicitConversion(), in the block that handles ICK_Qualification: 4453 case ICK_Qualification: { 4454 // The qualification keeps the category of the inner expression, unless the 4455 // target type isn't a reference. 4456 ExprValueKind VK = 4457 ToType->isReferenceType() ? From->getValueKind() : VK_RValue; 4458 4459 CastKind CK = CK_NoOp; 4460 4461 if (ToType->isReferenceType() && 4462 ToType->getPointeeType().getAddressSpace() != 4463 From->getType().getAddressSpace()) 4464 CK = CK_AddressSpaceConversion; 4465 4466 if (ToType->isPointerType() && 4467 ToType->getPointeeType().getAddressSpace() != 4468 From->getType()->getPointeeType().getAddressSpace()) 4469 CK = CK_AddressSpaceConversion; 4470 4471 From = ImpCastExprToType(From, ToType.getNonLValueExprType(Context), CK, VK, 4472 /*BasePath=*/nullptr, CCK) 4473 .get(); 4474 4475 if (SCS.DeprecatedStringLiteralToCharPtr && 4476 !getLangOpts().WritableStrings) { 4477 Diag(From->getBeginLoc(), 4478 getLangOpts().CPlusPlus11 4479 ? diag::ext_deprecated_string_literal_conversion 4480 : diag::warn_deprecated_string_literal_conversion) 4481 << ToType.getNonReferenceType(); 4482 } 4483 4484 break; 4485 } Initially, CK is set to the CK_NoOp value, and then never changed before calling ImpCastExprToType(). As a quick test, I added CK_NoOp to the case list, like this: diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 5e5a90ad014..b38e6527c46 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -543,6 +543,7 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, "kind"); case CK_Dependent: case CK_LValueToRValue: + case CK_NoOp: case CK_ArrayToPointerDecay: case CK_FunctionToPointerDecay: case CK_ToVoid: and that *appears* to work, but I'm unsure if it is the right approach...
Indeed, this error seems to be caused by the following diff hunk from https://reviews.llvm.org/rGf041e9ad706aee7987c5299427c33424fcabbd0d: @@ -4665,12 +4681,20 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType, auto SetAsReferenceBinding = [&](bool BindsDirectly) { ICS.setStandard(); ICS.Standard.First = ICK_Identity; + // FIXME: A reference binding can be a function conversion too. We should + // consider that when ordering reference-to-function bindings. ICS.Standard.Second = (RefConv & Sema::ReferenceConversions::DerivedToBase) ? ICK_Derived_To_Base : (RefConv & Sema::ReferenceConversions::ObjC) ? ICK_Compatible_Conversion : ICK_Identity; - ICS.Standard.Third = ICK_Identity; + // FIXME: As a speculative fix to a defect introduced by CWG2352, we rank + // a reference binding that performs a non-top-level qualification + // conversion as a qualification conversion, not as an identity conversion. + ICS.Standard.Third = (RefConv & + Sema::ReferenceConversions::NestedQualification) + ? ICK_Qualification + : ICK_Identity; ICS.Standard.FromTypePtr = T2.getAsOpaquePtr(); ICS.Standard.setToType(0, T2); ICS.Standard.setToType(1, T1); As this now introduces ICK_Qualification in some code paths. If I just revert this part, the problem also seems fixed. I guess the CK_NoOp insertion might be handier, though.
Even more minimized test case, originally from https://bugs.freebsd.org/247812 ("Clang 10 crashes building CPAN module SYBER/Date-5.2.0"): // clang -cc1 -triple x86_64-- -S -std=c++14 MyTest_xsgen-min.cpp struct a { template <class b> a(const b *const &); }; struct c { c(const a &); } * d; void e() { auto f = [] { (c(d)); }; } I'm probably just going to put up a review for this.
Very slightly more reduced testcase: struct a { template<class b> a(const b * const&); }; int *d; const a &r = d; The code in Sema::PerformImplicitConversion() appears to be wrong. If the target type is not a reference, it's not correct to use a CK_NoOp cast to change the value kind. But in any case, the "to" types of a standard conversion sequence are never reference types.
> the "to" types of a standard conversion sequence are never reference types. Hmm, but it probably makes sense to model them as reference types when building a standard conversion sequence for a reference binding.
Fixed in 065fc1eafe7c6f67f8029bcd38e6864b3c429e35.