[cfe-commits] r100753 - in /cfe/trunk: include/clang/AST/Decl.h include/clang/AST/DeclFriend.h include/clang/AST/DeclTemplate.h lib/AST/Decl.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/CXX/temp/temp.decls/temp.friend/p1.cpp
Douglas Gregor
dgregor at apple.com
Thu Apr 8 08:16:52 PDT 2010
On Apr 8, 2010, at 2:05 AM, John McCall wrote:
> Author: rjmccall
> Date: Thu Apr 8 04:05:18 2010
> New Revision: 100753
>
> URL: http://llvm.org/viewvc/llvm-project?rev=100753&view=rev
> Log:
> Implement dependent friend function template specializations.
>
>
> Modified:
> cfe/trunk/include/clang/AST/Decl.h
> cfe/trunk/include/clang/AST/DeclFriend.h
> cfe/trunk/include/clang/AST/DeclTemplate.h
> cfe/trunk/lib/AST/Decl.cpp
> cfe/trunk/lib/Sema/Sema.h
> cfe/trunk/lib/Sema/SemaDecl.cpp
> cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> cfe/trunk/lib/Sema/SemaTemplate.cpp
> cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
> cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp
>
> Modified: cfe/trunk/include/clang/AST/Decl.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=100753&r1=100752&r2=100753&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Decl.h (original)
> +++ cfe/trunk/include/clang/AST/Decl.h Thu Apr 8 04:05:18 2010
> @@ -31,7 +31,9 @@
> class TemplateArgumentList;
> class MemberSpecializationInfo;
> class FunctionTemplateSpecializationInfo;
> +class DependentFunctionTemplateSpecializationInfo;
> class TypeLoc;
> +class UnresolvedSetImpl;
>
> /// \brief A container of type source information.
> ///
> @@ -1037,9 +1039,10 @@
> /// FunctionTemplateSpecializationInfo, which contains information about
> /// the template being specialized and the template arguments involved in
> /// that specialization.
> - llvm::PointerUnion3<FunctionTemplateDecl *,
> + llvm::PointerUnion4<FunctionTemplateDecl *,
> MemberSpecializationInfo *,
> - FunctionTemplateSpecializationInfo *>
> + FunctionTemplateSpecializationInfo *,
> + DependentFunctionTemplateSpecializationInfo *>
> TemplateOrSpecialization;
>
> protected:
> @@ -1365,6 +1368,18 @@
> void *InsertPos,
> TemplateSpecializationKind TSK = TSK_ImplicitInstantiation);
>
> + /// \brief Specifies that this function declaration is actually a
> + /// dependent function template specialization.
> + void setDependentTemplateSpecialization(ASTContext &Context,
> + const UnresolvedSetImpl &Templates,
> + const TemplateArgumentListInfo &TemplateArgs);
> +
> + DependentFunctionTemplateSpecializationInfo *
> + getDependentSpecializationInfo() const {
> + return TemplateOrSpecialization.
> + dyn_cast<DependentFunctionTemplateSpecializationInfo*>();
> + }
> +
> /// \brief Determine what kind of template instantiation this function
> /// represents.
> TemplateSpecializationKind getTemplateSpecializationKind() const;
>
> Modified: cfe/trunk/include/clang/AST/DeclFriend.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclFriend.h?rev=100753&r1=100752&r2=100753&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/DeclFriend.h (original)
> +++ cfe/trunk/include/clang/AST/DeclFriend.h Thu Apr 8 04:05:18 2010
> @@ -48,10 +48,6 @@
> // Location of the 'friend' specifier.
> SourceLocation FriendLoc;
>
> - // FIXME: Hack to keep track of whether this was a friend function
> - // template specialization.
> - bool WasSpecialization;
Yay!
> +/// \brief Provides information about a dependent function-template
> +/// specialization declaration. Since explicit function template
> +/// specialization and instantiation declarations can only appear in
> +/// namespace scope, and you can only specialize a member of a
> +/// fully-specialized class, the only way to get one of these is in
> +/// a friend declaration like the following:
> +///
> +/// template <class T> void foo(T);
> +/// template <class T> class A {
> +/// friend void foo<>(T);
> +/// };
> +class DependentFunctionTemplateSpecializationInfo {
> + union {
> + // Force sizeof to be a multiple of sizeof(void*) so that the
> + // trailing data is aligned.
> + void *Aligner;
> +
> + struct {
> + /// The number of potential template candidates.
> + unsigned NumTemplates;
> +
> + /// The number of template arguments.
> + unsigned NumArgs;
> + } d;
> + };
> +
> + /// The locations of the left and right angle brackets.
> + SourceRange AngleLocs;
> +
> + FunctionTemplateDecl * const *getTemplates() const {
> + return reinterpret_cast<FunctionTemplateDecl*const*>(this+1);
> + }
> +
> + const TemplateArgumentLoc *getTemplateArgs() const {
> + return reinterpret_cast<const TemplateArgumentLoc*>(
> + getTemplates()[getNumTemplates()]);
> + }
> +
> +public:
> + DependentFunctionTemplateSpecializationInfo(
> + const UnresolvedSetImpl &Templates,
> + const TemplateArgumentListInfo &TemplateArgs);
> +
> + /// \brief Returns the number of function templates that this might
> + /// be a specialization of.
> + unsigned getNumTemplates() const {
> + return d.NumTemplates;
> + }
> +
> + /// \brief Returns the i'th template candidate.
> + FunctionTemplateDecl *getTemplate(unsigned I) const {
> + assert(I < getNumTemplates() && "template index out of range");
> + return getTemplates()[I];
> + }
> +
> + /// \brief Returns the number of explicit template arguments that were given.
> + unsigned getNumTemplateArgs() const {
> + return d.NumArgs;
> + }
> +
> + /// \brief Returns the nth template argument.
> + const TemplateArgumentLoc &getTemplateArg(unsigned I) const {
> + assert(I < getNumTemplateArgs() && "template arg index out of range");
> + return getTemplateArgs()[I];
> + }
> +
> + SourceLocation getLAngleLoc() const {
> + return AngleLocs.getBegin();
> + }
> +
> + SourceLocation getRAngleLoc() const {
> + return AngleLocs.getEnd();
> + }
> +};
Very good, I like this representation.
I do wonder if we'll need to hold on to a TemplateName, for the case where the name of the template we're specializing is dependent, e.g.,
template<typename T, typename U>
struct X {
friend void T::foo<>(U);
};
(that's yet another level of complexity)
> Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=100753&r1=100752&r2=100753&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Apr 8 04:05:18 2010
> @@ -5638,9 +5638,6 @@
> FrD->setAccess(AS_public);
> CurContext->addDecl(FrD);
>
> - if (D.getName().getKind() == UnqualifiedId::IK_TemplateId)
> - FrD->setSpecialization(true);
> -
> return DeclPtrTy::make(ND);
> }
--Hack :)
>
> Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=100753&r1=100752&r2=100753&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Apr 8 04:05:18 2010
> @@ -4083,6 +4083,42 @@
> 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;
It should be diagnosed somewhere, since the template we're specializing must already have been declared. That said, I'm having trouble finding the standard reference. C++0x [temp.expl.spec]p3 says as much for specializations, so I think that's the closest we'll get.
> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=100753&r1=100752&r2=100753&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Apr 8 04:05:18 2010
> @@ -497,18 +497,11 @@
> 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);
> - }
Excellent. Is PR5866 now fixed?
> + // 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 @@
>
> 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;
I guess the instantiation of template declarations could matter if we're friending a specialization of a member function template within the current instantiation. That'll be fun to test :)
- Doug
More information about the cfe-commits
mailing list