diff options
author | John McCall <rjmccall@apple.com> | 2010-04-08 09:05:18 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-04-08 09:05:18 +0000 |
commit | af2094e7cecadf36667deb61a83587ffdd979bd3 (patch) | |
tree | 5ff432cdff32239bd62431a429dd09292c69c1ec /lib | |
parent | 2b60513052e81f66f852b21226ab488f9ed88f1d (diff) |
Implement dependent friend function template specializations.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@100753 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/Decl.cpp | 34 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 4 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 49 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 36 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 57 |
6 files changed, 149 insertions, 34 deletions
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 3f2baf7c9c..965f32da28 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1309,6 +1309,40 @@ FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template, } } +void +FunctionDecl::setDependentTemplateSpecialization(ASTContext &Context, + const UnresolvedSetImpl &Templates, + const TemplateArgumentListInfo &TemplateArgs) { + assert(TemplateOrSpecialization.isNull()); + size_t Size = sizeof(DependentFunctionTemplateSpecializationInfo); + Size += Templates.size() * sizeof(FunctionTemplateDecl*); + Size += TemplateArgs.size(); + void *Buffer = Context.Allocate(Size); + DependentFunctionTemplateSpecializationInfo *Info = + new (Buffer) DependentFunctionTemplateSpecializationInfo(Templates, + TemplateArgs); + TemplateOrSpecialization = Info; +} + +DependentFunctionTemplateSpecializationInfo:: +DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts, + const TemplateArgumentListInfo &TArgs) + : AngleLocs(TArgs.getLAngleLoc(), TArgs.getRAngleLoc()) { + + d.NumTemplates = Ts.size(); + d.NumArgs = TArgs.size(); + + FunctionTemplateDecl **TsArray = + const_cast<FunctionTemplateDecl**>(getTemplates()); + for (unsigned I = 0, E = Ts.size(); I != E; ++I) + TsArray[I] = cast<FunctionTemplateDecl>(Ts[I]->getUnderlyingDecl()); + + TemplateArgumentLoc *ArgsArray = + const_cast<TemplateArgumentLoc*>(getTemplateArgs()); + for (unsigned I = 0, E = TArgs.size(); I != E; ++I) + new (&ArgsArray[I]) TemplateArgumentLoc(TArgs[I]); +} + TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { // For a function template specialization, query the specialization // information object. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 45574b9d69..dc669a9ad5 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2839,6 +2839,10 @@ public: SourceLocation PrevPointOfInstantiation, bool &SuppressNew); + bool CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, + const TemplateArgumentListInfo &ExplicitTemplateArgs, + LookupResult &Previous); + bool CheckFunctionTemplateSpecialization(FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 590a014c92..8df611fcf1 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2935,7 +2935,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // This is a function template specialization. isFunctionTemplateSpecialization = true; - // C++0x [temp.expl.spec]p20 forbids "template<> void foo(int);". + // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);". if (isFriend && isFunctionTemplateSpecialization) { // We want to remove the "template<>", found here. SourceRange RemoveRange = TemplateParams->getSourceRange(); @@ -3139,23 +3139,38 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // "friend void foo<>(int);" is an implicit specialization decl. isFunctionTemplateSpecialization = true; } - } - - if (isFunctionTemplateSpecialization) { - if (isFriend && NewFD->getType()->isDependentType()) { - // FIXME: When we see a friend of a function template - // specialization with a dependent type, we can't match it now; - // for now, we just drop it, until we have a reasonable way to - // represent the parsed-but-not-matched friend function template - // specialization in the AST. - return 0; - } else if (CheckFunctionTemplateSpecialization(NewFD, - (HasExplicitTemplateArgs ? &TemplateArgs : 0), - Previous)) + } else if (isFriend && isFunctionTemplateSpecialization) { + // This combination is only possible in a recovery case; the user + // wrote something like: + // template <> friend void foo(int); + // which we're recovering from as if the user had written: + // friend void foo<>(int); + // Go ahead and fake up a template id. + HasExplicitTemplateArgs = true; + TemplateArgs.setLAngleLoc(D.getIdentifierLoc()); + TemplateArgs.setRAngleLoc(D.getIdentifierLoc()); + } + + // If it's a friend (and only if it's a friend), it's possible + // that either the specialized function type or the specialized + // template is dependent, and therefore matching will fail. In + // this case, don't check the specialization yet. + if (isFunctionTemplateSpecialization && isFriend && + (NewFD->getType()->isDependentType() || DC->isDependentContext())) { + assert(HasExplicitTemplateArgs && + "friend function specialization without template args"); + if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs, + Previous)) NewFD->setInvalidDecl(); - } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) && - CheckMemberSpecialization(NewFD, Previous)) - NewFD->setInvalidDecl(); + } else if (isFunctionTemplateSpecialization) { + if (CheckFunctionTemplateSpecialization(NewFD, + (HasExplicitTemplateArgs ? &TemplateArgs : 0), + Previous)) + NewFD->setInvalidDecl(); + } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) { + if (CheckMemberSpecialization(NewFD, Previous)) + NewFD->setInvalidDecl(); + } // Perform semantic checking on the function declaration. bool OverloadableAttrRequired = false; // FIXME: HACK! diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 298ce066f7..7cdeea4160 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -5638,9 +5638,6 @@ Sema::ActOnFriendFunctionDecl(Scope *S, FrD->setAccess(AS_public); CurContext->addDecl(FrD); - if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) - FrD->setSpecialization(true); - return DeclPtrTy::make(ND); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 44afbd7d1b..584cc3e871 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -4083,6 +4083,42 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, return false; } +/// \brief Perform semantic analysis for the given dependent function +/// template specialization. The only possible way to get a dependent +/// function template specialization is with a friend declaration, +/// like so: +/// +/// template <class T> void foo(T); +/// template <class T> class A { +/// friend void foo<>(T); +/// }; +/// +/// There really isn't any useful analysis we can do here, so we +/// just store the information. +bool +Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, + const TemplateArgumentListInfo &ExplicitTemplateArgs, + LookupResult &Previous) { + // Remove anything from Previous that isn't a function template in + // the correct context. + DeclContext *FDLookupContext = FD->getDeclContext()->getLookupContext(); + LookupResult::Filter F = Previous.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next()->getUnderlyingDecl(); + if (!isa<FunctionTemplateDecl>(D) || + !FDLookupContext->Equals(D->getDeclContext()->getLookupContext())) + F.erase(); + } + F.done(); + + // Should this be diagnosed here? + if (Previous.empty()) return true; + + FD->setDependentTemplateSpecialization(Context, Previous.asUnresolvedSet(), + ExplicitTemplateArgs); + return false; +} + /// \brief Perform semantic analysis for the given function template /// specialization. /// diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 69f183c706..9df345a11f 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -497,18 +497,11 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { NamedDecl *ND = D->getFriendDecl(); assert(ND && "friend decl must be a decl or a type!"); - // FIXME: We have a problem here, because the nested call to Visit(ND) - // will inject the thing that the friend references into the current - // owner, which is wrong. - Decl *NewND; - - // Hack to make this work almost well pending a rewrite. - if (D->wasSpecialization()) { - // Totally egregious hack to work around PR5866 - return 0; - } else { - NewND = Visit(ND); - } + // All of the Visit implementations for the various potential friend + // declarations have to be carefully written to work for friend + // objects, with the most important detail being that the target + // decl should almost certainly not be placed in Owner. + Decl *NewND = Visit(ND); if (!NewND) return 0; FriendDecl *FD = @@ -1024,11 +1017,47 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, bool Redeclaration = false; bool OverloadableAttrRequired = false; + bool isExplicitSpecialization = false; LookupResult Previous(SemaRef, Function->getDeclName(), SourceLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); - if (TemplateParams || !FunctionTemplate) { + if (DependentFunctionTemplateSpecializationInfo *Info + = D->getDependentSpecializationInfo()) { + assert(isFriend && "non-friend has dependent specialization info?"); + + // This needs to be set now for future sanity. + Function->setObjectOfFriendDecl(/*HasPrevious*/ true); + + // Instantiate the explicit template arguments. + TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), + Info->getRAngleLoc()); + for (unsigned I = 0, E = Info->getNumTemplateArgs(); I != E; ++I) { + TemplateArgumentLoc Loc; + if (SemaRef.Subst(Info->getTemplateArg(I), Loc, TemplateArgs)) + return 0; + + ExplicitArgs.addArgument(Loc); + } + + // Map the candidate templates to their instantiations. + for (unsigned I = 0, E = Info->getNumTemplates(); I != E; ++I) { + Decl *Temp = SemaRef.FindInstantiatedDecl(D->getLocation(), + Info->getTemplate(I), + TemplateArgs); + if (!Temp) return 0; + + Previous.addDecl(cast<FunctionTemplateDecl>(Temp)); + } + + if (SemaRef.CheckFunctionTemplateSpecialization(Function, + &ExplicitArgs, + Previous)) + Function->setInvalidDecl(); + + isExplicitSpecialization = true; + + } else if (TemplateParams || !FunctionTemplate) { // Look only into the namespace where the friend would be declared to // find a previous declaration. This is the innermost enclosing namespace, // as described in ActOnFriendFunctionDecl. @@ -1043,7 +1072,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, } SemaRef.CheckFunctionDeclaration(/*Scope*/ 0, Function, Previous, - false, Redeclaration, + isExplicitSpecialization, Redeclaration, /*FIXME:*/OverloadableAttrRequired); // If the original function was part of a friend declaration, |