Skip to content

Commit da38e25

Browse files
authored
Merge pull request #26342 from xedin/rdar-53404683
[AST] DiagnosticEngine: retain strings used in tentative diagnostic arguments
2 parents 123f4b9 + b1e0980 commit da38e25

File tree

3 files changed

+42
-4
lines changed

3 files changed

+42
-4
lines changed

include/swift/AST/DiagnosticEngine.h

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include "swift/AST/TypeLoc.h"
2323
#include "swift/AST/DeclNameLoc.h"
2424
#include "swift/AST/DiagnosticConsumer.h"
25+
#include "llvm/ADT/StringMap.h"
26+
#include "llvm/Support/Allocator.h"
2527

2628
namespace swift {
2729
class Decl;
@@ -323,6 +325,8 @@ namespace swift {
323325
SourceLoc Loc;
324326
const Decl *Decl = nullptr;
325327

328+
friend DiagnosticEngine;
329+
326330
public:
327331
// All constructors are intentionally implicit.
328332
template<typename ...ArgTypes>
@@ -564,6 +568,12 @@ namespace swift {
564568
/// results that we can point to on the command line.
565569
llvm::DenseMap<const Decl *, SourceLoc> PrettyPrintedDeclarations;
566570

571+
llvm::BumpPtrAllocator TransactionAllocator;
572+
/// A set of all strings involved in current transactional chain.
573+
/// This is required because diagnostics are not directly emitted
574+
/// but rather stored until all transactions complete.
575+
llvm::StringMap<char, llvm::BumpPtrAllocator &> TransactionStrings;
576+
567577
/// The number of open diagnostic transactions. Diagnostics are only
568578
/// emitted once all transactions have closed.
569579
unsigned TransactionCount = 0;
@@ -579,8 +589,8 @@ namespace swift {
579589

580590
public:
581591
explicit DiagnosticEngine(SourceManager &SourceMgr)
582-
: SourceMgr(SourceMgr), ActiveDiagnostic() {
583-
}
592+
: SourceMgr(SourceMgr), ActiveDiagnostic(),
593+
TransactionStrings(TransactionAllocator) {}
584594

585595
/// hadAnyError - return true if any *error* diagnostics have been emitted.
586596
bool hadAnyError() const { return state.hadAnyError(); }
@@ -797,6 +807,11 @@ namespace swift {
797807
DiagnosticFormatOptions FormatOpts = DiagnosticFormatOptions());
798808

799809
private:
810+
/// Called when tentative diagnostic is about to be flushed,
811+
/// to apply any required transformations e.g. copy string arguments
812+
/// to extend their lifetime.
813+
void onTentativeDiagnosticFlush(Diagnostic &diagnostic);
814+
800815
/// Flush the active diagnostic.
801816
void flushActiveDiagnostic();
802817

@@ -856,6 +871,9 @@ namespace swift {
856871
bool IsOpen = true;
857872

858873
public:
874+
DiagnosticTransaction(const DiagnosticTransaction &) = delete;
875+
DiagnosticTransaction &operator=(const DiagnosticTransaction &) = delete;
876+
859877
explicit DiagnosticTransaction(DiagnosticEngine &engine)
860878
: Engine(engine),
861879
PrevDiagnostics(Engine.TentativeDiagnostics.size()),
@@ -870,6 +888,11 @@ namespace swift {
870888
if (IsOpen) {
871889
commit();
872890
}
891+
892+
if (Depth == 0) {
893+
Engine.TransactionStrings.clear();
894+
Engine.TransactionAllocator.Reset();
895+
}
873896
}
874897

875898
/// Abort and close this transaction and erase all diagnostics

lib/AST/DiagnosticEngine.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,7 @@ void DiagnosticEngine::flushActiveDiagnostic() {
754754
if (TransactionCount == 0) {
755755
emitDiagnostic(*ActiveDiagnostic);
756756
} else {
757+
onTentativeDiagnosticFlush(*ActiveDiagnostic);
757758
TentativeDiagnostics.emplace_back(std::move(*ActiveDiagnostic));
758759
}
759760
ActiveDiagnostic.reset();
@@ -940,3 +941,17 @@ BufferIndirectlyCausingDiagnosticRAII::BufferIndirectlyCausingDiagnosticRAII(
940941
if (loc.isValid())
941942
Diags.setBufferIndirectlyCausingDiagnosticToInput(loc);
942943
}
944+
945+
void DiagnosticEngine::onTentativeDiagnosticFlush(Diagnostic &diagnostic) {
946+
for (auto &argument : diagnostic.Args) {
947+
if (argument.getKind() != DiagnosticArgumentKind::String)
948+
continue;
949+
950+
auto content = argument.getAsString();
951+
if (content.empty())
952+
continue;
953+
954+
auto I = TransactionStrings.insert(std::make_pair(content, char())).first;
955+
argument = DiagnosticArgument(StringRef(I->getKeyData()));
956+
}
957+
}

lib/Sema/DerivedConformanceCodable.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,7 +1180,7 @@ ValueDecl *DerivedConformance::deriveEncodable(ValueDecl *requirement) {
11801180
// diagnostics, then potentially collect notes. If we succeed in
11811181
// synthesizing Encodable, we can cancel the transaction and get rid of the
11821182
// fake failures.
1183-
auto diagnosticTransaction = DiagnosticTransaction(TC.Context.Diags);
1183+
DiagnosticTransaction diagnosticTransaction(TC.Context.Diags);
11841184
TC.diagnose(ConformanceDecl, diag::type_does_not_conform,
11851185
Nominal->getDeclaredType(), getProtocolType());
11861186
TC.diagnose(requirement, diag::no_witnesses, diag::RequirementKind::Func,
@@ -1216,7 +1216,7 @@ ValueDecl *DerivedConformance::deriveDecodable(ValueDecl *requirement) {
12161216
// diagnostics produced by canSynthesize and deriveDecodable_init to produce
12171217
// them in the right order -- see the comment in deriveEncodable for
12181218
// background on this transaction.
1219-
auto diagnosticTransaction = DiagnosticTransaction(TC.Context.Diags);
1219+
DiagnosticTransaction diagnosticTransaction(TC.Context.Diags);
12201220
TC.diagnose(ConformanceDecl->getLoc(), diag::type_does_not_conform,
12211221
Nominal->getDeclaredType(), getProtocolType());
12221222
TC.diagnose(requirement, diag::no_witnesses,

0 commit comments

Comments
 (0)