LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 45521 - [c++17] can't implicitly cast lvalue to rvalue with this cast kind
Summary: [c++17] can't implicitly cast lvalue to rvalue with this cast kind
Status: RESOLVED FIXED
Alias: None
Product: clang
Classification: Unclassified
Component: C++17 (show other bugs)
Version: trunk
Hardware: PC All
: P enhancement
Assignee: Unassigned Clang Bugs
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-04-13 15:23 PDT by Dimitry Andric
Modified: 2020-07-07 18:29 PDT (History)
5 users (show)

See Also:
Fixed By Commit(s):


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Dimitry Andric 2020-04-13 15:23:30 PDT
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);
}
Comment 1 Dimitry Andric 2020-04-13 23:37:13 PDT
Bisecting shows this regressed with https://reviews.llvm.org/rGf041e9ad706aee7987c5299427c33424fcabbd0d ("CWG2352: Allow qualification conversions during reference binding").
Comment 2 Dimitry Andric 2020-04-14 11:34:10 PDT
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...
Comment 3 Dimitry Andric 2020-04-14 11:48:22 PDT
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.
Comment 4 Dimitry Andric 2020-07-07 10:24:17 PDT
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.
Comment 5 Richard Smith 2020-07-07 18:04:57 PDT
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.
Comment 6 Richard Smith 2020-07-07 18:08:11 PDT
> 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.
Comment 7 Richard Smith 2020-07-07 18:29:32 PDT
Fixed in 065fc1eafe7c6f67f8029bcd38e6864b3c429e35.