@@ -1440,59 +1440,72 @@ Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) {
1440
1440
static void emitCallStackNotes (Sema &S, FunctionDecl *FD) {
1441
1441
auto FnIt = S.DeviceKnownEmittedFns .find (FD);
1442
1442
while (FnIt != S.DeviceKnownEmittedFns .end ()) {
1443
+ // Respect error limit.
1444
+ if (S.Diags .hasFatalErrorOccurred ())
1445
+ return ;
1443
1446
DiagnosticBuilder Builder (
1444
1447
S.Diags .Report (FnIt->second .Loc , diag::note_called_by));
1445
1448
Builder << FnIt->second .FD ;
1446
- Builder.setForceEmit ();
1447
-
1448
1449
FnIt = S.DeviceKnownEmittedFns .find (FnIt->second .FD );
1449
1450
}
1450
1451
}
1451
1452
1452
- // Emit any deferred diagnostics for FD and erase them from the map in which
1453
- // they're stored.
1454
- void Sema::emitDeferredDiags (FunctionDecl *FD, bool ShowCallStack) {
1455
- auto It = DeviceDeferredDiags.find (FD);
1456
- if (It == DeviceDeferredDiags.end ())
1457
- return ;
1458
- bool HasWarningOrError = false ;
1459
- bool FirstDiag = true ;
1460
- for (PartialDiagnosticAt &PDAt : It->second ) {
1461
- const SourceLocation &Loc = PDAt.first ;
1462
- const PartialDiagnostic &PD = PDAt.second ;
1463
- HasWarningOrError |= getDiagnostics ().getDiagnosticLevel (
1464
- PD.getDiagID (), Loc) >= DiagnosticsEngine::Warning;
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
- }
1477
- }
1478
-
1479
- }
1480
-
1481
1453
namespace {
1454
+
1482
1455
// / Helper class that emits deferred diagnostic messages if an entity directly
1483
1456
// / or indirectly using the function that causes the deferred diagnostic
1484
1457
// / messages is known to be emitted.
1458
+ // /
1459
+ // / During parsing of AST, certain diagnostic messages are recorded as deferred
1460
+ // / diagnostics since it is unknown whether the functions containing such
1461
+ // / diagnostics will be emitted. A list of potentially emitted functions and
1462
+ // / variables that may potentially trigger emission of functions are also
1463
+ // / recorded. DeferredDiagnosticsEmitter recursively visits used functions
1464
+ // / by each function to emit deferred diagnostics.
1465
+ // /
1466
+ // / During the visit, certain OpenMP directives or initializer of variables
1467
+ // / with certain OpenMP attributes will cause subsequent visiting of any
1468
+ // / functions enter a state which is called OpenMP device context in this
1469
+ // / implementation. The state is exited when the directive or initializer is
1470
+ // / exited. This state can change the emission states of subsequent uses
1471
+ // / of functions.
1472
+ // /
1473
+ // / Conceptually the functions or variables to be visited form a use graph
1474
+ // / where the parent node uses the child node. At any point of the visit,
1475
+ // / the tree nodes traversed from the tree root to the current node form a use
1476
+ // / stack. The emission state of the current node depends on two factors:
1477
+ // / 1. the emission state of the root node
1478
+ // / 2. whether the current node is in OpenMP device context
1479
+ // / If the function is decided to be emitted, its contained deferred diagnostics
1480
+ // / are emitted, together with the information about the use stack.
1481
+ // /
1485
1482
class DeferredDiagnosticsEmitter
1486
1483
: public UsedDeclVisitor<DeferredDiagnosticsEmitter> {
1487
1484
public:
1488
1485
typedef UsedDeclVisitor<DeferredDiagnosticsEmitter> Inherited;
1489
- llvm::SmallSet<CanonicalDeclPtr<Decl>, 4 > Visited;
1490
- llvm::SmallVector<CanonicalDeclPtr<FunctionDecl>, 4 > UseStack;
1491
- bool ShouldEmit;
1486
+
1487
+ // Whether the function is already in the current use-path.
1488
+ llvm::SmallSet<CanonicalDeclPtr<Decl>, 4 > InUsePath;
1489
+
1490
+ // The current use-path.
1491
+ llvm::SmallVector<CanonicalDeclPtr<FunctionDecl>, 4 > UsePath;
1492
+
1493
+ // Whether the visiting of the function has been done. Done[0] is for the
1494
+ // case not in OpenMP device context. Done[1] is for the case in OpenMP
1495
+ // device context. We need two sets because diagnostics emission may be
1496
+ // different depending on whether it is in OpenMP device context.
1497
+ llvm::SmallSet<CanonicalDeclPtr<Decl>, 4 > DoneMap[2 ];
1498
+
1499
+ // Emission state of the root node of the current use graph.
1500
+ bool ShouldEmitRootNode;
1501
+
1502
+ // Current OpenMP device context level. It is initialized to 0 and each
1503
+ // entering of device context increases it by 1 and each exit decreases
1504
+ // it by 1. Non-zero value indicates it is currently in device context.
1492
1505
unsigned InOMPDeviceContext;
1493
1506
1494
1507
DeferredDiagnosticsEmitter (Sema &S)
1495
- : Inherited(S), ShouldEmit (false ), InOMPDeviceContext(0 ) {}
1508
+ : Inherited(S), ShouldEmitRootNode (false ), InOMPDeviceContext(0 ) {}
1496
1509
1497
1510
void VisitOMPTargetDirective (OMPTargetDirective *Node) {
1498
1511
++InOMPDeviceContext;
@@ -1525,36 +1538,72 @@ class DeferredDiagnosticsEmitter
1525
1538
}
1526
1539
1527
1540
void checkFunc (SourceLocation Loc, FunctionDecl *FD) {
1528
- FunctionDecl *Caller = UseStack.empty () ? nullptr : UseStack.back ();
1529
- auto IsKnownEmitted = S.getEmissionStatus (FD, /* Final=*/ true ) ==
1530
- Sema::FunctionEmissionStatus::Emitted;
1531
- if (!Caller)
1532
- ShouldEmit = IsKnownEmitted;
1533
- if ((!ShouldEmit && !S.getLangOpts ().OpenMP && !Caller) ||
1534
- S.shouldIgnoreInHostDeviceCheck (FD) || Visited.count (FD))
1541
+ auto &Done = DoneMap[InOMPDeviceContext];
1542
+ FunctionDecl *Caller = UsePath.empty () ? nullptr : UsePath.back ();
1543
+ if ((!ShouldEmitRootNode && !S.getLangOpts ().OpenMP && !Caller) ||
1544
+ S.shouldIgnoreInHostDeviceCheck (FD) || InUsePath.count (FD))
1535
1545
return ;
1536
1546
// Finalize analysis of OpenMP-specific constructs.
1537
- if (Caller && S.LangOpts .OpenMP && UseStack .size () == 1 )
1547
+ if (Caller && S.LangOpts .OpenMP && UsePath .size () == 1 )
1538
1548
S.finalizeOpenMPDelayedAnalysis (Caller, FD, Loc);
1539
1549
if (Caller)
1540
1550
S.DeviceKnownEmittedFns [FD] = {Caller, Loc};
1541
- if (ShouldEmit || InOMPDeviceContext)
1542
- S.emitDeferredDiags (FD, Caller);
1543
- Visited.insert (FD);
1544
- UseStack.push_back (FD);
1551
+ // Always emit deferred diagnostics for the direct users. This does not
1552
+ // lead to explosion of diagnostics since each user is visited at most
1553
+ // twice.
1554
+ if (ShouldEmitRootNode || InOMPDeviceContext)
1555
+ emitDeferredDiags (FD, Caller);
1556
+ // Do not revisit a function if the function body has been completely
1557
+ // visited before.
1558
+ if (Done.count (FD))
1559
+ return ;
1560
+ InUsePath.insert (FD);
1561
+ UsePath.push_back (FD);
1545
1562
if (auto *S = FD->getBody ()) {
1546
1563
this ->Visit (S);
1547
1564
}
1548
- UseStack.pop_back ();
1549
- Visited.erase (FD);
1565
+ UsePath.pop_back ();
1566
+ InUsePath.erase (FD);
1567
+ Done.insert (FD);
1550
1568
}
1551
1569
1552
1570
void checkRecordedDecl (Decl *D) {
1553
- if (auto *FD = dyn_cast<FunctionDecl>(D))
1571
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
1572
+ ShouldEmitRootNode = S.getEmissionStatus (FD, /* Final=*/ true ) ==
1573
+ Sema::FunctionEmissionStatus::Emitted;
1554
1574
checkFunc (SourceLocation (), FD);
1555
- else
1575
+ } else
1556
1576
checkVar (cast<VarDecl>(D));
1557
1577
}
1578
+
1579
+ // Emit any deferred diagnostics for FD
1580
+ void emitDeferredDiags (FunctionDecl *FD, bool ShowCallStack) {
1581
+ auto It = S.DeviceDeferredDiags .find (FD);
1582
+ if (It == S.DeviceDeferredDiags .end ())
1583
+ return ;
1584
+ bool HasWarningOrError = false ;
1585
+ bool FirstDiag = true ;
1586
+ for (PartialDiagnosticAt &PDAt : It->second ) {
1587
+ // Respect error limit.
1588
+ if (S.Diags .hasFatalErrorOccurred ())
1589
+ return ;
1590
+ const SourceLocation &Loc = PDAt.first ;
1591
+ const PartialDiagnostic &PD = PDAt.second ;
1592
+ HasWarningOrError |=
1593
+ S.getDiagnostics ().getDiagnosticLevel (PD.getDiagID (), Loc) >=
1594
+ DiagnosticsEngine::Warning;
1595
+ {
1596
+ DiagnosticBuilder Builder (S.Diags .Report (Loc, PD.getDiagID ()));
1597
+ PD.Emit (Builder);
1598
+ }
1599
+ // Emit the note on the first diagnostic in case too many diagnostics
1600
+ // cause the note not emitted.
1601
+ if (FirstDiag && HasWarningOrError && ShowCallStack) {
1602
+ emitCallStackNotes (S, FD);
1603
+ FirstDiag = false ;
1604
+ }
1605
+ }
1606
+ }
1558
1607
};
1559
1608
} // namespace
1560
1609
0 commit comments