[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
This commit is contained in:
Yaxun (Sam) Liu 2020-09-23 16:16:00 -04:00
parent ea693a1627
commit 7e561b62d2
25 changed files with 402 additions and 544 deletions

View File

@ -573,7 +573,7 @@ private:
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 @@ public:
/// 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 @@ private:
};
/// 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) {

View File

@ -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

View File

@ -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;
}

View File

@ -4513,14 +4513,8 @@ public:
/// 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;

View File

@ -4075,11 +4075,8 @@ public:
/// 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

View File

@ -811,19 +811,10 @@ private:
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;

View File

@ -100,8 +100,8 @@ private:
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,

View File

@ -519,8 +519,8 @@ public:
/// 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;

View File

@ -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 {

View File

@ -342,10 +342,8 @@ public:
/// 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.

View File

@ -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;

View File

@ -144,6 +144,44 @@ public:
}
};
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 @@ private:
/// 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 @@ public:
}
};
/// 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 @@ public:
/// 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 @@ protected:
// (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,18 +1286,35 @@ public:
/// 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;
}
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;
}
// 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!");
const StreamingDiagnostic &DB = *this;
DB << std::move(V);
return *this;
}
DiagnosticBuilder &operator=(const DiagnosticBuilder &) = delete;
/// Emits the diagnostic.
~DiagnosticBuilder() {
Emit();
}
~DiagnosticBuilder() { Emit(); }
/// Forces the diagnostic to be emitted.
const DiagnosticBuilder &setForceEmit() const {
@ -1150,42 +1322,6 @@ public:
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 {
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);
}
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;
}
void AddSourceRange(const CharSourceRange &R) const {
assert(isActive() && "Clients must not add to cleared diagnostic!");
DiagObj->DiagRanges.push_back(R);
}
void AddFixItHint(const FixItHint &Hint) const {
assert(isActive() && "Clients must not add to cleared diagnostic!");
if (!Hint.isNull())
DiagObj->DiagFixItHints.push_back(Hint);
}
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 @@ public:
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 @@ public:
/// \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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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

View File

@ -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 @@ private:
/// 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 @@ public:
/// 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 @@ public:
return *this;
}
~PartialDiagnostic() {
freeStorage();
}
void swap(PartialDiagnostic &PD) {
std::swap(DiagID, PD.DiagID);
std::swap(DiagStorage, PD.DiagStorage);
@ -267,27 +142,6 @@ public:
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 @@ public:
// 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 @@ public:
== 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,

View File

@ -57,21 +57,16 @@ public:
/// 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) {}

View File

@ -133,14 +133,13 @@ namespace llvm {
namespace clang {
// Basic
class DiagnosticBuilder;
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;
// 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); }

View File

@ -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

View File

@ -1487,16 +1487,14 @@ public:
// 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 @@ public:
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.

View File

@ -77,7 +77,7 @@ private:
/// 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;

View File

@ -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";

View File

@ -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);

View File

@ -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);
}

View File

@ -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) {

View File

@ -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;

View File

@ -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 ||

View File

@ -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"