aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaTemplate.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-03-31 00:43:58 +0000
committerDouglas Gregor <dgregor@apple.com>2009-03-31 00:43:58 +0000
commitc45c232440dfafedca1a3773b904fb42609b1b19 (patch)
tree8fc8ee76514079ac19b30b1200dddedd6f74dece /lib/Sema/SemaTemplate.cpp
parentaf3e72285238369c2ea4ebd40a1c9a87bd3eabb7 (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68081 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaTemplate.cpp')
-rw-r--r--lib/Sema/SemaTemplate.cpp134
1 files changed, 126 insertions, 8 deletions
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 56a016d270..591f323347 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -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,