|
11 | 11 | //
|
12 | 12 | //===----------------------------------------------------------------------===//
|
13 | 13 |
|
| 14 | +#include "UsedDeclVisitor.h" |
14 | 15 | #include "clang/AST/ASTContext.h"
|
15 | 16 | #include "clang/AST/ASTDiagnostic.h"
|
16 | 17 | #include "clang/AST/DeclCXX.h"
|
@@ -955,9 +956,7 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) {
|
955 | 956 | PerformPendingInstantiations();
|
956 | 957 | }
|
957 | 958 |
|
958 |
| - // Finalize analysis of OpenMP-specific constructs. |
959 |
| - if (LangOpts.OpenMP) |
960 |
| - finalizeOpenMPDelayedAnalysis(); |
| 959 | + emitDeferredDiags(); |
961 | 960 |
|
962 | 961 | assert(LateParsedInstantiations.empty() &&
|
963 | 962 | "end of TU template instantiation should not create more "
|
@@ -1452,27 +1451,108 @@ static void emitCallStackNotes(Sema &S, FunctionDecl *FD) {
|
1452 | 1451 |
|
1453 | 1452 | // Emit any deferred diagnostics for FD and erase them from the map in which
|
1454 | 1453 | // they're stored.
|
1455 |
| -static void emitDeferredDiags(Sema &S, FunctionDecl *FD, bool ShowCallStack) { |
1456 |
| - auto It = S.DeviceDeferredDiags.find(FD); |
1457 |
| - if (It == S.DeviceDeferredDiags.end()) |
| 1454 | +void Sema::emitDeferredDiags(FunctionDecl *FD, bool ShowCallStack) { |
| 1455 | + auto It = DeviceDeferredDiags.find(FD); |
| 1456 | + if (It == DeviceDeferredDiags.end()) |
1458 | 1457 | return;
|
1459 | 1458 | bool HasWarningOrError = false;
|
| 1459 | + bool FirstDiag = true; |
1460 | 1460 | for (PartialDiagnosticAt &PDAt : It->second) {
|
1461 | 1461 | const SourceLocation &Loc = PDAt.first;
|
1462 | 1462 | const PartialDiagnostic &PD = PDAt.second;
|
1463 |
| - HasWarningOrError |= S.getDiagnostics().getDiagnosticLevel( |
| 1463 | + HasWarningOrError |= getDiagnostics().getDiagnosticLevel( |
1464 | 1464 | PD.getDiagID(), Loc) >= DiagnosticsEngine::Warning;
|
1465 |
| - DiagnosticBuilder Builder(S.Diags.Report(Loc, PD.getDiagID())); |
1466 |
| - Builder.setForceEmit(); |
1467 |
| - PD.Emit(Builder); |
| 1465 | + { |
| 1466 | + DiagnosticBuilder Builder(Diags.Report(Loc, PD.getDiagID())); |
| 1467 | + Builder.setForceEmit(); |
| 1468 | + PD.Emit(Builder); |
| 1469 | + } |
| 1470 | + |
| 1471 | + // Emit the note on the first diagnostic in case too many diagnostics cause |
| 1472 | + // the note not emitted. |
| 1473 | + if (FirstDiag && HasWarningOrError && ShowCallStack) { |
| 1474 | + emitCallStackNotes(*this, FD); |
| 1475 | + FirstDiag = false; |
| 1476 | + } |
1468 | 1477 | }
|
1469 |
| - S.DeviceDeferredDiags.erase(It); |
1470 | 1478 |
|
1471 |
| - // FIXME: Should this be called after every warning/error emitted in the loop |
1472 |
| - // above, instead of just once per function? That would be consistent with |
1473 |
| - // how we handle immediate errors, but it also seems like a bit much. |
1474 |
| - if (HasWarningOrError && ShowCallStack) |
1475 |
| - emitCallStackNotes(S, FD); |
| 1479 | +} |
| 1480 | + |
| 1481 | +namespace { |
| 1482 | +/// Helper class that emits deferred diagnostic messages if an entity directly |
| 1483 | +/// or indirectly using the function that causes the deferred diagnostic |
| 1484 | +/// messages is known to be emitted. |
| 1485 | +class DeferredDiagnosticsEmitter |
| 1486 | + : public UsedDeclVisitor<DeferredDiagnosticsEmitter> { |
| 1487 | +public: |
| 1488 | + typedef UsedDeclVisitor<DeferredDiagnosticsEmitter> Inherited; |
| 1489 | + llvm::SmallSet<CanonicalDeclPtr<Decl>, 4> Visited; |
| 1490 | + llvm::SmallVector<CanonicalDeclPtr<FunctionDecl>, 4> UseStack; |
| 1491 | + bool ShouldEmit; |
| 1492 | + unsigned InOMPDeviceContext; |
| 1493 | + |
| 1494 | + DeferredDiagnosticsEmitter(Sema &S) |
| 1495 | + : Inherited(S), ShouldEmit(false), InOMPDeviceContext(0) {} |
| 1496 | + |
| 1497 | + void VisitOMPTargetDirective(OMPTargetDirective *Node) { |
| 1498 | + ++InOMPDeviceContext; |
| 1499 | + Inherited::VisitOMPTargetDirective(Node); |
| 1500 | + --InOMPDeviceContext; |
| 1501 | + } |
| 1502 | + |
| 1503 | + void visitUsedDecl(SourceLocation Loc, Decl *D) { |
| 1504 | + if (auto *FD = dyn_cast<FunctionDecl>(D)) { |
| 1505 | + FunctionDecl *Caller = UseStack.empty() ? nullptr : UseStack.back(); |
| 1506 | + auto IsKnownEmitted = S.getEmissionStatus(FD, /*Final=*/true) == |
| 1507 | + Sema::FunctionEmissionStatus::Emitted; |
| 1508 | + if (!Caller) |
| 1509 | + ShouldEmit = IsKnownEmitted; |
| 1510 | + if ((!ShouldEmit && !S.getLangOpts().OpenMP && !Caller) || |
| 1511 | + S.shouldIgnoreInHostDeviceCheck(FD) || Visited.count(D)) |
| 1512 | + return; |
| 1513 | + // Finalize analysis of OpenMP-specific constructs. |
| 1514 | + if (Caller && S.LangOpts.OpenMP && UseStack.size() == 1) |
| 1515 | + S.finalizeOpenMPDelayedAnalysis(Caller, FD, Loc); |
| 1516 | + if (Caller) |
| 1517 | + S.DeviceKnownEmittedFns[FD] = {Caller, Loc}; |
| 1518 | + if (ShouldEmit || InOMPDeviceContext) |
| 1519 | + S.emitDeferredDiags(FD, Caller); |
| 1520 | + Visited.insert(D); |
| 1521 | + UseStack.push_back(FD); |
| 1522 | + if (auto *S = FD->getBody()) { |
| 1523 | + this->Visit(S); |
| 1524 | + } |
| 1525 | + UseStack.pop_back(); |
| 1526 | + Visited.erase(D); |
| 1527 | + } else if (auto *VD = dyn_cast<VarDecl>(D)) { |
| 1528 | + if (auto *Init = VD->getInit()) { |
| 1529 | + auto DevTy = OMPDeclareTargetDeclAttr::getDeviceType(VD); |
| 1530 | + bool IsDev = DevTy && (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost || |
| 1531 | + *DevTy == OMPDeclareTargetDeclAttr::DT_Any); |
| 1532 | + if (IsDev) |
| 1533 | + ++InOMPDeviceContext; |
| 1534 | + this->Visit(Init); |
| 1535 | + if (IsDev) |
| 1536 | + --InOMPDeviceContext; |
| 1537 | + } |
| 1538 | + } else |
| 1539 | + Inherited::visitUsedDecl(Loc, D); |
| 1540 | + } |
| 1541 | +}; |
| 1542 | +} // namespace |
| 1543 | + |
| 1544 | +void Sema::emitDeferredDiags() { |
| 1545 | + if (ExternalSource) |
| 1546 | + ExternalSource->ReadDeclsToCheckForDeferredDiags( |
| 1547 | + DeclsToCheckForDeferredDiags); |
| 1548 | + |
| 1549 | + if ((DeviceDeferredDiags.empty() && !LangOpts.OpenMP) || |
| 1550 | + DeclsToCheckForDeferredDiags.empty()) |
| 1551 | + return; |
| 1552 | + |
| 1553 | + DeferredDiagnosticsEmitter DDE(*this); |
| 1554 | + for (auto D : DeclsToCheckForDeferredDiags) |
| 1555 | + DDE.visitUsedDecl(SourceLocation(), D); |
1476 | 1556 | }
|
1477 | 1557 |
|
1478 | 1558 | // In CUDA, there are some constructs which may appear in semantically-valid
|
@@ -1545,71 +1625,6 @@ Sema::DeviceDiagBuilder::~DeviceDiagBuilder() {
|
1545 | 1625 | }
|
1546 | 1626 | }
|
1547 | 1627 |
|
1548 |
| -// Indicate that this function (and thus everything it transtively calls) will |
1549 |
| -// be codegen'ed, and emit any deferred diagnostics on this function and its |
1550 |
| -// (transitive) callees. |
1551 |
| -void Sema::markKnownEmitted( |
1552 |
| - Sema &S, FunctionDecl *OrigCaller, FunctionDecl *OrigCallee, |
1553 |
| - SourceLocation OrigLoc, |
1554 |
| - const llvm::function_ref<bool(Sema &, FunctionDecl *)> IsKnownEmitted) { |
1555 |
| - // Nothing to do if we already know that FD is emitted. |
1556 |
| - if (IsKnownEmitted(S, OrigCallee)) { |
1557 |
| - assert(!S.DeviceCallGraph.count(OrigCallee)); |
1558 |
| - return; |
1559 |
| - } |
1560 |
| - |
1561 |
| - // We've just discovered that OrigCallee is known-emitted. Walk our call |
1562 |
| - // graph to see what else we can now discover also must be emitted. |
1563 |
| - |
1564 |
| - struct CallInfo { |
1565 |
| - FunctionDecl *Caller; |
1566 |
| - FunctionDecl *Callee; |
1567 |
| - SourceLocation Loc; |
1568 |
| - }; |
1569 |
| - llvm::SmallVector<CallInfo, 4> Worklist = {{OrigCaller, OrigCallee, OrigLoc}}; |
1570 |
| - llvm::SmallSet<CanonicalDeclPtr<FunctionDecl>, 4> Seen; |
1571 |
| - Seen.insert(OrigCallee); |
1572 |
| - while (!Worklist.empty()) { |
1573 |
| - CallInfo C = Worklist.pop_back_val(); |
1574 |
| - assert(!IsKnownEmitted(S, C.Callee) && |
1575 |
| - "Worklist should not contain known-emitted functions."); |
1576 |
| - S.DeviceKnownEmittedFns[C.Callee] = {C.Caller, C.Loc}; |
1577 |
| - emitDeferredDiags(S, C.Callee, C.Caller); |
1578 |
| - |
1579 |
| - // If this is a template instantiation, explore its callgraph as well: |
1580 |
| - // Non-dependent calls are part of the template's callgraph, while dependent |
1581 |
| - // calls are part of to the instantiation's call graph. |
1582 |
| - if (auto *Templ = C.Callee->getPrimaryTemplate()) { |
1583 |
| - FunctionDecl *TemplFD = Templ->getAsFunction(); |
1584 |
| - if (!Seen.count(TemplFD) && !S.DeviceKnownEmittedFns.count(TemplFD)) { |
1585 |
| - Seen.insert(TemplFD); |
1586 |
| - Worklist.push_back( |
1587 |
| - {/* Caller = */ C.Caller, /* Callee = */ TemplFD, C.Loc}); |
1588 |
| - } |
1589 |
| - } |
1590 |
| - |
1591 |
| - // Add all functions called by Callee to our worklist. |
1592 |
| - auto CGIt = S.DeviceCallGraph.find(C.Callee); |
1593 |
| - if (CGIt == S.DeviceCallGraph.end()) |
1594 |
| - continue; |
1595 |
| - |
1596 |
| - for (std::pair<CanonicalDeclPtr<FunctionDecl>, SourceLocation> FDLoc : |
1597 |
| - CGIt->second) { |
1598 |
| - FunctionDecl *NewCallee = FDLoc.first; |
1599 |
| - SourceLocation CallLoc = FDLoc.second; |
1600 |
| - if (Seen.count(NewCallee) || IsKnownEmitted(S, NewCallee)) |
1601 |
| - continue; |
1602 |
| - Seen.insert(NewCallee); |
1603 |
| - Worklist.push_back( |
1604 |
| - {/* Caller = */ C.Callee, /* Callee = */ NewCallee, CallLoc}); |
1605 |
| - } |
1606 |
| - |
1607 |
| - // C.Callee is now known-emitted, so we no longer need to maintain its list |
1608 |
| - // of callees in DeviceCallGraph. |
1609 |
| - S.DeviceCallGraph.erase(CGIt); |
1610 |
| - } |
1611 |
| -} |
1612 |
| - |
1613 | 1628 | Sema::DeviceDiagBuilder Sema::targetDiag(SourceLocation Loc, unsigned DiagID) {
|
1614 | 1629 | if (LangOpts.OpenMP)
|
1615 | 1630 | return LangOpts.OpenMPIsDevice ? diagIfOpenMPDeviceCode(Loc, DiagID)
|
|
0 commit comments