From fc298e37ab9d613b4053ad32435a15c5336c79be Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes Date: Thu, 24 Aug 2023 16:26:45 -0700 Subject: [PATCH 1/4] [CIR][ClangTidy] Change the approach to running CIR passes We previously were relying on adding a custom ASTConsumer to run the passes and generate diagnostics (e.g. lifetime checker). The problem with this approach is that it doesn't work when trying to use clang-tidy from clangd. Since clangd plays differently with ASTConsumer's, it's not possible to apply the same approach. This is mitigated by setting up a simple matcher for TranslationUnitDecl, and use ASTContext to emit CIR at `check` time. --- clang-tools-extra/clang-tidy/ClangTidy.cpp | 233 +----------------- .../clang-tidy/ClangTidyDiagnosticConsumer.h | 22 ++ .../clang-tidy/ClangTidyForceLinker.h | 2 + .../clang-tidy/cir-tidy/CIRTidy.cpp | 2 + clang-tools-extra/clang-tidy/cir/Lifetime.cpp | 177 ++++++++++++- clang-tools-extra/clang-tidy/cir/Lifetime.h | 13 +- clang/lib/CIR/CodeGen/CIRGenModule.cpp | 10 + 7 files changed, 221 insertions(+), 238 deletions(-) diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp index 421cf6be9000..1bd610360af8 100644 --- a/clang-tools-extra/clang-tidy/ClangTidy.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -20,7 +20,9 @@ #include "ClangTidyModuleRegistry.h" #include "ClangTidyProfiling.h" #include "ExpandModularHeadersPPCallbacks.h" +#ifndef CLANG_TIDY_CONFIG_H #include "clang-tidy-config.h" +#endif #include "utils/OptionsUtils.h" #include "clang/AST/ASTConsumer.h" #include "clang/ASTMatchers/ASTMatchFinder.h" @@ -49,17 +51,6 @@ #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" #endif // CLANG_TIDY_ENABLE_STATIC_ANALYZER -#if CLANG_ENABLE_CIR -#include "mlir/IR/BuiltinOps.h" -#include "mlir/IR/MLIRContext.h" -#include "mlir/Pass/Pass.h" -#include "mlir/Pass/PassManager.h" -#include "clang/AST/ASTContext.h" -#include "clang/CIR/CIRGenerator.h" -#include "clang/CIR/Dialect/Passes.h" -#include -#endif // CLANG_ENABLE_CIR - using namespace clang::ast_matchers; using namespace clang::driver; using namespace clang::tooling; @@ -104,205 +95,6 @@ class AnalyzerDiagnosticConsumer : public ento::PathDiagnosticConsumer { }; #endif // CLANG_TIDY_ENABLE_STATIC_ANALYZER -#if CLANG_ENABLE_CIR -namespace cir { - -constexpr const char *LifetimeCheckName = "cir-lifetime-check"; -struct CIROpts { - std::vector RemarksList; - std::vector HistoryList; - unsigned HistLimit; -}; - -static const char StringsDelimiter[] = ";"; - -// FIXME(cir): this function was extracted from clang::tidy::utils::options -// given that ClangTidy.cpp cannot be linked with ClangTidyUtils. -std::vector parseStringList(StringRef Option) { - Option = Option.trim().trim(StringsDelimiter); - if (Option.empty()) - return {}; - std::vector Result; - Result.reserve(Option.count(StringsDelimiter) + 1); - StringRef Cur; - while (std::tie(Cur, Option) = Option.split(StringsDelimiter), - !Option.empty()) { - Cur = Cur.trim(); - if (!Cur.empty()) - Result.push_back(Cur); - } - Cur = Cur.trim(); - if (!Cur.empty()) - Result.push_back(Cur); - return Result; -} - -class CIRASTConsumer : public ASTConsumer { -public: - CIRASTConsumer(CompilerInstance &CI, StringRef inputFile, - clang::tidy::ClangTidyContext &Context, CIROpts &cirOpts); - -private: - void Initialize(ASTContext &Context) override; - void HandleTranslationUnit(ASTContext &C) override; - bool HandleTopLevelDecl(DeclGroupRef D) override; - std::unique_ptr<::cir::CIRGenerator> Gen; - ASTContext *AstContext{nullptr}; - clang::tidy::ClangTidyContext &Context; - CIROpts cirOpts; -}; - -/// CIR AST Consumer -CIRASTConsumer::CIRASTConsumer(CompilerInstance &CI, StringRef inputFile, - clang::tidy::ClangTidyContext &Context, - CIROpts &O) - : Context(Context), cirOpts(O) { - Gen = std::make_unique<::cir::CIRGenerator>(CI.getDiagnostics(), nullptr, - CI.getCodeGenOpts()); -} - -bool CIRASTConsumer::HandleTopLevelDecl(DeclGroupRef D) { - PrettyStackTraceDecl CrashInfo(*D.begin(), SourceLocation(), - AstContext->getSourceManager(), - "CIR generation of declaration"); - Gen->HandleTopLevelDecl(D); - return true; -} - -void CIRASTConsumer::Initialize(ASTContext &Context) { - AstContext = &Context; - Gen->Initialize(Context); -} - -void CIRASTConsumer::HandleTranslationUnit(ASTContext &C) { - Gen->HandleTranslationUnit(C); - Gen->verifyModule(); - - mlir::ModuleOp mlirMod = Gen->getModule(); - std::unique_ptr mlirCtx = Gen->takeContext(); - - mlir::OpPrintingFlags flags; - flags.enableDebugInfo(/*prettyForm=*/false); - - clang::SourceManager &clangSrcMgr = C.getSourceManager(); - FileID MainFileID = clangSrcMgr.getMainFileID(); - - llvm::MemoryBufferRef MainFileBuf = clangSrcMgr.getBufferOrFake(MainFileID); - std::unique_ptr FileBuf = - llvm::MemoryBuffer::getMemBuffer(MainFileBuf); - - llvm::SourceMgr llvmSrcMgr; - llvmSrcMgr.AddNewSourceBuffer(std::move(FileBuf), llvm::SMLoc()); - - class CIRTidyDiagnosticHandler : public mlir::SourceMgrDiagnosticHandler { - clang::tidy::ClangTidyContext &tidyCtx; - clang::SourceManager &clangSrcMgr; - - clang::SourceLocation getClangFromFileLineCol(mlir::FileLineColLoc loc) { - clang::SourceLocation clangLoc; - FileManager &fileMgr = clangSrcMgr.getFileManager(); - assert(loc && "not a valid mlir::FileLineColLoc"); - // The column and line may be zero to represent unknown column and/or - // unknown line/column information. - if (loc.getLine() == 0 || loc.getColumn() == 0) { - llvm_unreachable("How should we workaround this?"); - return clangLoc; - } - if (auto FE = fileMgr.getFile(loc.getFilename())) { - return clangSrcMgr.translateFileLineCol(*FE, loc.getLine(), - loc.getColumn()); - } - llvm_unreachable("location doesn't map to a file?"); - } - - clang::SourceLocation getClangSrcLoc(mlir::Location loc) { - // Direct maps into a clang::SourceLocation. - if (auto fileLoc = loc.dyn_cast()) { - return getClangFromFileLineCol(fileLoc); - } - - // FusedLoc needs to be decomposed but the canonical one - // is the first location, we handle source ranges somewhere - // else. - if (auto fileLoc = loc.dyn_cast()) { - auto locArray = fileLoc.getLocations(); - assert(locArray.size() > 0 && "expected multiple locs"); - return getClangFromFileLineCol( - locArray[0].dyn_cast()); - } - - // Many loc styles are yet to be handled. - if (auto fileLoc = loc.dyn_cast()) { - llvm_unreachable("mlir::UnknownLoc not implemented!"); - } - if (auto fileLoc = loc.dyn_cast()) { - llvm_unreachable("mlir::CallSiteLoc not implemented!"); - } - llvm_unreachable("Unknown location style"); - } - - clang::DiagnosticIDs::Level - translateToClangDiagLevel(const mlir::DiagnosticSeverity &sev) { - switch (sev) { - case mlir::DiagnosticSeverity::Note: - return clang::DiagnosticIDs::Level::Note; - case mlir::DiagnosticSeverity::Warning: - return clang::DiagnosticIDs::Level::Warning; - case mlir::DiagnosticSeverity::Error: - return clang::DiagnosticIDs::Level::Error; - case mlir::DiagnosticSeverity::Remark: - return clang::DiagnosticIDs::Level::Remark; - } - llvm_unreachable("should not get here!"); - } - - public: - void emitClangTidyDiagnostic(mlir::Diagnostic &diag) { - auto clangBeginLoc = getClangSrcLoc(diag.getLocation()); - tidyCtx.diag(LifetimeCheckName, clangBeginLoc, diag.str(), - translateToClangDiagLevel(diag.getSeverity())); - for (const auto ¬e : diag.getNotes()) { - auto clangNoteBeginLoc = getClangSrcLoc(note.getLocation()); - tidyCtx.diag(LifetimeCheckName, clangNoteBeginLoc, note.str(), - translateToClangDiagLevel(note.getSeverity())); - } - } - - CIRTidyDiagnosticHandler(llvm::SourceMgr &mgr, mlir::MLIRContext *ctx, - clang::tidy::ClangTidyContext &tidyContext, - clang::SourceManager &clangMgr, - ShouldShowLocFn &&shouldShowLocFn = {}) - : SourceMgrDiagnosticHandler(mgr, ctx, llvm::errs(), - std::move(shouldShowLocFn)), - tidyCtx(tidyContext), clangSrcMgr(clangMgr) { - setHandler( - [this](mlir::Diagnostic &diag) { emitClangTidyDiagnostic(diag); }); - } - ~CIRTidyDiagnosticHandler() = default; - }; - - // Use a custom diagnostic handler that can allow both regular printing to - // stderr but also populates clang-tidy context with diagnostics (and allow - // for instance, diagnostics to be later converted to YAML). - CIRTidyDiagnosticHandler sourceMgrHandler(llvmSrcMgr, mlirCtx.get(), Context, - clangSrcMgr); - - mlir::PassManager pm(mlirCtx.get()); - pm.addPass(mlir::createMergeCleanupsPass()); - - if (Context.isCheckEnabled(LifetimeCheckName)) - pm.addPass(mlir::createLifetimeCheckPass( - cirOpts.RemarksList, cirOpts.HistoryList, cirOpts.HistLimit, &C)); - - bool Result = !mlir::failed(pm.run(mlirMod)); - if (!Result) - llvm::report_fatal_error( - "The pass manager failed to run pass on the module!"); -} -} // namespace cir - -#endif - class ErrorReporter { public: ErrorReporter(ClangTidyContext &Context, FixBehaviour ApplyFixes, @@ -661,27 +453,6 @@ ClangTidyASTConsumerFactory::createASTConsumer( } #endif // CLANG_TIDY_ENABLE_STATIC_ANALYZER -#if CLANG_ENABLE_CIR - if (Context.isCheckEnabled(cir::LifetimeCheckName)) { - auto OV = ClangTidyCheck::OptionsView( - cir::LifetimeCheckName, Context.getOptions().CheckOptions, &Context); - // Setup CIR codegen options via config specified information. - Compiler.getCodeGenOpts().ClangIRBuildDeferredThreshold = - OV.get("CodeGenBuildDeferredThreshold", 500U); - Compiler.getCodeGenOpts().ClangIRSkipFunctionsFromSystemHeaders = - OV.get("CodeGenSkipFunctionsFromSystemHeaders", false); - - cir::CIROpts opts; - opts.RemarksList = cir::parseStringList(OV.get("RemarksList", "")); - opts.HistoryList = cir::parseStringList(OV.get("HistoryList", "all")); - opts.HistLimit = OV.get("HistLimit", 1U); - - std::unique_ptr CIRConsumer = - std::make_unique(Compiler, File, Context, opts); - Consumers.push_back(std::move(CIRConsumer)); - } -#endif // CLANG_ENABLE_CIR - return std::make_unique( std::move(Consumers), std::move(Profiling), std::move(Finder), std::move(Checks)); diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h index 15f1b672e6d4..69892add321d 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -20,6 +20,18 @@ #include "llvm/Support/Regex.h" #include +// Workaround unitests not needing to change unittests to require +// "clang-tidy-config.h" being generated. +#if __has_include("clang-tidy-config.h") +#ifndef CLANG_TIDY_CONFIG_H +#include "clang-tidy-config.h" +#endif +#endif + +#if CLANG_ENABLE_CIR +#include "clang/Basic/CodeGenOptions.h" +#endif + namespace clang { class ASTContext; @@ -136,6 +148,12 @@ class ClangTidyContext { /// Gets the language options from the AST context. const LangOptions &getLangOpts() const { return LangOpts; } +#if CLANG_ENABLE_CIR + /// Get and set CodeGenOpts + CodeGenOptions &getCodeGenOpts() { return CodeGenOpts; }; + void setCodeGenOpts(CodeGenOptions &CGO) { CodeGenOpts = CGO; } +#endif + /// Returns the name of the clang-tidy check which produced this /// diagnostic ID. std::string getCheckName(unsigned DiagnosticID) const; @@ -235,6 +253,10 @@ class ClangTidyContext { LangOptions LangOpts; +#if CLANG_ENABLE_CIR + CodeGenOptions CodeGenOpts; +#endif + ClangTidyStats Stats; std::string CurrentBuildDirectory; diff --git a/clang-tools-extra/clang-tidy/ClangTidyForceLinker.h b/clang-tools-extra/clang-tidy/ClangTidyForceLinker.h index 9926571fe989..6d3ffa743460 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyForceLinker.h +++ b/clang-tools-extra/clang-tidy/ClangTidyForceLinker.h @@ -9,7 +9,9 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYFORCELINKER_H #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANGTIDYFORCELINKER_H +#ifndef CLANG_TIDY_CONFIG_H #include "clang-tidy-config.h" +#endif #include "llvm/Support/Compiler.h" namespace clang::tidy { diff --git a/clang-tools-extra/clang-tidy/cir-tidy/CIRTidy.cpp b/clang-tools-extra/clang-tidy/cir-tidy/CIRTidy.cpp index e333e562c3cc..2a751fab2744 100644 --- a/clang-tools-extra/clang-tidy/cir-tidy/CIRTidy.cpp +++ b/clang-tools-extra/clang-tidy/cir-tidy/CIRTidy.cpp @@ -18,7 +18,9 @@ #include "CIRASTConsumer.h" #include "ClangTidyModuleRegistry.h" #include "ClangTidyProfiling.h" +#ifndef CLANG_TIDY_CONFIG_H #include "clang-tidy-config.h" +#endif #include "clang/Frontend/CompilerInstance.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Tooling/DiagnosticsYaml.h" diff --git a/clang-tools-extra/clang-tidy/cir/Lifetime.cpp b/clang-tools-extra/clang-tidy/cir/Lifetime.cpp index 93aec96271ee..e74b34825318 100644 --- a/clang-tools-extra/clang-tidy/cir/Lifetime.cpp +++ b/clang-tools-extra/clang-tidy/cir/Lifetime.cpp @@ -7,22 +7,191 @@ //===----------------------------------------------------------------------===// #include "Lifetime.h" +#include "../utils/OptionsUtils.h" +#include "mlir/IR/BuiltinOps.h" +#include "mlir/IR/MLIRContext.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Pass/PassManager.h" +#include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/DeclGroup.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/CIR/CIRGenerator.h" +#include "clang/CIR/Dialect/Passes.h" +#include "clang/Format/Format.h" +#include "clang/Frontend/ASTConsumers.h" #include "clang/Tooling/FixIt.h" +#include using namespace clang::ast_matchers; +using namespace clang; namespace clang::tidy::cir { +Lifetime::Lifetime(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), codeGenOpts(Context->getCodeGenOpts()), + cirOpts{} { + auto OV = OptionsView(Name, Context->getOptions().CheckOptions, Context); + codeGenOpts.ClangIRBuildDeferredThreshold = + OV.get("CodeGenBuildDeferredThreshold", 500U); + codeGenOpts.ClangIRSkipFunctionsFromSystemHeaders = + OV.get("CodeGenSkipFunctionsFromSystemHeaders", false); + + cirOpts.RemarksList = + utils::options::parseStringList(OV.get("RemarksList", "")); + cirOpts.HistoryList = + utils::options::parseStringList(OV.get("HistoryList", "all")); + cirOpts.HistLimit = OV.get("HistLimit", 1U); +} + void Lifetime::registerMatchers(MatchFinder *Finder) { - // Finder->addMatcher(callExpr().bind("CE"), this); - // assert(0 && "BOOM0!"); + Finder->addMatcher(translationUnitDecl(), this); +} + +void Lifetime::setupAndRunClangIRLifetimeChecker(ASTContext &astCtx) { + auto *TU = astCtx.getTranslationUnitDecl(); + // This is the hook used to build clangir and run the lifetime checker + // pass. Perhaps in the future it's possible to come up with a better + // integration story. + + // Create an instance of CIRGenerator and use it to build CIR, followed by + // MLIR module verification. + std::unique_ptr<::cir::CIRGenerator> Gen = + std::make_unique<::cir::CIRGenerator>(astCtx.getDiagnostics(), nullptr, + codeGenOpts); + Gen->Initialize(astCtx); + Gen->HandleTopLevelDecl(DeclGroupRef(TU)); + Gen->HandleTranslationUnit(astCtx); + Gen->verifyModule(); + + mlir::ModuleOp mlirMod = Gen->getModule(); + std::unique_ptr mlirCtx = Gen->takeContext(); + + mlir::OpPrintingFlags flags; + flags.enableDebugInfo(/*prettyForm=*/false); + + clang::SourceManager &clangSrcMgr = astCtx.getSourceManager(); + FileID MainFileID = clangSrcMgr.getMainFileID(); + + // Do some big dance with diagnostics here: hijack clang's diagnostics with + // MLIR one. + llvm::MemoryBufferRef MainFileBuf = clangSrcMgr.getBufferOrFake(MainFileID); + std::unique_ptr FileBuf = + llvm::MemoryBuffer::getMemBuffer(MainFileBuf); + + llvm::SourceMgr llvmSrcMgr; + llvmSrcMgr.AddNewSourceBuffer(std::move(FileBuf), llvm::SMLoc()); + + class CIRTidyDiagnosticHandler : public mlir::SourceMgrDiagnosticHandler { + ClangTidyCheck &tidyCheck; + clang::SourceManager &clangSrcMgr; + + clang::SourceLocation getClangFromFileLineCol(mlir::FileLineColLoc loc) { + clang::SourceLocation clangLoc; + FileManager &fileMgr = clangSrcMgr.getFileManager(); + assert(loc && "not a valid mlir::FileLineColLoc"); + // The column and line may be zero to represent unknown column + // and/or unknown line/column information. + if (loc.getLine() == 0 || loc.getColumn() == 0) { + llvm_unreachable("How should we workaround this?"); + return clangLoc; + } + if (auto FE = fileMgr.getFile(loc.getFilename())) { + return clangSrcMgr.translateFileLineCol(*FE, loc.getLine(), + loc.getColumn()); + } + llvm_unreachable("location doesn't map to a file?"); + } + + clang::SourceLocation getClangSrcLoc(mlir::Location loc) { + // Direct maps into a clang::SourceLocation. + if (auto fileLoc = loc.dyn_cast()) { + return getClangFromFileLineCol(fileLoc); + } + + // FusedLoc needs to be decomposed but the canonical one + // is the first location, we handle source ranges somewhere + // else. + if (auto fileLoc = loc.dyn_cast()) { + auto locArray = fileLoc.getLocations(); + assert(locArray.size() > 0 && "expected multiple locs"); + return getClangFromFileLineCol( + locArray[0].dyn_cast()); + } + + // Many loc styles are yet to be handled. + if (auto fileLoc = loc.dyn_cast()) { + llvm_unreachable("mlir::UnknownLoc not implemented!"); + } + if (auto fileLoc = loc.dyn_cast()) { + llvm_unreachable("mlir::CallSiteLoc not implemented!"); + } + llvm_unreachable("Unknown location style"); + } + + clang::DiagnosticIDs::Level + translateToClangDiagLevel(const mlir::DiagnosticSeverity &sev) { + switch (sev) { + case mlir::DiagnosticSeverity::Note: + return clang::DiagnosticIDs::Level::Note; + case mlir::DiagnosticSeverity::Warning: + return clang::DiagnosticIDs::Level::Warning; + case mlir::DiagnosticSeverity::Error: + return clang::DiagnosticIDs::Level::Error; + case mlir::DiagnosticSeverity::Remark: + return clang::DiagnosticIDs::Level::Remark; + } + llvm_unreachable("should not get here!"); + } + + public: + void emitClangTidyDiagnostic(mlir::Diagnostic &diag) { + auto clangBeginLoc = getClangSrcLoc(diag.getLocation()); + tidyCheck.diag(clangBeginLoc, diag.str(), + translateToClangDiagLevel(diag.getSeverity())); + for (const auto ¬e : diag.getNotes()) { + auto clangNoteBeginLoc = getClangSrcLoc(note.getLocation()); + tidyCheck.diag(clangNoteBeginLoc, note.str(), + translateToClangDiagLevel(note.getSeverity())); + } + } + + CIRTidyDiagnosticHandler(llvm::SourceMgr &mgr, mlir::MLIRContext *ctx, + ClangTidyCheck &tidyCheck, + clang::SourceManager &clangMgr, + ShouldShowLocFn &&shouldShowLocFn = {}) + : SourceMgrDiagnosticHandler(mgr, ctx, llvm::errs(), + std::move(shouldShowLocFn)), + tidyCheck(tidyCheck), clangSrcMgr(clangMgr) { + setHandler( + [this](mlir::Diagnostic &diag) { emitClangTidyDiagnostic(diag); }); + } + ~CIRTidyDiagnosticHandler() = default; + }; + + // Use a custom diagnostic handler that can allow both regular printing + // to stderr but also populates clang-tidy context with diagnostics (and + // allow for instance, diagnostics to be later converted to YAML). + CIRTidyDiagnosticHandler sourceMgrHandler(llvmSrcMgr, mlirCtx.get(), *this, + clangSrcMgr); + + mlir::PassManager pm(mlirCtx.get()); + + // Add pre-requisite passes to the pipeline + pm.addPass(mlir::createMergeCleanupsPass()); + + // Insert the lifetime checker. + pm.addPass(mlir::createLifetimeCheckPass( + cirOpts.RemarksList, cirOpts.HistoryList, cirOpts.HistLimit, &astCtx)); + + bool passResult = !mlir::failed(pm.run(mlirMod)); + if (!passResult) + llvm::report_fatal_error( + "The pass manager failed to run pass on the module!"); } void Lifetime::check(const MatchFinder::MatchResult &Result) { - // assert(0 && "BOOM1!"); + setupAndRunClangIRLifetimeChecker(*Result.Context); } -void Lifetime::onEndOfTranslationUnit() { assert(0 && "BOOM2!"); } } // namespace clang::tidy::cir diff --git a/clang-tools-extra/clang-tidy/cir/Lifetime.h b/clang-tools-extra/clang-tidy/cir/Lifetime.h index 684f1e09f698..fb65bbf5be80 100644 --- a/clang-tools-extra/clang-tidy/cir/Lifetime.h +++ b/clang-tools-extra/clang-tidy/cir/Lifetime.h @@ -14,13 +14,20 @@ namespace clang::tidy::cir { +struct CIROpts { + std::vector RemarksList; + std::vector HistoryList; + unsigned HistLimit; +}; class Lifetime : public ClangTidyCheck { public: - Lifetime(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} + Lifetime(StringRef Name, ClangTidyContext *Context); void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; - void onEndOfTranslationUnit() override; + void setupAndRunClangIRLifetimeChecker(ASTContext &astCtx); + + CodeGenOptions codeGenOpts; + CIROpts cirOpts; }; } // namespace clang::tidy::cir diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 8ba2a7d797f8..105197dd3c3c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -1210,6 +1210,16 @@ void CIRGenModule::buildTopLevelDecl(Decl *decl) { << decl->getDeclKindName() << "' not implemented\n"; assert(false && "Not yet implemented"); + case Decl::TranslationUnit: { + // This path is CIR only - CIRGen handles TUDecls because + // of clang-tidy checks, that operate on TU granularity. + TranslationUnitDecl *TU = cast(decl); + for (DeclContext::decl_iterator D = TU->decls_begin(), + DEnd = TU->decls_end(); + D != DEnd; ++D) + buildTopLevelDecl(*D); + return; + } case Decl::Var: case Decl::Decomposition: case Decl::VarTemplateSpecialization: From 40d031a12db98dc277380a73a4080dba8b9d4735 Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes Date: Thu, 24 Aug 2023 17:33:14 -0700 Subject: [PATCH 2/4] [CIR][ClangTidy] Remove CIR/MLIR dep from main cmakefile --- clang-tools-extra/clang-tidy/CMakeLists.txt | 83 ++++----------------- 1 file changed, 14 insertions(+), 69 deletions(-) diff --git a/clang-tools-extra/clang-tidy/CMakeLists.txt b/clang-tools-extra/clang-tidy/CMakeLists.txt index 6f49b792623e..2881f2e75d11 100644 --- a/clang-tools-extra/clang-tidy/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/CMakeLists.txt @@ -3,81 +3,26 @@ set(LLVM_LINK_COMPONENTS Support ) -if(CLANG_ENABLE_CIR) - include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/.. ) - include_directories( ${LLVM_MAIN_SRC_DIR}/../mlir/include ) - include_directories( ${CMAKE_BINARY_DIR}/tools/mlir/include ) - - get_property(dialect_libs GLOBAL PROPERTY MLIR_DIALECT_LIBS) -endif() - configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/clang-tidy-config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/clang-tidy-config.h) include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}) -if(CLANG_ENABLE_CIR) - add_clang_library(clangTidy - ClangTidy.cpp - ClangTidyCheck.cpp - ClangTidyModule.cpp - ClangTidyDiagnosticConsumer.cpp - ClangTidyOptions.cpp - ClangTidyProfiling.cpp - ExpandModularHeadersPPCallbacks.cpp - GlobList.cpp - NoLintDirectiveHandler.cpp - - DEPENDS - MLIRBuiltinLocationAttributesIncGen - MLIRCIROpsIncGen - MLIRCIREnumsGen - MLIRSymbolInterfacesIncGen +add_clang_library(clangTidy + ClangTidy.cpp + ClangTidyCheck.cpp + ClangTidyModule.cpp + ClangTidyDiagnosticConsumer.cpp + ClangTidyOptions.cpp + ClangTidyProfiling.cpp + ExpandModularHeadersPPCallbacks.cpp + GlobList.cpp + NoLintDirectiveHandler.cpp - LINK_LIBS - clangCIR - ${dialect_libs} - MLIRCIR - MLIRCIRTransforms - MLIRAffineToStandard - MLIRAnalysis - MLIRIR - MLIRLLVMCommonConversion - MLIRLLVMDialect - MLIRLLVMToLLVMIRTranslation - MLIRMemRefDialect - MLIRMemRefToLLVM - MLIRParser - MLIRPass - MLIRSideEffectInterfaces - MLIRSCFToControlFlow - MLIRFuncToLLVM - MLIRSupport - MLIRMemRefDialect - MLIRTargetLLVMIRExport - MLIRTransforms - - DEPENDS - ClangSACheckers - omp_gen - ) -else() - add_clang_library(clangTidy - ClangTidy.cpp - ClangTidyCheck.cpp - ClangTidyModule.cpp - ClangTidyDiagnosticConsumer.cpp - ClangTidyOptions.cpp - ClangTidyProfiling.cpp - ExpandModularHeadersPPCallbacks.cpp - GlobList.cpp - NoLintDirectiveHandler.cpp - - DEPENDS - ClangSACheckers - omp_gen - ) -endif() + DEPENDS + ClangSACheckers + omp_gen +) clang_target_link_libraries(clangTidy PRIVATE From e82c05c03d65e99b15e007ac034ad8bca9b1f098 Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes Date: Thu, 24 Aug 2023 20:11:36 -0700 Subject: [PATCH 3/4] [CIR][ClangTidy] Add dep to clangTidyUtils --- clang-tools-extra/clang-tidy/cir/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/clang-tools-extra/clang-tidy/cir/CMakeLists.txt b/clang-tools-extra/clang-tidy/cir/CMakeLists.txt index 5c40efc09a12..0b892f332790 100644 --- a/clang-tools-extra/clang-tidy/cir/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/cir/CMakeLists.txt @@ -19,6 +19,7 @@ add_clang_library(clangTidyCIRModule clangFrontend clangSerialization clangTidy + clangTidyUtils ${dialect_libs} MLIRCIR MLIRCIRTransforms From 08fee1e3cb093586c2f302cf75bf7e5535a90de0 Mon Sep 17 00:00:00 2001 From: Andrew Lenharth Date: Wed, 2 Aug 2023 23:43:52 -0500 Subject: [PATCH 4/4] [Backport-to-CIR][TableGen] OpInterface inheritance duplicates bases OpInterface inheritance will duplicate base interfaces, causing compilation failure. Unique the set of base interfaces. Reviewed By: rriddle, jdd Differential Revision: https://reviews.llvm.org/D156964 (cherry picked from commit d5c2204cfc9b48fc59d765422c33f98350f79dcf) CIR note: We should remove this once we do our next rebase against ToT --- mlir/lib/TableGen/Interfaces.cpp | 6 ++++++ mlir/test/mlir-tblgen/op-interface.td | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/mlir/lib/TableGen/Interfaces.cpp b/mlir/lib/TableGen/Interfaces.cpp index c1d1ba0540c3..a209b003b0f3 100644 --- a/mlir/lib/TableGen/Interfaces.cpp +++ b/mlir/lib/TableGen/Interfaces.cpp @@ -9,6 +9,7 @@ #include "mlir/TableGen/Interfaces.h" #include "llvm/ADT/FunctionExtras.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" @@ -83,6 +84,8 @@ Interface::Interface(const llvm::Record *def) : def(def) { // Initialize the interface base classes. auto *basesInit = dyn_cast(def->getValueInit("baseInterfaces")); + // Chained inheritance will produce duplicates in the base interface set. + StringSet<> basesAdded; llvm::unique_function addBaseInterfaceFn = [&](const Interface &baseInterface) { // Inherit any base interfaces. @@ -90,7 +93,10 @@ Interface::Interface(const llvm::Record *def) : def(def) { addBaseInterfaceFn(baseBaseInterface); // Add the base interface. + if (basesAdded.contains(baseInterface.getName())) + return; baseInterfaces.push_back(std::make_unique(baseInterface)); + basesAdded.insert(baseInterface.getName()); }; for (llvm::Init *init : basesInit->getValues()) addBaseInterfaceFn(Interface(cast(init)->getDef())); diff --git a/mlir/test/mlir-tblgen/op-interface.td b/mlir/test/mlir-tblgen/op-interface.td index 76467f50152c..feffe2097dbd 100644 --- a/mlir/test/mlir-tblgen/op-interface.td +++ b/mlir/test/mlir-tblgen/op-interface.td @@ -34,7 +34,18 @@ def ExtraShardDeclsInterface : OpInterface<"ExtraShardDeclsInterface"> { // DECL-NEXT: return (*static_cast(this)).someOtherMethod(); // DECL-NEXT: } -def TestInheritanceBaseInterface : OpInterface<"TestInheritanceBaseInterface"> { +def TestInheritanceMultiBaseInterface : OpInterface<"TestInheritanceMultiBaseInterface"> { + let methods = [ + InterfaceMethod< + /*desc=*/[{some function comment}], + /*retTy=*/"int", + /*methodName=*/"baz", + /*args=*/(ins "int":$input) + > + ]; +} + +def TestInheritanceBaseInterface : OpInterface<"TestInheritanceBaseInterface", [TestInheritanceMultiBaseInterface]> { let methods = [ InterfaceMethod< /*desc=*/[{some function comment}], @@ -60,6 +71,8 @@ def TestInheritanceZDerivedInterface // DECL: class TestInheritanceZDerivedInterface // DECL: struct Concept { +// DECL: const TestInheritanceMultiBaseInterface::Concept *implTestInheritanceMultiBaseInterface = nullptr; +// DECL-NOT: const TestInheritanceMultiBaseInterface::Concept // DECL: const TestInheritanceBaseInterface::Concept *implTestInheritanceBaseInterface = nullptr; // DECL: const TestInheritanceMiddleBaseInterface::Concept *implTestInheritanceMiddleBaseInterface = nullptr;