Author: Richard Smith Date: 2020-01-19T18:16:36-08:00 New Revision: 13fa4e2e5ae6ab5403be19e24415e0c7a5569681
URL: https://github.com/llvm/llvm-project/commit/13fa4e2e5ae6ab5403be19e24415e0c7a5569681 DIFF: https://github.com/llvm/llvm-project/commit/13fa4e2e5ae6ab5403be19e24415e0c7a5569681.diff LOG: 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. Added: Modified: clang/lib/Sema/SemaExprCXX.cpp clang/lib/Sema/SemaTemplate.cpp clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp Removed: ################################################################################ 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<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()); 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 <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}} + } +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits