diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/AST/Decl.h | 6 | ||||
-rw-r--r-- | clang/include/clang/AST/DeclBase.h | 13 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 12 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 11 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 20 | ||||
-rw-r--r-- | clang/test/CXX/temp/temp.decls/temp.friend/p4.cpp | 17 | ||||
-rw-r--r-- | clang/test/SemaCXX/friend.cpp | 12 |
8 files changed, 66 insertions, 28 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index e90f454db30..2b2bf1a1efc 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -3402,6 +3402,12 @@ void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) { First->RedeclLink = LatestDeclLink(static_cast<decl_type*>(this)); assert(!isa<NamedDecl>(static_cast<decl_type*>(this)) || cast<NamedDecl>(static_cast<decl_type*>(this))->isLinkageValid()); + + // If the declaration was previously visible, a redeclaration of it remains + // visible even if it wouldn't be visible by itself. + static_cast<decl_type*>(this)->IdentifierNamespace |= + First->getIdentifierNamespace() & + (Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Type); } // Inline function definitions. diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 4f289d315ad..157506d2a60 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -295,6 +295,8 @@ protected: friend class ASTReader; friend class LinkageComputer; + template<typename decl_type> friend class Redeclarable; + private: void CheckAccessDeclContext() const; @@ -824,7 +826,7 @@ public: /// class, but in the semantic context of the actual entity. This property /// applies only to a specific decl object; other redeclarations of the /// same entity may not (and probably don't) share this property. - void setObjectOfFriendDecl(bool PreviouslyDeclared) { + void setObjectOfFriendDecl(bool PerformFriendInjection = false) { unsigned OldNS = IdentifierNamespace; assert((OldNS & (IDNS_Tag | IDNS_Ordinary | IDNS_TagFriend | IDNS_OrdinaryFriend)) && @@ -833,15 +835,20 @@ public: IDNS_TagFriend | IDNS_OrdinaryFriend)) && "namespace includes other than ordinary or tag"); + Decl *Prev = getPreviousDecl(); IdentifierNamespace = 0; if (OldNS & (IDNS_Tag | IDNS_TagFriend)) { IdentifierNamespace |= IDNS_TagFriend; - if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Tag | IDNS_Type; + if (PerformFriendInjection || + (Prev && Prev->getIdentifierNamespace() & IDNS_Tag)) + IdentifierNamespace |= IDNS_Tag | IDNS_Type; } if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend)) { IdentifierNamespace |= IDNS_OrdinaryFriend; - if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Ordinary; + if (PerformFriendInjection || + (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary)) + IdentifierNamespace |= IDNS_Ordinary; } } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 5e535da19a1..fd4ddcf55e6 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -6328,12 +6328,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } if (isFriend) { - // For now, claim that the objects have no previous declaration. if (FunctionTemplate) { - FunctionTemplate->setObjectOfFriendDecl(false); + FunctionTemplate->setObjectOfFriendDecl(); FunctionTemplate->setAccess(AS_public); } - NewFD->setObjectOfFriendDecl(false); + NewFD->setObjectOfFriendDecl(); NewFD->setAccess(AS_public); } @@ -6652,8 +6651,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setAccess(Access); if (FunctionTemplate) FunctionTemplate->setAccess(Access); - - PrincipalDecl->setObjectOfFriendDecl(true); } if (NewFD->isOverloadedOperator() && !DC->isRecord() && @@ -10384,9 +10381,8 @@ CreateNewDecl: // declaration so we always pass true to setObjectOfFriendDecl to make // the tag name visible. if (TUK == TUK_Friend) - New->setObjectOfFriendDecl(/* PreviouslyDeclared = */ !Previous.empty() || - (!FriendSawTagOutsideEnclosingNamespace && - getLangOpts().MicrosoftExt)); + New->setObjectOfFriendDecl(!FriendSawTagOutsideEnclosingNamespace && + getLangOpts().MicrosoftExt); // Set the access specifier. if (!Invalid && SearchDC->isRecord()) diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 8d954ca994c..0667b8adc04 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -2757,8 +2757,15 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, // If the only declaration here is an ordinary friend, consider // it only if it was declared in an associated classes. if (D->getIdentifierNamespace() == Decl::IDNS_OrdinaryFriend) { - DeclContext *LexDC = D->getLexicalDeclContext(); - if (!AssociatedClasses.count(cast<CXXRecordDecl>(LexDC))) + bool DeclaredInAssociatedClass = false; + for (Decl *DI = D; DI; DI = D->getPreviousDecl()) { + DeclContext *LexDC = DI->getLexicalDeclContext(); + if (AssociatedClasses.count(cast<CXXRecordDecl>(LexDC))) { + DeclaredInAssociatedClass = true; + break; + } + } + if (!DeclaredInAssociatedClass) continue; } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index e6006b6bf97..6f1ab19f10e 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1120,8 +1120,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, NewClass->setAccess(PrevClassTemplate->getAccess()); } - NewTemplate->setObjectOfFriendDecl(/* PreviouslyDeclared = */ - PrevClassTemplate != NULL); + NewTemplate->setObjectOfFriendDecl(); // Friend templates are visible in fairly strange ways. if (!CurContext->isDependentContext()) { diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index b5a80d3f6a0..14185c37ad1 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -960,7 +960,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { else Inst->setAccess(D->getAccess()); - Inst->setObjectOfFriendDecl(PrevClassTemplate != 0); + Inst->setObjectOfFriendDecl(); // TODO: do we want to track the instantiation progeny of this // friend target decl? } else { @@ -1110,8 +1110,8 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { // If the original function was part of a friend declaration, // inherit its namespace state. - if (Decl::FriendObjectKind FOK = D->getFriendObjectKind()) - Record->setObjectOfFriendDecl(FOK == Decl::FOK_Declared); + if (D->getFriendObjectKind()) + Record->setObjectOfFriendDecl(); // Make sure that anonymous structs and unions are recorded. if (D->isAnonymousStructOrUnion()) { @@ -1315,7 +1315,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, assert(isFriend && "non-friend has dependent specialization info?"); // This needs to be set now for future sanity. - Function->setObjectOfFriendDecl(/*HasPrevious*/ true); + Function->setObjectOfFriendDecl(); // Instantiate the explicit template arguments. TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), @@ -1365,13 +1365,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, // If the original function was part of a friend declaration, // inherit its namespace state and add it to the owner. if (isFriend) { - NamedDecl *PrevDecl; - if (TemplateParams) - PrevDecl = FunctionTemplate->getPreviousDecl(); - else - PrevDecl = Function->getPreviousDecl(); - - PrincipalDecl->setObjectOfFriendDecl(PrevDecl != 0); + PrincipalDecl->setObjectOfFriendDecl(); DC->makeDeclVisibleInContext(PrincipalDecl); bool queuedInstantiation = false; @@ -1639,7 +1633,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, TemplateParams, Method); if (isFriend) { FunctionTemplate->setLexicalDeclContext(Owner); - FunctionTemplate->setObjectOfFriendDecl(true); + FunctionTemplate->setObjectOfFriendDecl(); } else if (D->isOutOfLine()) FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); Method->setDescribedFunctionTemplate(FunctionTemplate); @@ -1666,7 +1660,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, TempParamLists.data()); Method->setLexicalDeclContext(Owner); - Method->setObjectOfFriendDecl(true); + Method->setObjectOfFriendDecl(); } else if (D->isOutOfLine()) Method->setLexicalDeclContext(D->getLexicalDeclContext()); diff --git a/clang/test/CXX/temp/temp.decls/temp.friend/p4.cpp b/clang/test/CXX/temp/temp.decls/temp.friend/p4.cpp index e036cef32b2..8571a141201 100644 --- a/clang/test/CXX/temp/temp.decls/temp.friend/p4.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.friend/p4.cpp @@ -26,3 +26,20 @@ void g() { X2<float> xf; f(xf); } + +template<typename T> +struct X3 { + operator int(); + + friend void h(int x); +}; + +int array2[sizeof(X3<int>)]; +int array3[sizeof(X3<float>)]; + +void i() { + X3<int> xi; + h(xi); + X3<float> xf; + h(xf); +} diff --git a/clang/test/SemaCXX/friend.cpp b/clang/test/SemaCXX/friend.cpp index ce2f34ff6b9..60eb03da34f 100644 --- a/clang/test/SemaCXX/friend.cpp +++ b/clang/test/SemaCXX/friend.cpp @@ -163,3 +163,15 @@ namespace test9 { friend void C::f(int, int, int) {} // expected-error {{no function named 'f' with type 'void (int, int, int)' was found in the specified scope}} }; } + +namespace test10 { + struct A { + friend void f10(); + }; + struct B { + friend void f10(); + }; + void g() { + f10(); // expected-error {{undeclared identifier}} + } +} |