Fix crash and rejects-valid when a later template parameter or default

template argument contains a backreference to a dependently-typed
earlier parameter.

In a case like:
  template<typename T, T A, decltype(A) = A> struct X {};
  template<typename U> auto Y = X<U, 0>();
we previously treated both references to `A` in the third parameter as
being of type `int` when checking the template-id in `Y`. That`s wrong;
the type of `A` in these contexts is the dependent type `U`.

When we encounter a non-type template argument that we can't convert to
the parameter type because of type-dependence, we now insert a dependent
conversion node so that the SubstNonTypeTemplateParmExpr for the
template argument will have the parameter's type rather than whatever
type the argument had.

llvm-svn: 363972
This commit is contained in:
Richard Smith 2019-06-20 19:49:13 +00:00
parent 97dc622ab3
commit 07ed9cfc3e
5 changed files with 70 additions and 12 deletions

View File

@ -4499,7 +4499,7 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
// It's possible to end up with a DeclRefExpr here in certain
// dependent cases, in which case we should mangle as a
// declaration.
const Expr *E = A.getAsExpr()->IgnoreParens();
const Expr *E = A.getAsExpr()->IgnoreParenImpCasts();
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
const ValueDecl *D = DRE->getDecl();
if (isa<VarDecl>(D) || isa<FunctionDecl>(D)) {

View File

@ -491,6 +491,7 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
default:
llvm_unreachable("can't implicitly cast lvalue to rvalue with this cast "
"kind");
case CK_Dependent:
case CK_LValueToRValue:
case CK_ArrayToPointerDecay:
case CK_FunctionToPointerDecay:
@ -499,7 +500,8 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty,
break;
}
}
assert((VK == VK_RValue || !E->isRValue()) && "can't cast rvalue to lvalue");
assert((VK == VK_RValue || Kind == CK_Dependent || !E->isRValue()) &&
"can't cast rvalue to lvalue");
#endif
diagnoseNullableToNonnullConversion(Ty, E->getType(), E->getBeginLoc());

View File

@ -4888,10 +4888,22 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
Converted);
NTTPType = SubstType(NTTPType,
MultiLevelTemplateArgumentList(TemplateArgs),
NTTP->getLocation(),
NTTP->getDeclName());
// If the parameter is a pack expansion, expand this slice of the pack.
if (auto *PET = NTTPType->getAs<PackExpansionType>()) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this,
ArgumentPackIndex);
NTTPType = SubstType(PET->getPattern(),
MultiLevelTemplateArgumentList(TemplateArgs),
NTTP->getLocation(),
NTTP->getDeclName());
} else {
NTTPType = SubstType(NTTPType,
MultiLevelTemplateArgumentList(TemplateArgs),
NTTP->getLocation(),
NTTP->getDeclName());
}
// If that worked, check the non-type template parameter type
// for validity.
if (!NTTPType.isNull())
@ -6310,9 +6322,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// When checking a deduced template argument, deduce from its type even if
// the type is dependent, in order to check the types of non-type template
// arguments line up properly in partial ordering.
Optional<unsigned> Depth;
if (CTAK != CTAK_Specified)
Depth = Param->getDepth() + 1;
Optional<unsigned> Depth = Param->getDepth() + 1;
if (DeduceAutoType(
Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()),
Arg, ParamType, Depth) == DAR_Failed) {
@ -6367,9 +6377,24 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// If either the parameter has a dependent type or the argument is
// type-dependent, there's nothing we can check now.
if (ParamType->isDependentType() || Arg->isTypeDependent()) {
// FIXME: Produce a cloned, canonical expression?
Converted = TemplateArgument(Arg);
return Arg;
// Force the argument to the type of the parameter to maintain invariants.
auto *PE = dyn_cast<PackExpansionExpr>(Arg);
if (PE)
Arg = PE->getPattern();
ExprResult E = ImpCastExprToType(
Arg, ParamType.getNonLValueExprType(Context), CK_Dependent,
ParamType->isLValueReferenceType() ? VK_LValue :
ParamType->isRValueReferenceType() ? VK_XValue : VK_RValue);
if (E.isInvalid())
return ExprError();
if (PE) {
// Recreate a pack expansion if we unwrapped one.
E = new (Context)
PackExpansionExpr(E.get()->getType(), E.get(), PE->getEllipsisLoc(),
PE->getNumExpansions());
}
Converted = TemplateArgument(E.get());
return E;
}
// The initialization of the parameter from the argument is

View File

@ -88,3 +88,15 @@ struct rdar9108698 {
void test_rdar9108698(rdar9108698 x) {
x.f<int>; // expected-error{{reference to non-static member function must be called}}
}
namespace GCC_PR67898 {
void f(int);
void f(float);
template<typename T, T F, T G, bool b = F == G> struct X {
static_assert(b, "");
};
template<typename T> void test1() { X<void(T), f, f>(); }
template<typename T> void test2() { X<void(*)(T), f, f>(); }
template void test1<int>();
template void test2<int>();
}

View File

@ -463,3 +463,22 @@ namespace pointer_to_char_array {
T foo = "foo";
void g() { A<&foo>().f(); }
}
namespace dependent_backreference {
struct Incomplete; // expected-note 2{{forward declaration}}
Incomplete f(int); // expected-note 2{{here}}
int f(short);
template<typename T, T Value, int(*)[sizeof(f(Value))]> struct X {}; // expected-error 2{{incomplete}}
int arr[sizeof(int)];
// When checking this template-id, we must not treat 'Value' as having type
// 'int'; its type is the dependent type 'T'.
template<typename T> void f() { X<T, 0, &arr> x; } // expected-note {{substituting}}
void g() { f<short>(); }
void h() { f<int>(); } // expected-note {{instantiation}}
// The second of these is OK to diagnose eagerly because 'Value' has the
// non-dependent type 'int'.
template<short S> void a() { X<short, S, &arr> x; }
template<short S> void b() { X<int, S, &arr> x; } // expected-note {{substituting}}
}