@@ -279,6 +279,19 @@ namespace swift {
279279 }
280280 };
281281
282+ namespace detail {
283+ // / Stores information for an active diagnostic that hasn't been emitted yet.
284+ // / This includes both "in-flight" diagnostics as well as diagnostics queued
285+ // / for a transaction.
286+ struct ActiveDiagnostic {
287+ Diagnostic Diag;
288+ SmallVector<DiagnosticInfo, 2 > WrappedDiagnostics;
289+ SmallVector<std::vector<DiagnosticArgument>, 4 > WrappedDiagnosticArgs;
290+
291+ ActiveDiagnostic (Diagnostic diag) : Diag(std::move(diag)) {}
292+ };
293+ } // namespace detail
294+
282295 // / A diagnostic that has no input arguments, so it is trivially-destructable.
283296 using ZeroArgDiagnostic = Diag<>;
284297
@@ -293,33 +306,40 @@ namespace swift {
293306 friend class DiagnosticEngine ;
294307
295308 DiagnosticEngine *Engine;
309+ unsigned Idx;
296310 bool IsActive;
297311
298312 // / Create a new in-flight diagnostic.
299313 // /
300314 // / This constructor is only available to the DiagnosticEngine.
301- InFlightDiagnostic (DiagnosticEngine &Engine)
302- : Engine(&Engine), IsActive(true ) { }
303-
315+ InFlightDiagnostic (DiagnosticEngine &Engine, unsigned idx )
316+ : Engine(&Engine), Idx(idx), IsActive(true ) {}
317+
304318 InFlightDiagnostic (const InFlightDiagnostic &) = delete ;
305319 InFlightDiagnostic &operator =(const InFlightDiagnostic &) = delete ;
306320 InFlightDiagnostic &operator =(InFlightDiagnostic &&) = delete ;
307321
322+ // / Retrieve the underlying active diagnostic information.
323+ detail::ActiveDiagnostic &getActiveDiag () const ;
324+
325+ // / Retrieve the underlying diagnostic.
326+ Diagnostic &getDiag () const { return getActiveDiag ().Diag ; }
327+
308328 public:
309329 // / Create an active but unattached in-flight diagnostic.
310330 // /
311331 // / The resulting diagnostic can be used as a dummy, accepting the
312332 // / syntax to add additional information to a diagnostic without
313333 // / actually emitting a diagnostic.
314- InFlightDiagnostic () : Engine(0 ), IsActive(true ) { }
315-
334+ InFlightDiagnostic () : Engine(0 ), Idx( 0 ), IsActive(true ) {}
335+
316336 // / Transfer an in-flight diagnostic to a new object, which is
317337 // / typically used when returning in-flight diagnostics.
318338 InFlightDiagnostic (InFlightDiagnostic &&Other)
319- : Engine(Other.Engine), IsActive(Other.IsActive) {
339+ : Engine(Other.Engine), Idx(Other.Idx ), IsActive(Other.IsActive) {
320340 Other.IsActive = false ;
321341 }
322-
342+
323343 ~InFlightDiagnostic () {
324344 if (IsActive)
325345 flush ();
@@ -784,16 +804,12 @@ namespace swift {
784804 // / Tracks diagnostic behaviors and state
785805 DiagnosticState state;
786806
787- // / The currently active diagnostic, if there is one.
788- std::optional<Diagnostic> ActiveDiagnostic;
789-
790- // / Diagnostics wrapped by ActiveDiagnostic, if any.
791- SmallVector<DiagnosticInfo, 2 > WrappedDiagnostics;
792- SmallVector<std::vector<DiagnosticArgument>, 4 > WrappedDiagnosticArgs;
807+ // / The currently active diagnostics.
808+ SmallVector<detail::ActiveDiagnostic, 4 > ActiveDiagnostics;
793809
794810 // / All diagnostics that have are no longer active but have not yet
795811 // / been emitted due to an open transaction.
796- SmallVector<Diagnostic , 4 > TentativeDiagnostics;
812+ SmallVector<detail::ActiveDiagnostic , 4 > TentativeDiagnostics;
797813
798814 llvm::BumpPtrAllocator TransactionAllocator;
799815 // / A set of all strings involved in current transactional chain.
@@ -816,6 +832,9 @@ namespace swift {
816832 // / emitted once all transactions have closed.
817833 unsigned TransactionCount = 0 ;
818834
835+ // / The number of currently in-flight diagnostics.
836+ unsigned NumActiveDiags = 0 ;
837+
819838 // / For batch mode, use this to know where to output a diagnostic from a
820839 // / non-primary file. It's any location in the buffer of the current primary
821840 // / input being compiled.
@@ -851,7 +870,7 @@ namespace swift {
851870
852871 public:
853872 explicit DiagnosticEngine (SourceManager &SourceMgr)
854- : SourceMgr(SourceMgr), ActiveDiagnostic (),
873+ : SourceMgr(SourceMgr), ActiveDiagnostics (),
855874 TransactionStrings(TransactionAllocator),
856875 DiagnosticStringsSaver(DiagnosticStringsAllocator) {}
857876
@@ -870,6 +889,7 @@ namespace swift {
870889 }
871890
872891 void flushConsumers () {
892+ ASSERT (NumActiveDiags == 0 && " Expected in-flight diags to be flushed" );
873893 for (auto consumer : Consumers)
874894 consumer->flush ();
875895 }
@@ -1001,10 +1021,9 @@ namespace swift {
10011021 // / \returns An in-flight diagnostic, to which additional information can
10021022 // / be attached.
10031023 InFlightDiagnostic diagnose (SourceLoc Loc, const Diagnostic &D) {
1004- assert (!ActiveDiagnostic && " Already have an active diagnostic" );
1005- ActiveDiagnostic = D;
1006- ActiveDiagnostic->setLoc (Loc);
1007- return InFlightDiagnostic (*this );
1024+ auto IFD = beginDiagnostic (D);
1025+ getActiveDiagnostic (IFD).Diag .setLoc (Loc);
1026+ return IFD;
10081027 }
10091028
10101029 // / Emit a diagnostic with the given set of diagnostic arguments.
@@ -1080,10 +1099,9 @@ namespace swift {
10801099 // / \returns An in-flight diagnostic, to which additional information can
10811100 // / be attached.
10821101 InFlightDiagnostic diagnose (const Decl *decl, const Diagnostic &diag) {
1083- assert (!ActiveDiagnostic && " Already have an active diagnostic" );
1084- ActiveDiagnostic = diag;
1085- ActiveDiagnostic->setDecl (decl);
1086- return InFlightDiagnostic (*this );
1102+ auto IFD = beginDiagnostic (diag);
1103+ getActiveDiagnostic (IFD).Diag .setDecl (decl);
1104+ return IFD;
10871105 }
10881106
10891107 // / Emit a diagnostic with the given set of diagnostic arguments.
@@ -1137,16 +1155,21 @@ namespace swift {
11371155 DiagnosticFormatOptions FormatOpts = DiagnosticFormatOptions());
11381156
11391157 private:
1158+ // / Begins a new in-flight diagnostic.
1159+ InFlightDiagnostic beginDiagnostic (const Diagnostic &D);
1160+
1161+ // / Ends an in-flight diagnostic. Once all in-flight diagnostics have ended,
1162+ // / they will either be emitted, or captured by an open transaction.
1163+ void endDiagnostic (const InFlightDiagnostic &D);
1164+
11401165 // / Called when tentative diagnostic is about to be flushed,
11411166 // / to apply any required transformations e.g. copy string arguments
11421167 // / to extend their lifetime.
11431168 void onTentativeDiagnosticFlush (Diagnostic &diagnostic);
11441169
1145- // / Flush the active diagnostic.
1146- void flushActiveDiagnostic ();
1147-
1148- // / Retrieve the active diagnostic.
1149- Diagnostic &getActiveDiagnostic () { return *ActiveDiagnostic; }
1170+ // / Retrieve the stored active diagnostic for a given InFlightDiagnostic.
1171+ detail::ActiveDiagnostic &
1172+ getActiveDiagnostic (const InFlightDiagnostic &diag);
11501173
11511174 // / Generate DiagnosticInfo for a Diagnostic to be passed to consumers.
11521175 std::optional<DiagnosticInfo>
@@ -1162,7 +1185,7 @@ namespace swift {
11621185
11631186 // / Handle a new diagnostic, which will either be emitted, or added to an
11641187 // / active transaction.
1165- void handleDiagnostic (Diagnostic &&diag);
1188+ void handleDiagnostic (detail::ActiveDiagnostic &&diag);
11661189
11671190 // / Clear any tentative diagnostics.
11681191 void clearTentativeDiagnostics ();
@@ -1291,12 +1314,12 @@ namespace swift {
12911314 }
12921315
12931316 bool hasErrors () const {
1294- ArrayRef<Diagnostic > diagnostics (Engine. TentativeDiagnostics . begin () +
1295- PrevDiagnostics,
1296- Engine.TentativeDiagnostics .end ());
1317+ ArrayRef<detail::ActiveDiagnostic > diagnostics (
1318+ Engine. TentativeDiagnostics . begin () + PrevDiagnostics,
1319+ Engine.TentativeDiagnostics .end ());
12971320
12981321 for (auto &diagnostic : diagnostics) {
1299- auto behavior = Engine.state .determineBehavior (diagnostic);
1322+ auto behavior = Engine.state .determineBehavior (diagnostic. Diag );
13001323 if (behavior == DiagnosticBehavior::Fatal ||
13011324 behavior == DiagnosticBehavior::Error)
13021325 return true ;
@@ -1361,14 +1384,14 @@ namespace swift {
13611384
13621385 // The first diagnostic is assumed to be the parent. If this is not an
13631386 // error or warning, we'll assert later when trying to add children.
1364- Diagnostic &parent = Engine.TentativeDiagnostics [PrevDiagnostics];
1387+ Diagnostic &parent = Engine.TentativeDiagnostics [PrevDiagnostics]. Diag ;
13651388
13661389 // Associate the children with the parent.
13671390 for (auto diag =
13681391 Engine.TentativeDiagnostics .begin () + PrevDiagnostics + 1 ;
13691392 diag != Engine.TentativeDiagnostics .end (); ++diag) {
1370- diag->setIsChildNote (true );
1371- parent.addChildNote (std::move (* diag));
1393+ diag->Diag . setIsChildNote (true );
1394+ parent.addChildNote (std::move (diag-> Diag ));
13721395 }
13731396
13741397 // Erase the children, they'll be emitted alongside their parent.
0 commit comments