Index: include/clang/Basic/Diagnostic.h =================================================================== --- include/clang/Basic/Diagnostic.h +++ include/clang/Basic/Diagnostic.h @@ -933,14 +933,12 @@ } public: - /// Copy constructor. When copied, this "takes" the diagnostic info from the - /// input and neuters it. - DiagnosticBuilder(const DiagnosticBuilder &D) { - DiagObj = D.DiagObj; - IsActive = D.IsActive; - IsForceEmit = D.IsForceEmit; + /// Move constructor. When moved, the source DiagnosticBuilder is made + /// inactive and will not emit a diagnostic during its destruction. + DiagnosticBuilder(DiagnosticBuilder &&D) + : DiagObj(D.DiagObj), NumArgs(D.NumArgs), IsActive(D.IsActive), + IsForceEmit(D.IsForceEmit) { D.Clear(); - NumArgs = D.NumArgs; } /// \brief Retrieve an empty diagnostic builder. Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -1051,16 +1051,13 @@ unsigned DiagID; public: - SemaDiagnosticBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) - : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) { } + SemaDiagnosticBuilder(DiagnosticBuilder DB, Sema &SemaRef, unsigned DiagID) + : DiagnosticBuilder(std::move(DB)), SemaRef(SemaRef), DiagID(DiagID) {} - // This is a cunning lie. DiagnosticBuilder actually performs move - // construction in its copy constructor (but due to varied uses, it's not - // possible to conveniently express this as actual move construction). So - // the default copy ctor here is fine, because the base class disables the - // source anyway, so the user-defined ~SemaDiagnosticBuilder is a safe no-op - // in that case anwyay. - SemaDiagnosticBuilder(const SemaDiagnosticBuilder&) = default; + // DiagnosticBuilder's move ctor ensures that the source object becomes + // inactive, so ~SemaDiagnosticBuilder will be a safe/correct no-op on + // moved-from SemaDiagnosticBuilder instances. + SemaDiagnosticBuilder(SemaDiagnosticBuilder &&) = default; ~SemaDiagnosticBuilder() { // If we aren't active, there is nothing to do. @@ -1090,12 +1087,18 @@ BaseDiag << Value; return Diag; } + template + friend SemaDiagnosticBuilder operator<<(SemaDiagnosticBuilder &&Diag, + const T &Value) { + const DiagnosticBuilder &BaseDiag = Diag; + BaseDiag << Value; + return std::move(Diag); + } }; /// \brief Emit a diagnostic. SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { - DiagnosticBuilder DB = Diags.Report(Loc, DiagID); - return SemaDiagnosticBuilder(DB, *this, DiagID); + return SemaDiagnosticBuilder(Diags.Report(Loc, DiagID), *this, DiagID); } /// \brief Emit a partial diagnostic. Index: lib/ARCMigrate/TransformActions.cpp =================================================================== --- lib/ARCMigrate/TransformActions.cpp +++ lib/ARCMigrate/TransformActions.cpp @@ -675,7 +675,9 @@ SourceRange range) { assert(!static_cast(Impl)->isInTransaction() && "Errors should be emitted out of a transaction"); - return Diags.Report(loc, diagId) << range; + auto D = Diags.Report(loc, diagId); + D << range; + return D; } void TransformActions::reportError(StringRef message, SourceLocation loc, Index: lib/Lex/LiteralSupport.cpp =================================================================== --- lib/Lex/LiteralSupport.cpp +++ lib/Lex/LiteralSupport.cpp @@ -69,8 +69,10 @@ SourceLocation Begin = Lexer::AdvanceToTokenCharacter(TokLoc, TokRangeBegin - TokBegin, TokLoc.getManager(), Features); - return Diags->Report(Begin, DiagID) << - MakeCharSourceRange(Features, TokLoc, TokBegin, TokRangeBegin, TokRangeEnd); + auto D = Diags->Report(Begin, DiagID); + D << MakeCharSourceRange(Features, TokLoc, TokBegin, TokRangeBegin, + TokRangeEnd); + return D; } /// ProcessCharEscape - Parse a standard C escape sequence, which can occur in Index: lib/Parse/Parser.cpp =================================================================== --- lib/Parse/Parser.cpp +++ lib/Parse/Parser.cpp @@ -160,10 +160,15 @@ if (EndLoc.isValid()) Spelling = tok::getPunctuatorSpelling(ExpectedTok); - DiagnosticBuilder DB = - Spelling - ? Diag(EndLoc, DiagID) << FixItHint::CreateInsertion(EndLoc, Spelling) - : Diag(Tok, DiagID); + DiagnosticBuilder DB = [&]() { + if (!Spelling) + return Diag(Tok, DiagID); + + auto D = Diag(EndLoc, DiagID); + D << FixItHint::CreateInsertion(EndLoc, Spelling); + return D; + }(); + if (DiagID == diag::err_expected) DB << ExpectedTok; else if (DiagID == diag::err_expected_after)