mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-27 15:41:46 +00:00
Implement dependent friend function template specializations.
llvm-svn: 100753
This commit is contained in:
parent
ebe47c872f
commit
b9c7848ba7
@ -31,7 +31,9 @@ class StringLiteral;
|
||||
class TemplateArgumentList;
|
||||
class MemberSpecializationInfo;
|
||||
class FunctionTemplateSpecializationInfo;
|
||||
class DependentFunctionTemplateSpecializationInfo;
|
||||
class TypeLoc;
|
||||
class UnresolvedSetImpl;
|
||||
|
||||
/// \brief A container of type source information.
|
||||
///
|
||||
@ -1037,9 +1039,10 @@ private:
|
||||
/// 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 @@ public:
|
||||
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;
|
||||
|
@ -48,10 +48,6 @@ private:
|
||||
// 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 @@ private:
|
||||
: Decl(Decl::Friend, DC, L),
|
||||
Friend(Friend),
|
||||
NextFriend(0),
|
||||
FriendLoc(FriendL),
|
||||
WasSpecialization(false) {
|
||||
FriendLoc(FriendL) {
|
||||
}
|
||||
|
||||
public:
|
||||
@ -88,9 +83,6 @@ public:
|
||||
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; }
|
||||
|
@ -376,6 +376,81 @@ public:
|
||||
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 {
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
} 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!
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -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,
|
||||
|
@ -216,3 +216,25 @@ namespace test9 {
|
||||
|
||||
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}}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user