diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 17 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 23 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 43 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 29 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 25 |
5 files changed, 78 insertions, 59 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 40b0ed3779..f607873a73 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -5518,15 +5518,8 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, // If this has an identifier and is not a function template specialization, // add it to the scope stack. - if (New->getDeclName() && AddToScope) { - // Only make a locally-scoped extern declaration visible if it is the first - // declaration of this entity. Qualified lookup for such an entity should - // only find this declaration if there is no visible declaration of it. - bool AddToContext = !D.isRedeclaration() || !New->isLocalExternDecl(); - PushOnScopeChains(New, S, AddToContext); - if (!AddToContext) - CurContext->addHiddenDecl(New); - } + if (New->getDeclName() && AddToScope) + PushOnScopeChains(New, S); if (isInOpenMPDeclareTargetContext()) checkDeclIsAllowedInOpenMPTarget(nullptr, New); @@ -7728,8 +7721,10 @@ static NamedDecl *DiagnoseInvalidRedeclaration( SmallVector<std::pair<FunctionDecl *, unsigned>, 1> NearMatches; TypoCorrection Correction; bool IsDefinition = ExtraArgs.D.isFunctionDefinition(); - unsigned DiagMsg = IsLocalFriend ? diag::err_no_matching_local_friend - : diag::err_member_decl_does_not_match; + unsigned DiagMsg = + IsLocalFriend ? diag::err_no_matching_local_friend : + NewFD->getFriendObjectKind() ? diag::err_qualified_friend_no_match : + diag::err_member_decl_does_not_match; LookupResult Prev(SemaRef, Name, NewFD->getLocation(), IsLocalFriend ? Sema::LookupLocalFriendName : Sema::LookupOrdinaryName, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 2b380bf0dc..50d01f309b 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -14414,25 +14414,6 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, LookupQualifiedName(Previous, DC); - // Ignore things found implicitly in the wrong scope. - // TODO: better diagnostics for this case. Suggesting the right - // qualified scope would be nice... - LookupResult::Filter F = Previous.makeFilter(); - while (F.hasNext()) { - NamedDecl *D = F.next(); - if (!DC->InEnclosingNamespaceSetOf( - D->getDeclContext()->getRedeclContext())) - F.erase(); - } - F.done(); - - if (Previous.empty()) { - D.setInvalidType(); - Diag(Loc, diag::err_qualified_friend_not_found) - << Name << TInfo->getType(); - return nullptr; - } - // C++ [class.friend]p1: A friend of a class is a function or // class that is not a member of the class . . . if (DC->Equals(CurContext)) @@ -14446,6 +14427,10 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, // A function can be defined in a friend declaration of a class if and // only if the class is a non-local class (9.8), the function name is // unqualified, and the function has namespace scope. + // + // FIXME: We should only do this if the scope specifier names the + // innermost enclosing namespace; otherwise the fixit changes the + // meaning of the code. SemaDiagnosticBuilder DB = Diag(SS.getRange().getBegin(), diag::err_qualified_friend_def); diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index a8a3651c5d..effccc2f3d 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -3337,38 +3337,29 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, !isa<FunctionTemplateDecl>(Underlying)) continue; - if (!isVisible(D)) { - D = findAcceptableDecl( - *this, D, (Decl::IDNS_Ordinary | Decl::IDNS_OrdinaryFriend)); - if (!D) - continue; - if (auto *USD = dyn_cast<UsingShadowDecl>(D)) - Underlying = USD->getTargetDecl(); - } - - // 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_Ordinary) == 0) { - // If it's neither ordinarily visible nor a friend, we can't find it. - if ((D->getIdentifierNamespace() & Decl::IDNS_OrdinaryFriend) == 0) - continue; - - bool DeclaredInAssociatedClass = false; - for (Decl *DI = D; DI; DI = DI->getPreviousDecl()) { - DeclContext *LexDC = DI->getLexicalDeclContext(); - if (isa<CXXRecordDecl>(LexDC) && - AssociatedClasses.count(cast<CXXRecordDecl>(LexDC)) && - isVisible(cast<NamedDecl>(DI))) { - DeclaredInAssociatedClass = true; + // The declaration is visible to argument-dependent lookup if either + // it's ordinarily visible or declared as a friend in an associated + // class. + bool Visible = false; + for (D = D->getMostRecentDecl(); D; + D = cast_or_null<NamedDecl>(D->getPreviousDecl())) { + if (D->getIdentifierNamespace() & Decl::IDNS_Ordinary) { + if (isVisible(D)) { + Visible = true; + break; + } + } else if (D->getFriendObjectKind()) { + auto *RD = cast<CXXRecordDecl>(D->getLexicalDeclContext()); + if (AssociatedClasses.count(RD) && isVisible(D)) { + Visible = true; break; } } - if (!DeclaredInAssociatedClass) - continue; } // FIXME: Preserve D as the FoundDecl. - Result.insert(Underlying); + if (Visible) + Result.insert(Underlying); } } } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 257eef435f..172116e30c 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1041,6 +1041,35 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old, } } + // C++ [temp.friend]p1: + // For a friend function declaration that is not a template declaration: + // -- if the name of the friend is a qualified or unqualified template-id, + // [...], otherwise + // -- if the name of the friend is a qualified-id and a matching + // non-template function is found in the specified class or namespace, + // the friend declaration refers to that function, otherwise, + // -- if the name of the friend is a qualified-id and a matching function + // template is found in the specified class or namespace, the friend + // declaration refers to the deduced specialization of that function + // template, otherwise + // -- the name shall be an unqualified-id [...] + // If we get here for a qualified friend declaration, we've just reached the + // third bullet. If the type of the friend is dependent, skip this lookup + // until instantiation. + if (New->getFriendObjectKind() && New->getQualifier() && + !New->getType()->isDependentType()) { + LookupResult TemplateSpecResult(LookupResult::Temporary, Old); + TemplateSpecResult.addAllDecls(Old); + if (CheckFunctionTemplateSpecialization(New, nullptr, TemplateSpecResult, + /*QualifiedFriend*/true)) { + New->setInvalidDecl(); + return Ovl_Overload; + } + + Match = TemplateSpecResult.getAsSingle<FunctionDecl>(); + return Ovl_Match; + } + return Ovl_Overload; } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 8485ecd3a3..35935f994c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -8104,9 +8104,13 @@ Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, /// /// \param Previous the set of declarations that may be specialized by /// this function specialization. +/// +/// \param QualifiedFriend whether this is a lookup for a qualified friend +/// declaration with no explicit template argument list that might be +/// befriending a function template specialization. bool Sema::CheckFunctionTemplateSpecialization( FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs, - LookupResult &Previous) { + LookupResult &Previous, bool QualifiedFriend) { // The set of function template specializations that could match this // explicit function template specialization. UnresolvedSet<8> Candidates; @@ -8193,10 +8197,25 @@ bool Sema::CheckFunctionTemplateSpecialization( } } + // For a qualified friend declaration (with no explicit marker to indicate + // that a template specialization was intended), note all (template and + // non-template) candidates. + if (QualifiedFriend && Candidates.empty()) { + Diag(FD->getLocation(), diag::err_qualified_friend_no_match) + << FD->getDeclName() << FDLookupContext; + // FIXME: We should form a single candidate list and diagnose all + // candidates at once, to get proper sorting and limiting. + for (auto *OldND : Previous) { + if (auto *OldFD = dyn_cast<FunctionDecl>(OldND->getUnderlyingDecl())) + NoteOverloadCandidate(OldND, OldFD, FD->getType(), false); + } + FailedCandidates.NoteCandidates(*this, FD->getLocation()); + return true; + } + // Find the most specialized function template. UnresolvedSetIterator Result = getMostSpecialized( - Candidates.begin(), Candidates.end(), FailedCandidates, - FD->getLocation(), + Candidates.begin(), Candidates.end(), FailedCandidates, FD->getLocation(), PDiag(diag::err_function_template_spec_no_match) << FD->getDeclName(), PDiag(diag::err_function_template_spec_ambiguous) << FD->getDeclName() << (ExplicitTemplateArgs != nullptr), |