diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 192c237b6c1c..b609bd904cee 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -3866,7 +3866,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, ICS.DiagnoseAmbiguousConversion(*this, From->getExprLoc(), PDiag(diag::err_typecheck_ambiguous_condition) << From->getSourceRange()); - return ExprError(); + return ExprError(); case ImplicitConversionSequence::EllipsisConversion: llvm_unreachable("Cannot perform an ellipsis conversion"); @@ -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)) diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 661a66246a53..2d87e7b367f3 100755 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -6670,7 +6670,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // -- a predefined __func__ variable APValue::LValueBase Base = Value.getLValueBase(); auto *VD = const_cast(Base.dyn_cast()); - if (Base && !VD) { + if (Base && (!VD || isa(VD))) { auto *E = Base.dyn_cast(); if (E && isa(E)) { Converted = TemplateArgument(ArgResult.get()->IgnoreImpCasts()); diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp index 7232598215ac..253ad7bc5606 100644 --- a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp @@ -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 struct A {}; + void f() { + A(); // expected-error {{would bind reference to a temporary}} + A(); // 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(); // expected-error {{non-type template argument is not a constant expression}} expected-note 2{{temporary}} + } +}