forked from OSchip/llvm-project
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.
This commit is contained in:
parent
819421745c
commit
13fa4e2e5a
|
@ -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))
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue