diff --git a/clang/docs/ClangPlugins.rst b/clang/docs/ClangPlugins.rst index f83bb666a630..1b81bdeb7ac1 100644 --- a/clang/docs/ClangPlugins.rst +++ b/clang/docs/ClangPlugins.rst @@ -43,6 +43,26 @@ register a plugin in a library, use ``FrontendPluginRegistry::Add<>``: static FrontendPluginRegistry::Add X("my-plugin-name", "my plugin description"); +Defining pragmas +================ + +Plugins can also define pragmas by declaring a ``PragmaHandler`` and +registering it using ``PragmaHandlerRegistry::Add<>``: + +.. code-block:: c++ + + // Define a pragma handler for #pragma example_pragma + class ExamplePragmaHandler : public PragmaHandler { + public: + ExamplePragmaHandler() : PragmaHandler("example_pragma") { } + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &PragmaTok) { + // Handle the pragma + } + }; + + static PragmaHandlerRegistry::Add Y("example_pragma","example pragma description"); + Putting it all together ======================= diff --git a/clang/examples/AnnotateFunctions/AnnotateFunctions.cpp b/clang/examples/AnnotateFunctions/AnnotateFunctions.cpp index f2e7322183a9..375f18f8e09a 100644 --- a/clang/examples/AnnotateFunctions/AnnotateFunctions.cpp +++ b/clang/examples/AnnotateFunctions/AnnotateFunctions.cpp @@ -7,20 +7,29 @@ // //===----------------------------------------------------------------------===// // -// Example clang plugin which adds an annotation to every function. +// Example clang plugin which adds an annotation to every function in +// translation units that start with #pragma enable_annotate. // //===----------------------------------------------------------------------===// #include "clang/Frontend/FrontendPluginRegistry.h" #include "clang/AST/AST.h" #include "clang/AST/ASTConsumer.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/LexDiagnostic.h" using namespace clang; namespace { +static bool EnableAnnotate = false; +static bool HandledDecl = false; + class AnnotateFunctionsConsumer : public ASTConsumer { public: bool HandleTopLevelDecl(DeclGroupRef DG) override { + HandledDecl = true; + if (!EnableAnnotate) + return true; for (auto D : DG) if (FunctionDecl *FD = dyn_cast(D)) FD->addAttr(AnnotateAttr::CreateImplicit(FD->getASTContext(), @@ -46,7 +55,34 @@ public: } }; +class PragmaAnnotateHandler : public PragmaHandler { +public: + PragmaAnnotateHandler() : PragmaHandler("enable_annotate") { } + + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &PragmaTok) override { + + Token Tok; + PP.LexUnexpandedToken(Tok); + if (Tok.isNot(tok::eod)) + PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma"; + + if (HandledDecl) { + DiagnosticsEngine &D = PP.getDiagnostics(); + unsigned ID = D.getCustomDiagID( + DiagnosticsEngine::Error, + "#pragma enable_annotate not allowed after declarations"); + D.Report(PragmaTok.getLocation(), ID); + } + + EnableAnnotate = true; + } +}; + } static FrontendPluginRegistry::Add X("annotate-fns", "annotate functions"); + +static PragmaHandlerRegistry::Add +Y("enable_annotate","enable annotation"); diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index d8e61713b3f9..f7a9ea951825 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -32,6 +32,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/Registry.h" #include #include @@ -1937,6 +1938,9 @@ public: virtual bool HandleComment(Preprocessor &PP, SourceRange Comment) = 0; }; +/// \brief Registry of pragma handlers added by plugins +typedef llvm::Registry PragmaHandlerRegistry; + } // end namespace clang #endif diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index ff10acc6adca..1819f4f06bc5 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -1490,6 +1490,13 @@ void Preprocessor::RegisterBuiltinPragmas() { AddPragmaHandler(new PragmaRegionHandler("region")); AddPragmaHandler(new PragmaRegionHandler("endregion")); } + + // Pragmas added by plugins + for (PragmaHandlerRegistry::iterator it = PragmaHandlerRegistry::begin(), + ie = PragmaHandlerRegistry::end(); + it != ie; ++it) { + AddPragmaHandler(it->instantiate().release()); + } } /// Ignore all pragmas, useful for modes such as -Eonly which would otherwise diff --git a/clang/test/Frontend/plugin-annotate-functions.c b/clang/test/Frontend/plugin-annotate-functions.c index 1d7b79bf6ee9..b8baf7ce77ee 100644 --- a/clang/test/Frontend/plugin-annotate-functions.c +++ b/clang/test/Frontend/plugin-annotate-functions.c @@ -1,7 +1,25 @@ -// RUN: %clang -fplugin=%llvmshlibdir/AnnotateFunctions%pluginext -emit-llvm -S %s -o - | FileCheck %s +// RUN: %clang -fplugin=%llvmshlibdir/AnnotateFunctions%pluginext -emit-llvm -DPRAGMA_ON -S %s -o - | FileCheck %s --check-prefix=PRAGMA +// RUN: %clang -fplugin=%llvmshlibdir/AnnotateFunctions%pluginext -emit-llvm -S %s -o - | FileCheck %s --check-prefix=NOPRAGMA +// RUN: not %clang -fplugin=%llvmshlibdir/AnnotateFunctions%pluginext -emit-llvm -DBAD_PRAGMA -S %s -o - 2>&1 | FileCheck %s --check-prefix=BADPRAGMA // REQUIRES: plugins, examples -// CHECK: [[STR_VAR:@.+]] = private unnamed_addr constant [19 x i8] c"example_annotation\00" -// CHECK: @llvm.global.annotations = {{.*}}@fn1{{.*}}[[STR_VAR]]{{.*}}@fn2{{.*}}[[STR_VAR]] +#ifdef PRAGMA_ON +#pragma enable_annotate +#endif + +// BADPRAGMA: warning: extra tokens at end of #pragma directive +#ifdef BAD_PRAGMA +#pragma enable_annotate something +#endif + +// PRAGMA: [[STR_VAR:@.+]] = private unnamed_addr constant [19 x i8] c"example_annotation\00" +// PRAGMA: @llvm.global.annotations = {{.*}}@fn1{{.*}}[[STR_VAR]]{{.*}}@fn2{{.*}}[[STR_VAR]] +// NOPRAGMA-NOT: [[STR_VAR:@.+]] = private unnamed_addr constant [19 x i8] c"example_annotation\00" +// NOPRAGMA-NOT: @llvm.global.annotations = {{.*}}@fn1{{.*}}[[STR_VAR]]{{.*}}@fn2{{.*}}[[STR_VAR]] void fn1() { } void fn2() { } + +// BADPRAGMA: error: #pragma enable_annotate not allowed after declarations +#ifdef BAD_PRAGMA +#pragma enable_annotate +#endif