forked from OSchip/llvm-project
Improve handling of friend function templates somewhat
llvm-svn: 82950
This commit is contained in:
parent
277e767578
commit
a29a3ffd18
|
@ -4220,9 +4220,6 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
|
||||||
DeclarationName Name = GetNameForDeclarator(D);
|
DeclarationName Name = GetNameForDeclarator(D);
|
||||||
assert(Name);
|
assert(Name);
|
||||||
|
|
||||||
// The existing declaration we found.
|
|
||||||
FunctionDecl *FD = NULL;
|
|
||||||
|
|
||||||
// The context we found the declaration in, or in which we should
|
// The context we found the declaration in, or in which we should
|
||||||
// create the declaration.
|
// create the declaration.
|
||||||
DeclContext *DC;
|
DeclContext *DC;
|
||||||
|
@ -4230,19 +4227,20 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
|
||||||
// FIXME: handle local classes
|
// FIXME: handle local classes
|
||||||
|
|
||||||
// Recover from invalid scope qualifiers as if they just weren't there.
|
// Recover from invalid scope qualifiers as if they just weren't there.
|
||||||
|
NamedDecl *PrevDecl = 0;
|
||||||
if (!ScopeQual.isInvalid() && ScopeQual.isSet()) {
|
if (!ScopeQual.isInvalid() && ScopeQual.isSet()) {
|
||||||
DC = computeDeclContext(ScopeQual);
|
DC = computeDeclContext(ScopeQual);
|
||||||
|
|
||||||
// FIXME: handle dependent contexts
|
// FIXME: handle dependent contexts
|
||||||
if (!DC) return DeclPtrTy();
|
if (!DC) return DeclPtrTy();
|
||||||
|
|
||||||
Decl *Dec = LookupQualifiedNameWithType(DC, Name, T);
|
PrevDecl = LookupQualifiedName(DC, Name, LookupOrdinaryName, true);
|
||||||
|
|
||||||
// If searching in that context implicitly found a declaration in
|
// If searching in that context implicitly found a declaration in
|
||||||
// a different context, treat it like it wasn't found at all.
|
// a different context, treat it like it wasn't found at all.
|
||||||
// TODO: better diagnostics for this case. Suggesting the right
|
// TODO: better diagnostics for this case. Suggesting the right
|
||||||
// qualified scope would be nice...
|
// qualified scope would be nice...
|
||||||
if (!Dec || Dec->getDeclContext() != DC) {
|
if (!PrevDecl || !PrevDecl->getDeclContext()->Equals(DC)) {
|
||||||
D.setInvalidType();
|
D.setInvalidType();
|
||||||
Diag(Loc, diag::err_qualified_friend_not_found) << Name << T;
|
Diag(Loc, diag::err_qualified_friend_not_found) << Name << T;
|
||||||
return DeclPtrTy();
|
return DeclPtrTy();
|
||||||
|
@ -4250,11 +4248,9 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
|
||||||
|
|
||||||
// C++ [class.friend]p1: A friend of a class is a function or
|
// C++ [class.friend]p1: A friend of a class is a function or
|
||||||
// class that is not a member of the class . . .
|
// class that is not a member of the class . . .
|
||||||
if (DC == CurContext)
|
if (DC->Equals(CurContext))
|
||||||
Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
|
Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
|
||||||
|
|
||||||
FD = cast<FunctionDecl>(Dec);
|
|
||||||
|
|
||||||
// Otherwise walk out to the nearest namespace scope looking for matches.
|
// Otherwise walk out to the nearest namespace scope looking for matches.
|
||||||
} else {
|
} else {
|
||||||
// TODO: handle local class contexts.
|
// TODO: handle local class contexts.
|
||||||
|
@ -4268,15 +4264,15 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
|
||||||
// declarations should stop at the nearest enclosing namespace,
|
// declarations should stop at the nearest enclosing namespace,
|
||||||
// not that they should only consider the nearest enclosing
|
// not that they should only consider the nearest enclosing
|
||||||
// namespace.
|
// namespace.
|
||||||
while (DC->isRecord()) DC = DC->getParent();
|
while (DC->isRecord())
|
||||||
|
DC = DC->getParent();
|
||||||
|
|
||||||
Decl *Dec = LookupQualifiedNameWithType(DC, Name, T);
|
PrevDecl = LookupQualifiedName(DC, Name, LookupOrdinaryName, true);
|
||||||
|
|
||||||
// TODO: decide what we think about using declarations.
|
// TODO: decide what we think about using declarations.
|
||||||
if (Dec) {
|
if (PrevDecl)
|
||||||
FD = cast<FunctionDecl>(Dec);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
if (DC->isFileContext()) break;
|
if (DC->isFileContext()) break;
|
||||||
DC = DC->getParent();
|
DC = DC->getParent();
|
||||||
}
|
}
|
||||||
|
@ -4286,24 +4282,11 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
|
||||||
// C++0x changes this for both friend types and functions.
|
// C++0x changes this for both friend types and functions.
|
||||||
// Most C++ 98 compilers do seem to give an error here, so
|
// Most C++ 98 compilers do seem to give an error here, so
|
||||||
// we do, too.
|
// we do, too.
|
||||||
if (FD && DC == CurContext && !getLangOptions().CPlusPlus0x)
|
if (PrevDecl && DC->Equals(CurContext) && !getLangOptions().CPlusPlus0x)
|
||||||
Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
|
Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Redeclaration = (FD != 0);
|
if (DC->isFileContext()) {
|
||||||
|
|
||||||
// If we found a match, create a friend function declaration with
|
|
||||||
// that function as the previous declaration.
|
|
||||||
if (Redeclaration) {
|
|
||||||
// Create it in the semantic context of the original declaration.
|
|
||||||
DC = FD->getDeclContext();
|
|
||||||
|
|
||||||
// If we didn't find something matching the type exactly, create
|
|
||||||
// a declaration. This declaration should only be findable via
|
|
||||||
// argument-dependent lookup.
|
|
||||||
} else {
|
|
||||||
assert(DC->isFileContext());
|
|
||||||
|
|
||||||
// This implies that it has to be an operator or function.
|
// This implies that it has to be an operator or function.
|
||||||
if (D.getKind() == Declarator::DK_Constructor ||
|
if (D.getKind() == Declarator::DK_Constructor ||
|
||||||
D.getKind() == Declarator::DK_Destructor ||
|
D.getKind() == Declarator::DK_Destructor ||
|
||||||
|
@ -4315,20 +4298,15 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NamedDecl *ND = ActOnFunctionDeclarator(S, D, DC, T, DInfo,
|
bool Redeclaration = false;
|
||||||
/* PrevDecl = */ FD,
|
NamedDecl *ND = ActOnFunctionDeclarator(S, D, DC, T, DInfo, PrevDecl,
|
||||||
MultiTemplateParamsArg(*this),
|
MultiTemplateParamsArg(*this),
|
||||||
IsDefinition,
|
IsDefinition,
|
||||||
Redeclaration);
|
Redeclaration);
|
||||||
if (!ND) return DeclPtrTy();
|
if (!ND) return DeclPtrTy();
|
||||||
|
|
||||||
assert(cast<FunctionDecl>(ND)->getPreviousDeclaration() == FD &&
|
assert(ND->getDeclContext() == DC);
|
||||||
"lost reference to previous declaration");
|
assert(ND->getLexicalDeclContext() == CurContext);
|
||||||
|
|
||||||
FD = cast<FunctionDecl>(ND);
|
|
||||||
|
|
||||||
assert(FD->getDeclContext() == DC);
|
|
||||||
assert(FD->getLexicalDeclContext() == CurContext);
|
|
||||||
|
|
||||||
// Add the function declaration to the appropriate lookup tables,
|
// Add the function declaration to the appropriate lookup tables,
|
||||||
// adjusting the redeclarations list as necessary. We don't
|
// adjusting the redeclarations list as necessary. We don't
|
||||||
|
@ -4338,18 +4316,18 @@ Sema::ActOnFriendFunctionDecl(Scope *S,
|
||||||
// lookup context is in lexical scope.
|
// lookup context is in lexical scope.
|
||||||
if (!CurContext->isDependentContext()) {
|
if (!CurContext->isDependentContext()) {
|
||||||
DC = DC->getLookupContext();
|
DC = DC->getLookupContext();
|
||||||
DC->makeDeclVisibleInContext(FD, /* Recoverable=*/ false);
|
DC->makeDeclVisibleInContext(ND, /* Recoverable=*/ false);
|
||||||
if (Scope *EnclosingScope = getScopeForDeclContext(S, DC))
|
if (Scope *EnclosingScope = getScopeForDeclContext(S, DC))
|
||||||
PushOnScopeChains(FD, EnclosingScope, /*AddToContext=*/ false);
|
PushOnScopeChains(ND, EnclosingScope, /*AddToContext=*/ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
FriendDecl *FrD = FriendDecl::Create(Context, CurContext,
|
FriendDecl *FrD = FriendDecl::Create(Context, CurContext,
|
||||||
D.getIdentifierLoc(), FD,
|
D.getIdentifierLoc(), ND,
|
||||||
DS.getFriendSpecLoc());
|
DS.getFriendSpecLoc());
|
||||||
FrD->setAccess(AS_public);
|
FrD->setAccess(AS_public);
|
||||||
CurContext->addDecl(FrD);
|
CurContext->addDecl(FrD);
|
||||||
|
|
||||||
return DeclPtrTy::make(FD);
|
return DeclPtrTy::make(ND);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sema::SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc) {
|
void Sema::SetDeclDeleted(DeclPtrTy dcl, SourceLocation DelLoc) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// RUN: clang-cc -fsyntax-only %s
|
// RUN: clang-cc -fsyntax-only -verify %s
|
||||||
|
|
||||||
// PR5057
|
// PR5057
|
||||||
namespace std {
|
namespace std {
|
||||||
|
@ -15,3 +15,16 @@ namespace std {
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace N {
|
||||||
|
template<typename T> void f1(T) { } // expected-note{{here}}
|
||||||
|
|
||||||
|
class X {
|
||||||
|
template<typename T> friend void f0(T);
|
||||||
|
template<typename T> friend void f1(T);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T> void f0(T) { }
|
||||||
|
template<typename T> void f1(T) { } // expected-error{{redefinition}}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue