aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaTemplateInstantiateDecl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaTemplateInstantiateDecl.cpp')
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp57
1 files changed, 43 insertions, 14 deletions
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,