diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-08-25 17:23:04 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-08-25 17:23:04 +0000 |
commit | 1d5e9f9368b612c4a970b2b7d926ecb2d61baa1c (patch) | |
tree | 014082baed425ff6d86cc6cf8ea1e90eb2cd0520 | |
parent | ae6bc8214ad16bf67ed6fbd1a07c35175f6c5b5d (diff) | |
download | bcm5719-llvm-1d5e9f9368b612c4a970b2b7d926ecb2d61baa1c.tar.gz bcm5719-llvm-1d5e9f9368b612c4a970b2b7d926ecb2d61baa1c.zip |
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.
llvm-svn: 80003
-rw-r--r-- | clang/lib/Sema/Sema.h | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 18 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 145 | ||||
-rw-r--r-- | clang/test/SemaTemplate/nested-template.cpp | 53 |
4 files changed, 121 insertions, 100 deletions
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 363f3ade790..85f287e688b 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -2258,7 +2258,7 @@ public: 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 @@ public: 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". diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 99c1338fbae..ee6238c56c4 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2106,11 +2106,6 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, } } - // 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 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, 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 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, 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 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, 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 diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 7b29c9432a9..bb6fe922831 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -444,14 +444,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, 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 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, } // 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 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, /// 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 @@ Sema::CheckTemplateDeclScope(Scope *S, 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 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // 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 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, ClassTemplate->getIdentifier(), TemplateNameLoc, Attr, - move(TemplateParameterLists), + TemplateParams, AS_none); } diff --git a/clang/test/SemaTemplate/nested-template.cpp b/clang/test/SemaTemplate/nested-template.cpp index 9562bcb51ef..05ab3e9c1bf 100644 --- a/clang/test/SemaTemplate/nested-template.cpp +++ b/clang/test/SemaTemplate/nested-template.cpp @@ -15,16 +15,55 @@ int i; 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 |