Parsing and AST representation for dependent template names that occur

within nested-name-specifiers, e.g., for the "apply" in

  typename MetaFun::template apply<T1, T2>::type

At present, we can't instantiate these nested-name-specifiers, so our
testing is sketchy.

llvm-svn: 68081
This commit is contained in:
Douglas Gregor 2009-03-31 00:43:58 +00:00
parent b874bd9f41
commit b67535d1b6
16 changed files with 238 additions and 52 deletions

View File

@ -699,6 +699,9 @@ def err_typename_nested_not_type : Error<
def note_typename_refers_here : Note<
"referenced member %0 is declared here">;
def err_template_kw_refers_to_non_template : Error<
"%0 following the 'template' keyword does not refer to a template">;
def err_unexpected_typedef : Error<
"unexpected type name %0: expected expression">;
def err_unexpected_namespace : Error<

View File

@ -22,12 +22,14 @@ enum TemplateNameKind {
/// The name refers to a function template or a set of overloaded
/// functions that includes at least one function template.
TNK_Function_template,
/// The name refers to a class template.
TNK_Class_template,
/// The name referes to a template template parameter.
TNK_Template_template_parm,
/// The name is dependent and is known to be a template name based
/// on syntax, e.g., "Alloc::template rebind<Other>".
/// The name refers to a template whose specialization produces a
/// type. The template itself could be a class template, template
/// template parameter, or C++0x template alias.
TNK_Type_template,
/// The name refers to a dependent template name. Whether the
/// template name is assumed to refer to a type template or a
/// function template depends on the context in which the template
/// name occurs.
TNK_Dependent_template_name
};

View File

@ -157,7 +157,7 @@ public:
/// returned, and \p TemplateDecl receives the declaration. An
/// optional CXXScope can be passed to indicate the C++ scope in
/// which the identifier will be found.
virtual TemplateNameKind isTemplateName(IdentifierInfo &II, Scope *S,
virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
TemplateTy &Template,
const CXXScopeSpec *SS = 0) = 0;
@ -1229,6 +1229,20 @@ public:
return TypeResult();
};
/// \brief Form a dependent template name.
///
/// This action forms a dependent template name given the template
/// name and its (presumably dependent) scope specifier. For
/// example, given "MetaFun::template apply", the scope specifier \p
/// SS will be "MetaFun::", \p TemplateKWLoc contains the location
/// of the "template" keyword, and "apply" is the \p Name.
virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
const IdentifierInfo &Name,
SourceLocation NameLoc,
const CXXScopeSpec &SS) {
return TemplateTy();
}
/// \brief Process the declaration or definition of an explicit
/// class template specialization or a class template partial
/// specialization.
@ -1568,7 +1582,7 @@ public:
virtual bool isCurrentClassName(const IdentifierInfo& II, Scope *S,
const CXXScopeSpec *SS);
virtual TemplateNameKind isTemplateName(IdentifierInfo &II, Scope *S,
virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
TemplateTy &Template,
const CXXScopeSpec *SS = 0);

View File

@ -1373,8 +1373,6 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgument *Args,
unsigned NumArgs,
QualType Canon) {
// FIXME: If Template is dependent, canonicalize it!
if (!Canon.isNull())
Canon = getCanonicalType(Canon);

View File

@ -94,8 +94,12 @@ QualType Type::getDesugaredType() const {
if (const TypeOfType *TOT = dyn_cast<TypeOfType>(this))
return TOT->getUnderlyingType().getDesugaredType();
if (const TemplateSpecializationType *Spec
= dyn_cast<TemplateSpecializationType>(this))
return Spec->getCanonicalTypeInternal().getDesugaredType();
= dyn_cast<TemplateSpecializationType>(this)) {
QualType Canon = Spec->getCanonicalTypeInternal();
if (Canon->getAsTemplateSpecializationType())
return QualType(this, 0);
return Canon->getDesugaredType();
}
if (const QualifiedNameType *QualName = dyn_cast<QualifiedNameType>(this))
return QualName->getNamedType().getDesugaredType();

View File

@ -134,7 +134,7 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *,
}
TemplateNameKind
MinimalAction::isTemplateName(IdentifierInfo &II, Scope *S,
MinimalAction::isTemplateName(const IdentifierInfo &II, Scope *S,
TemplateTy &TemplateDecl,
const CXXScopeSpec *SS) {
return TNK_Non_template;

View File

@ -513,7 +513,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
Token Next = NextToken();
if (Next.is(tok::annot_template_id) &&
static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue())
->Kind == TNK_Class_template) {
->Kind == TNK_Type_template) {
// We have a qualified template-id, e.g., N::A<int>
CXXScopeSpec SS;
ParseOptionalCXXScopeSpecifier(SS);
@ -640,7 +640,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
case tok::annot_template_id: {
TemplateIdAnnotation *TemplateId
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
if (TemplateId->Kind != TNK_Class_template) {
if (TemplateId->Kind != TNK_Type_template) {
// This template-id does not refer to a type name, so we're
// done with the type-specifiers.
goto DoneWithDeclSpec;

View File

@ -307,7 +307,7 @@ Parser::TypeTy *Parser::ParseClassName(SourceLocation &EndLocation,
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
if (TemplateId->Kind == TNK_Class_template) {
if (TemplateId->Kind == TNK_Type_template) {
if (AnnotateTemplateIdTokenAsType(SS))
return 0;
@ -419,7 +419,7 @@ void Parser::ParseClassSpecifier(DeclSpec &DS,
TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
NameLoc = ConsumeToken();
if (TemplateId->Kind != TNK_Class_template) {
if (TemplateId->Kind != TNK_Type_template) {
// The template-name in the simple-template-id refers to
// something other than a class template. Give an appropriate
// error message and skip to the ';'.

View File

@ -92,9 +92,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
Tok.is(tok::kw_template)) {
// Parse the optional 'template' keyword, then make sure we have
// 'identifier <' after it.
SourceLocation TemplateKWLoc;
if (Tok.is(tok::kw_template)) {
TemplateKWLoc = ConsumeToken();
SourceLocation TemplateKWLoc = ConsumeToken();
if (Tok.isNot(tok::identifier)) {
Diag(Tok.getLocation(),
@ -110,20 +109,20 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
<< SourceRange(TemplateKWLoc, Tok.getLocation());
break;
}
}
else {
// FIXME: If the nested-name-specifier thus far is dependent,
// we need to break out of here, because this '<' is taken as
// an operator and not as part of a simple-template-id.
TemplateTy Template
= Actions.ActOnDependentTemplateName(TemplateKWLoc,
*Tok.getIdentifierInfo(),
Tok.getLocation(),
SS);
AnnotateTemplateIdToken(Template, TNK_Dependent_template_name,
&SS, TemplateKWLoc, false);
continue;
}
TemplateTy Template;
TemplateNameKind TNK = TNK_Non_template;
// FIXME: If the nested-name-specifier thus far is dependent,
// set TNK = TNK_Dependent_template_name and skip the
// "isTemplateName" check.
TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(),
CurScope, Template, &SS);
TemplateNameKind TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(),
CurScope, Template, &SS);
if (TNK) {
// We have found a template name, so annotate this this token
// with a template-id annotation. We do not permit the
@ -131,7 +130,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
// because some clients (e.g., the parsing of class template
// specializations) still want to see the original template-id
// token.
AnnotateTemplateIdToken(Template, TNK, &SS, TemplateKWLoc, false);
AnnotateTemplateIdToken(Template, TNK, &SS, SourceLocation(), false);
continue;
}
}
@ -142,12 +141,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
// simple-template-id '::'
//
// So we need to check whether the simple-template-id is of the
// right kind (it should name a type), and then convert it into
// a type within the nested-name-specifier.
// right kind (it should name a type or be dependent), and then
// convert it into a type within the nested-name-specifier.
TemplateIdAnnotation *TemplateId
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
if (TemplateId->Kind == TNK_Class_template) {
if (TemplateId->Kind == TNK_Type_template ||
TemplateId->Kind == TNK_Dependent_template_name) {
if (AnnotateTemplateIdTokenAsType(&SS))
SS.clear();
@ -172,7 +172,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
SS.setEndLoc(CCLoc);
continue;
} else
assert(false && "FIXME: Only class template names supported here");
assert(false && "FIXME: Only type template names supported here");
}
// We don't have any tokens that form the beginning of a

View File

@ -531,8 +531,7 @@ void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
return;
// Build the annotation token.
// FIXME: Not just for class templates!
if (TNK == TNK_Class_template && AllowTypeAnnotation) {
if (TNK == TNK_Type_template && AllowTypeAnnotation) {
Action::TypeResult Type
= Actions.ActOnTemplateIdType(Template, TemplateNameLoc,
LAngleLoc, TemplateArgsPtr,
@ -550,8 +549,8 @@ void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
else
Tok.setLocation(TemplateNameLoc);
} else {
// This is a function template. We'll be building a template-id
// annotation token.
// Build a template-id annotation token that can be processed
// later.
Tok.setKind(tok::annot_template_id);
TemplateIdAnnotation *TemplateId
= TemplateIdAnnotation::Allocate(TemplateArgs.size());
@ -595,8 +594,9 @@ bool Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) {
TemplateIdAnnotation *TemplateId
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
assert(TemplateId->Kind == TNK_Class_template &&
"Only works for class templates");
assert((TemplateId->Kind == TNK_Type_template ||
TemplateId->Kind == TNK_Dependent_template_name) &&
"Only works for type and dependent templates");
ASTTemplateArgsPtr TemplateArgsPtr(Actions,
TemplateId->getTemplateArgs(),

View File

@ -901,7 +901,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() {
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId
= static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
if (TemplateId->Kind == TNK_Class_template) {
if (TemplateId->Kind == TNK_Type_template) {
// A template-id that refers to a type was parsed into a
// template-id annotation in a context where we weren't allowed
// to produce a type annotation token. Update the template-id

View File

@ -1690,7 +1690,7 @@ public:
//===--------------------------------------------------------------------===//
// C++ Templates [C++ 14]
//
virtual TemplateNameKind isTemplateName(IdentifierInfo &II, Scope *S,
virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S,
TemplateTy &Template,
const CXXScopeSpec *SS = 0);
bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
@ -1756,6 +1756,11 @@ public:
SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc);
virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
const IdentifierInfo &Name,
SourceLocation NameLoc,
const CXXScopeSpec &SS);
bool CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
ClassTemplateSpecializationDecl *PrevDecl,
SourceLocation TemplateNameLoc,

View File

@ -26,7 +26,7 @@ using namespace clang;
/// declaration if II names a template. An optional CXXScope can be
/// passed to indicate the C++ scope in which the identifier will be
/// found.
TemplateNameKind Sema::isTemplateName(IdentifierInfo &II, Scope *S,
TemplateNameKind Sema::isTemplateName(const IdentifierInfo &II, Scope *S,
TemplateTy &TemplateResult,
const CXXScopeSpec *SS) {
NamedDecl *IIDecl = LookupParsedName(S, SS, &II, LookupOrdinaryName);
@ -38,10 +38,9 @@ TemplateNameKind Sema::isTemplateName(IdentifierInfo &II, Scope *S,
if ((Template = dyn_cast<TemplateDecl>(IIDecl))) {
if (isa<FunctionTemplateDecl>(IIDecl))
TNK = TNK_Function_template;
else if (isa<ClassTemplateDecl>(IIDecl))
TNK = TNK_Class_template;
else if (isa<TemplateTemplateParmDecl>(IIDecl))
TNK = TNK_Template_template_parm;
else if (isa<ClassTemplateDecl>(IIDecl) ||
isa<TemplateTemplateParmDecl>(IIDecl))
TNK = TNK_Type_template;
else
assert(false && "Unknown template declaration kind");
} else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(IIDecl)) {
@ -59,11 +58,11 @@ TemplateNameKind Sema::isTemplateName(IdentifierInfo &II, Scope *S,
if (Record->isInjectedClassName()) {
Record = cast<CXXRecordDecl>(Context.getCanonicalDecl(Record));
if ((Template = Record->getDescribedClassTemplate()))
TNK = TNK_Class_template;
TNK = TNK_Type_template;
else if (ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(Record)) {
Template = Spec->getSpecializedTemplate();
TNK = TNK_Class_template;
TNK = TNK_Type_template;
}
}
}
@ -716,6 +715,56 @@ translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn,
}
}
/// \brief Build a canonical version of a template argument list.
///
/// This function builds a canonical version of the given template
/// argument list, where each of the template arguments has been
/// converted into its canonical form. This routine is typically used
/// to canonicalize a template argument list when the template name
/// itself is dependent. When the template name refers to an actual
/// template declaration, Sema::CheckTemplateArgumentList should be
/// used to check and canonicalize the template arguments.
///
/// \param TemplateArgs The incoming template arguments.
///
/// \param NumTemplateArgs The number of template arguments in \p
/// TemplateArgs.
///
/// \param Canonical A vector to be filled with the canonical versions
/// of the template arguments.
///
/// \param Context The ASTContext in which the template arguments live.
static void CanonicalizeTemplateArguments(const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
llvm::SmallVectorImpl<TemplateArgument> &Canonical,
ASTContext &Context) {
Canonical.reserve(NumTemplateArgs);
for (unsigned Idx = 0; Idx < NumTemplateArgs; ++Idx) {
switch (TemplateArgs[Idx].getKind()) {
case TemplateArgument::Expression:
// FIXME: Build canonical expression (!)
Canonical.push_back(TemplateArgs[Idx]);
break;
case TemplateArgument::Declaration:
Canonical.push_back(TemplateArgument(SourceLocation(),
TemplateArgs[Idx].getAsDecl()));
break;
case TemplateArgument::Integral:
Canonical.push_back(TemplateArgument(SourceLocation(),
*TemplateArgs[Idx].getAsIntegral(),
TemplateArgs[Idx].getIntegralType()));
case TemplateArgument::Type: {
QualType CanonType
= Context.getCanonicalType(TemplateArgs[Idx].getAsType());
Canonical.push_back(TemplateArgument(SourceLocation(), CanonType));
}
}
}
}
QualType Sema::CheckTemplateIdType(TemplateName Name,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
@ -723,7 +772,25 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
unsigned NumTemplateArgs,
SourceLocation RAngleLoc) {
TemplateDecl *Template = Name.getAsTemplateDecl();
assert(Template && "Cannot handle dependent template-names yet");
if (!Template) {
// The template name does not resolve to a template, so we just
// build a dependent template-id type.
// Canonicalize the template arguments to build the canonical
// template-id type.
llvm::SmallVector<TemplateArgument, 16> CanonicalTemplateArgs;
CanonicalizeTemplateArguments(TemplateArgs, NumTemplateArgs,
CanonicalTemplateArgs, Context);
// FIXME: Get the canonical template-name
QualType CanonType
= Context.getTemplateSpecializationType(Name, &CanonicalTemplateArgs[0],
CanonicalTemplateArgs.size());
// Build the dependent template-id type.
return Context.getTemplateSpecializationType(Name, TemplateArgs,
NumTemplateArgs, CanonType);
}
// Check that the template argument list is well-formed for this
// template.
@ -808,6 +875,57 @@ Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc,
return Result.getAsOpaquePtr();
}
/// \brief Form a dependent template name.
///
/// This action forms a dependent template name given the template
/// name and its (presumably dependent) scope specifier. For
/// example, given "MetaFun::template apply", the scope specifier \p
/// SS will be "MetaFun::", \p TemplateKWLoc contains the location
/// of the "template" keyword, and "apply" is the \p Name.
Sema::TemplateTy
Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
const IdentifierInfo &Name,
SourceLocation NameLoc,
const CXXScopeSpec &SS) {
if (!SS.isSet() || SS.isInvalid())
return TemplateTy();
NestedNameSpecifier *Qualifier
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
// FIXME: member of the current instantiation
if (!Qualifier->isDependent()) {
// 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
// template may not be applied to non-template members of class
// templates. -end note ] [ Note: as is the case with the
// typename prefix, the template prefix is allowed in cases
// where it is not strictly necessary; i.e., when the
// nested-name-specifier or the expression on the left of the ->
// or . is not dependent on a template-parameter, or the use
// does not appear in the scope of a template. -end note]
//
// Note: C++03 was more strict here, because it banned the use of
// the "template" keyword prior to a template-name that was not a
// dependent name. C++ DR468 relaxed this requirement (the
// "template" keyword is now permitted). We follow the C++0x
// rules, even in C++03 mode, retroactively applying the DR.
TemplateTy Template;
TemplateNameKind TNK = isTemplateName(Name, 0, Template, &SS);
if (TNK == TNK_Non_template) {
Diag(NameLoc, diag::err_template_kw_refers_to_non_template)
<< &Name;
return TemplateTy();
}
return Template;
}
return TemplateTy::make(Context.getDependentTemplateName(Qualifier, &Name));
}
/// \brief Check that the given template argument list is well-formed
/// for specializing the given template.
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,

View File

@ -475,7 +475,7 @@ InstantiateTemplateSpecializationType(
// FIXME: Need to instantiate into the template name.
return SemaRef.CheckTemplateIdType(T->getTemplateName(),
Loc,
SourceLocation(),
SourceLocation(),
&InstantiatedTemplateArgs[0],
InstantiatedTemplateArgs.size(),
SourceLocation());

View File

@ -0,0 +1,29 @@
// RUN: clang-cc -fsyntax-only %s
struct add_pointer {
template<typename T>
struct apply {
typedef T* type;
};
};
struct add_reference {
template<typename T>
struct apply {
typedef T& type;
};
};
template<typename MetaFun, typename T>
struct apply1 {
typedef typename MetaFun::template apply<T>::type type;
};
#if 0
// FIXME: The code below requires template instantiation for dependent
// template-names that occur within nested-name-specifiers.
int i;
apply1<add_pointer, int>::type ip = &i;
apply1<add_reference, int>::type ir = i;
#endif

View File

@ -42,8 +42,21 @@ namespace N {
struct A<int> {
struct X;
};
struct B;
}
struct ::N::A<int>::X {
int foo;
};
#if 0
// FIXME: the following crashes the parser, because Sema has no way to
// community that the "dependent" template-name N::template B doesn't
// actually refer to a template.
template<typename T>
struct TestA {
typedef typename N::template B<T>::type type; // xpected-error{{'B' following the 'template' keyword does not refer to a template}}
// FIXME: should show what B *does* refer to.
};
#endif