When parsing typename specifiers (with either the identifier or

simple-template-id form), check whether the scope specifier is
computable as a declaration context rather than checking whether it is
dependent, so that we properly cope with members of the current
instantiation. 

Improve testing for typename specifiers that terminate in a
simpe-template-id.

llvm-svn: 80783
This commit is contained in:
Douglas Gregor 2009-09-02 13:05:45 +00:00
parent 4469c164d0
commit 12bbfe1d31
3 changed files with 68 additions and 8 deletions

View File

@ -530,7 +530,7 @@ const TemplateSpecializationType *
Type::getAsTemplateSpecializationType() const {
// There is no sugar for class template specialization types, so
// just return the canonical type pointer if it is the right class.
return dyn_cast<TemplateSpecializationType>(CanonicalType);
return this->getAs<TemplateSpecializationType>();
}
bool Type::isIntegerType() const {

View File

@ -1137,9 +1137,7 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
NestedNameSpecifier *Qualifier
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
// FIXME: member of the current instantiation
if (!Qualifier->isDependent()) {
if (computeDeclContext(SS, false)) {
// C++0x [temp.names]p5:
// If a name prefixed by the keyword template is not the name of
// a template, the program is ill-formed. [Note: the keyword
@ -3010,10 +3008,16 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
= T->getAsTemplateSpecializationType();
assert(TemplateId && "Expected a template specialization type");
if (NNS->isDependent())
return Context.getTypenameType(NNS, TemplateId).getAsOpaquePtr();
return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr();
if (computeDeclContext(SS, false)) {
// If we can compute a declaration context, then the "typename"
// keyword was superfluous. Just build a QualifiedNameType to keep
// track of the nested-name-specifier.
// FIXME: Note that the QualifiedNameType had the "typename" keyword!
return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr();
}
return Context.getTypenameType(NNS, TemplateId).getAsOpaquePtr();
}
/// \brief Build the type that describes a C++ typename specifier,

View File

@ -0,0 +1,56 @@
// RUN: clang-cc -fsyntax-only -verify %s
template<typename T, typename U>
struct is_same {
static const bool value = false;
};
template<typename T>
struct is_same<T, T> {
static const bool value = true;
};
template<typename MetaFun, typename T1, typename T2>
struct metafun_apply2 {
typedef typename MetaFun::template apply<T1, T2> inner;
typedef typename inner::type type;
};
template<typename T, typename U> struct pair;
struct make_pair {
template<typename T1, typename T2>
struct apply {
typedef pair<T1, T2> type;
};
};
int a0[is_same<metafun_apply2<make_pair, int, float>::type,
pair<int, float> >::value? 1 : -1];
int a1[is_same<
typename make_pair::template apply<int, float>,
make_pair::apply<int, float>
>::value? 1 : -1];
template<typename MetaFun>
struct swap_and_apply2 {
template<typename T1, typename T2>
struct apply {
typedef typename MetaFun::template apply<T2, T1> new_metafun;
typedef typename new_metafun::type type;
};
};
int a2[is_same<swap_and_apply2<make_pair>::apply<int, float>::type,
pair<float, int> >::value? 1 : -1];
template<typename T>
struct X0 {
template<typename U, typename V>
struct Inner;
void f0(X0<T>::Inner<T*, T&>); // expected-note{{here}}
void f0(typename X0<T>::Inner<T*, T&>); // expected-error{{redecl}}
void f1(X0<T>::Inner<T*, T&>); // expected-note{{here}}
void f1(typename X0<T>::template Inner<T*, T&>); // expected-error{{redecl}}
};