diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Frontend/FrontendActions.cpp | 153 | ||||
-rw-r--r-- | clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp | 9 | ||||
-rw-r--r-- | clang/lib/Parse/ParseAST.cpp | 12 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 19 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 9 |
8 files changed, 205 insertions, 4 deletions
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index b107f65adf1..95fd1665b40 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1358,6 +1358,8 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ProgramAction = frontend::PrintPreamble; break; case OPT_E: Opts.ProgramAction = frontend::PrintPreprocessedInput; break; + case OPT_templight_dump: + Opts.ProgramAction = frontend::TemplightDump; break; case OPT_rewrite_macros: Opts.ProgramAction = frontend::RewriteMacros; break; case OPT_rewrite_objc: @@ -2620,6 +2622,7 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { case frontend::RewriteObjC: case frontend::RewriteTest: case frontend::RunAnalysis: + case frontend::TemplightDump: case frontend::MigrateSource: return false; diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index ffa5b410d2d..4a7e6f33974 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -18,17 +18,36 @@ #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" +#include "clang/Sema/TemplateInstCallback.h" #include "clang/Serialization/ASTReader.h" #include "clang/Serialization/ASTWriter.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/YAMLTraits.h" #include <memory> #include <system_error> using namespace clang; +namespace { +CodeCompleteConsumer *GetCodeCompletionConsumer(CompilerInstance &CI) { + return CI.hasCodeCompletionConsumer() ? &CI.getCodeCompletionConsumer() + : nullptr; +} + +void EnsureSemaIsCreated(CompilerInstance &CI, FrontendAction &Action) { + if (Action.hasCodeCompletionSupport() && + !CI.getFrontendOpts().CodeCompletionAt.FileName.empty()) + CI.createCodeCompletionConsumer(); + + if (!CI.hasSema()) + CI.createSema(Action.getTranslationUnitKind(), + GetCodeCompletionConsumer(CI)); +} +} // namespace + //===----------------------------------------------------------------------===// // Custom Actions //===----------------------------------------------------------------------===// @@ -262,6 +281,140 @@ void VerifyPCHAction::ExecuteAction() { } namespace { +struct TemplightEntry { + std::string Name; + std::string Kind; + std::string Event; + std::string DefinitionLocation; + std::string PointOfInstantiation; +}; +} // namespace + +namespace llvm { +namespace yaml { +template <> struct MappingTraits<TemplightEntry> { + static void mapping(IO &io, TemplightEntry &fields) { + io.mapRequired("name", fields.Name); + io.mapRequired("kind", fields.Kind); + io.mapRequired("event", fields.Event); + io.mapRequired("orig", fields.DefinitionLocation); + io.mapRequired("poi", fields.PointOfInstantiation); + } +}; +} // namespace yaml +} // namespace llvm + +namespace { +class DefaultTemplateInstCallback : public TemplateInstantiationCallback { + using CodeSynthesisContext = Sema::CodeSynthesisContext; + +public: + virtual void initialize(const Sema &) {} + + virtual void finalize(const Sema &) {} + + virtual void atTemplateBegin(const Sema &TheSema, + const CodeSynthesisContext &Inst) override { + displayTemplightEntry<true>(llvm::outs(), TheSema, Inst); + } + + virtual void atTemplateEnd(const Sema &TheSema, + const CodeSynthesisContext &Inst) override { + displayTemplightEntry<false>(llvm::outs(), TheSema, Inst); + } + +private: + static std::string toString(CodeSynthesisContext::SynthesisKind Kind) { + switch (Kind) { + case CodeSynthesisContext::TemplateInstantiation: + return "TemplateInstantiation"; + case CodeSynthesisContext::DefaultTemplateArgumentInstantiation: + return "DefaultTemplateArgumentInstantiation"; + case CodeSynthesisContext::DefaultFunctionArgumentInstantiation: + return "DefaultFunctionArgumentInstantiation"; + case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution: + return "ExplicitTemplateArgumentSubstitution"; + case CodeSynthesisContext::DeducedTemplateArgumentSubstitution: + return "DeducedTemplateArgumentSubstitution"; + case CodeSynthesisContext::PriorTemplateArgumentSubstitution: + return "PriorTemplateArgumentSubstitution"; + case CodeSynthesisContext::DefaultTemplateArgumentChecking: + return "DefaultTemplateArgumentChecking"; + case CodeSynthesisContext::ExceptionSpecInstantiation: + return "ExceptionSpecInstantiation"; + case CodeSynthesisContext::DeclaringSpecialMember: + return "DeclaringSpecialMember"; + case CodeSynthesisContext::DefiningSynthesizedFunction: + return "DefiningSynthesizedFunction"; + case CodeSynthesisContext::Memoization: + return "Memoization"; + } + return ""; + } + + template <bool BeginInstantiation> + static void displayTemplightEntry(llvm::raw_ostream &Out, const Sema &TheSema, + const CodeSynthesisContext &Inst) { + std::string YAML; + { + llvm::raw_string_ostream OS(YAML); + llvm::yaml::Output YO(OS); + TemplightEntry Entry = + getTemplightEntry<BeginInstantiation>(TheSema, Inst); + llvm::yaml::EmptyContext Context; + llvm::yaml::yamlize(YO, Entry, true, Context); + } + Out << "---" << YAML << "\n"; + } + + template <bool BeginInstantiation> + static TemplightEntry getTemplightEntry(const Sema &TheSema, + const CodeSynthesisContext &Inst) { + TemplightEntry Entry; + Entry.Kind = toString(Inst.Kind); + Entry.Event = BeginInstantiation ? "Begin" : "End"; + if (auto *NamedTemplate = dyn_cast_or_null<NamedDecl>(Inst.Entity)) { + llvm::raw_string_ostream OS(Entry.Name); + NamedTemplate->getNameForDiagnostic(OS, TheSema.getLangOpts(), true); + const PresumedLoc DefLoc = + TheSema.getSourceManager().getPresumedLoc(Inst.Entity->getLocation()); + if(!DefLoc.isInvalid()) + Entry.DefinitionLocation = std::string(DefLoc.getFilename()) + ":" + + std::to_string(DefLoc.getLine()) + ":" + + std::to_string(DefLoc.getColumn()); + } + const PresumedLoc PoiLoc = + TheSema.getSourceManager().getPresumedLoc(Inst.PointOfInstantiation); + if (!PoiLoc.isInvalid()) { + Entry.PointOfInstantiation = std::string(PoiLoc.getFilename()) + ":" + + std::to_string(PoiLoc.getLine()) + ":" + + std::to_string(PoiLoc.getColumn()); + } + return Entry; + } +}; +} // namespace + +std::unique_ptr<ASTConsumer> +TemplightDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { + return llvm::make_unique<ASTConsumer>(); +} + +void TemplightDumpAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + + // This part is normally done by ASTFrontEndAction, but needs to happen + // before Templight observers can be created + // FIXME: Move the truncation aspect of this into Sema, we delayed this till + // here so the source manager would be initialized. + EnsureSemaIsCreated(CI, *this); + + CI.getSema().TemplateInstCallbacks.push_back( + llvm::make_unique<DefaultTemplateInstCallback>()); + ASTFrontendAction::ExecuteAction(); +} + +namespace { /// \brief AST reader listener that dumps module information for a module /// file. class DumpModuleInfoListener : public ASTReaderListener { diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 4167e1fe20b..59f30d5c306 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -32,6 +32,8 @@ using namespace clang; using namespace llvm::opt; +namespace clang { + static std::unique_ptr<FrontendAction> CreateFrontendBaseAction(CompilerInstance &CI) { using namespace clang::frontend; @@ -63,6 +65,7 @@ CreateFrontendBaseAction(CompilerInstance &CI) { case ParseSyntaxOnly: return llvm::make_unique<SyntaxOnlyAction>(); case ModuleFileInfo: return llvm::make_unique<DumpModuleInfoAction>(); case VerifyPCH: return llvm::make_unique<VerifyPCHAction>(); + case TemplightDump: return llvm::make_unique<TemplightDumpAction>(); case PluginAction: { for (FrontendPluginRegistry::iterator it = @@ -122,7 +125,7 @@ CreateFrontendBaseAction(CompilerInstance &CI) { #endif } -static std::unique_ptr<FrontendAction> +std::unique_ptr<FrontendAction> CreateFrontendAction(CompilerInstance &CI) { // Create the underlying action. std::unique_ptr<FrontendAction> Act = CreateFrontendBaseAction(CI); @@ -173,7 +176,7 @@ CreateFrontendAction(CompilerInstance &CI) { return Act; } -bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) { +bool ExecuteCompilerInvocation(CompilerInstance *Clang) { // Honor -help. if (Clang->getFrontendOpts().ShowHelp) { std::unique_ptr<OptTable> Opts = driver::createDriverOptTable(); @@ -254,3 +257,5 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) { BuryPointer(std::move(Act)); return Success; } + +} //namespace clang diff --git a/clang/lib/Parse/ParseAST.cpp b/clang/lib/Parse/ParseAST.cpp index d018d4c08ed..354b3800791 100644 --- a/clang/lib/Parse/ParseAST.cpp +++ b/clang/lib/Parse/ParseAST.cpp @@ -21,6 +21,7 @@ #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaConsumer.h" +#include "clang/Sema/TemplateInstCallback.h" #include "llvm/Support/CrashRecoveryContext.h" #include <cstdio> #include <memory> @@ -121,6 +122,10 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { bool OldCollectStats = PrintStats; std::swap(OldCollectStats, S.CollectStats); + // Initialize the template instantiation observer chain. + // FIXME: See note on "finalize" below. + initialize(S.TemplateInstCallbacks, S); + ASTConsumer *Consumer = &S.getASTConsumer(); std::unique_ptr<Parser> ParseOP( @@ -158,6 +163,13 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { Consumer->HandleTranslationUnit(S.getASTContext()); + // Finalize the template instantiation observer chain. + // FIXME: This (and init.) should be done in the Sema class, but because + // Sema does not have a reliable "Finalize" function (it has a + // destructor, but it is not guaranteed to be called ("-disable-free")). + // So, do the initialization above and do the finalization here: + finalize(S.TemplateInstCallbacks, S); + std::swap(OldCollectStats, S.CollectStats); if (PrintStats) { llvm::errs() << "\nSTATISTICS:\n"; diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 45fd2d3249d..65183b434b1 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -37,6 +37,7 @@ #include "clang/Sema/SemaConsumer.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/TemplateDeduction.h" +#include "clang/Sema/TemplateInstCallback.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallSet.h" using namespace clang; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 313d99cf453..489d026027d 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -25,6 +25,7 @@ #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" +#include "clang/Sema/TemplateInstCallback.h" using namespace clang; using namespace sema; @@ -199,6 +200,10 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const { case DeclaringSpecialMember: case DefiningSynthesizedFunction: return false; + + // This function should never be called when Kind's value is Memoization. + case Memoization: + break; } llvm_unreachable("Invalid SynthesisKind!"); @@ -235,6 +240,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( !SemaRef.InstantiatingSpecializations .insert(std::make_pair(Inst.Entity->getCanonicalDecl(), Inst.Kind)) .second; + atTemplateBegin(SemaRef.TemplateInstCallbacks, SemaRef, Inst); } } @@ -394,8 +400,10 @@ void Sema::InstantiatingTemplate::Clear() { std::make_pair(Active.Entity, Active.Kind)); } - SemaRef.popCodeSynthesisContext(); + atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef, + SemaRef.CodeSynthesisContexts.back()); + SemaRef.popCodeSynthesisContext(); Invalid = true; } } @@ -626,7 +634,7 @@ void Sema::PrintInstantiationStack() { << cast<CXXRecordDecl>(Active->Entity) << Active->SpecialMember; break; - case CodeSynthesisContext::DefiningSynthesizedFunction: + case CodeSynthesisContext::DefiningSynthesizedFunction: { // FIXME: For synthesized members other than special members, produce a note. auto *MD = dyn_cast<CXXMethodDecl>(Active->Entity); auto CSM = MD ? getSpecialMember(MD) : CXXInvalid; @@ -637,6 +645,10 @@ void Sema::PrintInstantiationStack() { } break; } + + case CodeSynthesisContext::Memoization: + break; + } } } @@ -682,6 +694,9 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { // This happens in a context unrelated to template instantiation, so // there is no SFINAE. return None; + + case CodeSynthesisContext::Memoization: + break; } // The inner context was transparent for SFINAE. If it occurred within a diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index b8b74408cb8..15b53ca7612 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -23,6 +23,7 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Template.h" +#include "clang/Sema/TemplateInstCallback.h" using namespace clang; @@ -3648,8 +3649,10 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, assert(FunTmpl->getTemplatedDecl() == Tmpl && "Deduction from the wrong function template?"); (void) FunTmpl; + atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef, ActiveInst); ActiveInst.Kind = ActiveInstType::TemplateInstantiation; ActiveInst.Entity = New; + atTemplateBegin(SemaRef.TemplateInstCallbacks, SemaRef, ActiveInst); } } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 8219d4dbb70..8f3b359fde1 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -31,6 +31,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" +#include "clang/Sema/TemplateInstCallback.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" @@ -7565,6 +7566,14 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, diagnoseMissingImport(Loc, SuggestedDef, MissingImportKind::Definition, /*Recover*/TreatAsComplete); return !TreatAsComplete; + } else if (Def && !TemplateInstCallbacks.empty()) { + CodeSynthesisContext TempInst; + TempInst.Kind = CodeSynthesisContext::Memoization; + TempInst.Template = Def; + TempInst.Entity = Def; + TempInst.PointOfInstantiation = Loc; + atTemplateBegin(TemplateInstCallbacks, *this, TempInst); + atTemplateEnd(TemplateInstCallbacks, *this, TempInst); } return false; |