[clang] 3f03c12 - Add an attribute plugin example

John Brawn via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 25 07:34:38 PDT 2020


Author: John Brawn
Date: 2020-03-25T14:33:44Z
New Revision: 3f03c12a51be656c595301ace832c24a68601ee2

URL: https://github.com/llvm/llvm-project/commit/3f03c12a51be656c595301ace832c24a68601ee2
DIFF: https://github.com/llvm/llvm-project/commit/3f03c12a51be656c595301ace832c24a68601ee2.diff

LOG: Add an attribute plugin example

Differential Revision: https://reviews.llvm.org/D31343

Added: 
    clang/examples/Attribute/Attribute.cpp
    clang/examples/Attribute/CMakeLists.txt
    clang/test/Frontend/plugin-attribute.cpp

Modified: 
    clang/docs/ClangPlugins.rst
    clang/examples/CMakeLists.txt
    clang/test/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/clang/docs/ClangPlugins.rst b/clang/docs/ClangPlugins.rst
index 7e33ea33c0df..4194491d396a 100644
--- a/clang/docs/ClangPlugins.rst
+++ b/clang/docs/ClangPlugins.rst
@@ -110,6 +110,9 @@ attribute, are:
  * ``existsInTarget``, which checks if the attribute is permitted for the given
    target.
 
+To see a working example of an attribute plugin, see `the Attribute.cpp example
+<https://github.com/llvm/llvm-project/blob/master/clang/examples/Attribute/Attribute.cpp>`_.
+
 Putting it all together
 =======================
 

diff  --git a/clang/examples/Attribute/Attribute.cpp b/clang/examples/Attribute/Attribute.cpp
new file mode 100644
index 000000000000..04e30e1bd21b
--- /dev/null
+++ b/clang/examples/Attribute/Attribute.cpp
@@ -0,0 +1,80 @@
+//===- Attribute.cpp ------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Example clang plugin which adds an an annotation to file-scope declarations
+// with the 'example' attribute.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/Sema/ParsedAttr.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "llvm/IR/Attributes.h"
+using namespace clang;
+
+namespace {
+
+struct ExampleAttrInfo : public ParsedAttrInfo {
+  ExampleAttrInfo() {
+    // Can take an optional string argument (the check that the argument
+    // actually is a string happens in handleDeclAttribute).
+    OptArgs = 1;
+    // GNU-style __attribute__(("example")) and C++-style [[example]] and
+    // [[plugin::example]] supported.
+    Spellings.push_back({ParsedAttr::AS_GNU, "example"});
+    Spellings.push_back({ParsedAttr::AS_CXX11, "example"});
+    Spellings.push_back({ParsedAttr::AS_CXX11, "plugin::example"});
+  }
+
+  bool diagAppertainsToDecl(Sema &S, const ParsedAttr &Attr,
+                            const Decl *D) const override {
+    // This attribute appertains to functions only.
+    if (!isa<FunctionDecl>(D)) {
+      S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type_str)
+        << Attr << "functions";
+      return false;
+    }
+    return true;
+  }
+
+  AttrHandling handleDeclAttribute(Sema &S, Decl *D,
+                                   const ParsedAttr &Attr) const override {
+    // Check if the decl is at file scope.
+    if (!D->getDeclContext()->isFileContext()) {
+      unsigned ID = S.getDiagnostics().getCustomDiagID(
+          DiagnosticsEngine::Error,
+          "'example' attribute only allowed at file scope");
+      S.Diag(Attr.getLoc(), ID);
+      return AttributeNotApplied;
+    }
+    // Check if we have an optional string argument.
+    StringRef Str = "";
+    if (Attr.getNumArgs() > 0) {
+      Expr *ArgExpr = Attr.getArgAsExpr(0);
+      StringLiteral *Literal =
+          dyn_cast<StringLiteral>(ArgExpr->IgnoreParenCasts());
+      if (Literal) {
+        Str = Literal->getString();
+      } else {
+        S.Diag(ArgExpr->getExprLoc(), diag::err_attribute_argument_type)
+            << Attr.getAttrName() << AANT_ArgumentString;
+        return AttributeNotApplied;
+      }
+    }
+    // Attach an annotate attribute to the Decl.
+    D->addAttr(AnnotateAttr::Create(S.Context, "example(" + Str.str() + ")",
+                                    Attr.getRange()));
+    return AttributeApplied;
+  }
+};
+
+} // namespace
+
+static ParsedAttrInfoRegistry::Add<ExampleAttrInfo> X("example", "");

diff  --git a/clang/examples/Attribute/CMakeLists.txt b/clang/examples/Attribute/CMakeLists.txt
new file mode 100644
index 000000000000..19323bb0962b
--- /dev/null
+++ b/clang/examples/Attribute/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_llvm_library(Attribute MODULE Attribute.cpp PLUGIN_TOOL clang)
+
+if(LLVM_ENABLE_PLUGINS AND (WIN32 OR CYGWIN))
+  target_link_libraries(AnnotateFunctions ${cmake_2_8_12_PRIVATE}
+    clangAST
+    clangBasic
+    clangFrontend
+    clangLex
+    LLVMSupport
+    )
+endif()

diff  --git a/clang/examples/CMakeLists.txt b/clang/examples/CMakeLists.txt
index e4fedf3682e8..c014b3ddfe97 100644
--- a/clang/examples/CMakeLists.txt
+++ b/clang/examples/CMakeLists.txt
@@ -6,3 +6,4 @@ endif()
 add_subdirectory(clang-interpreter)
 add_subdirectory(PrintFunctionNames)
 add_subdirectory(AnnotateFunctions)
+add_subdirectory(Attribute)

diff  --git a/clang/test/CMakeLists.txt b/clang/test/CMakeLists.txt
index 7fdc7d0be79f..d453074d7926 100644
--- a/clang/test/CMakeLists.txt
+++ b/clang/test/CMakeLists.txt
@@ -81,6 +81,7 @@ endif ()
 
 if (CLANG_BUILD_EXAMPLES)
   list(APPEND CLANG_TEST_DEPS
+    Attribute
     AnnotateFunctions
     clang-interpreter
     PrintFunctionNames

diff  --git a/clang/test/Frontend/plugin-attribute.cpp b/clang/test/Frontend/plugin-attribute.cpp
new file mode 100644
index 000000000000..571ede3dc0b1
--- /dev/null
+++ b/clang/test/Frontend/plugin-attribute.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang -fplugin=%llvmshlibdir/Attribute%pluginext -emit-llvm -S %s -o - 2>&1 | FileCheck %s --check-prefix=ATTRIBUTE
+// RUN: not %clang -fplugin=%llvmshlibdir/Attribute%pluginext -emit-llvm -DBAD_ATTRIBUTE -S %s -o - 2>&1 | FileCheck %s --check-prefix=BADATTRIBUTE
+// REQUIRES: plugins, examples
+
+void fn1a() __attribute__((example)) { }
+[[example]] void fn1b() { }
+[[plugin::example]] void fn1c() { }
+void fn2() __attribute__((example("somestring"))) { }
+// ATTRIBUTE: warning: 'example' attribute only applies to functions
+int var1 __attribute__((example("otherstring"))) = 1;
+
+// ATTRIBUTE: [[STR1_VAR:@.+]] = private unnamed_addr constant [10 x i8] c"example()\00"
+// ATTRIBUTE: [[STR2_VAR:@.+]] = private unnamed_addr constant [20 x i8] c"example(somestring)\00"
+// ATTRIBUTE: @llvm.global.annotations = {{.*}}@{{.*}}fn1a{{.*}}[[STR1_VAR]]{{.*}}@{{.*}}fn1b{{.*}}[[STR1_VAR]]{{.*}}@{{.*}}fn1c{{.*}}[[STR1_VAR]]{{.*}}@{{.*}}fn2{{.*}}[[STR2_VAR]]
+
+#ifdef BAD_ATTRIBUTE
+class Example {
+  // BADATTRIBUTE: error: 'example' attribute only allowed at file scope
+  void __attribute__((example)) fn3();
+};
+// BADATTRIBUTE: error: 'example' attribute requires a string
+void fn4() __attribute__((example(123))) { }
+// BADATTRIBUTE: error: 'example' attribute takes no more than 1 argument
+void fn5() __attribute__((example("a","b"))) { }
+#endif


        


More information about the cfe-commits mailing list