forked from OSchip/llvm-project
Related to PR11848 and core-21989: switch ContainsUnexpandedParameterPack from
being a property of a canonical type to being a property of the fully-sugared type. This should only make a difference in the case where an alias template ignores one of its parameters, and that parameter is an unexpanded parameter pack. llvm-svn: 160244
This commit is contained in:
parent
36e2ecf528
commit
68eea507fa
|
@ -2892,10 +2892,17 @@ QualType ASTContext::getPackExpansionType(QualType Pattern,
|
||||||
|
|
||||||
QualType Canon;
|
QualType Canon;
|
||||||
if (!Pattern.isCanonical()) {
|
if (!Pattern.isCanonical()) {
|
||||||
Canon = getPackExpansionType(getCanonicalType(Pattern), NumExpansions);
|
Canon = getCanonicalType(Pattern);
|
||||||
|
// The canonical type might not contain an unexpanded parameter pack, if it
|
||||||
|
// contains an alias template specialization which ignores one of its
|
||||||
|
// parameters.
|
||||||
|
if (Canon->containsUnexpandedParameterPack()) {
|
||||||
|
Canon = getPackExpansionType(getCanonicalType(Pattern), NumExpansions);
|
||||||
|
|
||||||
// Find the insert position again.
|
// Find the insert position again, in case we inserted an element into
|
||||||
PackExpansionTypes.FindNodeOrInsertPos(ID, InsertPos);
|
// PackExpansionTypes and invalidated our insert position.
|
||||||
|
PackExpansionTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
T = new (*this) PackExpansionType(Pattern, Canon, NumExpansions);
|
T = new (*this) PackExpansionType(Pattern, Canon, NumExpansions);
|
||||||
|
|
|
@ -1862,8 +1862,7 @@ TemplateSpecializationType(TemplateName T,
|
||||||
Canon.isNull()? T.isDependent()
|
Canon.isNull()? T.isDependent()
|
||||||
: Canon->isInstantiationDependentType(),
|
: Canon->isInstantiationDependentType(),
|
||||||
false,
|
false,
|
||||||
Canon.isNull()? T.containsUnexpandedParameterPack()
|
T.containsUnexpandedParameterPack()),
|
||||||
: Canon->containsUnexpandedParameterPack()),
|
|
||||||
Template(T), NumArgs(NumArgs), TypeAlias(!AliasedType.isNull()) {
|
Template(T), NumArgs(NumArgs), TypeAlias(!AliasedType.isNull()) {
|
||||||
assert(!T.getAsDependentTemplateName() &&
|
assert(!T.getAsDependentTemplateName() &&
|
||||||
"Use DependentTemplateSpecializationType for dependent template-name");
|
"Use DependentTemplateSpecializationType for dependent template-name");
|
||||||
|
@ -1888,6 +1887,8 @@ TemplateSpecializationType(TemplateName T,
|
||||||
// arguments is. Given:
|
// arguments is. Given:
|
||||||
// template<typename T> using U = int;
|
// template<typename T> using U = int;
|
||||||
// U<T> is always non-dependent, irrespective of the type T.
|
// U<T> is always non-dependent, irrespective of the type T.
|
||||||
|
// However, U<Ts> contains an unexpanded parameter pack, even though
|
||||||
|
// its expansion (and thus its desugared type) doesn't.
|
||||||
if (Canon.isNull() && Args[Arg].isDependent())
|
if (Canon.isNull() && Args[Arg].isDependent())
|
||||||
setDependent();
|
setDependent();
|
||||||
else if (Args[Arg].isInstantiationDependent())
|
else if (Args[Arg].isInstantiationDependent())
|
||||||
|
@ -1896,7 +1897,7 @@ TemplateSpecializationType(TemplateName T,
|
||||||
if (Args[Arg].getKind() == TemplateArgument::Type &&
|
if (Args[Arg].getKind() == TemplateArgument::Type &&
|
||||||
Args[Arg].getAsType()->isVariablyModifiedType())
|
Args[Arg].getAsType()->isVariablyModifiedType())
|
||||||
setVariablyModified();
|
setVariablyModified();
|
||||||
if (Canon.isNull() && Args[Arg].containsUnexpandedParameterPack())
|
if (Args[Arg].containsUnexpandedParameterPack())
|
||||||
setContainsUnexpandedParameterPack();
|
setContainsUnexpandedParameterPack();
|
||||||
|
|
||||||
new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]);
|
new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]);
|
||||||
|
|
|
@ -73,19 +73,38 @@ namespace PR11848 {
|
||||||
template<typename T> using U = int;
|
template<typename T> using U = int;
|
||||||
|
|
||||||
template<typename T, typename ...Ts>
|
template<typename T, typename ...Ts>
|
||||||
void f(U<T> i, U<Ts> ...is) { // expected-error {{type 'U<Ts>' (aka 'int') of function parameter pack does not contain any unexpanded parameter packs}}
|
void f1(U<T> i, U<Ts> ...is) { // expected-note 2{{couldn't infer template argument 'T'}}
|
||||||
return i + f<Ts...>(is...); // expected-error {{pack expansion does not contain any unexpanded parameter packs}}
|
return i + f1<Ts...>(is...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: This note is technically correct, but could be better. We
|
||||||
|
// should really say that we couldn't infer template argument 'Ts'.
|
||||||
|
template<typename ...Ts>
|
||||||
|
void f2(U<Ts> ...is) { } // expected-note {{requires 0 arguments, but 1 was provided}}
|
||||||
|
|
||||||
|
template<typename...> struct type_tuple {};
|
||||||
|
template<typename ...Ts>
|
||||||
|
void f3(type_tuple<Ts...>, U<Ts> ...is) {} // expected-note {{requires 4 arguments, but 3 were provided}}
|
||||||
|
|
||||||
|
void g() {
|
||||||
|
f1(U<void>()); // expected-error {{no match}}
|
||||||
|
f1(1, 2, 3, 4, 5); // expected-error {{no match}}
|
||||||
|
f2(); // ok
|
||||||
|
f2(1); // expected-error {{no match}}
|
||||||
|
f3(type_tuple<>());
|
||||||
|
f3(type_tuple<void, void, void>(), 1, 2); // expected-error {{no match}}
|
||||||
|
f3(type_tuple<void, void, void>(), 1, 2, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ...Ts>
|
template<typename ...Ts>
|
||||||
struct S {
|
struct S {
|
||||||
S(U<Ts>...ts); // expected-error {{does not contain any unexpanded parameter packs}}
|
S(U<Ts>...ts);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Hidden1 {
|
struct Hidden1 {
|
||||||
template<typename ...Ts>
|
template<typename ...Ts>
|
||||||
Hidden1(typename T::template U<Ts> ...ts); // expected-error{{type 'typename Hide::U<Ts>' (aka 'int') of function parameter pack does not contain any unexpanded parameter packs}}
|
Hidden1(typename T::template U<Ts> ...ts);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, typename ...Ts>
|
template<typename T, typename ...Ts>
|
||||||
|
@ -97,10 +116,28 @@ namespace PR11848 {
|
||||||
template<typename T> using U = int;
|
template<typename T> using U = int;
|
||||||
};
|
};
|
||||||
|
|
||||||
Hidden1<Hide> h1; // expected-note{{in instantiation of template class 'PR11848::Hidden1<PR11848::Hide>' requested here}}
|
Hidden1<Hide> h1;
|
||||||
Hidden2<Hide, double, char> h2(1, 2);
|
Hidden2<Hide, double, char> h2(1, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Core22036 {
|
||||||
|
struct X {};
|
||||||
|
void h(...);
|
||||||
|
template<typename T> using Y = X;
|
||||||
|
template<typename T, typename ...Ts> struct S {
|
||||||
|
void f1(Y<T> a) { h(g(a)); } // expected-error {{undeclared identifier 'g'}}
|
||||||
|
// FIXME: We should reject this too: 'as' has non-dependent type 'X', so
|
||||||
|
// ADL should be performed at the point of definition of the
|
||||||
|
// template.
|
||||||
|
void f2(Y<Ts>...as) { h(g(as)...); }
|
||||||
|
};
|
||||||
|
int g(X);
|
||||||
|
void test() {
|
||||||
|
S<int, int>().f1({});
|
||||||
|
S<int, int>().f2({});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace PR13243 {
|
namespace PR13243 {
|
||||||
template<typename A> struct X {};
|
template<typename A> struct X {};
|
||||||
template<int I> struct C {};
|
template<int I> struct C {};
|
||||||
|
@ -126,5 +163,6 @@ namespace PR13136 {
|
||||||
int main() {
|
int main() {
|
||||||
foo(1, NumberTuple<unsigned int, 0, 1>());
|
foo(1, NumberTuple<unsigned int, 0, 1>());
|
||||||
bar(1, NumberTuple<unsigned int, 0, 1>());
|
bar(1, NumberTuple<unsigned int, 0, 1>());
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue