[cfe-commits] r78653 - in /cfe/trunk: include/clang/AST/DeclBase.h include/clang/AST/DeclCXX.h include/clang/AST/DeclNodes.def include/clang/Parse/Action.h lib/AST/DeclBase.cpp lib/AST/DeclCXX.cpp lib/Parse/ParseCXXInlineMethods.cpp lib/Parse/ParseDeclCXX.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaLookup.cpp test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
John McCall
rjmccall at apple.com
Mon Aug 10 23:59:38 PDT 2009
Author: rjmccall
Date: Tue Aug 11 01:59:38 2009
New Revision: 78653
URL: http://llvm.org/viewvc/llvm-project?rev=78653&view=rev
Log:
Argument-dependent lookup for friend declarations. Add a new decl type,
FriendFunctionDecl, and create instances as appropriate.
The design of FriendFunctionDecl is still somewhat up in the air; you can
befriend arbitrary types of functions --- methods, constructors, etc. ---
and it's not clear that this representation captures that very well.
We'll have a better picture when we start consuming this data in access
control.
Added:
cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
Modified:
cfe/trunk/include/clang/AST/DeclBase.h
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/include/clang/AST/DeclNodes.def
cfe/trunk/include/clang/Parse/Action.h
cfe/trunk/lib/AST/DeclBase.cpp
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
cfe/trunk/lib/Parse/ParseDeclCXX.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaLookup.cpp
Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=78653&r1=78652&r2=78653&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Tue Aug 11 01:59:38 2009
@@ -827,6 +827,14 @@
/// semantic context via makeDeclVisibleInContext.
void addDecl(Decl *D);
+ /// @brief Add the declaration D to this context without modifying
+ /// any lookup tables.
+ ///
+ /// This is useful for some operations in dependent contexts where
+ /// the semantic context might not be dependent; this basically
+ /// only happens with friends.
+ void addHiddenDecl(Decl *D);
+
/// lookup_iterator - An iterator that provides access to the results
/// of looking up a name within this context.
typedef NamedDecl **lookup_iterator;
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=78653&r1=78652&r2=78653&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Tue Aug 11 01:59:38 2009
@@ -1213,6 +1213,36 @@
static bool classof(const CXXConversionDecl *D) { return true; }
};
+/// FriendFunctionDecl - Represents the declaration (and possibly
+/// the definition) of a friend function.
+class FriendFunctionDecl : public FunctionDecl {
+ // Location of the 'friend' specifier.
+ const SourceLocation FriendLoc;
+
+ FriendFunctionDecl(DeclContext *DC, SourceLocation L,
+ DeclarationName N, QualType T,
+ bool isInline, SourceLocation FriendL)
+ : FunctionDecl(FriendFunction, DC, L, N, T, None, isInline),
+ FriendLoc(FriendL)
+ {}
+
+public:
+ static FriendFunctionDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, DeclarationName N,
+ QualType T, bool isInline,
+ SourceLocation FriendL);
+
+ SourceLocation getFriendLoc() const {
+ return FriendLoc;
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) {
+ return D->getKind() == FriendFunction;
+ }
+ static bool classof(const FriendFunctionDecl *D) { return true; }
+};
+
/// LinkageSpecDecl - This represents a linkage specification. For example:
/// extern "C" void foo();
///
Modified: cfe/trunk/include/clang/AST/DeclNodes.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclNodes.def?rev=78653&r1=78652&r2=78653&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclNodes.def (original)
+++ cfe/trunk/include/clang/AST/DeclNodes.def Tue Aug 11 01:59:38 2009
@@ -92,6 +92,7 @@
ABSTRACT_DECL(Value, NamedDecl)
DECL(EnumConstant, ValueDecl)
DECL(Function, ValueDecl)
+ DECL(FriendFunction, FunctionDecl)
DECL(CXXMethod, FunctionDecl)
DECL(CXXConstructor, CXXMethodDecl)
DECL(CXXDestructor, CXXMethodDecl)
Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=78653&r1=78652&r2=78653&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Tue Aug 11 01:59:38 2009
@@ -1143,7 +1143,8 @@
/// ActOnFriendDecl - This action is called when a friend declaration is
/// encountered.
virtual DeclPtrTy ActOnFriendDecl(Scope *S,
- llvm::PointerUnion<const DeclSpec*,Declarator*> D) {
+ llvm::PointerUnion<const DeclSpec*,Declarator*> D,
+ bool IsDefinition) {
return DeclPtrTy();
}
Modified: cfe/trunk/lib/AST/DeclBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=78653&r1=78652&r2=78653&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclBase.cpp (original)
+++ cfe/trunk/lib/AST/DeclBase.cpp Tue Aug 11 01:59:38 2009
@@ -198,6 +198,9 @@
case ObjCProperty:
case ObjCCompatibleAlias:
return IDNS_Ordinary;
+
+ case FriendFunction:
+ return IDNS_Friend;
case ObjCProtocol:
return IDNS_ObjCProtocol;
@@ -583,7 +586,7 @@
return !FirstDecl;
}
-void DeclContext::addDecl(Decl *D) {
+void DeclContext::addHiddenDecl(Decl *D) {
assert(D->getLexicalDeclContext() == this &&
"Decl inserted into wrong lexical context");
assert(!D->getNextDeclInContext() && D != LastDecl &&
@@ -595,6 +598,10 @@
} else {
FirstDecl = LastDecl = D;
}
+}
+
+void DeclContext::addDecl(Decl *D) {
+ addHiddenDecl(D);
if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
ND->getDeclContext()->makeDeclVisibleInContext(ND);
@@ -608,9 +615,12 @@
for (decl_iterator D = DCtx->decls_begin(),
DEnd = DCtx->decls_end();
D != DEnd; ++D) {
- // Insert this declaration into the lookup structure
+ // Insert this declaration into the lookup structure, but only
+ // if it's semantically in its decl context. During non-lazy
+ // lookup building, this is implicitly enforced by addDecl.
if (NamedDecl *ND = dyn_cast<NamedDecl>(*D))
- makeDeclVisibleInContextImpl(ND);
+ if (D->getDeclContext() == DCtx)
+ makeDeclVisibleInContextImpl(ND);
// If this declaration is itself a transparent declaration context,
// add its members (recursively).
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=78653&r1=78652&r2=78653&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Tue Aug 11 01:59:38 2009
@@ -738,6 +738,15 @@
return !isa<OverloadedFunctionDecl>(D) || Iter == Other.Iter;
}
+FriendFunctionDecl *FriendFunctionDecl::Create(ASTContext &C,DeclContext *DC,
+ SourceLocation L,
+ DeclarationName N, QualType T,
+ bool isInline,
+ SourceLocation FriendL) {
+ return new (C) FriendFunctionDecl(DC, L, N, T, isInline, FriendL);
+}
+
+
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
Modified: cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp?rev=78653&r1=78652&r2=78653&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp (original)
+++ cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp Tue Aug 11 01:59:38 2009
@@ -29,7 +29,7 @@
DeclPtrTy FnD;
if (D.getDeclSpec().isFriendSpecified())
- FnD = Actions.ActOnFriendDecl(CurScope, &D);
+ FnD = Actions.ActOnFriendDecl(CurScope, &D, /*IsDefinition*/ true);
else
FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, 0, 0);
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=78653&r1=78652&r2=78653&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Tue Aug 11 01:59:38 2009
@@ -954,7 +954,7 @@
ConsumeToken();
if (DS.isFriendSpecified())
- Actions.ActOnFriendDecl(CurScope, &DS);
+ Actions.ActOnFriendDecl(CurScope, &DS, /*IsDefinition*/ false);
else
Actions.ParsedFreeStandingDeclSpec(CurScope, DS);
@@ -1060,7 +1060,8 @@
DeclPtrTy ThisDecl;
if (DS.isFriendSpecified()) {
// TODO: handle initializers, bitfields, 'delete'
- ThisDecl = Actions.ActOnFriendDecl(CurScope, &DeclaratorInfo);
+ ThisDecl = Actions.ActOnFriendDecl(CurScope, &DeclaratorInfo,
+ /*IsDefinition*/ false);
} else
ThisDecl = Actions.ActOnCXXMemberDeclarator(CurScope, AS,
DeclaratorInfo,
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=78653&r1=78652&r2=78653&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Aug 11 01:59:38 2009
@@ -2036,7 +2036,8 @@
ExprArg AssertMessageExpr);
virtual DeclPtrTy ActOnFriendDecl(Scope *S,
- llvm::PointerUnion<const DeclSpec*,Declarator*> D);
+ llvm::PointerUnion<const DeclSpec*,Declarator*> D,
+ bool IsDefinition);
QualType CheckConstructorDeclarator(Declarator &D, QualType R,
FunctionDecl::StorageClass& SC);
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=78653&r1=78652&r2=78653&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Aug 11 01:59:38 2009
@@ -2353,6 +2353,7 @@
if (D.getDeclSpec().isThreadSpecified())
Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);
+ bool isFriend = D.getDeclSpec().isFriendSpecified();
bool isInline = D.getDeclSpec().isInlineSpecified();
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
bool isExplicit = D.getDeclSpec().isExplicitSpecified();
@@ -2382,7 +2383,20 @@
bool isVirtualOkay = false;
FunctionDecl *NewFD;
- if (D.getKind() == Declarator::DK_Constructor) {
+ if (isFriend) {
+ // DC is the namespace in which the function is being declared.
+ assert(DC->isFileContext() || PrevDecl);
+
+ // C++ [class.friend]p5
+ // A function can be defined in a friend declaration of a
+ // class . . . . Such a function is implicitly inline.
+ isInline |= IsFunctionDefinition;
+
+ NewFD = FriendFunctionDecl::Create(Context, DC,
+ D.getIdentifierLoc(), Name, R,
+ isInline,
+ D.getDeclSpec().getFriendSpecLoc());
+ } else if (D.getKind() == Declarator::DK_Constructor) {
// This is a C++ constructor declaration.
assert(DC->isRecord() &&
"Constructors can only be declared in a member context");
@@ -2643,7 +2657,7 @@
if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) {
// An out-of-line member function declaration must also be a
// definition (C++ [dcl.meaning]p1).
- if (!IsFunctionDefinition) {
+ if (!IsFunctionDefinition && !isFriend) {
Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
<< D.getCXXScopeSpec().getRange();
NewFD->setInvalidDecl();
@@ -4142,7 +4156,7 @@
// If a friend declaration in a non-local class first declares a
// class or function, the friend class or function is a member of
// the innermost enclosing namespace.
- while (!SearchDC->isNamespace() && !SearchDC->isTranslationUnit())
+ while (!SearchDC->isFileContext())
SearchDC = SearchDC->getParent();
// The entity of a decl scope is a DeclContext; see PushDeclContext.
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=78653&r1=78652&r2=78653&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Aug 11 01:59:38 2009
@@ -3305,7 +3305,8 @@
}
Sema::DeclPtrTy Sema::ActOnFriendDecl(Scope *S,
- llvm::PointerUnion<const DeclSpec*,Declarator*> DU) {
+ llvm::PointerUnion<const DeclSpec*,Declarator*> DU,
+ bool IsDefinition) {
Declarator *D = DU.dyn_cast<Declarator*>();
const DeclSpec &DS = (D ? D->getDeclSpec() : *DU.get<const DeclSpec*>());
@@ -3483,10 +3484,18 @@
Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member);
}
+ bool Redeclaration = (FD != 0);
+
+ // 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.
- if (!FD) {
+ } else {
assert(DC->isFileContext());
// This implies that it has to be an operator or function.
@@ -3498,23 +3507,25 @@
D->getKind() == Declarator::DK_Destructor ? 1 : 2);
return DeclPtrTy();
}
-
- bool Redeclaration = false;
- NamedDecl *ND = ActOnFunctionDeclarator(S, *D, DC, T,
- /* PrevDecl = */ NULL,
- MultiTemplateParamsArg(*this),
- /* isFunctionDef */ false,
- Redeclaration);
-
- FD = cast_or_null<FunctionDecl>(ND);
-
- // Note that we're creating a declaration but *not* pushing
- // it onto the scope chains.
-
- // TODO: make accessible via argument-dependent lookup.
}
- // TODO: actually register the function as a friend.
+ NamedDecl *ND = ActOnFunctionDeclarator(S, *D, DC, T,
+ /* PrevDecl = */ FD,
+ MultiTemplateParamsArg(*this),
+ IsDefinition,
+ Redeclaration);
+ FD = cast_or_null<FriendFunctionDecl>(ND);
+
+ // If this is a dependent context, just add the decl to the
+ // class's decl list and don't both with the lookup tables. This
+ // doesn't affect lookup because any call that might find this
+ // function via ADL necessarily has to involve dependently-typed
+ // arguments and hence can't be resolved until
+ // template-instantiation anyway.
+ if (CurContext->isDependentContext())
+ CurContext->addHiddenDecl(FD);
+ else
+ CurContext->addDecl(FD);
return DeclPtrTy::make(FD);
}
Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=78653&r1=78652&r2=78653&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Tue Aug 11 01:59:38 2009
@@ -1756,28 +1756,17 @@
// associated classes are visible within their respective
// namespaces even if they are not visible during an ordinary
// lookup (11.4).
- //
- // We implement the second clause in the loop below.
DeclContext::lookup_iterator I, E;
- for (llvm::tie(I, E) = (*NS)->lookup(Name); I != E; ++I)
- CollectFunctionDecl(Functions, *I);
- }
-
- // Look for friend function declarations in associated classes
- // which name functions in associated namespaces.
- for (AssociatedClassSet::iterator AC = AssociatedClasses.begin(),
- ACEnd = AssociatedClasses.end();
- AC != ACEnd; ++AC) {
- DeclContext::lookup_iterator I, E;
- for (llvm::tie(I, E) = (*AC)->lookup(Name); I != E; ++I) {
+ for (llvm::tie(I, E) = (*NS)->lookup(Name); I != E; ++I) {
Decl *D = *I;
- if (!D->isInIdentifierNamespace(Decl::IDNS_Friend))
- continue;
-
- DeclContext *DC = D->getDeclContext();
- if (!AssociatedNamespaces.count(DC))
- continue;
-
+ // Only count friend declarations which were declared in
+ // associated classes.
+ if (D->isInIdentifierNamespace(Decl::IDNS_Friend)) {
+ DeclContext *LexDC = D->getLexicalDeclContext();
+ if (!AssociatedClasses.count(cast<CXXRecordDecl>(LexDC)))
+ continue;
+ }
+
CollectFunctionDecl(Functions, D);
}
}
Added: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp?rev=78653&view=auto
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp (added)
+++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp Tue Aug 11 01:59:38 2009
@@ -0,0 +1,42 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace A {
+ class A {
+ friend void func(A);
+ friend A operator+(A,A);
+ };
+}
+
+namespace B {
+ class B {
+ static void func(B);
+ };
+ B operator+(B,B);
+}
+
+namespace D {
+ class D {};
+}
+
+namespace C {
+ class C {};
+ void func(C);
+ C operator+(C,C);
+ D::D operator+(D::D,D::D);
+}
+
+namespace D {
+ using namespace C;
+}
+
+namespace Test {
+ void test() {
+ func(A::A());
+ func(B::B()); // expected-error {{ no matching function for call to 'func' }}
+ func(C::C());
+ A::A() + A::A();
+ B::B() + B::B();
+ C::C() + C::C();
+ D::D() + D::D(); // expected-error {{ invalid operands to binary expression ('D::D' and 'D::D') }}
+ }
+}
More information about the cfe-commits
mailing list