Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -1500,9 +1500,6 @@ public: // Emit all deferred diagnostics. void emitDeferredDiags(); - // Emit any deferred diagnostics for FD and erase them from the map in which - // they're stored. - void emitDeferredDiags(FunctionDecl *FD, bool ShowCallStack); enum TUFragmentKind { /// The global module fragment, between 'module;' and a module-declaration. Index: clang/lib/Sema/Sema.cpp =================================================================== --- clang/lib/Sema/Sema.cpp +++ clang/lib/Sema/Sema.cpp @@ -1436,48 +1436,24 @@ } // Print notes showing how we can reach FD starting from an a priori -// known-callable function. -static void emitCallStackNotes(Sema &S, FunctionDecl *FD) { +// known-callable function. If \DiagsCount is not null pointer, the number +// of diagnostics emitted for a function is accumulated. +static void emitCallStackNotes(Sema &S, FunctionDecl *FD, + llvm::DenseMap, + unsigned> *DiagsCount = nullptr) { auto FnIt = S.DeviceKnownEmittedFns.find(FD); while (FnIt != S.DeviceKnownEmittedFns.end()) { DiagnosticBuilder Builder( S.Diags.Report(FnIt->second.Loc, diag::note_called_by)); Builder << FnIt->second.FD; Builder.setForceEmit(); + if (DiagsCount) + (*DiagsCount)[FnIt->second.FD]++; FnIt = S.DeviceKnownEmittedFns.find(FnIt->second.FD); } } -// Emit any deferred diagnostics for FD and erase them from the map in which -// they're stored. -void Sema::emitDeferredDiags(FunctionDecl *FD, bool ShowCallStack) { - auto It = DeviceDeferredDiags.find(FD); - if (It == DeviceDeferredDiags.end()) - return; - bool HasWarningOrError = false; - bool FirstDiag = true; - for (PartialDiagnosticAt &PDAt : It->second) { - const SourceLocation &Loc = PDAt.first; - const PartialDiagnostic &PD = PDAt.second; - HasWarningOrError |= getDiagnostics().getDiagnosticLevel( - PD.getDiagID(), Loc) >= DiagnosticsEngine::Warning; - { - DiagnosticBuilder Builder(Diags.Report(Loc, PD.getDiagID())); - Builder.setForceEmit(); - PD.Emit(Builder); - } - - // Emit the note on the first diagnostic in case too many diagnostics cause - // the note not emitted. - if (FirstDiag && HasWarningOrError && ShowCallStack) { - emitCallStackNotes(*this, FD); - FirstDiag = false; - } - } - -} - namespace { /// Helper class that emits deferred diagnostic messages if an entity directly /// or indirectly using the function that causes the deferred diagnostic @@ -1488,6 +1464,10 @@ typedef UsedDeclVisitor Inherited; llvm::SmallSet, 4> Visited; llvm::SmallVector, 4> UseStack; + + // Deferred diagnostics triggered by a declaration. + llvm::DenseMap, unsigned> DiagsCount; + bool ShouldEmit; unsigned InOMPDeviceContext; @@ -1509,6 +1489,8 @@ void visitUsedDecl(SourceLocation Loc, Decl *D) { if (auto *FD = dyn_cast(D)) { + + auto DiagsCountIt = DiagsCount.find(FD); FunctionDecl *Caller = UseStack.empty() ? nullptr : UseStack.back(); auto IsKnownEmitted = S.getEmissionStatus(FD, /*Final=*/true) == Sema::FunctionEmissionStatus::Emitted; @@ -1520,10 +1502,15 @@ // Finalize analysis of OpenMP-specific constructs. if (Caller && S.LangOpts.OpenMP && UseStack.size() == 1) S.finalizeOpenMPDelayedAnalysis(Caller, FD, Loc); + else if (DiagsCountIt != DiagsCount.end() && DiagsCountIt->second == 0 && + !InOMPDeviceContext) + return; + if (DiagsCountIt == DiagsCount.end()) + DiagsCount[FD] = 0; if (Caller) S.DeviceKnownEmittedFns[FD] = {Caller, Loc}; if (ShouldEmit || InOMPDeviceContext) - S.emitDeferredDiags(FD, Caller); + emitDeferredDiags(FD, Caller); Visited.insert(D); UseStack.push_back(FD); if (auto *S = FD->getBody()) { @@ -1551,6 +1538,35 @@ } else Inherited::visitUsedDecl(Loc, D); } + + // Emit any deferred diagnostics for FD + void emitDeferredDiags(FunctionDecl *FD, bool ShowCallStack) { + auto It = S.DeviceDeferredDiags.find(FD); + if (It == S.DeviceDeferredDiags.end()) + return; + bool HasWarningOrError = false; + bool FirstDiag = true; + for (PartialDiagnosticAt &PDAt : It->second) { + const SourceLocation &Loc = PDAt.first; + const PartialDiagnostic &PD = PDAt.second; + HasWarningOrError |= + S.getDiagnostics().getDiagnosticLevel(PD.getDiagID(), Loc) >= + DiagnosticsEngine::Warning; + { + DiagnosticBuilder Builder(S.Diags.Report(Loc, PD.getDiagID())); + Builder.setForceEmit(); + PD.Emit(Builder); + } + + DiagsCount[FD]++; + // Emit the note on the first diagnostic in case too many diagnostics + // cause the note not emitted. + if (FirstDiag && HasWarningOrError && ShowCallStack) { + emitCallStackNotes(S, FD, &DiagsCount); + FirstDiag = false; + } + } + } }; } // namespace