[cfe-commits] r68081 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/TemplateKinds.h include/clang/Parse/Action.h lib/AST/ASTContext.cpp lib/AST/Type.cpp lib/Parse/MinimalAction.cpp lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/ParseTemplate.cpp lib/Parse/Parser.cpp lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateInstantiate.cpp test/SemaTemplate/metafun-apply.cpp test/SemaTemplate/nested-name-spec-template.cpp
Douglas Gregor
dgregor at apple.com
Mon Mar 30 17:43:59 PDT 2009
Author: dgregor
Date: Mon Mar 30 19:43:58 2009
New Revision: 68081
URL: http://llvm.org/viewvc/llvm-project?rev=68081&view=rev
Log:
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.
Added:
cfe/trunk/test/SemaTemplate/metafun-apply.cpp
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Basic/TemplateKinds.h
cfe/trunk/include/clang/Parse/Action.h
cfe/trunk/lib/AST/ASTContext.cpp
cfe/trunk/lib/AST/Type.cpp
cfe/trunk/lib/Parse/MinimalAction.cpp
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Parse/ParseDeclCXX.cpp
cfe/trunk/lib/Parse/ParseExprCXX.cpp
cfe/trunk/lib/Parse/ParseTemplate.cpp
cfe/trunk/lib/Parse/Parser.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=68081&r1=68080&r2=68081&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Mar 30 19:43:58 2009
@@ -699,6 +699,9 @@
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<
Modified: cfe/trunk/include/clang/Basic/TemplateKinds.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TemplateKinds.h?rev=68081&r1=68080&r2=68081&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TemplateKinds.h (original)
+++ cfe/trunk/include/clang/Basic/TemplateKinds.h Mon Mar 30 19:43:58 2009
@@ -22,12 +22,14 @@
/// 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
};
Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=68081&r1=68080&r2=68081&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Mon Mar 30 19:43:58 2009
@@ -157,7 +157,7 @@
/// 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 @@
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 @@
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);
Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=68081&r1=68080&r2=68081&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Mon Mar 30 19:43:58 2009
@@ -1373,8 +1373,6 @@
const TemplateArgument *Args,
unsigned NumArgs,
QualType Canon) {
- // FIXME: If Template is dependent, canonicalize it!
-
if (!Canon.isNull())
Canon = getCanonicalType(Canon);
Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=68081&r1=68080&r2=68081&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Mon Mar 30 19:43:58 2009
@@ -94,8 +94,12 @@
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();
Modified: cfe/trunk/lib/Parse/MinimalAction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/MinimalAction.cpp?rev=68081&r1=68080&r2=68081&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/MinimalAction.cpp (original)
+++ cfe/trunk/lib/Parse/MinimalAction.cpp Mon Mar 30 19:43:58 2009
@@ -134,7 +134,7 @@
}
TemplateNameKind
-MinimalAction::isTemplateName(IdentifierInfo &II, Scope *S,
+MinimalAction::isTemplateName(const IdentifierInfo &II, Scope *S,
TemplateTy &TemplateDecl,
const CXXScopeSpec *SS) {
return TNK_Non_template;
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=68081&r1=68080&r2=68081&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Mar 30 19:43:58 2009
@@ -513,7 +513,7 @@
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 @@
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;
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=68081&r1=68080&r2=68081&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Mar 30 19:43:58 2009
@@ -307,7 +307,7 @@
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 @@
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 ';'.
Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=68081&r1=68080&r2=68081&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Mon Mar 30 19:43:58 2009
@@ -92,9 +92,8 @@
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 @@
<< 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 @@
// 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 @@
// 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 @@
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
Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=68081&r1=68080&r2=68081&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Mon Mar 30 19:43:58 2009
@@ -531,8 +531,7 @@
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 @@
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 @@
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(),
Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=68081&r1=68080&r2=68081&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Mon Mar 30 19:43:58 2009
@@ -901,7 +901,7 @@
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
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=68081&r1=68080&r2=68081&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Mar 30 19:43:58 2009
@@ -1690,7 +1690,7 @@
//===--------------------------------------------------------------------===//
// 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 @@
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,
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=68081&r1=68080&r2=68081&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Mar 30 19:43:58 2009
@@ -26,7 +26,7 @@
/// 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 @@
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 @@
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 @@
}
}
+/// \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 @@
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 @@
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,
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=68081&r1=68080&r2=68081&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Mon Mar 30 19:43:58 2009
@@ -475,7 +475,7 @@
// FIXME: Need to instantiate into the template name.
return SemaRef.CheckTemplateIdType(T->getTemplateName(),
Loc,
- SourceLocation(),
+ SourceLocation(),
&InstantiatedTemplateArgs[0],
InstantiatedTemplateArgs.size(),
SourceLocation());
Added: cfe/trunk/test/SemaTemplate/metafun-apply.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/metafun-apply.cpp?rev=68081&view=auto
==============================================================================
--- cfe/trunk/test/SemaTemplate/metafun-apply.cpp (added)
+++ cfe/trunk/test/SemaTemplate/metafun-apply.cpp Mon Mar 30 19:43:58 2009
@@ -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
Modified: cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp?rev=68081&r1=68080&r2=68081&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp Mon Mar 30 19:43:58 2009
@@ -42,8 +42,21 @@
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
More information about the cfe-commits
mailing list