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