Index: clang/include/clang/AST/ASTContext.h =================================================================== --- clang/include/clang/AST/ASTContext.h +++ clang/include/clang/AST/ASTContext.h @@ -3027,6 +3027,8 @@ /// Insertion operator for diagnostics. const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, const ASTContext::SectionInfo &Section); +const PartialDiagnostic &operator<<(const PartialDiagnostic &DB, + const ASTContext::SectionInfo &Section); /// Utility function for constructing a nullary selector. inline Selector GetNullarySelector(StringRef name, ASTContext &Ctx) { Index: clang/include/clang/AST/Attr.h =================================================================== --- clang/include/clang/AST/Attr.h +++ clang/include/clang/AST/Attr.h @@ -344,8 +344,10 @@ #include "clang/AST/Attrs.inc" -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - const Attr *At) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, const Attr *At) { DB.AddTaggedVal(reinterpret_cast(At), DiagnosticsEngine::ak_attr); return DB; Index: clang/include/clang/AST/CanonicalType.h =================================================================== --- clang/include/clang/AST/CanonicalType.h +++ clang/include/clang/AST/CanonicalType.h @@ -215,8 +215,10 @@ return CanQualType::CreateUnsafe(getCanonicalTypeInternal()); } -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - CanQualType T) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, CanQualType T) { DB << static_cast(T); return DB; } Index: clang/include/clang/AST/Decl.h =================================================================== --- clang/include/clang/AST/Decl.h +++ clang/include/clang/AST/Decl.h @@ -4498,8 +4498,11 @@ /// Insertion operator for diagnostics. This allows sending NamedDecl's /// into a diagnostic with <<. -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - const NamedDecl* ND) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, + const NamedDecl *ND) { DB.AddTaggedVal(reinterpret_cast(ND), DiagnosticsEngine::ak_nameddecl); return DB; Index: clang/include/clang/AST/DeclarationName.h =================================================================== --- clang/include/clang/AST/DeclarationName.h +++ clang/include/clang/AST/DeclarationName.h @@ -813,8 +813,11 @@ /// Insertion operator for diagnostics. This allows sending DeclarationName's /// into a diagnostic with <<. -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - DeclarationName N) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, + DeclarationName N) { DB.AddTaggedVal(N.getAsOpaqueInteger(), DiagnosticsEngine::ak_declarationname); return DB; Index: clang/include/clang/AST/NestedNameSpecifier.h =================================================================== --- clang/include/clang/AST/NestedNameSpecifier.h +++ clang/include/clang/AST/NestedNameSpecifier.h @@ -518,8 +518,11 @@ /// Insertion operator for diagnostics. This allows sending /// NestedNameSpecifiers into a diagnostic with <<. -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - NestedNameSpecifier *NNS) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, + NestedNameSpecifier *NNS) { DB.AddTaggedVal(reinterpret_cast(NNS), DiagnosticsEngine::ak_nestednamespec); return DB; Index: clang/include/clang/AST/TemplateBase.h =================================================================== --- clang/include/clang/AST/TemplateBase.h +++ clang/include/clang/AST/TemplateBase.h @@ -683,6 +683,8 @@ const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, const TemplateArgument &Arg); +const PartialDiagnostic &operator<<(const PartialDiagnostic &DB, + const TemplateArgument &Arg); inline TemplateSpecializationType::iterator TemplateSpecializationType::end() const { Index: clang/include/clang/AST/Type.h =================================================================== --- clang/include/clang/AST/Type.h +++ clang/include/clang/AST/Type.h @@ -7095,8 +7095,10 @@ } /// Insertion operator for diagnostics. This allows sending address spaces into /// a diagnostic with <<. -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - LangAS AS) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, LangAS AS) { DB.AddTaggedVal(static_cast>(AS), DiagnosticsEngine::ArgumentKind::ak_addrspace); return DB; @@ -7113,8 +7115,10 @@ /// Insertion operator for diagnostics. This allows sending Qualifiers into a /// diagnostic with <<. -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - Qualifiers Q) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, Qualifiers Q) { DB.AddTaggedVal(Q.getAsOpaqueValue(), DiagnosticsEngine::ArgumentKind::ak_qual); return DB; @@ -7131,8 +7135,10 @@ /// Insertion operator for diagnostics. This allows sending QualType's into a /// diagnostic with <<. -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - QualType T) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, QualType T) { DB.AddTaggedVal(reinterpret_cast(T.getAsOpaquePtr()), DiagnosticsEngine::ak_qualtype); return DB; Index: clang/include/clang/Basic/Diagnostic.h =================================================================== --- clang/include/clang/Basic/Diagnostic.h +++ clang/include/clang/Basic/Diagnostic.h @@ -1187,6 +1187,7 @@ } void addFlagValue(StringRef V) const { DiagObj->FlagValue = std::string(V); } + const static bool IsDiagBuilder = true; }; struct AddFlagValue { @@ -1199,53 +1200,82 @@ /// value will be shown as the suffix "=value" after the flag name. It is /// useful in cases where the diagnostic flag accepts values (e.g., /// -Rpass or -Wframe-larger-than). -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - const AddFlagValue V) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, + const AddFlagValue V) { DB.addFlagValue(V.Val); return DB; } -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - StringRef S) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, StringRef S) { DB.AddString(S); return DB; } -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - const char *Str) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, + const std::string &S) { + DB.AddString(StringRef(S)); + return DB; +} + +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, const char *Str) { DB.AddTaggedVal(reinterpret_cast(Str), DiagnosticsEngine::ak_c_string); return DB; } -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, int I) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, int I) { DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint); return DB; } // 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) { +template +inline std::enable_if_t::value && + DiagBuilderT::IsDiagBuilder, + const DiagBuilderT &> +operator<<(const DiagBuilderT &DB, T I) { DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint); return DB; } -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - unsigned I) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, unsigned I) { DB.AddTaggedVal(I, DiagnosticsEngine::ak_uint); return DB; } -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - tok::TokenKind I) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, + tok::TokenKind I) { DB.AddTaggedVal(static_cast(I), DiagnosticsEngine::ak_tokenkind); return DB; } -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - const IdentifierInfo *II) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, + const IdentifierInfo *II) { DB.AddTaggedVal(reinterpret_cast(II), DiagnosticsEngine::ak_identifierinfo); return DB; @@ -1255,66 +1285,88 @@ // so that we only match those arguments that are (statically) DeclContexts; // other arguments that derive from DeclContext (e.g., RecordDecls) will not // match. -template +template inline std::enable_if_t< - std::is_same, DeclContext>::value, - const DiagnosticBuilder &> -operator<<(const DiagnosticBuilder &DB, T *DC) { + std::is_same, DeclContext>::value && + DiagBuilderT::IsDiagBuilder, + const DiagBuilderT &> +operator<<(const DiagBuilderT &DB, T *DC) { DB.AddTaggedVal(reinterpret_cast(DC), DiagnosticsEngine::ak_declcontext); return DB; } -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - SourceRange R) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, SourceRange R) { DB.AddSourceRange(CharSourceRange::getTokenRange(R)); return DB; } -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - ArrayRef Ranges) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, + ArrayRef Ranges) { for (SourceRange R : Ranges) DB.AddSourceRange(CharSourceRange::getTokenRange(R)); return DB; } -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - const CharSourceRange &R) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, + const CharSourceRange &R) { DB.AddSourceRange(R); return DB; } -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - const FixItHint &Hint) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, + const FixItHint &Hint) { DB.AddFixItHint(Hint); return DB; } -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - ArrayRef Hints) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, + ArrayRef Hints) { for (const FixItHint &Hint : Hints) DB.AddFixItHint(Hint); return DB; } -inline const DiagnosticBuilder & -operator<<(const DiagnosticBuilder &DB, - const llvm::Optional &Opt) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, + const llvm::Optional &Opt) { if (Opt) DB << *Opt; return DB; } -inline const DiagnosticBuilder & -operator<<(const DiagnosticBuilder &DB, - const llvm::Optional &Opt) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT & +operator<<(const DiagBuilderT &DB, const llvm::Optional &Opt) { if (Opt) DB << *Opt; return DB; } -inline const DiagnosticBuilder & -operator<<(const DiagnosticBuilder &DB, const llvm::Optional &Opt) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, + const llvm::Optional &Opt) { if (Opt) DB << *Opt; return DB; @@ -1324,8 +1376,29 @@ /// context-sensitive keyword. using DiagNullabilityKind = std::pair; -const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - DiagNullabilityKind nullability); +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +const DiagBuilderT &operator<<(const DiagBuilderT &DB, + DiagNullabilityKind nullability) { + StringRef string; + switch (nullability.first) { + case NullabilityKind::NonNull: + string = nullability.second ? "'nonnull'" : "'_Nonnull'"; + break; + + case NullabilityKind::Nullable: + string = nullability.second ? "'nullable'" : "'_Nullable'"; + break; + + case NullabilityKind::Unspecified: + string = nullability.second ? "'null_unspecified'" : "'_Null_unspecified'"; + break; + } + + DB.AddString(string); + return DB; +} inline DiagnosticBuilder DiagnosticsEngine::Report(SourceLocation Loc, unsigned DiagID) { Index: clang/include/clang/Basic/PartialDiagnostic.h =================================================================== --- clang/include/clang/Basic/PartialDiagnostic.h +++ clang/include/clang/Basic/PartialDiagnostic.h @@ -163,24 +163,8 @@ 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: + const static bool IsDiagBuilder = true; struct NullDiagnostic {}; /// Create a null partial diagnostic, which cannot carry a payload, @@ -288,6 +272,23 @@ 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); + } + void Emit(const DiagnosticBuilder &DB) const { if (!DiagStorage) return; @@ -406,8 +407,11 @@ } }; -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - const PartialDiagnostic &PD) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &DB, + const PartialDiagnostic &PD) { PD.Emit(DB); return DB; } Index: clang/include/clang/Sema/Ownership.h =================================================================== --- clang/include/clang/Sema/Ownership.h +++ clang/include/clang/Sema/Ownership.h @@ -134,6 +134,7 @@ // Basic class DiagnosticBuilder; + class PartialDiagnostic; // Determines whether the low bit of the result pointer for the // given UID is always zero. If so, ActionResult will use that bit Index: clang/include/clang/Sema/ParsedAttr.h =================================================================== --- clang/include/clang/Sema/ParsedAttr.h +++ clang/include/clang/Sema/ParsedAttr.h @@ -1040,34 +1040,26 @@ ExpectedFunctionWithProtoType, }; -inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, - const ParsedAttr &At) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &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) { +template < + typename DiagBuilderT, + typename std::enable_if::type * = nullptr> +inline const DiagBuilderT &operator<<(const DiagBuilderT &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 Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -11164,3 +11164,11 @@ return DB << Section.Decl; return DB << "a prior #pragma section"; } + +const PartialDiagnostic &clang:: +operator<<(const PartialDiagnostic &DB, + const ASTContext::SectionInfo &Section) { + if (Section.Decl) + return DB << Section.Decl; + return DB << "a prior #pragma section"; +} Index: clang/lib/AST/TemplateBase.cpp =================================================================== --- clang/lib/AST/TemplateBase.cpp +++ clang/lib/AST/TemplateBase.cpp @@ -26,6 +26,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/FoldingSet.h" @@ -448,8 +449,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 +503,16 @@ llvm_unreachable("Invalid TemplateArgument Kind!"); } +const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, + const TemplateArgument &Arg) { + return DiagTemplateArg(DB, Arg); +} + +const PartialDiagnostic &clang::operator<<(const PartialDiagnostic &DB, + const TemplateArgument &Arg) { + return DiagTemplateArg(DB, Arg); +} + const ASTTemplateArgumentListInfo * ASTTemplateArgumentListInfo::Create(const ASTContext &C, const TemplateArgumentListInfo &List) { Index: clang/lib/Basic/Diagnostic.cpp =================================================================== --- clang/lib/Basic/Diagnostic.cpp +++ clang/lib/Basic/Diagnostic.cpp @@ -40,26 +40,6 @@ using namespace clang; -const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, - DiagNullabilityKind nullability) { - StringRef string; - switch (nullability.first) { - case NullabilityKind::NonNull: - string = nullability.second ? "'nonnull'" : "'_Nonnull'"; - break; - - case NullabilityKind::Nullable: - string = nullability.second ? "'nullable'" : "'_Nullable'"; - break; - - case NullabilityKind::Unspecified: - string = nullability.second ? "'null_unspecified'" : "'_Null_unspecified'"; - break; - } - - DB.AddString(string); - return DB; -} const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, llvm::Error &&E) {