summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Sema/SemaDecl.cpp16
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp5
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp11
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp119
4 files changed, 117 insertions, 34 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 998abb34037..69426ee7554 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2575,9 +2575,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// lexical context will be different from the semantic context.
NewFD->setLexicalDeclContext(CurContext);
- if (isFriend)
- NewFD->setObjectOfFriendDecl(/* PreviouslyDeclared= */ PrevDecl != NULL);
-
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
FunctionTemplateDecl *FunctionTemplate = 0;
@@ -2640,6 +2637,19 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
}
+ if (isFriend) {
+ if (FunctionTemplate) {
+ FunctionTemplate->setObjectOfFriendDecl(
+ /* PreviouslyDeclared= */ PrevDecl != NULL);
+ FunctionTemplate->setAccess(AS_public);
+ }
+ else
+ NewFD->setObjectOfFriendDecl(/* PreviouslyDeclared= */ PrevDecl != NULL);
+
+ NewFD->setAccess(AS_public);
+ }
+
+
if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD)) {
// Look for virtual methods in base classes that this method might override.
CXXBasePaths Paths;
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index eb1abafb7d0..519694aea84 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4347,8 +4347,6 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
Declarator &D,
bool IsDefinition,
MultiTemplateParamsArg TemplateParams) {
- // FIXME: do something with template parameters
-
const DeclSpec &DS = D.getDeclSpec();
assert(DS.isFriendSpecified());
@@ -4404,6 +4402,7 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
// Recover from invalid scope qualifiers as if they just weren't there.
NamedDecl *PrevDecl = 0;
if (!ScopeQual.isInvalid() && ScopeQual.isSet()) {
+ // FIXME: RequireCompleteDeclContext
DC = computeDeclContext(ScopeQual);
// FIXME: handle dependent contexts
@@ -4479,7 +4478,7 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
bool Redeclaration = false;
NamedDecl *ND = ActOnFunctionDeclarator(S, D, DC, T, DInfo, PrevDecl,
- MultiTemplateParamsArg(*this),
+ move(TemplateParams),
IsDefinition,
Redeclaration);
if (!ND) return DeclPtrTy();
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 9d39ddbe68f..74120498573 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2720,7 +2720,16 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
}
}
}
- } else if (!TemplateParams && TUK != TUK_Friend) {
+ } else if (TemplateParams) {
+ if (TUK == TUK_Friend)
+ Diag(KWLoc, diag::err_template_spec_friend)
+ << CodeModificationHint::CreateRemoval(
+ SourceRange(TemplateParams->getTemplateLoc(),
+ TemplateParams->getRAngleLoc()))
+ << SourceRange(LAngleLoc, RAngleLoc);
+ else
+ isExplicitSpecialization = true;
+ } else if (TUK != TUK_Friend) {
Diag(KWLoc, diag::err_template_spec_needs_header)
<< CodeModificationHint::CreateInsertion(KWLoc, "template<> ");
isExplicitSpecialization = true;
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 4fd2a734b1f..b03734346c4 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -47,7 +47,8 @@ namespace {
Decl *VisitEnumDecl(EnumDecl *D);
Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
Decl *VisitFriendDecl(FriendDecl *D);
- Decl *VisitFunctionDecl(FunctionDecl *D);
+ Decl *VisitFunctionDecl(FunctionDecl *D,
+ TemplateParameterList *TemplateParams = 0);
Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
Decl *VisitCXXMethodDecl(CXXMethodDecl *D,
TemplateParameterList *TemplateParams = 0);
@@ -280,6 +281,9 @@ 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 = Visit(ND);
if (!NewND) return 0;
@@ -423,24 +427,31 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
if (!InstParams)
return NULL;
- // FIXME: Handle instantiation of nested function templates that aren't
- // member function templates. This could happen inside a FriendDecl.
- assert(isa<CXXMethodDecl>(D->getTemplatedDecl()));
- CXXMethodDecl *InstMethod
- = cast_or_null<CXXMethodDecl>(
- VisitCXXMethodDecl(cast<CXXMethodDecl>(D->getTemplatedDecl()),
- InstParams));
- if (!InstMethod)
+ FunctionDecl *Instantiated = 0;
+ if (CXXMethodDecl *DMethod = dyn_cast<CXXMethodDecl>(D->getTemplatedDecl()))
+ Instantiated = cast_or_null<FunctionDecl>(VisitCXXMethodDecl(DMethod,
+ InstParams));
+ else
+ Instantiated = cast_or_null<FunctionDecl>(VisitFunctionDecl(
+ D->getTemplatedDecl(),
+ InstParams));
+
+ if (!Instantiated)
return 0;
// Link the instantiated function template declaration to the function
// template from which it was instantiated.
FunctionTemplateDecl *InstTemplate
- = InstMethod->getDescribedFunctionTemplate();
+ = Instantiated->getDescribedFunctionTemplate();
InstTemplate->setAccess(D->getAccess());
- assert(InstTemplate && "VisitCXXMethodDecl didn't create a template!");
- InstTemplate->setInstantiatedFromMemberTemplate(D);
- Owner->addDecl(InstTemplate);
+ assert(InstTemplate &&
+ "VisitFunctionDecl/CXXMethodDecl didn't create a template!");
+ if (!InstTemplate->getInstantiatedFromMemberTemplate())
+ InstTemplate->setInstantiatedFromMemberTemplate(D);
+
+ // Add non-friends into the owner.
+ if (!InstTemplate->getFriendObjectKind())
+ Owner->addDecl(InstTemplate);
return InstTemplate;
}
@@ -478,12 +489,13 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
/// 1) instantiating function templates
/// 2) substituting friend declarations
/// FIXME: preserve function definitions in case #2
-Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
+ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
+ TemplateParameterList *TemplateParams) {
// Check whether there is already a function template specialization for
// this declaration.
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
void *InsertPos = 0;
- if (FunctionTemplate) {
+ if (FunctionTemplate && !TemplateParams) {
llvm::FoldingSetNodeID ID;
FunctionTemplateSpecializationInfo::Profile(ID,
TemplateArgs.getInnermost().getFlatArgumentList(),
@@ -521,27 +533,79 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
Params[P]->setOwningFunction(Function);
Function->setParams(SemaRef.Context, Params.data(), Params.size());
- // If the original function was part of a friend declaration,
- // inherit its namespace state and add it to the owner.
- if (Decl::FriendObjectKind FOK = D->getFriendObjectKind()) {
- bool WasDeclared = (FOK == Decl::FOK_Declared);
- Function->setObjectOfFriendDecl(WasDeclared);
- if (!Owner->isDependentContext())
- DC->makeDeclVisibleInContext(Function, /* Recoverable = */ false);
-
- Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
+ if (TemplateParams) {
+ // Our resulting instantiation is actually a function template, since we
+ // are substituting only the outer template parameters. For example, given
+ //
+ // template<typename T>
+ // struct X {
+ // template<typename U> friend void f(T, U);
+ // };
+ //
+ // X<int> x;
+ //
+ // We are instantiating the friend function template "f" within X<int>,
+ // which means substituting int for T, but leaving "f" as a friend function
+ // template.
+ // Build the function template itself.
+ FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, Owner,
+ Function->getLocation(),
+ Function->getDeclName(),
+ TemplateParams, Function);
+ Function->setDescribedFunctionTemplate(FunctionTemplate);
+ FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
}
-
+
if (InitFunctionInstantiation(Function, D))
Function->setInvalidDecl();
bool Redeclaration = false;
bool OverloadableAttrRequired = false;
+
NamedDecl *PrevDecl = 0;
+ 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.
+ Sema::LookupResult R;
+ SemaRef.LookupQualifiedName(R, DC, Function->getDeclName(),
+ Sema::LookupOrdinaryName, true);
+
+ PrevDecl = R.getAsSingleDecl(SemaRef.Context);
+
+ // In C++, the previous declaration we find might be a tag type
+ // (class or enum). In this case, the new declaration will hide the
+ // tag type. Note that this does does not apply if we're declaring a
+ // typedef (C++ [dcl.typedef]p4).
+ if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
+ PrevDecl = 0;
+ }
+
SemaRef.CheckFunctionDeclaration(Function, PrevDecl, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
- if (FunctionTemplate) {
+ // If the original function was part of a friend declaration,
+ // inherit its namespace state and add it to the owner.
+ NamedDecl *FromFriendD
+ = TemplateParams? cast<NamedDecl>(D->getDescribedFunctionTemplate()) : D;
+ if (FromFriendD->getFriendObjectKind()) {
+ NamedDecl *ToFriendD = 0;
+ if (TemplateParams) {
+ ToFriendD = cast<NamedDecl>(FunctionTemplate);
+ PrevDecl = FunctionTemplate->getPreviousDeclaration();
+ } else {
+ ToFriendD = Function;
+ PrevDecl = Function->getPreviousDeclaration();
+ }
+ ToFriendD->setObjectOfFriendDecl(PrevDecl != NULL);
+ if (!Owner->isDependentContext() && !PrevDecl)
+ DC->makeDeclVisibleInContext(ToFriendD, /* Recoverable = */ false);
+
+ if (!TemplateParams)
+ Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
+ }
+
+ if (FunctionTemplate && !TemplateParams) {
// Record this function template specialization.
Function->setFunctionTemplateSpecialization(SemaRef.Context,
FunctionTemplate,
@@ -687,7 +751,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration,
/*FIXME:*/OverloadableAttrRequired);
- if (!FunctionTemplate && (!Method->isInvalidDecl() || !PrevDecl))
+ if (!FunctionTemplate && (!Method->isInvalidDecl() || !PrevDecl) &&
+ !Method->getFriendObjectKind())
Owner->addDecl(Method);
return Method;
OpenPOWER on IntegriCloud