From 30a63fba50e0b6e0822e381685575cf84f20f353 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 19 May 2016 01:39:10 +0000 Subject: [PATCH] Make Sema::getPrintingPolicy less ridiculously expensive. This used to perform an identifier table lookup, *and* copy the LangOptions (including various std::vectors). Twice. We call this function once each time we start parsing a declaration specifier sequence, and once for each call to Sema::Diag. This reduces the compile time for a sample .c file from the linux kernel by 20%. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@270009 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 10 +++++ include/clang/AST/PrettyPrinter.h | 42 +++++++++++++++++---- lib/AST/DeclarationName.cpp | 27 +++++-------- lib/AST/StmtPrinter.cpp | 6 +-- lib/AST/TypePrinter.cpp | 22 +++++------ lib/Parse/ParseDecl.cpp | 2 +- lib/Sema/Sema.cpp | 9 +++-- lib/Sema/SemaCodeComplete.cpp | 1 - test/Analysis/initializers-cfg-output.cpp | 2 +- test/Analysis/temp-obj-dtors-cfg-output.cpp | 2 +- test/SemaCXX/member-pointer.cpp | 9 +++++ 11 files changed, 83 insertions(+), 49 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index b29593b73d..47f89c6361 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -243,6 +243,9 @@ class ASTContext : public RefCountedBase { QualType ObjCClassRedefinitionType; QualType ObjCSelRedefinitionType; + /// The identifier 'bool'. + mutable IdentifierInfo *BoolName = nullptr; + /// The identifier 'NSObject'. IdentifierInfo *NSObjectName = nullptr; @@ -1457,6 +1460,13 @@ public: return NSCopyingName; } + /// Retrieve the identifier 'bool'. + IdentifierInfo *getBoolName() const { + if (!BoolName) + BoolName = &Idents.get("bool"); + return BoolName; + } + IdentifierInfo *getMakeIntegerSeqName() const { if (!MakeIntegerSeqName) MakeIntegerSeqName = &Idents.get("__make_integer_seq"); diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h index df3e165c51..274df220e1 100644 --- a/include/clang/AST/PrettyPrinter.h +++ b/include/clang/AST/PrettyPrinter.h @@ -32,22 +32,35 @@ public: /// \brief Describes how types, statements, expressions, and /// declarations should be printed. +/// +/// This type is intended to be small and suitable for passing by value. +/// It is very frequently copied. struct PrintingPolicy { - /// \brief Create a default printing policy for C. + /// \brief Create a default printing policy for the specified language. PrintingPolicy(const LangOptions &LO) - : LangOpts(LO), Indentation(2), SuppressSpecifiers(false), - SuppressTagKeyword(false), + : Indentation(2), SuppressSpecifiers(false), + SuppressTagKeyword(LO.CPlusPlus), IncludeTagDefinition(false), SuppressScope(false), SuppressUnwrittenScope(false), SuppressInitializers(false), ConstantArraySizeAsWritten(false), AnonymousTagLocations(true), SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false), SuppressTemplateArgsInCXXConstructors(false), - Bool(LO.Bool), TerseOutput(false), PolishForDeclaration(false), + Bool(LO.Bool), Restrict(LO.C99), + Alignof(LO.CPlusPlus11), UnderscoreAlignof(LO.C11), + UseVoidForZeroParams(!LO.CPlusPlus), + TerseOutput(false), PolishForDeclaration(false), Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true), MSVCFormatting(false) { } - /// \brief What language we're printing. - LangOptions LangOpts; + /// \brief Adjust this printing policy for cases where it's known that + /// we're printing C++ code (for instance, if AST dumping reaches a + /// C++-only construct). This should not be used if a real LangOptions + /// object is available. + void adjustForCPlusPlus() { + SuppressTagKeyword = true; + Bool = true; + UseVoidForZeroParams = false; + } /// \brief The number of spaces to use to indent each line. unsigned Indentation : 8; @@ -143,10 +156,23 @@ struct PrintingPolicy { /// constructors. unsigned SuppressTemplateArgsInCXXConstructors : 1; - /// \brief Whether we can use 'bool' rather than '_Bool', even if the language - /// doesn't actually have 'bool' (because, e.g., it is defined as a macro). + /// \brief Whether we can use 'bool' rather than '_Bool' (even if the language + /// doesn't actually have 'bool', because, e.g., it is defined as a macro). unsigned Bool : 1; + /// \brief Whether we can use 'restrict' rather than '__restrict'. + unsigned Restrict : 1; + + /// \brief Whether we can use 'alignof' rather than '__alignof'. + unsigned Alignof : 1; + + /// \brief Whether we can use '_Alignof' rather than '__alignof'. + unsigned UnderscoreAlignof : 1; + + /// \brief Whether we should use '(void)' rather than '()' for a function + /// prototype with zero parameters. + unsigned UseVoidForZeroParams : 1; + /// \brief Provide a 'terse' output. /// /// For example, in this mode we don't print function bodies, class members, diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index 344a238922..2a988e1d22 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -135,7 +135,10 @@ int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) { static void printCXXConstructorDestructorName(QualType ClassType, raw_ostream &OS, - const PrintingPolicy &Policy) { + PrintingPolicy Policy) { + // We know we're printing C++ here. Ensure we print types properly. + Policy.adjustForCPlusPlus(); + if (const RecordType *ClassRec = ClassType->getAs()) { OS << *ClassRec->getDecl(); return; @@ -146,14 +149,7 @@ static void printCXXConstructorDestructorName(QualType ClassType, return; } } - if (!Policy.LangOpts.CPlusPlus) { - // Passed policy is the default one from operator <<, use a C++ policy. - LangOptions LO; - LO.CPlusPlus = true; - ClassType.print(OS, PrintingPolicy(LO)); - } else { - ClassType.print(OS, Policy); - } + ClassType.print(OS, Policy); } void DeclarationName::print(raw_ostream &OS, const PrintingPolicy &Policy) { @@ -206,15 +202,10 @@ void DeclarationName::print(raw_ostream &OS, const PrintingPolicy &Policy) { OS << *Rec->getDecl(); return; } - if (!Policy.LangOpts.CPlusPlus) { - // Passed policy is the default one from operator <<, use a C++ policy. - LangOptions LO; - LO.CPlusPlus = true; - LO.Bool = true; - Type.print(OS, PrintingPolicy(LO)); - } else { - Type.print(OS, Policy); - } + // We know we're printing C++ here, ensure we print 'bool' properly. + PrintingPolicy CXXPolicy = Policy; + CXXPolicy.adjustForCPlusPlus(); + Type.print(OS, CXXPolicy); return; } case DeclarationName::CXXUsingDirective: diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 0b3f908790..0aa327da85 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1397,9 +1397,9 @@ void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){ OS << "sizeof"; break; case UETT_AlignOf: - if (Policy.LangOpts.CPlusPlus) + if (Policy.Alignof) OS << "alignof"; - else if (Policy.LangOpts.C11) + else if (Policy.UnderscoreAlignof) OS << "_Alignof"; else OS << "__alignof"; @@ -1669,7 +1669,7 @@ void StmtPrinter::VisitNoInitExpr(NoInitExpr *Node) { } void StmtPrinter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *Node) { - if (Policy.LangOpts.CPlusPlus) { + if (Node->getType()->getAsCXXRecordDecl()) { OS << "/*implicit*/"; Node->getType().print(OS, Policy); OS << "()"; diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 7e04e81e8d..29a4845d4a 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -112,7 +112,8 @@ namespace { }; } -static void AppendTypeQualList(raw_ostream &OS, unsigned TypeQuals, bool C99) { +static void AppendTypeQualList(raw_ostream &OS, unsigned TypeQuals, + bool HasRestrictKeyword) { bool appendSpace = false; if (TypeQuals & Qualifiers::Const) { OS << "const"; @@ -125,7 +126,7 @@ static void AppendTypeQualList(raw_ostream &OS, unsigned TypeQuals, bool C99) { } if (TypeQuals & Qualifiers::Restrict) { if (appendSpace) OS << ' '; - if (C99) { + if (HasRestrictKeyword) { OS << "restrict"; } else { OS << "__restrict"; @@ -439,7 +440,8 @@ void TypePrinter::printConstantArrayAfter(const ConstantArrayType *T, raw_ostream &OS) { OS << '['; if (T->getIndexTypeQualifiers().hasQualifiers()) { - AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers(), Policy.LangOpts.C99); + AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers(), + Policy.Restrict); OS << ' '; } @@ -472,7 +474,7 @@ void TypePrinter::printVariableArrayAfter(const VariableArrayType *T, raw_ostream &OS) { OS << '['; if (T->getIndexTypeQualifiers().hasQualifiers()) { - AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers(), Policy.LangOpts.C99); + AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers(), Policy.Restrict); OS << ' '; } @@ -672,7 +674,7 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T, if (T->getNumParams()) OS << ", "; OS << "..."; - } else if (T->getNumParams() == 0 && !Policy.LangOpts.CPlusPlus) { + } else if (T->getNumParams() == 0 && Policy.UseVoidForZeroParams) { // Do not emit int() if we have a proto, emit 'int(void)'. OS << "void"; } @@ -746,7 +748,7 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T, if (unsigned quals = T->getTypeQuals()) { OS << ' '; - AppendTypeQualList(OS, quals, Policy.LangOpts.C99); + AppendTypeQualList(OS, quals, Policy.Restrict); } switch (T->getRefQualifier()) { @@ -947,13 +949,9 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) { bool HasKindDecoration = false; - // bool SuppressTagKeyword - // = Policy.LangOpts.CPlusPlus || Policy.SuppressTagKeyword; - // We don't print tags unless this is an elaborated type. // In C, we just assume every RecordType is an elaborated type. - if (!(Policy.LangOpts.CPlusPlus || Policy.SuppressTagKeyword || - D->getTypedefNameForAnonDecl())) { + if (!Policy.SuppressTagKeyword && !D->getTypedefNameForAnonDecl()) { HasKindDecoration = true; OS << D->getKindName(); OS << ' '; @@ -1590,7 +1588,7 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy, unsigned quals = getCVRQualifiers(); if (quals) { - AppendTypeQualList(OS, quals, Policy.LangOpts.C99); + AppendTypeQualList(OS, quals, Policy.Restrict); addSpace = true; } if (hasUnaligned()) { diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 9144528167..8a3110c515 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2661,7 +2661,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, bool AttrsLastTime = false; ParsedAttributesWithRange attrs(AttrFactory); // We use Sema's policy to get bool macros right. - const PrintingPolicy &Policy = Actions.getPrintingPolicy(); + PrintingPolicy Policy = Actions.getPrintingPolicy(); while (1) { bool isInvalid = false; bool isStorageClass = false; diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index b4692fca22..83ab247370 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -52,13 +52,14 @@ ModuleLoader &Sema::getModuleLoader() const { return PP.getModuleLoader(); } PrintingPolicy Sema::getPrintingPolicy(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. Policy.Bool = Context.getLangOpts().Bool; if (!Policy.Bool) { - if (const MacroInfo * - BoolMacro = PP.getMacroInfo(&Context.Idents.get("bool"))) { + if (const MacroInfo *BoolMacro = PP.getMacroInfo(Context.getBoolName())) { Policy.Bool = BoolMacro->isObjectLike() && - BoolMacro->getNumTokens() == 1 && - BoolMacro->getReplacementToken(0).is(tok::kw__Bool); + BoolMacro->getNumTokens() == 1 && + BoolMacro->getReplacementToken(0).is(tok::kw__Bool); } } diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 3f5afab7bf..ef14660135 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -1517,7 +1517,6 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, ResultBuilder &Results) { CodeCompletionAllocator &Allocator = Results.getAllocator(); CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo()); - PrintingPolicy Policy = getCompletionPrintingPolicy(SemaRef); typedef CodeCompletionResult Result; switch (CCC) { diff --git a/test/Analysis/initializers-cfg-output.cpp b/test/Analysis/initializers-cfg-output.cpp index db3c0fb990..deefbef077 100644 --- a/test/Analysis/initializers-cfg-output.cpp +++ b/test/Analysis/initializers-cfg-output.cpp @@ -61,7 +61,7 @@ class TestDelegating { // CHECK: 6: B([B1.5]) (Base initializer) // CHECK: 7: (CXXConstructExpr, class A) // CHECK: 8: A([B1.7]) (Base initializer) -// CHECK: 9: /*implicit*/int() +// CHECK: 9: /*implicit*/(int)0 // CHECK: 10: i([B1.9]) (Member initializer) // CHECK: 11: this // CHECK: 12: [B1.11]->i diff --git a/test/Analysis/temp-obj-dtors-cfg-output.cpp b/test/Analysis/temp-obj-dtors-cfg-output.cpp index dc10e875d3..b425d91611 100644 --- a/test/Analysis/temp-obj-dtors-cfg-output.cpp +++ b/test/Analysis/temp-obj-dtors-cfg-output.cpp @@ -1077,7 +1077,7 @@ int testConsistencyNestedNormalReturn(bool value) { // CHECK: 14: a([B1.13]) (Member initializer) // CHECK: 15: ~B() (Temporary object destructor) // CHECK: 16: ~A() (Temporary object destructor) -// CHECK: 17: /*implicit*/int() +// CHECK: 17: /*implicit*/(int)0 // CHECK: 18: b([B1.17]) (Member initializer) // CHECK: Preds (1): B2 // CHECK: Succs (1): B0 diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp index f3adb95977..ef76279c37 100644 --- a/test/SemaCXX/member-pointer.cpp +++ b/test/SemaCXX/member-pointer.cpp @@ -323,3 +323,12 @@ namespace test8 { .**(int A::**) 0; // expected-warning {{indirection of non-volatile null pointer will be deleted}} expected-note {{consider}} } } + +namespace PR27558 { + template struct A { void f(); }; + template struct B : A { + using A::f; + B() { (void)&B::f; } + }; + B b; +} -- 2.40.0