Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -639,6 +639,10 @@ void setPrintingPolicy(const clang::PrintingPolicy &Policy) { PrintingPolicy = Policy; } + /// Restore the printing policy computed when the context was constructed. + void restorePrintingPolicy() { + PrintingPolicy = clang::PrintingPolicy(LangOpts); + } SourceManager& getSourceManager() { return SourceMgr; } const SourceManager& getSourceManager() const { return SourceMgr; } Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -2111,14 +2111,14 @@ void checkPartialSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec); - /// \brief Retrieve a suitable printing policy. - PrintingPolicy getPrintingPolicy() const { - return getPrintingPolicy(Context, PP); + /// \brief Retrieve a suitable printing policy for diagnostics. + PrintingPolicy getDiagPrintingPolicy() const { + return getDiagPrintingPolicy(Context, PP); } - /// \brief Retrieve a suitable printing policy. - static PrintingPolicy getPrintingPolicy(const ASTContext &Ctx, - const Preprocessor &PP); + /// \brief Retrieve a suitable printing policy for diagnostics. + static PrintingPolicy getDiagPrintingPolicy(const ASTContext &Ctx, + const Preprocessor &PP); /// Scope actions. void ActOnPopScope(SourceLocation Loc, Scope *S); Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -2920,7 +2920,7 @@ bool AttrsLastTime = false; ParsedAttributesWithRange attrs(AttrFactory); // We use Sema's policy to get bool macros right. - PrintingPolicy Policy = Actions.getPrintingPolicy(); + PrintingPolicy Policy = Actions.getDiagPrintingPolicy(); while (1) { bool isInvalid = false; bool isStorageClass = false; Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp +++ lib/Sema/Sema.cpp @@ -49,11 +49,12 @@ ModuleLoader &Sema::getModuleLoader() const { return PP.getModuleLoader(); } -PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context, - const Preprocessor &PP) { +PrintingPolicy Sema::getDiagPrintingPolicy(const ASTContext &Context, + const Preprocessor &PP) { PrintingPolicy Policy = Context.getPrintingPolicy(); - // Our printing policy is copied over the ASTContext printing policy whenever - // a diagnostic is emitted, so recompute it. + // The ASTContext printing policy is for -ast-print, which must print _Bool + // as _Bool. In diagnostics, we print _Bool as bool if the latter is defined + // as the former. Policy.Bool = Context.getLangOpts().Bool; if (!Policy.Bool) { if (const MacroInfo *BoolMacro = PP.getMacroInfo(Context.getBoolName())) { @@ -1202,6 +1203,16 @@ return nullptr; } +class DiagPrintingPolicyRAII { + Sema &S; + +public: + DiagPrintingPolicyRAII(Sema &S) : S(S) { + S.getASTContext().setPrintingPolicy(S.getDiagPrintingPolicy()); + } + ~DiagPrintingPolicyRAII() { S.getASTContext().restorePrintingPolicy(); } +}; + void Sema::EmitCurrentDiagnostic(unsigned DiagID) { // FIXME: It doesn't make sense to me that DiagID is an incoming argument here // and yet we also use the current diag ID on the DiagnosticsEngine. This has @@ -1284,8 +1295,9 @@ } } - // Set up the context's printing policy based on our current state. - Context.setPrintingPolicy(getPrintingPolicy()); + // Copy the diagnostic printing policy over the ASTContext printing policy, + // and then restore it after emitting the diagnostic. + DiagPrintingPolicyRAII DiagPrintingPolicy(*this); // Emit the diagnostic. if (!Diags.EmitCurrentDiagnostic()) Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -7596,7 +7596,7 @@ SmallString<128> sizeString; llvm::raw_svector_ostream OS(sizeString); OS << "sizeof("; - DstArg->printPretty(OS, nullptr, getPrintingPolicy()); + DstArg->printPretty(OS, nullptr, getDiagPrintingPolicy()); OS << ")"; Diag(OriginalSizeArg->getLocStart(), diag::note_strlcpycat_wrong_size) @@ -7697,10 +7697,10 @@ SmallString<128> sizeString; llvm::raw_svector_ostream OS(sizeString); OS << "sizeof("; - DstArg->printPretty(OS, nullptr, getPrintingPolicy()); + DstArg->printPretty(OS, nullptr, getDiagPrintingPolicy()); OS << ") - "; OS << "strlen("; - DstArg->printPretty(OS, nullptr, getPrintingPolicy()); + DstArg->printPretty(OS, nullptr, getDiagPrintingPolicy()); OS << ") - 1"; Diag(SL, diag::note_strncat_wrong_size) @@ -10053,7 +10053,7 @@ bool IsParam = isa(NonnullAttr); std::string Str; llvm::raw_string_ostream S(Str); - E->printPretty(S, nullptr, getPrintingPolicy()); + E->printPretty(S, nullptr, getDiagPrintingPolicy()); unsigned DiagID = IsCompare ? diag::warn_nonnull_expr_compare : diag::warn_cast_nonnull_to_bool; Diag(E->getExprLoc(), DiagID) << IsParam << S.str() @@ -10130,7 +10130,7 @@ // Pretty print the expression for the diagnostic. std::string Str; llvm::raw_string_ostream S(Str); - E->printPretty(S, nullptr, getPrintingPolicy()); + E->printPretty(S, nullptr, getDiagPrintingPolicy()); unsigned DiagID = IsCompare ? diag::warn_null_pointer_compare : diag::warn_impcast_pointer_to_bool; Index: lib/Sema/SemaCodeComplete.cpp =================================================================== --- lib/Sema/SemaCodeComplete.cpp +++ lib/Sema/SemaCodeComplete.cpp @@ -1514,7 +1514,7 @@ static PrintingPolicy getCompletionPrintingPolicy(const ASTContext &Context, const Preprocessor &PP) { - PrintingPolicy Policy = Sema::getPrintingPolicy(Context, PP); + PrintingPolicy Policy = Sema::getDiagPrintingPolicy(Context, PP); Policy.AnonymousTagLocations = false; Policy.SuppressStrongLifetime = true; Policy.SuppressUnwrittenScope = true; Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -11287,7 +11287,7 @@ const char *PrevSpec; unsigned DiagID; DS.SetTypeSpecType(DeclSpec::TST_auto, IdentLoc, PrevSpec, DiagID, - getPrintingPolicy()); + getDiagPrintingPolicy()); Declarator D(DS, DeclaratorContext::ForContext); D.SetIdentifier(Ident, IdentLoc); Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -8514,7 +8514,7 @@ } void check(SourceLocation SpecLoc, DeclSpec::TST Spec) { return check(SpecLoc, - DeclSpec::getSpecifierName(Spec, S.getPrintingPolicy())); + DeclSpec::getSpecifierName(Spec, S.getDiagPrintingPolicy())); } void check(SourceLocation SpecLoc, const char *Spec) { if (SpecLoc.isInvalid()) return; @@ -13580,7 +13580,7 @@ SmallString<256> MsgBuffer; llvm::raw_svector_ostream Msg(MsgBuffer); if (AssertMessage) - AssertMessage->printPretty(Msg, nullptr, getPrintingPolicy()); + AssertMessage->printPretty(Msg, nullptr, getDiagPrintingPolicy()); Expr *InnerCond = nullptr; std::string InnerCondDescription; Index: lib/Sema/SemaExceptionSpec.cpp =================================================================== --- lib/Sema/SemaExceptionSpec.cpp +++ lib/Sema/SemaExceptionSpec.cpp @@ -356,8 +356,8 @@ OnFirstException = false; else OS << ", "; - - OS << E.getAsString(getPrintingPolicy()); + + OS << E.getAsString(getDiagPrintingPolicy()); } OS << ")"; break; @@ -370,7 +370,8 @@ case EST_ComputedNoexcept: OS << "noexcept("; assert(OldProto->getNoexceptExpr() != nullptr && "Expected non-null Expr"); - OldProto->getNoexceptExpr()->printPretty(OS, nullptr, getPrintingPolicy()); + OldProto->getNoexceptExpr()->printPretty(OS, nullptr, + getDiagPrintingPolicy()); OS << ")"; break; Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -3511,7 +3511,7 @@ } if (!IsDelete) { std::string TypeStr; - ClassType.getAsStringInternal(TypeStr, getPrintingPolicy()); + ClassType.getAsStringInternal(TypeStr, getDiagPrintingPolicy()); Diag(DtorLoc, diag::note_delete_non_virtual) << FixItHint::CreateInsertion(DtorLoc, TypeStr + "::"); } Index: lib/Sema/SemaLookup.cpp =================================================================== --- lib/Sema/SemaLookup.cpp +++ lib/Sema/SemaLookup.cpp @@ -4202,7 +4202,7 @@ std::string NewQualified = TC.getAsString(SemaRef.getLangOpts()); std::string OldQualified; llvm::raw_string_ostream OldOStream(OldQualified); - SS->getScopeRep()->print(OldOStream, SemaRef.getPrintingPolicy()); + SS->getScopeRep()->print(OldOStream, SemaRef.getDiagPrintingPolicy()); OldOStream << Typo->getName(); // If correction candidate would be an identical written qualified // identifer, then the existing CXXScopeSpec probably included a Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -5546,7 +5546,7 @@ // conversion; use it. QualType ConvTy = Conversion->getConversionType().getNonReferenceType(); std::string TypeStr; - ConvTy.getAsStringInternal(TypeStr, SemaRef.getPrintingPolicy()); + ConvTy.getAsStringInternal(TypeStr, SemaRef.getDiagPrintingPolicy()); Converter.diagnoseExplicitConv(SemaRef, Loc, T, ConvTy) << FixItHint::CreateInsertion(From->getLocStart(), Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -3012,7 +3012,7 @@ std::string Description; { llvm::raw_string_ostream Out(Description); - FailedCond->printPretty(Out, nullptr, getPrintingPolicy()); + FailedCond->printPretty(Out, nullptr, getDiagPrintingPolicy()); } return { FailedCond, Description }; } @@ -9821,7 +9821,7 @@ } Out << " = "; - Args[I].print(getPrintingPolicy(), Out); + Args[I].print(getDiagPrintingPolicy(), Out); } Out << ']'; Index: lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiate.cpp +++ lib/Sema/SemaTemplateInstantiate.cpp @@ -505,7 +505,7 @@ llvm::raw_svector_ostream OS(TemplateArgsStr); Template->printName(OS); printTemplateArgumentList(OS, Active->template_arguments(), - getPrintingPolicy()); + getDiagPrintingPolicy()); Diags.Report(Active->PointOfInstantiation, diag::note_default_arg_instantiation_here) << OS.str() @@ -571,7 +571,7 @@ llvm::raw_svector_ostream OS(TemplateArgsStr); FD->printName(OS); printTemplateArgumentList(OS, Active->template_arguments(), - getPrintingPolicy()); + getDiagPrintingPolicy()); Diags.Report(Active->PointOfInstantiation, diag::note_default_function_arg_instantiation_here) << OS.str() Index: test/Misc/ast-print-bool.c =================================================================== --- /dev/null +++ test/Misc/ast-print-bool.c @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -verify -ast-print %s -xc -DDEF_BOOL_CBOOL \ +// RUN: | FileCheck %s --check-prefixes=BOOL-AS-CBOOL,CBOOL +// +// RUN: %clang_cc1 -verify -ast-print %s -xc -DDEF_BOOL_CBOOL -DDIAG \ +// RUN: | FileCheck %s --check-prefixes=BOOL-AS-CBOOL,CBOOL +// +// RUN: %clang_cc1 -verify -ast-print %s -xc -DDEF_BOOL_INT \ +// RUN: | FileCheck %s --check-prefixes=BOOL-AS-INT,CBOOL +// +// RUN: %clang_cc1 -verify -ast-print %s -xc -DDEF_BOOL_INT -DDIAG \ +// RUN: | FileCheck %s --check-prefixes=BOOL-AS-INT,CBOOL +// +// RUN: %clang_cc1 -verify -ast-print %s -xc++ \ +// RUN: | FileCheck %s --check-prefixes=BOOL-AS-BOOL +// +// RUN: %clang_cc1 -verify -ast-print %s -xc++ -DDIAG \ +// RUN: | FileCheck %s --check-prefixes=BOOL-AS-BOOL + +#if DEF_BOOL_CBOOL +# define bool _Bool +#elif DEF_BOOL_INT +# define bool int +#endif + +// BOOL-AS-CBOOL: _Bool i; +// BOOL-AS-INT: int i; +// BOOL-AS-BOOL: bool i; +bool i; + +#ifndef __cplusplus +// CBOOL: _Bool j; +_Bool j; +#endif + +// Induce a diagnostic (and verify we actually managed to do so), which used to +// permanently alter the -ast-print printing policy for _Bool. How bool is +// defined by the preprocessor is examined only once per compilation, when the +// diagnostic is emitted, and it used to affect the entirety of -ast-print, so +// test only one definition of bool per compilation. +#if DIAG +void fn() { 1; } // expected-warning {{expression result unused}} +#else +// expected-no-diagnostics +#endif