[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
John McCall
rjmccall at apple.com
Thu Apr 8 02:05:18 PDT 2010
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;
-
friend class CXXRecordDecl::friend_iterator;
friend class CXXRecordDecl;
@@ -60,8 +56,7 @@
: Decl(Decl::Friend, DC, L),
Friend(Friend),
NextFriend(0),
- FriendLoc(FriendL),
- WasSpecialization(false) {
+ FriendLoc(FriendL) {
}
public:
@@ -88,9 +83,6 @@
return FriendLoc;
}
- bool wasSpecialization() const { return WasSpecialization; }
- void setSpecialization(bool WS) { WasSpecialization = WS; }
-
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classof(const FriendDecl *D) { return true; }
Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=100753&r1=100752&r2=100753&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Thu Apr 8 04:05:18 2010
@@ -376,6 +376,81 @@
PointOfInstantiation = POI;
}
};
+
+/// \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();
+ }
+};
/// Declaration of a template function.
class FunctionTemplateDecl : public TemplateDecl {
Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=100753&r1=100752&r2=100753&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Thu Apr 8 04:05:18 2010
@@ -1309,6 +1309,40 @@
}
}
+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.
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=100753&r1=100752&r2=100753&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Apr 8 04:05:18 2010
@@ -2839,6 +2839,10 @@
SourceLocation PrevPointOfInstantiation,
bool &SuppressNew);
+ bool CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD,
+ const TemplateArgumentListInfo &ExplicitTemplateArgs,
+ LookupResult &Previous);
+
bool CheckFunctionTemplateSpecialization(FunctionDecl *FD,
const TemplateArgumentListInfo *ExplicitTemplateArgs,
LookupResult &Previous);
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=100753&r1=100752&r2=100753&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Apr 8 04:05:18 2010
@@ -2935,7 +2935,7 @@
// 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 @@
// "friend void foo<>(int);" is an implicit specialization decl.
isFunctionTemplateSpecialization = true;
}
+ } 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 (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))
+ // 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!
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);
}
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;
+
+ FD->setDependentTemplateSpecialization(Context, Previous.asUnresolvedSet(),
+ ExplicitTemplateArgs);
+ return false;
+}
+
/// \brief Perform semantic analysis for the given function template
/// specialization.
///
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);
- }
+ // 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;
+
+ 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 @@
}
SemaRef.CheckFunctionDeclaration(/*Scope*/ 0, Function, Previous,
- false, Redeclaration,
+ isExplicitSpecialization, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
// If the original function was part of a friend declaration,
Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp?rev=100753&r1=100752&r2=100753&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp Thu Apr 8 04:05:18 2010
@@ -216,3 +216,25 @@
template class A<int>; // expected-note {{in instantiation}}
}
+
+namespace test10 {
+ template <class T> class A;
+ template <class T> A<T> bar(const T*, const A<T>&);
+ template <class T> class A {
+ private:
+ void foo(); // expected-note {{declared private here}}
+ friend A bar<>(const T*, const A<T>&);
+ };
+
+ template <class T> A<T> bar(const T *l, const A<T> &r) {
+ A<T> l1;
+ l1.foo();
+
+ A<char> l2;
+ l2.foo(); // expected-error {{'foo' is a private member of 'test10::A<char>'}}
+
+ return l1;
+ }
+
+ template A<int> bar<int>(const int *, const A<int> &); // expected-note {{in instantiation}}
+}
More information about the cfe-commits
mailing list