[clang] 7e561b6 - [NFC] Refactor DiagnosticBuilder and PartialDiagnostic

Yaxun Liu via cfe-commits cfe-commits at lists.llvm.org
Mon Oct 19 14:48:44 PDT 2020


Author: Yaxun (Sam) Liu
Date: 2020-10-19T17:48:04-04:00
New Revision: 7e561b62d2f2140fcacfcdf78c42f01181fe0df5

URL: https://github.com/llvm/llvm-project/commit/7e561b62d2f2140fcacfcdf78c42f01181fe0df5
DIFF: https://github.com/llvm/llvm-project/commit/7e561b62d2f2140fcacfcdf78c42f01181fe0df5.diff

LOG: [NFC] Refactor DiagnosticBuilder and PartialDiagnostic

PartialDiagnostic misses some functions compared to DiagnosticBuilder.

This patch refactors DiagnosticBuilder and PartialDiagnostic, extracts
the common functionality so that the streaming << operators are
shared.

Differential Revision: https://reviews.llvm.org/D84362

Added: 
    

Modified: 
    clang/include/clang/AST/ASTContext.h
    clang/include/clang/AST/Attr.h
    clang/include/clang/AST/CanonicalType.h
    clang/include/clang/AST/Decl.h
    clang/include/clang/AST/DeclCXX.h
    clang/include/clang/AST/DeclarationName.h
    clang/include/clang/AST/DependentDiagnostic.h
    clang/include/clang/AST/NestedNameSpecifier.h
    clang/include/clang/AST/TemplateBase.h
    clang/include/clang/AST/TemplateName.h
    clang/include/clang/AST/Type.h
    clang/include/clang/Basic/Diagnostic.h
    clang/include/clang/Basic/PartialDiagnostic.h
    clang/include/clang/Sema/DelayedDiagnostic.h
    clang/include/clang/Sema/Ownership.h
    clang/include/clang/Sema/ParsedAttr.h
    clang/include/clang/Sema/Sema.h
    clang/include/clang/Tooling/Refactoring/RefactoringRuleContext.h
    clang/lib/AST/ASTContext.cpp
    clang/lib/AST/DeclBase.cpp
    clang/lib/AST/DeclCXX.cpp
    clang/lib/AST/TemplateBase.cpp
    clang/lib/AST/TemplateName.cpp
    clang/lib/Basic/Diagnostic.cpp
    clang/unittests/Basic/DiagnosticTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 3f4079e2569b..60c4c1ce788e 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -573,7 +573,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
   mutable llvm::BumpPtrAllocator BumpAlloc;
 
   /// Allocator for partial diagnostics.
-  PartialDiagnostic::StorageAllocator DiagAllocator;
+  PartialDiagnostic::DiagStorageAllocator DiagAllocator;
 
   /// The current C++ ABI.
   std::unique_ptr<CXXABI> ABI;
@@ -652,7 +652,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
   /// Return the total memory used for various side tables.
   size_t getSideTableAllocatedMemory() const;
 
-  PartialDiagnostic::StorageAllocator &getDiagAllocator() {
+  PartialDiagnostic::DiagStorageAllocator &getDiagAllocator() {
     return DiagAllocator;
   }
 
@@ -3096,8 +3096,8 @@ OPT_LIST(V)
 };
 
 /// Insertion operator for diagnostics.
-const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                    const ASTContext::SectionInfo &Section);
+const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                      const ASTContext::SectionInfo &Section);
 
 /// Utility function for constructing a nullary selector.
 inline Selector GetNullarySelector(StringRef name, ASTContext &Ctx) {

diff  --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h
index b3729b2e0d99..545dc992c5ed 100644
--- a/clang/include/clang/AST/Attr.h
+++ b/clang/include/clang/AST/Attr.h
@@ -350,19 +350,12 @@ struct ParsedTargetAttr {
 
 #include "clang/AST/Attrs.inc"
 
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           const Attr *At) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                             const Attr *At) {
   DB.AddTaggedVal(reinterpret_cast<intptr_t>(At),
                   DiagnosticsEngine::ak_attr);
   return DB;
 }
-
-inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
-                                           const Attr *At) {
-  PD.AddTaggedVal(reinterpret_cast<intptr_t>(At),
-                  DiagnosticsEngine::ak_attr);
-  return PD;
-}
 }  // end namespace clang
 
 #endif

diff  --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h
index 488284713bce..15d7e9efc26a 100644
--- a/clang/include/clang/AST/CanonicalType.h
+++ b/clang/include/clang/AST/CanonicalType.h
@@ -215,8 +215,8 @@ inline CanQualType Type::getCanonicalTypeUnqualified() const {
   return CanQualType::CreateUnsafe(getCanonicalTypeInternal());
 }
 
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           CanQualType T) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                             CanQualType T) {
   DB << static_cast<QualType>(T);
   return DB;
 }

diff  --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index c2511514fe72..eae09832160d 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -4513,14 +4513,8 @@ class EmptyDecl : public Decl {
 
 /// Insertion operator for diagnostics.  This allows sending NamedDecl's
 /// into a diagnostic with <<.
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           const NamedDecl* ND) {
-  DB.AddTaggedVal(reinterpret_cast<intptr_t>(ND),
-                  DiagnosticsEngine::ak_nameddecl);
-  return DB;
-}
-inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
-                                           const NamedDecl* ND) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD,
+                                             const NamedDecl *ND) {
   PD.AddTaggedVal(reinterpret_cast<intptr_t>(ND),
                   DiagnosticsEngine::ak_nameddecl);
   return PD;

diff  --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index da5ae0fa999d..fc0632f07b51 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -4075,11 +4075,8 @@ class MSGuidDecl : public ValueDecl,
 
 /// Insertion operator for diagnostics.  This allows sending an AccessSpecifier
 /// into a diagnostic with <<.
-const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                    AccessSpecifier AS);
-
-const PartialDiagnostic &operator<<(const PartialDiagnostic &DB,
-                                    AccessSpecifier AS);
+const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                      AccessSpecifier AS);
 
 } // namespace clang
 

diff  --git a/clang/include/clang/AST/DeclarationName.h b/clang/include/clang/AST/DeclarationName.h
index a037e8b197bc..3cb0a02ff49b 100644
--- a/clang/include/clang/AST/DeclarationName.h
+++ b/clang/include/clang/AST/DeclarationName.h
@@ -811,19 +811,10 @@ struct DeclarationNameInfo {
   SourceLocation getEndLocPrivate() const;
 };
 
-/// Insertion operator for diagnostics.  This allows sending DeclarationName's
-/// into a diagnostic with <<.
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           DeclarationName N) {
-  DB.AddTaggedVal(N.getAsOpaqueInteger(),
-                  DiagnosticsEngine::ak_declarationname);
-  return DB;
-}
-
 /// Insertion operator for partial diagnostics.  This allows binding
 /// DeclarationName's into a partial diagnostic with <<.
-inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
-                                           DeclarationName N) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD,
+                                             DeclarationName N) {
   PD.AddTaggedVal(N.getAsOpaqueInteger(),
                   DiagnosticsEngine::ak_declarationname);
   return PD;

diff  --git a/clang/include/clang/AST/DependentDiagnostic.h b/clang/include/clang/AST/DependentDiagnostic.h
index 0a98dec0c25e..5a8624608e74 100644
--- a/clang/include/clang/AST/DependentDiagnostic.h
+++ b/clang/include/clang/AST/DependentDiagnostic.h
@@ -100,8 +100,8 @@ class DependentDiagnostic {
   friend class DependentStoredDeclsMap;
 
   DependentDiagnostic(const PartialDiagnostic &PDiag,
-                      PartialDiagnostic::Storage *Storage)
-    : Diag(PDiag, Storage) {}
+                      DiagnosticStorage *Storage)
+      : Diag(PDiag, Storage) {}
 
   static DependentDiagnostic *Create(ASTContext &Context,
                                      DeclContext *Parent,

diff  --git a/clang/include/clang/AST/NestedNameSpecifier.h b/clang/include/clang/AST/NestedNameSpecifier.h
index b11cb5f6b86d..8bc3e25c0f4b 100644
--- a/clang/include/clang/AST/NestedNameSpecifier.h
+++ b/clang/include/clang/AST/NestedNameSpecifier.h
@@ -519,8 +519,8 @@ class NestedNameSpecifierLocBuilder {
 
 /// Insertion operator for diagnostics.  This allows sending
 /// NestedNameSpecifiers into a diagnostic with <<.
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           NestedNameSpecifier *NNS) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                             NestedNameSpecifier *NNS) {
   DB.AddTaggedVal(reinterpret_cast<intptr_t>(NNS),
                   DiagnosticsEngine::ak_nestednamespec);
   return DB;

diff  --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h
index c158cde3580e..7967f8a91214 100644
--- a/clang/include/clang/AST/TemplateBase.h
+++ b/clang/include/clang/AST/TemplateBase.h
@@ -687,8 +687,8 @@ struct alignas(void *) ASTTemplateKWAndArgsInfo {
                 TemplateArgumentListInfo &List) const;
 };
 
-const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                    const TemplateArgument &Arg);
+const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                      const TemplateArgument &Arg);
 
 inline TemplateSpecializationType::iterator
     TemplateSpecializationType::end() const {

diff  --git a/clang/include/clang/AST/TemplateName.h b/clang/include/clang/AST/TemplateName.h
index 9bcf2838dcf1..010b813dc525 100644
--- a/clang/include/clang/AST/TemplateName.h
+++ b/clang/include/clang/AST/TemplateName.h
@@ -342,10 +342,8 @@ class TemplateName {
 
 /// Insertion operator for diagnostics.  This allows sending TemplateName's
 /// into a diagnostic with <<.
-const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                    TemplateName N);
-const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
-                                    TemplateName N);
+const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                      TemplateName N);
 
 /// A structure for storing the information associated with a
 /// substituted template template parameter.

diff  --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index d16edf8a6b12..5ccd07504e1c 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -7071,55 +7071,28 @@ inline const Type *Type::getPointeeOrArrayElementType() const {
     return type->getBaseElementTypeUnsafe();
   return type;
 }
-/// Insertion operator for diagnostics. This allows sending address spaces into
-/// a diagnostic with <<.
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           LangAS AS) {
-  DB.AddTaggedVal(static_cast<std::underlying_type_t<LangAS>>(AS),
-                  DiagnosticsEngine::ArgumentKind::ak_addrspace);
-  return DB;
-}
-
 /// Insertion operator for partial diagnostics. This allows sending adress
 /// spaces into a diagnostic with <<.
-inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
-                                           LangAS AS) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD,
+                                             LangAS AS) {
   PD.AddTaggedVal(static_cast<std::underlying_type_t<LangAS>>(AS),
                   DiagnosticsEngine::ArgumentKind::ak_addrspace);
   return PD;
 }
 
-/// Insertion operator for diagnostics. This allows sending Qualifiers into a
-/// diagnostic with <<.
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           Qualifiers Q) {
-  DB.AddTaggedVal(Q.getAsOpaqueValue(),
-                  DiagnosticsEngine::ArgumentKind::ak_qual);
-  return DB;
-}
-
 /// Insertion operator for partial diagnostics. This allows sending Qualifiers
 /// into a diagnostic with <<.
-inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
-                                           Qualifiers Q) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD,
+                                             Qualifiers Q) {
   PD.AddTaggedVal(Q.getAsOpaqueValue(),
                   DiagnosticsEngine::ArgumentKind::ak_qual);
   return PD;
 }
 
-/// Insertion operator for diagnostics.  This allows sending QualType's into a
-/// diagnostic with <<.
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           QualType T) {
-  DB.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()),
-                  DiagnosticsEngine::ak_qualtype);
-  return DB;
-}
-
 /// Insertion operator for partial diagnostics.  This allows sending QualType's
 /// into a diagnostic with <<.
-inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
-                                           QualType T) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD,
+                                             QualType T) {
   PD.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()),
                   DiagnosticsEngine::ak_qualtype);
   return PD;

diff  --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h
index 304207779c0f..f17b98f74038 100644
--- a/clang/include/clang/Basic/Diagnostic.h
+++ b/clang/include/clang/Basic/Diagnostic.h
@@ -144,6 +144,44 @@ class FixItHint {
   }
 };
 
+struct DiagnosticStorage {
+  enum {
+    /// The maximum number of arguments we can hold. We
+    /// currently only support up to 10 arguments (%0-%9).
+    ///
+    /// A single diagnostic with more than that almost certainly has to
+    /// be simplified anyway.
+    MaxArguments = 10
+  };
+
+  /// The number of entries in Arguments.
+  unsigned char NumDiagArgs = 0;
+
+  /// Specifies for each argument whether it is in DiagArgumentsStr
+  /// or in DiagArguments.
+  unsigned char DiagArgumentsKind[MaxArguments];
+
+  /// The values for the various substitution positions.
+  ///
+  /// This is used when the argument is not an std::string. The specific value
+  /// is mangled into an intptr_t and the interpretation depends on exactly
+  /// what sort of argument kind it is.
+  intptr_t DiagArgumentsVal[MaxArguments];
+
+  /// The values for the various substitution positions that have
+  /// string arguments.
+  std::string DiagArgumentsStr[MaxArguments];
+
+  /// The list of ranges added to this diagnostic.
+  SmallVector<CharSourceRange, 8> DiagRanges;
+
+  /// If valid, provides a hint with some code to insert, remove, or
+  /// modify at a particular position.
+  SmallVector<FixItHint, 6> FixItHints;
+
+  DiagnosticStorage() = default;
+};
+
 /// Concrete class used by the front-end to report problems and issues.
 ///
 /// This massages the diagnostics (e.g. handling things like "report warnings
@@ -928,38 +966,10 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> {
     /// We currently only support up to 10 arguments (%0-%9).  A single
     /// diagnostic with more than that almost certainly has to be simplified
     /// anyway.
-    MaxArguments = 10,
+    MaxArguments = DiagnosticStorage::MaxArguments,
   };
 
-  /// The number of entries in Arguments.
-  signed char NumDiagArgs;
-
-  /// Specifies whether an argument is in DiagArgumentsStr or
-  /// in DiagArguments.
-  ///
-  /// This is an array of ArgumentKind::ArgumentKind enum values, one for each
-  /// argument.
-  unsigned char DiagArgumentsKind[MaxArguments];
-
-  /// Holds the values of each string argument for the current
-  /// diagnostic.
-  ///
-  /// This is only used when the corresponding ArgumentKind is ak_std_string.
-  std::string DiagArgumentsStr[MaxArguments];
-
-  /// The values for the various substitution positions.
-  ///
-  /// This is used when the argument is not an std::string.  The specific
-  /// value is mangled into an intptr_t and the interpretation depends on
-  /// exactly what sort of argument kind it is.
-  intptr_t DiagArgumentsVal[MaxArguments];
-
-  /// The list of ranges added to this diagnostic.
-  SmallVector<CharSourceRange, 8> DiagRanges;
-
-  /// If valid, provides a hint with some code to insert, remove,
-  /// or modify at a particular position.
-  SmallVector<FixItHint, 8> DiagFixItHints;
+  DiagnosticStorage DiagStorage;
 
   DiagnosticMapping makeUserMapping(diag::Severity Map, SourceLocation L) {
     bool isPragma = L.isValid();
@@ -1043,6 +1053,156 @@ class DiagnosticErrorTrap {
   }
 };
 
+/// The streaming interface shared between DiagnosticBuilder and
+/// PartialDiagnostic. This class is not intended to be constructed directly
+/// but only as base class of DiagnosticBuilder and PartialDiagnostic builder.
+///
+/// Any new type of argument accepted by DiagnosticBuilder and PartialDiagnostic
+/// should be implemented as a '<<' operator of StreamingDiagnostic, e.g.
+///
+/// const StreamingDiagnostic&
+/// operator<<(const StreamingDiagnostic&, NewArgType);
+///
+class StreamingDiagnostic {
+public:
+  /// An allocator for DiagnosticStorage objects, which uses a small cache to
+  /// objects, used to reduce malloc()/free() traffic for partial diagnostics.
+  class DiagStorageAllocator {
+    static const unsigned NumCached = 16;
+    DiagnosticStorage Cached[NumCached];
+    DiagnosticStorage *FreeList[NumCached];
+    unsigned NumFreeListEntries;
+
+  public:
+    DiagStorageAllocator();
+    ~DiagStorageAllocator();
+
+    /// Allocate new storage.
+    DiagnosticStorage *Allocate() {
+      if (NumFreeListEntries == 0)
+        return new DiagnosticStorage;
+
+      DiagnosticStorage *Result = FreeList[--NumFreeListEntries];
+      Result->NumDiagArgs = 0;
+      Result->DiagRanges.clear();
+      Result->FixItHints.clear();
+      return Result;
+    }
+
+    /// Free the given storage object.
+    void Deallocate(DiagnosticStorage *S) {
+      if (S >= Cached && S <= Cached + NumCached) {
+        FreeList[NumFreeListEntries++] = S;
+        return;
+      }
+
+      delete S;
+    }
+  };
+
+protected:
+  mutable DiagnosticStorage *DiagStorage = nullptr;
+
+  /// Allocator used to allocate storage for this diagnostic.
+  DiagStorageAllocator *Allocator = nullptr;
+
+public:
+  /// Retrieve storage for this particular diagnostic.
+  DiagnosticStorage *getStorage() const {
+    if (DiagStorage)
+      return DiagStorage;
+
+    assert(Allocator);
+    DiagStorage = Allocator->Allocate();
+    return DiagStorage;
+  }
+
+  void freeStorage() {
+    if (!DiagStorage)
+      return;
+
+    // The hot path for PartialDiagnostic is when we just used it to wrap an ID
+    // (typically so we have the flexibility of passing a more complex
+    // diagnostic into the callee, but that does not commonly occur).
+    //
+    // Split this out into a slow function for silly compilers (*cough*) which
+    // can't do decent partial inlining.
+    freeStorageSlow();
+  }
+
+  void freeStorageSlow() {
+    if (!Allocator)
+      return;
+    Allocator->Deallocate(DiagStorage);
+    DiagStorage = nullptr;
+  }
+
+  void AddTaggedVal(intptr_t V, DiagnosticsEngine::ArgumentKind Kind) const {
+    if (!DiagStorage)
+      DiagStorage = getStorage();
+
+    assert(DiagStorage->NumDiagArgs < DiagnosticStorage::MaxArguments &&
+           "Too many arguments to diagnostic!");
+    DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind;
+    DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V;
+  }
+
+  void AddString(StringRef V) const {
+    if (!DiagStorage)
+      DiagStorage = getStorage();
+
+    assert(DiagStorage->NumDiagArgs < DiagnosticStorage::MaxArguments &&
+           "Too many arguments to diagnostic!");
+    DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] =
+        DiagnosticsEngine::ak_std_string;
+    DiagStorage->DiagArgumentsStr[DiagStorage->NumDiagArgs++] = std::string(V);
+  }
+
+  void AddSourceRange(const CharSourceRange &R) const {
+    if (!DiagStorage)
+      DiagStorage = getStorage();
+
+    DiagStorage->DiagRanges.push_back(R);
+  }
+
+  void AddFixItHint(const FixItHint &Hint) const {
+    if (Hint.isNull())
+      return;
+
+    if (!DiagStorage)
+      DiagStorage = getStorage();
+
+    DiagStorage->FixItHints.push_back(Hint);
+  }
+
+  /// Conversion of StreamingDiagnostic to bool always returns \c true.
+  ///
+  /// This allows is to be used in boolean error contexts (where \c true is
+  /// used to indicate that an error has occurred), like:
+  /// \code
+  /// return Diag(...);
+  /// \endcode
+  operator bool() const { return true; }
+
+protected:
+  StreamingDiagnostic() = default;
+
+  /// Construct with an external storage not owned by itself. The allocator
+  /// is a null pointer in this case.
+  explicit StreamingDiagnostic(DiagnosticStorage *Storage)
+      : DiagStorage(Storage) {}
+
+  /// Construct with a storage allocator which will manage the storage. The
+  /// allocator is not a null pointer in this case.
+  explicit StreamingDiagnostic(DiagStorageAllocator &Alloc)
+      : Allocator(&Alloc) {}
+
+  StreamingDiagnostic(const StreamingDiagnostic &Diag) = default;
+  StreamingDiagnostic(StreamingDiagnostic &&Diag) = default;
+
+  ~StreamingDiagnostic() { freeStorage(); }
+};
+
 //===----------------------------------------------------------------------===//
 // DiagnosticBuilder
 //===----------------------------------------------------------------------===//
@@ -1059,12 +1219,11 @@ class DiagnosticErrorTrap {
 /// This ensures that compilers with somewhat reasonable optimizers will promote
 /// the common fields to registers, eliminating increments of the NumArgs field,
 /// for example.
-class DiagnosticBuilder {
+class DiagnosticBuilder : public StreamingDiagnostic {
   friend class DiagnosticsEngine;
   friend class PartialDiagnostic;
 
   mutable DiagnosticsEngine *DiagObj = nullptr;
-  mutable unsigned NumArgs = 0;
 
   /// Status variable indicating if this diagnostic is still active.
   ///
@@ -1080,17 +1239,17 @@ class DiagnosticBuilder {
   DiagnosticBuilder() = default;
 
   explicit DiagnosticBuilder(DiagnosticsEngine *diagObj)
-      : DiagObj(diagObj), IsActive(true) {
+      : StreamingDiagnostic(&diagObj->DiagStorage), DiagObj(diagObj),
+        IsActive(true) {
     assert(diagObj && "DiagnosticBuilder requires a valid DiagnosticsEngine!");
-    diagObj->DiagRanges.clear();
-    diagObj->DiagFixItHints.clear();
+    assert(DiagStorage &&
+           "DiagnosticBuilder requires a valid DiagnosticStorage!");
+    DiagStorage->NumDiagArgs = 0;
+    DiagStorage->DiagRanges.clear();
+    DiagStorage->FixItHints.clear();
   }
 
 protected:
-  void FlushCounts() {
-    DiagObj->NumDiagArgs = NumArgs;
-  }
-
   /// Clear out the current diagnostic.
   void Clear() const {
     DiagObj = nullptr;
@@ -1113,10 +1272,6 @@ class DiagnosticBuilder {
     // (or by a subclass, as in SemaDiagnosticBuilder).
     if (!isActive()) return false;
 
-    // When emitting diagnostics, we set the final argument count into
-    // the DiagnosticsEngine object.
-    FlushCounts();
-
     // Process the diagnostic.
     bool Result = DiagObj->EmitCurrentDiagnostic(IsForceEmit);
 
@@ -1131,59 +1286,40 @@ class DiagnosticBuilder {
   /// input and neuters it.
   DiagnosticBuilder(const DiagnosticBuilder &D) {
     DiagObj = D.DiagObj;
+    DiagStorage = D.DiagStorage;
     IsActive = D.IsActive;
     IsForceEmit = D.IsForceEmit;
     D.Clear();
-    NumArgs = D.NumArgs;
   }
 
-  DiagnosticBuilder &operator=(const DiagnosticBuilder &) = delete;
-
-  /// Emits the diagnostic.
-  ~DiagnosticBuilder() {
-    Emit();
-  }
-
-  /// Forces the diagnostic to be emitted.
-  const DiagnosticBuilder &setForceEmit() const {
-    IsForceEmit = true;
+  template <typename T> const DiagnosticBuilder &operator<<(const T &V) const {
+    assert(isActive() && "Clients must not add to cleared diagnostic!");
+    const StreamingDiagnostic &DB = *this;
+    DB << V;
     return *this;
   }
 
-  /// Conversion of DiagnosticBuilder to bool always returns \c true.
-  ///
-  /// This allows is to be used in boolean error contexts (where \c true is
-  /// used to indicate that an error has occurred), like:
-  /// \code
-  /// return Diag(...);
-  /// \endcode
-  operator bool() const { return true; }
-
-  void AddString(StringRef S) const {
+  // It is necessary to limit this to rvalue reference to avoid calling this
+  // function with a bitfield lvalue argument since non-const reference to
+  // bitfield is not allowed.
+  template <typename T, typename = typename std::enable_if<
+                            !std::is_lvalue_reference<T>::value>::type>
+  const DiagnosticBuilder &operator<<(T &&V) const {
     assert(isActive() && "Clients must not add to cleared diagnostic!");
-    assert(NumArgs < DiagnosticsEngine::MaxArguments &&
-           "Too many arguments to diagnostic!");
-    DiagObj->DiagArgumentsKind[NumArgs] = DiagnosticsEngine::ak_std_string;
-    DiagObj->DiagArgumentsStr[NumArgs++] = std::string(S);
+    const StreamingDiagnostic &DB = *this;
+    DB << std::move(V);
+    return *this;
   }
 
-  void AddTaggedVal(intptr_t V, DiagnosticsEngine::ArgumentKind Kind) const {
-    assert(isActive() && "Clients must not add to cleared diagnostic!");
-    assert(NumArgs < DiagnosticsEngine::MaxArguments &&
-           "Too many arguments to diagnostic!");
-    DiagObj->DiagArgumentsKind[NumArgs] = Kind;
-    DiagObj->DiagArgumentsVal[NumArgs++] = V;
-  }
+  DiagnosticBuilder &operator=(const DiagnosticBuilder &) = delete;
 
-  void AddSourceRange(const CharSourceRange &R) const {
-    assert(isActive() && "Clients must not add to cleared diagnostic!");
-    DiagObj->DiagRanges.push_back(R);
-  }
+  /// Emits the diagnostic.
+  ~DiagnosticBuilder() { Emit(); }
 
-  void AddFixItHint(const FixItHint &Hint) const {
-    assert(isActive() && "Clients must not add to cleared diagnostic!");
-    if (!Hint.isNull())
-      DiagObj->DiagFixItHints.push_back(Hint);
+  /// Forces the diagnostic to be emitted.
+  const DiagnosticBuilder &setForceEmit() const {
+    IsForceEmit = true;
+    return *this;
   }
 
   void addFlagValue(StringRef V) const { DiagObj->FlagValue = std::string(V); }
@@ -1205,20 +1341,21 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
   return DB;
 }
 
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           StringRef S) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                             StringRef S) {
   DB.AddString(S);
   return DB;
 }
 
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           const char *Str) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                             const char *Str) {
   DB.AddTaggedVal(reinterpret_cast<intptr_t>(Str),
                   DiagnosticsEngine::ak_c_string);
   return DB;
 }
 
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, int I) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                             int I) {
   DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint);
   return DB;
 }
@@ -1226,26 +1363,27 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, int I) {
 // We use enable_if here to prevent that this overload is selected for
 // pointers or other arguments that are implicitly convertible to bool.
 template <typename T>
-inline std::enable_if_t<std::is_same<T, bool>::value, const DiagnosticBuilder &>
-operator<<(const DiagnosticBuilder &DB, T I) {
+inline std::enable_if_t<std::is_same<T, bool>::value,
+                        const StreamingDiagnostic &>
+operator<<(const StreamingDiagnostic &DB, T I) {
   DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint);
   return DB;
 }
 
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           unsigned I) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                             unsigned I) {
   DB.AddTaggedVal(I, DiagnosticsEngine::ak_uint);
   return DB;
 }
 
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           tok::TokenKind I) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                             tok::TokenKind I) {
   DB.AddTaggedVal(static_cast<unsigned>(I), DiagnosticsEngine::ak_tokenkind);
   return DB;
 }
 
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           const IdentifierInfo *II) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                             const IdentifierInfo *II) {
   DB.AddTaggedVal(reinterpret_cast<intptr_t>(II),
                   DiagnosticsEngine::ak_identifierinfo);
   return DB;
@@ -1258,63 +1396,64 @@ inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
 template <typename T>
 inline std::enable_if_t<
     std::is_same<std::remove_const_t<T>, DeclContext>::value,
-    const DiagnosticBuilder &>
-operator<<(const DiagnosticBuilder &DB, T *DC) {
+    const StreamingDiagnostic &>
+operator<<(const StreamingDiagnostic &DB, T *DC) {
   DB.AddTaggedVal(reinterpret_cast<intptr_t>(DC),
                   DiagnosticsEngine::ak_declcontext);
   return DB;
 }
 
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           SourceRange R) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                             SourceRange R) {
   DB.AddSourceRange(CharSourceRange::getTokenRange(R));
   return DB;
 }
 
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           ArrayRef<SourceRange> Ranges) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                             ArrayRef<SourceRange> Ranges) {
   for (SourceRange R : Ranges)
     DB.AddSourceRange(CharSourceRange::getTokenRange(R));
   return DB;
 }
 
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           const CharSourceRange &R) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                             const CharSourceRange &R) {
   DB.AddSourceRange(R);
   return DB;
 }
 
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           const FixItHint &Hint) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                             const FixItHint &Hint) {
   DB.AddFixItHint(Hint);
   return DB;
 }
 
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           ArrayRef<FixItHint> Hints) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                             ArrayRef<FixItHint> Hints) {
   for (const FixItHint &Hint : Hints)
     DB.AddFixItHint(Hint);
   return DB;
 }
 
-inline const DiagnosticBuilder &
-operator<<(const DiagnosticBuilder &DB,
+inline const StreamingDiagnostic &
+operator<<(const StreamingDiagnostic &DB,
            const llvm::Optional<SourceRange> &Opt) {
   if (Opt)
     DB << *Opt;
   return DB;
 }
 
-inline const DiagnosticBuilder &
-operator<<(const DiagnosticBuilder &DB,
+inline const StreamingDiagnostic &
+operator<<(const StreamingDiagnostic &DB,
            const llvm::Optional<CharSourceRange> &Opt) {
   if (Opt)
     DB << *Opt;
   return DB;
 }
 
-inline const DiagnosticBuilder &
-operator<<(const DiagnosticBuilder &DB, const llvm::Optional<FixItHint> &Opt) {
+inline const StreamingDiagnostic &
+operator<<(const StreamingDiagnostic &DB,
+           const llvm::Optional<FixItHint> &Opt) {
   if (Opt)
     DB << *Opt;
   return DB;
@@ -1324,8 +1463,8 @@ operator<<(const DiagnosticBuilder &DB, const llvm::Optional<FixItHint> &Opt) {
 /// context-sensitive keyword.
 using DiagNullabilityKind = std::pair<NullabilityKind, bool>;
 
-const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                    DiagNullabilityKind nullability);
+const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                      DiagNullabilityKind nullability);
 
 inline DiagnosticBuilder DiagnosticsEngine::Report(SourceLocation Loc,
                                                    unsigned DiagID) {
@@ -1337,8 +1476,8 @@ inline DiagnosticBuilder DiagnosticsEngine::Report(SourceLocation Loc,
   return DiagnosticBuilder(this);
 }
 
-const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                    llvm::Error &&E);
+const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                      llvm::Error &&E);
 
 inline DiagnosticBuilder DiagnosticsEngine::Report(unsigned DiagID) {
   return Report(SourceLocation(), DiagID);
@@ -1366,7 +1505,7 @@ class Diagnostic {
   bool hasSourceManager() const { return DiagObj->hasSourceManager(); }
   SourceManager &getSourceManager() const { return DiagObj->getSourceManager();}
 
-  unsigned getNumArgs() const { return DiagObj->NumDiagArgs; }
+  unsigned getNumArgs() const { return DiagObj->DiagStorage.NumDiagArgs; }
 
   /// Return the kind of the specified index.
   ///
@@ -1376,7 +1515,8 @@ class Diagnostic {
   /// \pre Idx < getNumArgs()
   DiagnosticsEngine::ArgumentKind getArgKind(unsigned Idx) const {
     assert(Idx < getNumArgs() && "Argument index out of range!");
-    return (DiagnosticsEngine::ArgumentKind)DiagObj->DiagArgumentsKind[Idx];
+    return (DiagnosticsEngine::ArgumentKind)
+        DiagObj->DiagStorage.DiagArgumentsKind[Idx];
   }
 
   /// Return the provided argument string specified by \p Idx.
@@ -1384,7 +1524,7 @@ class Diagnostic {
   const std::string &getArgStdStr(unsigned Idx) const {
     assert(getArgKind(Idx) == DiagnosticsEngine::ak_std_string &&
            "invalid argument accessor!");
-    return DiagObj->DiagArgumentsStr[Idx];
+    return DiagObj->DiagStorage.DiagArgumentsStr[Idx];
   }
 
   /// Return the specified C string argument.
@@ -1392,7 +1532,8 @@ class Diagnostic {
   const char *getArgCStr(unsigned Idx) const {
     assert(getArgKind(Idx) == DiagnosticsEngine::ak_c_string &&
            "invalid argument accessor!");
-    return reinterpret_cast<const char*>(DiagObj->DiagArgumentsVal[Idx]);
+    return reinterpret_cast<const char *>(
+        DiagObj->DiagStorage.DiagArgumentsVal[Idx]);
   }
 
   /// Return the specified signed integer argument.
@@ -1400,7 +1541,7 @@ class Diagnostic {
   int getArgSInt(unsigned Idx) const {
     assert(getArgKind(Idx) == DiagnosticsEngine::ak_sint &&
            "invalid argument accessor!");
-    return (int)DiagObj->DiagArgumentsVal[Idx];
+    return (int)DiagObj->DiagStorage.DiagArgumentsVal[Idx];
   }
 
   /// Return the specified unsigned integer argument.
@@ -1408,7 +1549,7 @@ class Diagnostic {
   unsigned getArgUInt(unsigned Idx) const {
     assert(getArgKind(Idx) == DiagnosticsEngine::ak_uint &&
            "invalid argument accessor!");
-    return (unsigned)DiagObj->DiagArgumentsVal[Idx];
+    return (unsigned)DiagObj->DiagStorage.DiagArgumentsVal[Idx];
   }
 
   /// Return the specified IdentifierInfo argument.
@@ -1416,7 +1557,8 @@ class Diagnostic {
   const IdentifierInfo *getArgIdentifier(unsigned Idx) const {
     assert(getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo &&
            "invalid argument accessor!");
-    return reinterpret_cast<IdentifierInfo*>(DiagObj->DiagArgumentsVal[Idx]);
+    return reinterpret_cast<IdentifierInfo *>(
+        DiagObj->DiagStorage.DiagArgumentsVal[Idx]);
   }
 
   /// Return the specified non-string argument in an opaque form.
@@ -1424,36 +1566,36 @@ class Diagnostic {
   intptr_t getRawArg(unsigned Idx) const {
     assert(getArgKind(Idx) != DiagnosticsEngine::ak_std_string &&
            "invalid argument accessor!");
-    return DiagObj->DiagArgumentsVal[Idx];
+    return DiagObj->DiagStorage.DiagArgumentsVal[Idx];
   }
 
   /// Return the number of source ranges associated with this diagnostic.
   unsigned getNumRanges() const {
-    return DiagObj->DiagRanges.size();
+    return DiagObj->DiagStorage.DiagRanges.size();
   }
 
   /// \pre Idx < getNumRanges()
   const CharSourceRange &getRange(unsigned Idx) const {
     assert(Idx < getNumRanges() && "Invalid diagnostic range index!");
-    return DiagObj->DiagRanges[Idx];
+    return DiagObj->DiagStorage.DiagRanges[Idx];
   }
 
   /// Return an array reference for this diagnostic's ranges.
   ArrayRef<CharSourceRange> getRanges() const {
-    return DiagObj->DiagRanges;
+    return DiagObj->DiagStorage.DiagRanges;
   }
 
   unsigned getNumFixItHints() const {
-    return DiagObj->DiagFixItHints.size();
+    return DiagObj->DiagStorage.FixItHints.size();
   }
 
   const FixItHint &getFixItHint(unsigned Idx) const {
     assert(Idx < getNumFixItHints() && "Invalid index!");
-    return DiagObj->DiagFixItHints[Idx];
+    return DiagObj->DiagStorage.FixItHints[Idx];
   }
 
   ArrayRef<FixItHint> getFixItHints() const {
-    return DiagObj->DiagFixItHints;
+    return DiagObj->DiagStorage.FixItHints;
   }
 
   /// Format this diagnostic into a string, substituting the

diff  --git a/clang/include/clang/Basic/PartialDiagnostic.h b/clang/include/clang/Basic/PartialDiagnostic.h
index 107d621f0dec..9e017902b120 100644
--- a/clang/include/clang/Basic/PartialDiagnostic.h
+++ b/clang/include/clang/Basic/PartialDiagnostic.h
@@ -31,89 +31,7 @@ namespace clang {
 class DeclContext;
 class IdentifierInfo;
 
-class PartialDiagnostic {
-public:
-  enum {
-      // The MaxArguments and MaxFixItHints member enum values from
-      // DiagnosticsEngine are private but DiagnosticsEngine declares
-      // PartialDiagnostic a friend.  These enum values are redeclared
-      // here so that the nested Storage class below can access them.
-      MaxArguments = DiagnosticsEngine::MaxArguments
-  };
-
-  struct Storage {
-    enum {
-        /// The maximum number of arguments we can hold. We
-        /// currently only support up to 10 arguments (%0-%9).
-        ///
-        /// A single diagnostic with more than that almost certainly has to
-        /// be simplified anyway.
-        MaxArguments = PartialDiagnostic::MaxArguments
-    };
-
-    /// The number of entries in Arguments.
-    unsigned char NumDiagArgs = 0;
-
-    /// Specifies for each argument whether it is in DiagArgumentsStr
-    /// or in DiagArguments.
-    unsigned char DiagArgumentsKind[MaxArguments];
-
-    /// The values for the various substitution positions.
-    ///
-    /// This is used when the argument is not an std::string. The specific value
-    /// is mangled into an intptr_t and the interpretation depends on exactly
-    /// what sort of argument kind it is.
-    intptr_t DiagArgumentsVal[MaxArguments];
-
-    /// The values for the various substitution positions that have
-    /// string arguments.
-    std::string DiagArgumentsStr[MaxArguments];
-
-    /// The list of ranges added to this diagnostic.
-    SmallVector<CharSourceRange, 8> DiagRanges;
-
-    /// If valid, provides a hint with some code to insert, remove, or
-    /// modify at a particular position.
-    SmallVector<FixItHint, 6>  FixItHints;
-
-    Storage() = default;
-  };
-
-  /// An allocator for Storage objects, which uses a small cache to
-  /// objects, used to reduce malloc()/free() traffic for partial diagnostics.
-  class StorageAllocator {
-    static const unsigned NumCached = 16;
-    Storage Cached[NumCached];
-    Storage *FreeList[NumCached];
-    unsigned NumFreeListEntries;
-
-  public:
-    StorageAllocator();
-    ~StorageAllocator();
-
-    /// Allocate new storage.
-    Storage *Allocate() {
-      if (NumFreeListEntries == 0)
-        return new Storage;
-
-      Storage *Result = FreeList[--NumFreeListEntries];
-      Result->NumDiagArgs = 0;
-      Result->DiagRanges.clear();
-      Result->FixItHints.clear();
-      return Result;
-    }
-
-    /// Free the given storage object.
-    void Deallocate(Storage *S) {
-      if (S >= Cached && S <= Cached + NumCached) {
-        FreeList[NumFreeListEntries++] = S;
-        return;
-      }
-
-      delete S;
-    }
-  };
-
+class PartialDiagnostic : public StreamingDiagnostic {
 private:
   // NOTE: Sema assumes that PartialDiagnostic is location-invariant
   // in the sense that its bits can be safely memcpy'ed and destructed
@@ -121,65 +39,6 @@ class PartialDiagnostic {
 
   /// The diagnostic ID.
   mutable unsigned DiagID = 0;
-
-  /// Storage for args and ranges.
-  mutable Storage *DiagStorage = nullptr;
-
-  /// Allocator used to allocate storage for this diagnostic.
-  StorageAllocator *Allocator = nullptr;
-
-  /// Retrieve storage for this particular diagnostic.
-  Storage *getStorage() const {
-    if (DiagStorage)
-      return DiagStorage;
-
-    if (Allocator)
-      DiagStorage = Allocator->Allocate();
-    else {
-      assert(Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0)));
-      DiagStorage = new Storage;
-    }
-    return DiagStorage;
-  }
-
-  void freeStorage() {
-    if (!DiagStorage)
-      return;
-
-    // The hot path for PartialDiagnostic is when we just used it to wrap an ID
-    // (typically so we have the flexibility of passing a more complex
-    // diagnostic into the callee, but that does not commonly occur).
-    //
-    // Split this out into a slow function for silly compilers (*cough*) which
-    // can't do decent partial inlining.
-    freeStorageSlow();
-  }
-
-  void freeStorageSlow() {
-    if (Allocator)
-      Allocator->Deallocate(DiagStorage);
-    else if (Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0)))
-      delete DiagStorage;
-    DiagStorage = nullptr;
-  }
-
-  void AddSourceRange(const CharSourceRange &R) const {
-    if (!DiagStorage)
-      DiagStorage = getStorage();
-
-    DiagStorage->DiagRanges.push_back(R);
-  }
-
-  void AddFixItHint(const FixItHint &Hint) const {
-    if (Hint.isNull())
-      return;
-
-    if (!DiagStorage)
-      DiagStorage = getStorage();
-
-    DiagStorage->FixItHints.push_back(Hint);
-  }
-
 public:
   struct NullDiagnostic {};
 
@@ -187,32 +46,52 @@ class PartialDiagnostic {
   /// and only exists to be swapped with a real partial diagnostic.
   PartialDiagnostic(NullDiagnostic) {}
 
-  PartialDiagnostic(unsigned DiagID, StorageAllocator &Allocator)
-      : DiagID(DiagID), Allocator(&Allocator) {}
+  PartialDiagnostic(unsigned DiagID, DiagStorageAllocator &Allocator_)
+      : StreamingDiagnostic(Allocator_), DiagID(DiagID) {}
 
-  PartialDiagnostic(const PartialDiagnostic &Other)
-      : DiagID(Other.DiagID), Allocator(Other.Allocator) {
+  PartialDiagnostic(const PartialDiagnostic &Other) : DiagID(Other.DiagID) {
+    Allocator = Other.Allocator;
     if (Other.DiagStorage) {
       DiagStorage = getStorage();
       *DiagStorage = *Other.DiagStorage;
     }
   }
 
-  PartialDiagnostic(PartialDiagnostic &&Other)
-      : DiagID(Other.DiagID), DiagStorage(Other.DiagStorage),
-        Allocator(Other.Allocator) {
+  template <typename T> const PartialDiagnostic &operator<<(const T &V) const {
+    const StreamingDiagnostic &DB = *this;
+    DB << V;
+    return *this;
+  }
+
+  // It is necessary to limit this to rvalue reference to avoid calling this
+  // function with a bitfield lvalue argument since non-const reference to
+  // bitfield is not allowed.
+  template <typename T, typename = typename std::enable_if<
+                            !std::is_lvalue_reference<T>::value>::type>
+  const PartialDiagnostic &operator<<(T &&V) const {
+    const StreamingDiagnostic &DB = *this;
+    DB << std::move(V);
+    return *this;
+  }
+
+  PartialDiagnostic(PartialDiagnostic &&Other) : DiagID(Other.DiagID) {
+    Allocator = Other.Allocator;
+    DiagStorage = Other.DiagStorage;
     Other.DiagStorage = nullptr;
   }
 
-  PartialDiagnostic(const PartialDiagnostic &Other, Storage *DiagStorage)
-      : DiagID(Other.DiagID), DiagStorage(DiagStorage),
-        Allocator(reinterpret_cast<StorageAllocator *>(~uintptr_t(0))) {
+  PartialDiagnostic(const PartialDiagnostic &Other,
+                    DiagnosticStorage *DiagStorage_)
+      : DiagID(Other.DiagID) {
+    Allocator = reinterpret_cast<DiagStorageAllocator *>(~uintptr_t(0));
+    DiagStorage = DiagStorage_;
     if (Other.DiagStorage)
       *this->DiagStorage = *Other.DiagStorage;
   }
 
-  PartialDiagnostic(const Diagnostic &Other, StorageAllocator &Allocator)
-      : DiagID(Other.getID()), Allocator(&Allocator) {
+  PartialDiagnostic(const Diagnostic &Other, DiagStorageAllocator &Allocator_)
+      : DiagID(Other.getID()) {
+    Allocator = &Allocator_;
     // Copy arguments.
     for (unsigned I = 0, N = Other.getNumArgs(); I != N; ++I) {
       if (Other.getArgKind(I) == DiagnosticsEngine::ak_std_string)
@@ -255,10 +134,6 @@ class PartialDiagnostic {
     return *this;
   }
 
-  ~PartialDiagnostic() {
-    freeStorage();
-  }
-
   void swap(PartialDiagnostic &PD) {
     std::swap(DiagID, PD.DiagID);
     std::swap(DiagStorage, PD.DiagStorage);
@@ -267,27 +142,6 @@ class PartialDiagnostic {
 
   unsigned getDiagID() const { return DiagID; }
 
-  void AddTaggedVal(intptr_t V, DiagnosticsEngine::ArgumentKind Kind) const {
-    if (!DiagStorage)
-      DiagStorage = getStorage();
-
-    assert(DiagStorage->NumDiagArgs < Storage::MaxArguments &&
-           "Too many arguments to diagnostic!");
-    DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind;
-    DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V;
-  }
-
-  void AddString(StringRef V) const {
-    if (!DiagStorage)
-      DiagStorage = getStorage();
-
-    assert(DiagStorage->NumDiagArgs < Storage::MaxArguments &&
-           "Too many arguments to diagnostic!");
-    DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs]
-      = DiagnosticsEngine::ak_std_string;
-    DiagStorage->DiagArgumentsStr[DiagStorage->NumDiagArgs++] = std::string(V);
-  }
-
   void Emit(const DiagnosticBuilder &DB) const {
     if (!DiagStorage)
       return;
@@ -317,7 +171,6 @@ class PartialDiagnostic {
     //        messing with the state of the diagnostics engine.
     DiagnosticBuilder DB(Diags.Report(getDiagID()));
     Emit(DB);
-    DB.FlushCounts();
     Diagnostic(&Diags).FormatDiagnostic(Buf);
     DB.Clear();
     Diags.Clear();
@@ -340,70 +193,6 @@ class PartialDiagnostic {
              == DiagnosticsEngine::ak_std_string && "Not a string arg");
     return DiagStorage->DiagArgumentsStr[I];
   }
-
-  friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
-                                             unsigned I) {
-    PD.AddTaggedVal(I, DiagnosticsEngine::ak_uint);
-    return PD;
-  }
-
-  friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
-                                             int I) {
-    PD.AddTaggedVal(I, DiagnosticsEngine::ak_sint);
-    return PD;
-  }
-
-  friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
-                                                    const char *S) {
-    PD.AddTaggedVal(reinterpret_cast<intptr_t>(S),
-                    DiagnosticsEngine::ak_c_string);
-    return PD;
-  }
-
-  friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
-                                                    StringRef S) {
-
-    PD.AddString(S);
-    return PD;
-  }
-
-  friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
-                                                    const IdentifierInfo *II) {
-    PD.AddTaggedVal(reinterpret_cast<intptr_t>(II),
-                    DiagnosticsEngine::ak_identifierinfo);
-    return PD;
-  }
-
-  // Adds a DeclContext to the diagnostic. The enable_if template magic is here
-  // so that we only match those arguments that are (statically) DeclContexts;
-  // other arguments that derive from DeclContext (e.g., RecordDecls) will not
-  // match.
-  template <typename T>
-  friend inline std::enable_if_t<std::is_same<T, DeclContext>::value,
-                                 const PartialDiagnostic &>
-  operator<<(const PartialDiagnostic &PD, T *DC) {
-    PD.AddTaggedVal(reinterpret_cast<intptr_t>(DC),
-                    DiagnosticsEngine::ak_declcontext);
-    return PD;
-  }
-
-  friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
-                                                    SourceRange R) {
-    PD.AddSourceRange(CharSourceRange::getTokenRange(R));
-    return PD;
-  }
-
-  friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
-                                                    const CharSourceRange &R) {
-    PD.AddSourceRange(R);
-    return PD;
-  }
-
-  friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
-                                             const FixItHint &Hint) {
-    PD.AddFixItHint(Hint);
-    return PD;
-  }
 };
 
 inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,

diff  --git a/clang/include/clang/Sema/DelayedDiagnostic.h b/clang/include/clang/Sema/DelayedDiagnostic.h
index 929db5dfce23..50abcc421d45 100644
--- a/clang/include/clang/Sema/DelayedDiagnostic.h
+++ b/clang/include/clang/Sema/DelayedDiagnostic.h
@@ -57,21 +57,16 @@ class AccessedEntity {
   /// The target is the base class.
   enum BaseNonce { Base };
 
-  AccessedEntity(PartialDiagnostic::StorageAllocator &Allocator,
-                 MemberNonce _,
-                 CXXRecordDecl *NamingClass,
-                 DeclAccessPair FoundDecl,
-                 QualType BaseObjectType)
+  AccessedEntity(PartialDiagnostic::DiagStorageAllocator &Allocator,
+                 MemberNonce _, CXXRecordDecl *NamingClass,
+                 DeclAccessPair FoundDecl, QualType BaseObjectType)
       : Access(FoundDecl.getAccess()), IsMember(true),
         Target(FoundDecl.getDecl()), NamingClass(NamingClass),
-        BaseObjectType(BaseObjectType), Diag(0, Allocator) {
-  }
+        BaseObjectType(BaseObjectType), Diag(0, Allocator) {}
 
-  AccessedEntity(PartialDiagnostic::StorageAllocator &Allocator,
-                 BaseNonce _,
-                 CXXRecordDecl *BaseClass,
-                 CXXRecordDecl *DerivedClass,
-                 AccessSpecifier Access)
+  AccessedEntity(PartialDiagnostic::DiagStorageAllocator &Allocator,
+                 BaseNonce _, CXXRecordDecl *BaseClass,
+                 CXXRecordDecl *DerivedClass, AccessSpecifier Access)
       : Access(Access), IsMember(false), Target(BaseClass),
         NamingClass(DerivedClass), Diag(0, Allocator) {}
 

diff  --git a/clang/include/clang/Sema/Ownership.h b/clang/include/clang/Sema/Ownership.h
index 7c7b1d35c9fd..5c7b010ed736 100644
--- a/clang/include/clang/Sema/Ownership.h
+++ b/clang/include/clang/Sema/Ownership.h
@@ -133,14 +133,13 @@ namespace llvm {
 namespace clang {
 
   // Basic
-  class DiagnosticBuilder;
-
-  // Determines whether the low bit of the result pointer for the
-  // given UID is always zero. If so, ActionResult will use that bit
-  // for it's "invalid" flag.
-  template<class Ptr>
-  struct IsResultPtrLowBitFree {
-    static const bool value = false;
+class StreamingDiagnostic;
+
+// Determines whether the low bit of the result pointer for the
+// given UID is always zero. If so, ActionResult will use that bit
+// for it's "invalid" flag.
+template <class Ptr> struct IsResultPtrLowBitFree {
+  static const bool value = false;
   };
 
   /// ActionResult - This structure is used while parsing/acting on
@@ -280,8 +279,12 @@ namespace clang {
   inline StmtResult StmtError() { return StmtResult(true); }
   inline TypeResult TypeError() { return TypeResult(true); }
 
-  inline ExprResult ExprError(const DiagnosticBuilder&) { return ExprError(); }
-  inline StmtResult StmtError(const DiagnosticBuilder&) { return StmtError(); }
+  inline ExprResult ExprError(const StreamingDiagnostic &) {
+    return ExprError();
+  }
+  inline StmtResult StmtError(const StreamingDiagnostic &) {
+    return StmtError();
+  }
 
   inline ExprResult ExprEmpty() { return ExprResult(false); }
   inline StmtResult StmtEmpty() { return StmtResult(false); }

diff  --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h
index 8946b12ee03f..45b0f85857f6 100644
--- a/clang/include/clang/Sema/ParsedAttr.h
+++ b/clang/include/clang/Sema/ParsedAttr.h
@@ -1044,34 +1044,20 @@ enum AttributeDeclKind {
   ExpectedFunctionWithProtoType,
 };
 
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           const ParsedAttr &At) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                             const ParsedAttr &At) {
   DB.AddTaggedVal(reinterpret_cast<intptr_t>(At.getAttrName()),
                   DiagnosticsEngine::ak_identifierinfo);
   return DB;
 }
 
-inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
-                                           const ParsedAttr &At) {
-  PD.AddTaggedVal(reinterpret_cast<intptr_t>(At.getAttrName()),
-                  DiagnosticsEngine::ak_identifierinfo);
-  return PD;
-}
-
-inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,
-                                           const ParsedAttr *At) {
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
+                                             const ParsedAttr *At) {
   DB.AddTaggedVal(reinterpret_cast<intptr_t>(At->getAttrName()),
                   DiagnosticsEngine::ak_identifierinfo);
   return DB;
 }
 
-inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
-                                           const ParsedAttr *At) {
-  PD.AddTaggedVal(reinterpret_cast<intptr_t>(At->getAttrName()),
-                  DiagnosticsEngine::ak_identifierinfo);
-  return PD;
-}
-
 } // namespace clang
 
 #endif // LLVM_CLANG_SEMA_ATTRIBUTELIST_H

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 52658715ee8c..ac9fffd08747 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1487,16 +1487,14 @@ class Sema final {
       // If we aren't active, there is nothing to do.
       if (!isActive()) return;
 
-      // Otherwise, we need to emit the diagnostic. First flush the underlying
-      // DiagnosticBuilder data, and clear the diagnostic builder itself so it
-      // won't emit the diagnostic in its own destructor.
+      // Otherwise, we need to emit the diagnostic. First clear the diagnostic
+      // builder itself so it won't emit the diagnostic in its own destructor.
       //
       // This seems wasteful, in that as written the DiagnosticBuilder dtor will
       // do its own needless checks to see if the diagnostic needs to be
       // emitted. However, because we take care to ensure that the builder
       // objects never escape, a sufficiently smart compiler will be able to
       // eliminate that code.
-      FlushCounts();
       Clear();
 
       // Dispatch to Sema to emit the diagnostic.
@@ -1511,6 +1509,17 @@ class Sema final {
       BaseDiag << Value;
       return Diag;
     }
+
+    // It is necessary to limit this to rvalue reference to avoid calling this
+    // function with a bitfield lvalue argument since non-const reference to
+    // bitfield is not allowed.
+    template <typename T, typename = typename std::enable_if<
+                              !std::is_lvalue_reference<T>::value>::type>
+    const SemaDiagnosticBuilder &operator<<(T &&V) const {
+      const StreamableDiagnosticBase &DB = *this;
+      DB << std::move(V);
+      return *this;
+    }
   };
 
   /// Emit a diagnostic.

diff  --git a/clang/include/clang/Tooling/Refactoring/RefactoringRuleContext.h b/clang/include/clang/Tooling/Refactoring/RefactoringRuleContext.h
index 5271a54075ea..e0da9469deb5 100644
--- a/clang/include/clang/Tooling/Refactoring/RefactoringRuleContext.h
+++ b/clang/include/clang/Tooling/Refactoring/RefactoringRuleContext.h
@@ -77,7 +77,7 @@ class RefactoringRuleContext {
   /// might operate on.
   ASTContext *AST = nullptr;
   /// The allocator for diagnostics.
-  PartialDiagnostic::StorageAllocator DiagStorage;
+  PartialDiagnostic::DiagStorageAllocator DiagStorage;
 
   // FIXME: Remove when memoized.
   std::unique_ptr<SelectedASTNode> ASTNodeSelection;

diff  --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 8caff6b33379..bddaaa6e19ec 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -11299,9 +11299,9 @@ OMPTraitInfo &ASTContext::getNewOMPTraitInfo() {
   return *OMPTraitInfoVector.back();
 }
 
-const DiagnosticBuilder &
-clang::operator<<(const DiagnosticBuilder &DB,
-                  const ASTContext::SectionInfo &Section) {
+const StreamingDiagnostic &clang::
+operator<<(const StreamingDiagnostic &DB,
+           const ASTContext::SectionInfo &Section) {
   if (Section.Decl)
     return DB << Section.Decl;
   return DB << "a prior #pragma section";

diff  --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index ab2b55c0762e..f2502c327a11 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -2027,9 +2027,9 @@ DependentDiagnostic *DependentDiagnostic::Create(ASTContext &C,
 
   // Allocate the copy of the PartialDiagnostic via the ASTContext's
   // BumpPtrAllocator, rather than the ASTContext itself.
-  PartialDiagnostic::Storage *DiagStorage = nullptr;
+  DiagnosticStorage *DiagStorage = nullptr;
   if (PDiag.hasStorage())
-    DiagStorage = new (C) PartialDiagnostic::Storage;
+    DiagStorage = new (C) DiagnosticStorage;
 
   auto *DD = new (C) DependentDiagnostic(PDiag, DiagStorage);
 

diff  --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 84a0be5ee199..3f522450e870 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -3333,12 +3333,7 @@ static const char *getAccessName(AccessSpecifier AS) {
   llvm_unreachable("Invalid access specifier!");
 }
 
-const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
-                                           AccessSpecifier AS) {
-  return DB << getAccessName(AS);
-}
-
-const PartialDiagnostic &clang::operator<<(const PartialDiagnostic &DB,
-                                           AccessSpecifier AS) {
+const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,
+                                             AccessSpecifier AS) {
   return DB << getAccessName(AS);
 }

diff  --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp
index a9113720fd45..891c9bd0fd7a 100644
--- a/clang/lib/AST/TemplateBase.cpp
+++ b/clang/lib/AST/TemplateBase.cpp
@@ -448,8 +448,8 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
   llvm_unreachable("Invalid TemplateArgument Kind!");
 }
 
-const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
-                                           const TemplateArgument &Arg) {
+template <typename T>
+static const T &DiagTemplateArg(const T &DB, const TemplateArgument &Arg) {
   switch (Arg.getKind()) {
   case TemplateArgument::Null:
     // This is bad, but not as bad as crashing because of argument
@@ -502,6 +502,11 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
   llvm_unreachable("Invalid TemplateArgument Kind!");
 }
 
+const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,
+                                             const TemplateArgument &Arg) {
+  return DiagTemplateArg(DB, Arg);
+}
+
 clang::TemplateArgumentLocInfo::TemplateArgumentLocInfo(
     ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc,
     SourceLocation TemplateNameLoc, SourceLocation EllipsisLoc) {

diff  --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp
index 40a8736ae1af..22cfa9acbe1b 100644
--- a/clang/lib/AST/TemplateName.cpp
+++ b/clang/lib/AST/TemplateName.cpp
@@ -254,8 +254,8 @@ TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
   }
 }
 
-const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
-                                           TemplateName N) {
+const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,
+                                             TemplateName N) {
   std::string NameStr;
   llvm::raw_string_ostream OS(NameStr);
   LangOptions LO;
@@ -268,20 +268,6 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
   return DB << NameStr;
 }
 
-const PartialDiagnostic&clang::operator<<(const PartialDiagnostic &PD,
-                                           TemplateName N) {
-  std::string NameStr;
-  llvm::raw_string_ostream OS(NameStr);
-  LangOptions LO;
-  LO.CPlusPlus = true;
-  LO.Bool = true;
-  OS << '\'';
-  N.print(OS, PrintingPolicy(LO));
-  OS << '\'';
-  OS.flush();
-  return PD << NameStr;
-}
-
 void TemplateName::dump(raw_ostream &OS) const {
   LangOptions LO;  // FIXME!
   LO.CPlusPlus = true;

diff  --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp
index ba8c2fb4731d..03ceca1262af 100644
--- a/clang/lib/Basic/Diagnostic.cpp
+++ b/clang/lib/Basic/Diagnostic.cpp
@@ -40,8 +40,8 @@
 
 using namespace clang;
 
-const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
-                                           DiagNullabilityKind nullability) {
+const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,
+                                             DiagNullabilityKind nullability) {
   StringRef string;
   switch (nullability.first) {
   case NullabilityKind::NonNull:
@@ -61,8 +61,8 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
   return DB;
 }
 
-const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
-                                           llvm::Error &&E) {
+const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,
+                                             llvm::Error &&E) {
   DB.AddString(toString(std::move(E)));
   return DB;
 }
@@ -482,13 +482,15 @@ void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) {
 
   CurDiagLoc = storedDiag.getLocation();
   CurDiagID = storedDiag.getID();
-  NumDiagArgs = 0;
+  DiagStorage.NumDiagArgs = 0;
 
-  DiagRanges.clear();
-  DiagRanges.append(storedDiag.range_begin(), storedDiag.range_end());
+  DiagStorage.DiagRanges.clear();
+  DiagStorage.DiagRanges.append(storedDiag.range_begin(),
+                                storedDiag.range_end());
 
-  DiagFixItHints.clear();
-  DiagFixItHints.append(storedDiag.fixit_begin(), storedDiag.fixit_end());
+  DiagStorage.FixItHints.clear();
+  DiagStorage.FixItHints.append(storedDiag.fixit_begin(),
+                                storedDiag.fixit_end());
 
   assert(Client && "DiagnosticConsumer not set!");
   Level DiagLevel = storedDiag.getLevel();
@@ -1141,13 +1143,13 @@ bool ForwardingDiagnosticConsumer::IncludeInDiagnosticCounts() const {
   return Target.IncludeInDiagnosticCounts();
 }
 
-PartialDiagnostic::StorageAllocator::StorageAllocator() {
+PartialDiagnostic::DiagStorageAllocator::DiagStorageAllocator() {
   for (unsigned I = 0; I != NumCached; ++I)
     FreeList[I] = Cached + I;
   NumFreeListEntries = NumCached;
 }
 
-PartialDiagnostic::StorageAllocator::~StorageAllocator() {
+PartialDiagnostic::DiagStorageAllocator::~DiagStorageAllocator() {
   // Don't assert if we are in a CrashRecovery context, as this invariant may
   // be invalidated during a crash.
   assert((NumFreeListEntries == NumCached ||

diff  --git a/clang/unittests/Basic/DiagnosticTest.cpp b/clang/unittests/Basic/DiagnosticTest.cpp
index ffb750bdaae3..8d018a8b9cef 100644
--- a/clang/unittests/Basic/DiagnosticTest.cpp
+++ b/clang/unittests/Basic/DiagnosticTest.cpp
@@ -74,7 +74,7 @@ TEST(DiagnosticTest, fatalsAsError) {
 TEST(DiagnosticTest, diagnosticError) {
   DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions,
                           new IgnoringDiagConsumer());
-  PartialDiagnostic::StorageAllocator Alloc;
+  PartialDiagnostic::DiagStorageAllocator Alloc;
   llvm::Expected<std::pair<int, int>> Value = DiagnosticError::create(
       SourceLocation(), PartialDiagnostic(diag::err_cannot_open_file, Alloc)
                             << "file"


        


More information about the cfe-commits mailing list