Skip to content

Commit 13fa4e2

Browse files
committed
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.
1 parent 8194217 commit 13fa4e2

File tree

3 files changed

+26
-2
lines changed

3 files changed

+26
-2
lines changed

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3866,7 +3866,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
38663866
ICS.DiagnoseAmbiguousConversion(*this, From->getExprLoc(),
38673867
PDiag(diag::err_typecheck_ambiguous_condition)
38683868
<< From->getSourceRange());
3869-
return ExprError();
3869+
return ExprError();
38703870

38713871
case ImplicitConversionSequence::EllipsisConversion:
38723872
llvm_unreachable("Cannot perform an ellipsis conversion");
@@ -4349,6 +4349,16 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
43494349
VK_RValue, nullptr, CCK).get();
43504350
}
43514351

4352+
// Materialize a temporary if we're implicitly converting to a reference
4353+
// type. This is not required by the C++ rules but is necessary to maintain
4354+
// AST invariants.
4355+
if (ToType->isReferenceType() && From->isRValue()) {
4356+
ExprResult Res = TemporaryMaterializationConversion(From);
4357+
if (Res.isInvalid())
4358+
return ExprError();
4359+
From = Res.get();
4360+
}
4361+
43524362
// If this conversion sequence succeeded and involved implicitly converting a
43534363
// _Nullable type to a _Nonnull one, complain.
43544364
if (!isCast(CCK))

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6670,7 +6670,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
66706670
// -- a predefined __func__ variable
66716671
APValue::LValueBase Base = Value.getLValueBase();
66726672
auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>());
6673-
if (Base && !VD) {
6673+
if (Base && (!VD || isa<LifetimeExtendedTemporaryDecl>(VD))) {
66746674
auto *E = Base.dyn_cast<const Expr *>();
66756675
if (E && isa<CXXUuidofExpr>(E)) {
66766676
Converted = TemplateArgument(ArgResult.get()->IgnoreImpCasts());

clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,3 +434,17 @@ namespace VoidPtr {
434434
int n;
435435
template void f<(void*)&n>();
436436
}
437+
438+
namespace PR42108 {
439+
struct R {};
440+
struct S { constexpr S() {} constexpr S(R) {} };
441+
struct T { constexpr operator S() { return {}; } };
442+
template <const S &> struct A {};
443+
void f() {
444+
A<R{}>(); // expected-error {{would bind reference to a temporary}}
445+
A<S{}>(); // expected-error {{non-type template argument is not a constant expression}} expected-note 2{{temporary}}
446+
// FIXME: We could diagnose this better if we treated this as not binding
447+
// directly. It's unclear whether that's the intent.
448+
A<T{}>(); // expected-error {{non-type template argument is not a constant expression}} expected-note 2{{temporary}}
449+
}
450+
}

0 commit comments

Comments
 (0)