diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index e90f454db3016bf806eb4cab84ededab3fd58586..2b2bf1a1efc13411eb193ae44b81d40006cec689 100644 --- a/include/clang/AST/Decl.h +++ b/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/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 4f289d315adb9f12064cfca21e944a03dd28b314..157506d2a607e3b6683ebe928e2f760fff4919f8 100644 --- a/include/clang/AST/DeclBase.h +++ b/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/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 5e535da19a1464e01a4f68ee42bd4bad90a62983..fd4ddcf55e657ec10d822f9a9b2144f6575ee429 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/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/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 8d954ca994cd918d886ac2648a6aa16c6a57c69c..0667b8adc04ba1e3149d13e3cd663f10c9ba1d6c 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/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/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index e6006b6bf973d87ba1214d739b154fede2bdfcf3..6f1ab19f10e061d2a61cf36973cad960b2c2d4a2 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/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/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index b5a80d3f6a064d821b59ff0d9283330adb2abe84..14185c37ad177074ba3049564e51333c9055599f 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/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/test/CXX/temp/temp.decls/temp.friend/p4.cpp b/test/CXX/temp/temp.decls/temp.friend/p4.cpp index e036cef32b283e5a712ea3d374ecf9148077f2a2..8571a141201bdb2d4b13c1ddc33db4033f4d8bc4 100644 --- a/test/CXX/temp/temp.decls/temp.friend/p4.cpp +++ b/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/test/SemaCXX/friend.cpp b/test/SemaCXX/friend.cpp index ce2f34ff6b983f481c8c76b1d124d1d54e11d2c2..60eb03da34fa37fa91b0b164735815e3a878b0e7 100644 --- a/test/SemaCXX/friend.cpp +++ b/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}} + } +}