Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp (revision 204559) +++ lib/Sema/Sema.cpp (working copy) @@ -361,11 +361,26 @@ return CK_Invalid; } + +typedef llvm::DenseMap RecordCompleteMap; + +static bool IsRecordFullyDefined(const CXXRecordDecl *RD, + RecordCompleteMap &RecordsComplete, + RecordCompleteMap &MNCComplete); + /// \brief Used to prune the decls of Sema's UnusedFileScopedDecls vector. static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { if (D->getMostRecentDecl()->isUsed()) return true; + if (const CXXMethodDecl *MD = dyn_cast(D)) { + RecordCompleteMap RecordsComplete; + RecordCompleteMap MNCComplete; + if (MD->getAccess() == AS_private && + IsRecordFullyDefined(MD->getParent(), RecordsComplete, MNCComplete)) + return false; + } + if (D->isExternallyVisible()) return true; @@ -500,8 +515,6 @@ } -typedef llvm::DenseMap RecordCompleteMap; - /// \brief Returns true, if all methods and nested classes of the given /// CXXRecordDecl are defined in this translation unit. /// @@ -750,14 +763,28 @@ // If there were errors, disable 'unused' warnings since they will mostly be // noise. if (!Diags.hasErrorOccurred()) { + llvm::SmallSet SeenDecls; + // Output warning for unused file scoped decls. for (UnusedFileScopedDeclsType::iterator I = UnusedFileScopedDecls.begin(ExternalSource), E = UnusedFileScopedDecls.end(); I != E; ++I) { - if (ShouldRemoveFromUnused(this, *I)) + if (ShouldRemoveFromUnused(this, *I) || !SeenDecls.insert(*I)) continue; if (const FunctionDecl *FD = dyn_cast(*I)) { + const FunctionDecl *First = FD->getFirstDecl(); + if (FD != First && !SeenDecls.insert(First)) + continue; + } + + if (const VarDecl *VD = dyn_cast(*I)) { + const VarDecl *First = VD->getFirstDecl(); + if (VD != First && !SeenDecls.insert(First)) + continue; + } + + if (const FunctionDecl *FD = dyn_cast(*I)) { const FunctionDecl *DiagD; if (!FD->hasBody(DiagD)) DiagD = FD; Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp (revision 204559) +++ lib/Sema/SemaDecl.cpp (working copy) @@ -1216,6 +1216,9 @@ if (const CXXMethodDecl *MD = dyn_cast(FD)) { if (MD->isVirtual() || IsDisallowedCopyOrAssign(MD)) return false; + + if (MD->getAccess() == AS_private) + return true; } else { // 'static inline' functions are defined in headers; don't warn. if (FD->isInlineSpecified() && @@ -1248,22 +1251,7 @@ } void Sema::MarkUnusedFileScopedDecl(const DeclaratorDecl *D) { - if (!D) - return; - - if (const FunctionDecl *FD = dyn_cast(D)) { - const FunctionDecl *First = FD->getFirstDecl(); - if (FD != First && ShouldWarnIfUnusedFileScopedDecl(First)) - return; // First should already be in the vector. - } - - if (const VarDecl *VD = dyn_cast(D)) { - const VarDecl *First = VD->getFirstDecl(); - if (VD != First && ShouldWarnIfUnusedFileScopedDecl(First)) - return; // First should already be in the vector. - } - - if (ShouldWarnIfUnusedFileScopedDecl(D)) + if (D && ShouldWarnIfUnusedFileScopedDecl(D)) UnusedFileScopedDecls.push_back(D); }