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())
// 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) {
// 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
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>();
+}
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}}
+}