diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -573,7 +573,7 @@ mutable llvm::BumpPtrAllocator BumpAlloc; /// Allocator for partial diagnostics. - PartialDiagnostic::StorageAllocator DiagAllocator; + PartialDiagnostic::DiagStorageAllocator DiagAllocator; /// The current C++ ABI. std::unique_ptr ABI; @@ -652,7 +652,7 @@ /// 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 @@ }; /// 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 --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -350,19 +350,12 @@ #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(At), DiagnosticsEngine::ak_attr); return DB; } - -inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, - const Attr *At) { - PD.AddTaggedVal(reinterpret_cast(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 --- a/clang/include/clang/AST/CanonicalType.h +++ b/clang/include/clang/AST/CanonicalType.h @@ -215,8 +215,8 @@ 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(T); return DB; } diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -4513,14 +4513,8 @@ /// 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(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(ND), DiagnosticsEngine::ak_nameddecl); return PD; diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -4075,11 +4075,8 @@ /// 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 --- a/clang/include/clang/AST/DeclarationName.h +++ b/clang/include/clang/AST/DeclarationName.h @@ -811,19 +811,10 @@ 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 --- a/clang/include/clang/AST/DependentDiagnostic.h +++ b/clang/include/clang/AST/DependentDiagnostic.h @@ -100,8 +100,8 @@ 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 --- a/clang/include/clang/AST/NestedNameSpecifier.h +++ b/clang/include/clang/AST/NestedNameSpecifier.h @@ -519,8 +519,8 @@ /// 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(NNS), DiagnosticsEngine::ak_nestednamespec); return DB; diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -687,8 +687,8 @@ 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 --- a/clang/include/clang/AST/TemplateName.h +++ b/clang/include/clang/AST/TemplateName.h @@ -342,10 +342,8 @@ /// 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 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -7071,55 +7071,28 @@ 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>(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>(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(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(T.getAsOpaquePtr()), DiagnosticsEngine::ak_qualtype); return PD; diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/include/clang/Basic/Diagnostic.h @@ -144,6 +144,44 @@ } }; +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 DiagRanges; + + /// If valid, provides a hint with some code to insert, remove, or + /// modify at a particular position. + SmallVector 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 @@ /// 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 DiagRanges; - - /// If valid, provides a hint with some code to insert, remove, - /// or modify at a particular position. - SmallVector DiagFixItHints; + DiagnosticStorage DiagStorage; DiagnosticMapping makeUserMapping(diag::Severity Map, SourceLocation L) { bool isPragma = L.isValid(); @@ -1043,6 +1053,156 @@ } }; +/// 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 @@ /// 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 @@ 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 @@ // (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 @@ /// 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 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 ::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 @@ 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(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 @@ // We use enable_if here to prevent that this overload is selected for // pointers or other arguments that are implicitly convertible to bool. template -inline std::enable_if_t::value, const DiagnosticBuilder &> -operator<<(const DiagnosticBuilder &DB, T I) { +inline std::enable_if_t::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(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(II), DiagnosticsEngine::ak_identifierinfo); return DB; @@ -1258,63 +1396,64 @@ template inline std::enable_if_t< std::is_same, DeclContext>::value, - const DiagnosticBuilder &> -operator<<(const DiagnosticBuilder &DB, T *DC) { + const StreamingDiagnostic &> +operator<<(const StreamingDiagnostic &DB, T *DC) { DB.AddTaggedVal(reinterpret_cast(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 Ranges) { +inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, + ArrayRef 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 Hints) { +inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, + ArrayRef 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 &Opt) { if (Opt) DB << *Opt; return DB; } -inline const DiagnosticBuilder & -operator<<(const DiagnosticBuilder &DB, +inline const StreamingDiagnostic & +operator<<(const StreamingDiagnostic &DB, const llvm::Optional &Opt) { if (Opt) DB << *Opt; return DB; } -inline const DiagnosticBuilder & -operator<<(const DiagnosticBuilder &DB, const llvm::Optional &Opt) { +inline const StreamingDiagnostic & +operator<<(const StreamingDiagnostic &DB, + const llvm::Optional &Opt) { if (Opt) DB << *Opt; return DB; @@ -1324,8 +1463,8 @@ /// context-sensitive keyword. using DiagNullabilityKind = std::pair; -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 @@ 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 @@ 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 @@ /// \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 @@ 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 @@ const char *getArgCStr(unsigned Idx) const { assert(getArgKind(Idx) == DiagnosticsEngine::ak_c_string && "invalid argument accessor!"); - return reinterpret_cast(DiagObj->DiagArgumentsVal[Idx]); + return reinterpret_cast( + DiagObj->DiagStorage.DiagArgumentsVal[Idx]); } /// Return the specified signed integer argument. @@ -1400,7 +1541,7 @@ 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 @@ 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 @@ const IdentifierInfo *getArgIdentifier(unsigned Idx) const { assert(getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo && "invalid argument accessor!"); - return reinterpret_cast(DiagObj->DiagArgumentsVal[Idx]); + return reinterpret_cast( + DiagObj->DiagStorage.DiagArgumentsVal[Idx]); } /// Return the specified non-string argument in an opaque form. @@ -1424,36 +1566,36 @@ 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 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 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 --- a/clang/include/clang/Basic/PartialDiagnostic.h +++ b/clang/include/clang/Basic/PartialDiagnostic.h @@ -31,89 +31,7 @@ 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 DiagRanges; - - /// If valid, provides a hint with some code to insert, remove, or - /// modify at a particular position. - SmallVector 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 @@ /// 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(~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(~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 @@ /// 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 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 ::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(~uintptr_t(0))) { + PartialDiagnostic(const PartialDiagnostic &Other, + DiagnosticStorage *DiagStorage_) + : DiagID(Other.DiagID) { + Allocator = reinterpret_cast(~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 @@ return *this; } - ~PartialDiagnostic() { - freeStorage(); - } - void swap(PartialDiagnostic &PD) { std::swap(DiagID, PD.DiagID); std::swap(DiagStorage, PD.DiagStorage); @@ -267,27 +142,6 @@ 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 @@ // 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 @@ == 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(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(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 - friend inline std::enable_if_t::value, - const PartialDiagnostic &> - operator<<(const PartialDiagnostic &PD, T *DC) { - PD.AddTaggedVal(reinterpret_cast(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 --- a/clang/include/clang/Sema/DelayedDiagnostic.h +++ b/clang/include/clang/Sema/DelayedDiagnostic.h @@ -57,21 +57,16 @@ /// 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 --- a/clang/include/clang/Sema/Ownership.h +++ b/clang/include/clang/Sema/Ownership.h @@ -133,14 +133,13 @@ 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 - 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 struct IsResultPtrLowBitFree { + static const bool value = false; }; /// ActionResult - This structure is used while parsing/acting on @@ -280,8 +279,12 @@ 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 --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -1044,34 +1044,20 @@ 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(At.getAttrName()), DiagnosticsEngine::ak_identifierinfo); return DB; } -inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, - const ParsedAttr &At) { - PD.AddTaggedVal(reinterpret_cast(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(At->getAttrName()), DiagnosticsEngine::ak_identifierinfo); return DB; } -inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, - const ParsedAttr *At) { - PD.AddTaggedVal(reinterpret_cast(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 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1487,16 +1487,14 @@ // 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 @@ 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 ::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 --- a/clang/include/clang/Tooling/Refactoring/RefactoringRuleContext.h +++ b/clang/include/clang/Tooling/Refactoring/RefactoringRuleContext.h @@ -77,7 +77,7 @@ /// might operate on. ASTContext *AST = nullptr; /// The allocator for diagnostics. - PartialDiagnostic::StorageAllocator DiagStorage; + PartialDiagnostic::DiagStorageAllocator DiagStorage; // FIXME: Remove when memoized. std::unique_ptr ASTNodeSelection; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -11299,9 +11299,9 @@ 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 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -2027,9 +2027,9 @@ // 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 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -3333,12 +3333,7 @@ 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 --- a/clang/lib/AST/TemplateBase.cpp +++ b/clang/lib/AST/TemplateBase.cpp @@ -448,8 +448,8 @@ llvm_unreachable("Invalid TemplateArgument Kind!"); } -const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, - const TemplateArgument &Arg) { +template +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 @@ 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 --- a/clang/lib/AST/TemplateName.cpp +++ b/clang/lib/AST/TemplateName.cpp @@ -254,8 +254,8 @@ } } -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 @@ 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 --- 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 @@ 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 @@ 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 @@ 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 --- a/clang/unittests/Basic/DiagnosticTest.cpp +++ b/clang/unittests/Basic/DiagnosticTest.cpp @@ -74,7 +74,7 @@ TEST(DiagnosticTest, diagnosticError) { DiagnosticsEngine Diags(new DiagnosticIDs(), new DiagnosticOptions, new IgnoringDiagConsumer()); - PartialDiagnostic::StorageAllocator Alloc; + PartialDiagnostic::DiagStorageAllocator Alloc; llvm::Expected> Value = DiagnosticError::create( SourceLocation(), PartialDiagnostic(diag::err_cannot_open_file, Alloc) << "file"