|
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