[cfe-commits] r80003 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplate.cpp test/SemaTemplate/nested-template.cpp
Douglas Gregor
dgregor at apple.com
Tue Aug 25 10:23:05 PDT 2009
Author: dgregor
Date: Tue Aug 25 12:23:04 2009
New Revision: 80003
URL: http://llvm.org/viewvc/llvm-project?rev=80003&view=rev
Log:
Implement out-of-line definitions of nested class templates. Most of
the logic is there for out-of-line definitions with multiple levels of
nested templates, but this is still a work-in-progress: we're having
trouble determining when we should look into a dependent
nested-name-specifier.
Modified:
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/SemaTemplate/nested-template.cpp
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=80003&r1=80002&r2=80003&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Aug 25 12:23:04 2009
@@ -2258,7 +2258,7 @@
SourceLocation KWLoc, const CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr,
- MultiTemplateParamsArg TemplateParameterLists,
+ TemplateParameterList *TemplateParams,
AccessSpecifier AS);
QualType CheckTemplateIdType(TemplateName Template,
@@ -2378,8 +2378,7 @@
SourceLocation TemplateArgLoc
= SourceLocation());
- bool CheckTemplateDeclScope(Scope *S,
- MultiTemplateParamsArg &TemplateParameterLists);
+ bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams);
/// \brief Called when the parser has parsed a C++ typename
/// specifier, e.g., "typename T::type".
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=80003&r1=80002&r2=80003&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Aug 25 12:23:04 2009
@@ -2106,11 +2106,6 @@
}
}
- // Check that we can declare a template here.
- if (TemplateParamLists.size() &&
- CheckTemplateDeclScope(S, TemplateParamLists))
- return 0;
-
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
if (TemplateParameterList *TemplateParams
@@ -2391,11 +2386,6 @@
D.setInvalidType();
}
- // Check that we can declare a template here.
- if (TemplateParamLists.size() &&
- CheckTemplateDeclScope(S, TemplateParamLists))
- return 0;
-
bool isVirtualOkay = false;
FunctionDecl *NewFD;
if (isFriend) {
@@ -2515,6 +2505,11 @@
TemplateParamLists.size())) {
if (TemplateParams->size() > 0) {
// This is a function template
+
+ // Check that we can declare a template here.
+ if (CheckTemplateDeclScope(S, TemplateParams))
+ return 0;
+
FunctionTemplate = FunctionTemplateDecl::Create(Context, CurContext,
NewFD->getLocation(),
Name, TemplateParams,
@@ -3960,8 +3955,9 @@
OwnedDecl = false;
DeclResult Result = CheckClassTemplate(S, TagSpec, TUK, KWLoc,
SS, Name, NameLoc, Attr,
- move(TemplateParameterLists),
+ TemplateParams,
AS);
+ TemplateParameterLists.release();
return Result.get();
} else {
// FIXME: diagnose the extraneous 'template<>', once we recover
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=80003&r1=80002&r2=80003&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Aug 25 12:23:04 2009
@@ -444,14 +444,15 @@
SourceLocation KWLoc, const CXXScopeSpec &SS,
IdentifierInfo *Name, SourceLocation NameLoc,
AttributeList *Attr,
- MultiTemplateParamsArg TemplateParameterLists,
+ TemplateParameterList *TemplateParams,
AccessSpecifier AS) {
- assert(TemplateParameterLists.size() > 0 && "No template parameter lists?");
+ assert(TemplateParams && TemplateParams->size() > 0 &&
+ "No template parameters");
assert(TUK != TUK_Reference && "Can only declare or define class templates");
bool Invalid = false;
// Check that we can declare a template here.
- if (CheckTemplateDeclScope(S, TemplateParameterLists))
+ if (CheckTemplateDeclScope(S, TemplateParams))
return true;
TagDecl::TagKind Kind;
@@ -469,27 +470,30 @@
}
// Find any previous declaration with this name.
- LookupResult Previous = LookupParsedName(S, &SS, Name, LookupOrdinaryName,
- true);
+ DeclContext *SemanticContext;
+ LookupResult Previous;
+ if (SS.isNotEmpty() && !SS.isInvalid()) {
+ SemanticContext = computeDeclContext(SS, true);
+ if (!SemanticContext) {
+ // FIXME: Produce a reasonable diagnostic here
+ return true;
+ }
+
+ Previous = LookupQualifiedName(SemanticContext, Name, LookupOrdinaryName,
+ true);
+ } else {
+ SemanticContext = CurContext;
+ Previous = LookupName(S, Name, LookupOrdinaryName, true);
+ }
+
assert(!Previous.isAmbiguous() && "Ambiguity in class template redecl?");
NamedDecl *PrevDecl = 0;
if (Previous.begin() != Previous.end())
PrevDecl = *Previous.begin();
- if (PrevDecl && !isDeclInScope(PrevDecl, CurContext, S))
+ if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S))
PrevDecl = 0;
- DeclContext *SemanticContext = CurContext;
- if (SS.isNotEmpty() && !SS.isInvalid()) {
- SemanticContext = computeDeclContext(SS);
-
- // FIXME: need to match up several levels of template parameter lists here.
- }
-
- // FIXME: member templates!
- TemplateParameterList *TemplateParams
- = static_cast<TemplateParameterList *>(*TemplateParameterLists.release());
-
// If there is a previous declaration with the same name, check
// whether this is a valid redeclaration.
ClassTemplateDecl *PrevClassTemplate
@@ -2106,28 +2110,20 @@
/// If the template declaration is valid in this scope, returns
/// false. Otherwise, issues a diagnostic and returns true.
bool
-Sema::CheckTemplateDeclScope(Scope *S,
- MultiTemplateParamsArg &TemplateParameterLists) {
- assert(TemplateParameterLists.size() > 0 && "Not a template");
-
+Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
// Find the nearest enclosing declaration scope.
while ((S->getFlags() & Scope::DeclScope) == 0 ||
(S->getFlags() & Scope::TemplateParamScope) != 0)
S = S->getParent();
- TemplateParameterList *TemplateParams =
- static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
- SourceLocation TemplateLoc = TemplateParams->getTemplateLoc();
- SourceRange TemplateRange
- = SourceRange(TemplateLoc, TemplateParams->getRAngleLoc());
-
// C++ [temp]p2:
// A template-declaration can appear only as a namespace scope or
// class scope declaration.
DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
if (Ctx && isa<LinkageSpecDecl>(Ctx) &&
cast<LinkageSpecDecl>(Ctx)->getLanguage() != LinkageSpecDecl::lang_cxx)
- return Diag(TemplateLoc, diag::err_template_linkage) << TemplateRange;
+ return Diag(TemplateParams->getTemplateLoc(), diag::err_template_linkage)
+ << TemplateParams->getSourceRange();
while (Ctx && isa<LinkageSpecDecl>(Ctx))
Ctx = Ctx->getParent();
@@ -2135,8 +2131,9 @@
if (Ctx && (Ctx->isFileContext() || Ctx->isRecord()))
return false;
- return Diag(TemplateLoc, diag::err_template_outside_namespace_or_class_scope)
- << TemplateRange;
+ return Diag(TemplateParams->getTemplateLoc(),
+ diag::err_template_outside_namespace_or_class_scope)
+ << TemplateParams->getSourceRange();
}
/// \brief Check whether a class template specialization or explicit
@@ -2369,57 +2366,47 @@
// Check the validity of the template headers that introduce this
// template.
- // FIXME: Once we have member templates, we'll need to check
- // C++ [temp.expl.spec]p17-18, where we could have multiple levels of
- // template<> headers.
- if (TemplateParameterLists.size() == 0)
- Diag(KWLoc, diag::err_template_spec_needs_header)
- << CodeModificationHint::CreateInsertion(KWLoc, "template<> ");
- else {
- TemplateParameterList *TemplateParams
- = static_cast<TemplateParameterList*>(*TemplateParameterLists.get());
- if (TemplateParameterLists.size() > 1) {
- Diag(TemplateParams->getTemplateLoc(),
- diag::err_template_spec_extra_headers);
- return true;
- }
-
- if (TemplateParams->size() > 0) {
- isPartialSpecialization = true;
-
- // C++ [temp.class.spec]p10:
- // The template parameter list of a specialization shall not
- // contain default template argument values.
- for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
- Decl *Param = TemplateParams->getParam(I);
- if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
- if (TTP->hasDefaultArgument()) {
- Diag(TTP->getDefaultArgumentLoc(),
- diag::err_default_arg_in_partial_spec);
- TTP->setDefaultArgument(QualType(), SourceLocation(), false);
- }
- } else if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
- if (Expr *DefArg = NTTP->getDefaultArgument()) {
- Diag(NTTP->getDefaultArgumentLoc(),
- diag::err_default_arg_in_partial_spec)
- << DefArg->getSourceRange();
- NTTP->setDefaultArgument(0);
- DefArg->Destroy(Context);
- }
- } else {
- TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(Param);
- if (Expr *DefArg = TTP->getDefaultArgument()) {
- Diag(TTP->getDefaultArgumentLoc(),
- diag::err_default_arg_in_partial_spec)
- << DefArg->getSourceRange();
- TTP->setDefaultArgument(0);
- DefArg->Destroy(Context);
- }
+ TemplateParameterList *TemplateParams
+ = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS,
+ (TemplateParameterList**)TemplateParameterLists.get(),
+ TemplateParameterLists.size());
+ if (TemplateParams && TemplateParams->size() > 0) {
+ isPartialSpecialization = true;
+
+ // C++ [temp.class.spec]p10:
+ // The template parameter list of a specialization shall not
+ // contain default template argument values.
+ for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
+ Decl *Param = TemplateParams->getParam(I);
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
+ if (TTP->hasDefaultArgument()) {
+ Diag(TTP->getDefaultArgumentLoc(),
+ diag::err_default_arg_in_partial_spec);
+ TTP->setDefaultArgument(QualType(), SourceLocation(), false);
+ }
+ } else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ if (Expr *DefArg = NTTP->getDefaultArgument()) {
+ Diag(NTTP->getDefaultArgumentLoc(),
+ diag::err_default_arg_in_partial_spec)
+ << DefArg->getSourceRange();
+ NTTP->setDefaultArgument(0);
+ DefArg->Destroy(Context);
+ }
+ } else {
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(Param);
+ if (Expr *DefArg = TTP->getDefaultArgument()) {
+ Diag(TTP->getDefaultArgumentLoc(),
+ diag::err_default_arg_in_partial_spec)
+ << DefArg->getSourceRange();
+ TTP->setDefaultArgument(0);
+ DefArg->Destroy(Context);
}
}
}
- }
+ } else if (!TemplateParams)
+ Diag(KWLoc, diag::err_template_spec_needs_header)
+ << CodeModificationHint::CreateInsertion(KWLoc, "template<> ");
// Check that the specialization uses the same tag kind as the
// original template.
@@ -2482,7 +2469,7 @@
ClassTemplate->getIdentifier(),
TemplateNameLoc,
Attr,
- move(TemplateParameterLists),
+ TemplateParams,
AS_none);
}
Modified: cfe/trunk/test/SemaTemplate/nested-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/nested-template.cpp?rev=80003&r1=80002&r2=80003&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/nested-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/nested-template.cpp Tue Aug 25 12:23:04 2009
@@ -15,16 +15,55 @@
S::A<int>::Nested::type *ip = &i;
template<typename T>
-struct X0 {
- template<typename U> void f0(T, U);
+struct Outer {
+ template<typename U>
+ class Inner0;
template<typename U>
- struct Inner0 {
- void f1(T, U);
+ class Inner1 {
+ struct ReallyInner;
+
+ T foo(U);
+ template<typename V> T bar(V);
};
};
-template<typename X> template<typename Y> void X0<X>::f0(X, Y) { }
+template<typename X>
+template<typename Y>
+class Outer<X>::Inner0 {
+public:
+ void f(X, Y);
+};
+
+#if 0
+// FIXME: These don't parse properly because we can't handle the template-name
+// "Inner0" or "Inner1" after the dependent type Outer<X>.
+template<typename X>
+template<typename Y>
+void Outer<X>::Inner0<Y>::f(X, Y) {
+}
+
+template<typename X>
+template<typename Y>
+struct Outer<X>::Inner1<Y>::ReallyInner {
+ void g(X, Y);
+};
+
+template<typename X>
+template<typename Y>
+void Outer<X>::Inner1<Y>::ReallyInner::g(X, Y) {
+}
+
+template<typename X>
+template<typename Y>
+X Outer<X>::Inner1<Y>::foo(Y) {
+ return X();
+}
-// FIXME:
-// template<typename X> template<typename Y> void X0<X>::Inner0<Y>::f1(X, Y) { }
+template<typename X>
+template<typename Y>
+template<typename Z>
+X Outer<X>::Inner1<Y>::bar(Z) {
+ return X();
+}
+#endif
\ No newline at end of file
More information about the cfe-commits
mailing list