diff options
author | John McCall <rjmccall@apple.com> | 2009-08-11 06:59:38 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2009-08-11 06:59:38 +0000 |
commit | d1e9d835f30a4505c280504bad9f59d68cbd7a50 (patch) | |
tree | b7b4a0abc67d79844bd531dde8844b7040d7949a /clang/lib/Sema | |
parent | 4d4a2e09a94968ba45dfeb6c294e7b339b81427f (diff) | |
download | bcm5719-llvm-d1e9d835f30a4505c280504bad9f59d68cbd7a50.tar.gz bcm5719-llvm-d1e9d835f30a4505c280504bad9f59d68cbd7a50.zip |
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.
llvm-svn: 78653
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/Sema.h | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 20 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 45 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 29 |
4 files changed, 56 insertions, 41 deletions
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index b35fe67de61..ddd6d7b5712 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -2036,7 +2036,8 @@ public: 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); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index aac79e9fc70..ab5578b378d 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2353,6 +2353,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, 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 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, 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 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, 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 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // 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. diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 20862d4c81f..a0bcfb2b780 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -3305,7 +3305,8 @@ Sema::DeclPtrTy Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, } 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 @@ Sema::DeclPtrTy Sema::ActOnFriendDecl(Scope *S, 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 @@ Sema::DeclPtrTy Sema::ActOnFriendDecl(Scope *S, 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); } diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index ef105374fac..c600f99a404 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1756,28 +1756,17 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, // 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); } } |