Commit 13fa4e2e authored by Richard Smith's avatar Richard Smith
Browse files

PR42108 Consistently diagnose binding a reference template parameter to

a temporary.

We previously failed to materialize a temporary when performing an
implicit conversion to a reference type, resulting in our thinking the
argument was a value rather than a reference in some cases.
parent 81942174
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -4349,6 +4349,16 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
                             VK_RValue, nullptr, CCK).get();
  }

  // Materialize a temporary if we're implicitly converting to a reference
  // type. This is not required by the C++ rules but is necessary to maintain
  // AST invariants.
  if (ToType->isReferenceType() && From->isRValue()) {
    ExprResult Res = TemporaryMaterializationConversion(From);
    if (Res.isInvalid())
      return ExprError();
    From = Res.get();
  }

  // If this conversion sequence succeeded and involved implicitly converting a
  // _Nullable type to a _Nonnull one, complain.
  if (!isCast(CCK))
+1 −1
Original line number Diff line number Diff line
@@ -6670,7 +6670,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
      // -- a predefined __func__ variable
      APValue::LValueBase Base = Value.getLValueBase();
      auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>());
      if (Base && !VD) {
      if (Base && (!VD || isa<LifetimeExtendedTemporaryDecl>(VD))) {
        auto *E = Base.dyn_cast<const Expr *>();
        if (E && isa<CXXUuidofExpr>(E)) {
          Converted = TemplateArgument(ArgResult.get()->IgnoreImpCasts());
+14 −0
Original line number Diff line number Diff line
@@ -434,3 +434,17 @@ namespace VoidPtr {
  int n;
  template void f<(void*)&n>();
}

namespace PR42108 {
  struct R {};
  struct S { constexpr S() {} constexpr S(R) {} };
  struct T { constexpr operator S() { return {}; } };
  template <const S &> struct A {};
  void f() {
    A<R{}>(); // expected-error {{would bind reference to a temporary}}
    A<S{}>(); // expected-error {{non-type template argument is not a constant expression}} expected-note 2{{temporary}}
    // FIXME: We could diagnose this better if we treated this as not binding
    // directly. It's unclear whether that's the intent.
    A<T{}>(); // expected-error {{non-type template argument is not a constant expression}} expected-note 2{{temporary}}
  }
}