[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