Add a PragmaHandler Registry for plugins to add PragmaHandlers to
authorJohn Brawn <john.brawn@arm.com>
Mon, 4 Apr 2016 14:22:58 +0000 (14:22 +0000)
committerJohn Brawn <john.brawn@arm.com>
Mon, 4 Apr 2016 14:22:58 +0000 (14:22 +0000)
This allows plugins which add AST passes to also define pragmas to do things
like only enable certain behaviour of the AST pass in files where a certain
pragma is used.

Differential Revision: http://reviews.llvm.org/D18319

llvm-svn: 265295

clang/docs/ClangPlugins.rst
clang/examples/AnnotateFunctions/AnnotateFunctions.cpp
clang/include/clang/Lex/Preprocessor.h
clang/lib/Lex/Pragma.cpp
clang/test/Frontend/plugin-annotate-functions.c

index f83bb66..1b81bde 100644 (file)
@@ -43,6 +43,26 @@ register a plugin in a library, use ``FrontendPluginRegistry::Add<>``:
 
   static FrontendPluginRegistry::Add<MyPlugin> 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<ExamplePragmaHandler> Y("example_pragma","example pragma description");
+
 Putting it all together
 =======================
 
index f2e7322..375f18f 100644 (file)
@@ -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<FunctionDecl>(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<AnnotateFunctionsAction>
 X("annotate-fns", "annotate functions");
+
+static PragmaHandlerRegistry::Add<PragmaAnnotateHandler>
+Y("enable_annotate","enable annotation");
index d8e6171..f7a9ea9 100644 (file)
@@ -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 <memory>
 #include <vector>
 
@@ -1937,6 +1938,9 @@ public:
   virtual bool HandleComment(Preprocessor &PP, SourceRange Comment) = 0;
 };
 
+/// \brief Registry of pragma handlers added by plugins
+typedef llvm::Registry<PragmaHandler> PragmaHandlerRegistry;
+
 }  // end namespace clang
 
 #endif
index ff10acc..1819f4f 100644 (file)
@@ -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
index 1d7b79b..b8baf7c 100644 (file)
@@ -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