jdoerfert updated this revision to Diff 180971.
jdoerfert added a comment.

Allow to use names in the callback metadata


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55483/new/

https://reviews.llvm.org/D55483

Files:
  include/clang/AST/ASTContext.h
  include/clang/Basic/Attr.td
  include/clang/Basic/AttrDocs.td
  include/clang/Basic/Builtins.def
  include/clang/Basic/Builtins.h
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ASTContext.cpp
  lib/Basic/Builtins.cpp
  lib/CodeGen/CGOpenMPRuntime.cpp
  lib/CodeGen/CodeGenModule.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaDeclAttr.cpp
  test/Analysis/retain-release.m
  test/CodeGen/attr-callback.c
  test/CodeGen/callback_annotated.c
  test/CodeGen/callback_openmp.c
  test/CodeGen/callback_pthread_create.c
  test/CodeGenCXX/attr-callback.cpp
  test/Misc/pragma-attribute-supported-attributes-list.test
  test/OpenMP/parallel_codegen.cpp
  test/Sema/attr-callback-broken.c
  test/Sema/attr-callback.c
  test/SemaCXX/attr-callback-broken.cpp
  test/SemaCXX/attr-callback.cpp
  utils/TableGen/ClangAttrEmitter.cpp

Index: utils/TableGen/ClangAttrEmitter.cpp
===================================================================
--- utils/TableGen/ClangAttrEmitter.cpp
+++ utils/TableGen/ClangAttrEmitter.cpp
@@ -775,6 +775,11 @@
     }
   };
 
+  struct VariadicParamOrParamIdxArgument : public VariadicArgument {
+    VariadicParamOrParamIdxArgument(const Record &Arg, StringRef Attr)
+        : VariadicArgument(Arg, Attr, "int") {}
+  };
+
   // Unique the enums, but maintain the original declaration ordering.
   std::vector<StringRef>
   uniqueEnumsInOrder(const std::vector<StringRef> &enums) {
@@ -1283,6 +1288,8 @@
     Ptr = llvm::make_unique<VariadicExprArgument>(Arg, Attr);
   else if (ArgName == "VariadicParamIdxArgument")
     Ptr = llvm::make_unique<VariadicParamIdxArgument>(Arg, Attr);
+  else if (ArgName == "VariadicParamOrParamIdxArgument")
+    Ptr = llvm::make_unique<VariadicParamOrParamIdxArgument>(Arg, Attr);
   else if (ArgName == "ParamIdxArgument")
     Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "ParamIdx");
   else if (ArgName == "VariadicIdentifierArgument")
@@ -2116,6 +2123,7 @@
          llvm::StringSwitch<bool>(
              Arg->getSuperClasses().back().first->getName())
              .Case("VariadicIdentifierArgument", true)
+             .Case("VariadicParamOrParamIdxArgument", true)
              .Default(false);
 }
 
Index: test/SemaCXX/attr-callback.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/attr-callback.cpp
@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+
+// expected-no-diagnostics
+
+class C_in_class {
+#include "../Sema/attr-callback.c"
+};
+
+struct Base {
+
+  void no_args_1(void (*callback)(void));
+  __attribute__((callback(1))) void no_args_2(void (*callback)(void));
+  __attribute__((callback(callback))) void no_args_3(void (*callback)(void)) {}
+
+  __attribute__((callback(1, 0))) virtual void
+  this_tr(void (*callback)(Base *));
+
+  __attribute__((callback(1, __this, __, __this))) virtual void
+  this_unknown_this(void (*callback)(Base *, Base *, Base *));
+
+  __attribute__((callback(1))) virtual void
+  virtual_1(void (*callback)(void));
+
+  __attribute__((callback(callback))) virtual void
+  virtual_2(void (*callback)(void));
+
+  __attribute__((callback(1))) virtual void
+  virtual_3(void (*callback)(void));
+};
+
+__attribute__((callback(1))) void
+Base::no_args_1(void (*callback)(void)) {
+}
+
+void Base::no_args_2(void (*callback)(void)) {
+}
+
+struct Derived_1 : public Base {
+
+  __attribute__((callback(1, 0))) virtual void
+  this_tr(void (*callback)(Base *)) override;
+
+  __attribute__((callback(1))) virtual void
+  virtual_1(void (*callback)(void)) override {}
+
+  virtual void
+  virtual_3(void (*callback)(void)) override {}
+};
+
+struct Derived_2 : public Base {
+
+  __attribute__((callback(callback))) virtual void
+  virtual_1(void (*callback)(void)) override;
+
+  virtual void
+  virtual_2(void (*callback)(void)) override;
+
+  virtual void
+  virtual_3(void (*callback)(void)) override;
+};
+
+void Derived_2::virtual_1(void (*callback)(void)) {}
+
+__attribute__((callback(1))) void
+Derived_2::virtual_2(void (*callback)(void)) {}
+
+void Derived_2::virtual_3(void (*callback)(void)) {}
Index: test/SemaCXX/attr-callback-broken.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/attr-callback-broken.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+
+class C_in_class {
+#define HAS_THIS
+#include "../Sema/attr-callback-broken.c"
+#undef HAS_THIS
+};
Index: test/Sema/attr-callback.c
===================================================================
--- /dev/null
+++ test/Sema/attr-callback.c
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+
+// expected-no-diagnostics
+
+__attribute__((callback(1)))         void no_args(void (*callback)(void));
+__attribute__((callback(1, 2, 3)))   void args_1(void (*callback)(int, double), int a, double b);
+__attribute__((callback(2, 3, 3)))   void args_2(int a, void (*callback)(double, double), double b);
+__attribute__((callback(2, -1, -1))) void args_3(int a, void (*callback)(double, double), double b);
+
+__attribute__((callback(callback)))          void no_argsb(void (*callback)(void));
+__attribute__((callback(callback, a, 3)))    void args_1b(void (*callback)(int, double), int a, double b);
+__attribute__((callback(callback, b, b)))    void args_2b(int a, void (*callback)(double, double), double b);
+__attribute__((callback(2, __, __)))         void args_3b(int a, void (*callback)(double, double), double b);
+__attribute__((callback(callback, -1, __)))  void args_3c(int a, void (*callback)(double, double), double b);
Index: test/Sema/attr-callback-broken.c
===================================================================
--- /dev/null
+++ test/Sema/attr-callback-broken.c
@@ -0,0 +1,75 @@
+// RUN: %clang_cc1 %s -verify -fsyntax-only
+
+__attribute__((callback())) void no_callee(void (*callback)(void)); // expected-error {{no callback callee specified}}
+
+__attribute__((callback(1, 1)))    void too_many_args_1(void   (*callback)(void)) {}   // expected-error {{'callback' attribute specifies too many arguments}}
+__attribute__((callback(1, -1)))    void too_many_args_2(double (*callback)(void));     // expected-error {{'callback' attribute specifies too many arguments}}
+__attribute__((callback(1, 2, 2))) void too_many_args_3(void   (*callback)(int), int); // expected-error {{'callback' attribute specifies too many arguments}}
+
+__attribute__((callback(1, 2)))  void too_few_args_1(void (*callback)(int, int), int); // expected-error {{'callback' attribute specifies too few arguments}}
+__attribute__((callback(1)))     void too_few_args_2(int  (*callback)(int));           // expected-error {{'callback' attribute specifies too few arguments}}
+__attribute__((callback(1, -1))) void too_few_args_3(void (*callback)(int, int)) {}    // expected-error {{'callback' attribute specifies too few arguments}}
+
+__attribute__((callback(-1)))    void oob_args_1(void  (*callback)(void));     // expected-error {{invalid callback callee specified}}
+__attribute__((callback(2)))     void oob_args_2(int*  (*callback)(void)) {}   // expected-error {{'callback' argument at position 1 is out-of-bounds}}
+__attribute__((callback(1, 3)))  void oob_args_3(short (*callback)(int), int); // expected-error {{'callback' argument at position 2 is out-of-bounds}}
+__attribute__((callback(-2, 2))) void oob_args_4(void* (*callback)(int), int); // expected-error {{'callback' argument at position 1 is out-of-bounds}}
+__attribute__((callback(1, -2))) void oob_args_5(void* (*callback)(int), int); // expected-error {{'callback' argument at position 2 is out-of-bounds}}
+__attribute__((callback(1,  2))) void oob_args_6(void* (*callback)(int), ...); // expected-error {{'callback' argument at position 2 is out-of-bounds}}
+
+__attribute__((callback(1))) __attribute__((callback(1))) void multiple_cb_1(void (*callback)(void));                           // expected-error {{multiple 'callback' attributes specified}}
+__attribute__((callback(1))) __attribute__((callback(2))) void multiple_cb_2(void (*callback1)(void), void (*callback2)(void)); // expected-error {{multiple 'callback' attributes specified}}
+
+#ifdef HAS_THIS
+__attribute__((callback(0)))    void oob_args_0(void (*callback)(void)); // expected-error {{invalid callback callee specified}}
+#else
+__attribute__((callback(0)))    void oob_args_0(void (*callback)(void));        // expected-error {{'callback' argument at position 1 references unavailable implicit 'this'}}
+__attribute__((callback(1, 0))) void no_this_1(void* (*callback)(void*));       // expected-error {{'callback' argument at position 2 references unavailable implicit 'this'}}
+__attribute__((callback(1, 0))) void no_this_2(void* (*callback)(int, void*));  // expected-error {{'callback' argument at position 2 references unavailable implicit 'this'}}
+#endif
+
+// We could allow the following declarations if we at some point need to:
+
+__attribute__((callback(1, -1))) void vararg_cb_1(void (*callback)(int, ...)) {}      // expected-error {{'callback' callee shall not be variadic}}
+__attribute__((callback(1,  1))) void vararg_cb_2(void (*callback)(int, ...), int a); // expected-error {{'callback' callee shall not be variadic}}
+
+__attribute__((callback(1, -1, 1, 2, 3, 4, -1)))   void varargs_1(void (*callback)(int, ...), int a, float b, double c) {}                // expected-error {{'callback' attribute specifies too many arguments}}
+__attribute__((callback(1, -1, 4, 2, 3, 4, -1)))   void varargs_2(void (*callback)(void *, double, int, ...), int a, float b , double c); // expected-error {{'callback' attribute specifies too many arguments}}
+
+__attribute__((callback(1, -1, 1)))          void self_arg_1(void (*callback)(int, ...)) {} // expected-error {{'callback' attribute specifies too many arguments}}
+__attribute__((callback(1, -1, 1, -1, -1, 1))) void self_arg_2(void (*callback)(int, ...));   // expected-error {{'callback' attribute specifies too many arguments}}
+
+__attribute__((callback(cb)))    void unknown_name1(void (*callback)(void)) {}   // expected-error {{'callback' argument 'cb' is not a known function parameter}}
+__attribute__((callback(cb, ab))) void unknown_name2(void (*cb)(int), int a) {}  // expected-error {{'callback' argument 'ab' is not a known function parameter}}
+
+__attribute__((callback(callback, 1)))    void too_many_args_1b(void   (*callback)(void)) {}   // expected-error {{'callback' attribute specifies too many arguments}}
+__attribute__((callback(callback, __)))   void too_many_args_2b(double (*callback)(void));     // expected-error {{'callback' attribute specifies too many arguments}}
+__attribute__((callback(callback, 2, 2))) void too_many_args_3b(void   (*callback)(int), int); // expected-error {{'callback' attribute specifies too many arguments}}
+
+__attribute__((callback(callback, a)))  void too_few_args_1b(void (*callback)(int, int), int a); // expected-error {{'callback' attribute specifies too few arguments}}
+__attribute__((callback(callback)))     void too_few_args_2b(int  (*callback)(int));           // expected-error {{'callback' attribute specifies too few arguments}}
+__attribute__((callback(callback, __))) void too_few_args_3b(void (*callback)(int, int)) {}    // expected-error {{'callback' attribute specifies too few arguments}}
+
+__attribute__((callback(__)))    void oob_args_1b(void  (*callback)(void));     // expected-error {{invalid callback callee specified}}
+
+__attribute__((callback(callback))) __attribute__((callback(callback))) void multiple_cb_1b(void (*callback)(void));                           // expected-error {{multiple 'callback' attributes specified}}
+__attribute__((callback(1)))        __attribute__((callback(callback2))) void multiple_cb_2b(void (*callback1)(void), void (*callback2)(void)); // expected-error {{multiple 'callback' attributes specified}}
+
+#ifdef HAS_THIS
+__attribute__((callback(__this)))    void oob_args_0b(void (*callback)(void)); // expected-error {{invalid callback callee specified}}
+#else
+__attribute__((callback(__this)))    void oob_args_0b(void (*callback)(void));        // expected-error {{'callback' argument at position 1 references unavailable implicit 'this'}}
+__attribute__((callback(1, __this))) void no_this_1b(void* (*callback)(void*));       // expected-error {{'callback' argument at position 2 references unavailable implicit 'this'}}
+__attribute__((callback(1, __this))) void no_this_2b(void* (*callback)(int, void*));  // expected-error {{'callback' argument at position 2 references unavailable implicit 'this'}}
+#endif
+
+// We could allow the following declarations if we at some point need to:
+
+__attribute__((callback(callback, __))) void vararg_cb_1b(void (*callback)(int, ...)) {} // expected-error {{'callback' callee shall not be variadic}}
+__attribute__((callback(1,  a))) void vararg_cb_2b(void (*callback)(int, ...), int a);   // expected-error {{'callback' callee shall not be variadic}}
+
+__attribute__((callback(callback, __, callback, a, b, c, __)))   void varargs_1b(void (*callback)(int, ...), int a, float b, double c) {}                // expected-error {{'callback' attribute specifies too many arguments}}
+__attribute__((callback(1, __, c, a, b, c, -1)))   void varargs_2b(void (*callback)(void *, double, int, ...), int a, float b , double c); // expected-error {{'callback' attribute specifies too many arguments}}
+
+__attribute__((callback(1, __, callback)))          void self_arg_1b(void (*callback)(int, ...)) {} // expected-error {{'callback' attribute specifies too many arguments}}
+__attribute__((callback(callback, __, callback, __, __, callback))) void self_arg_2b(void (*callback)(int, ...));   // expected-error {{'callback' attribute specifies too many arguments}}
Index: test/OpenMP/parallel_codegen.cpp
===================================================================
--- test/OpenMP/parallel_codegen.cpp
+++ test/OpenMP/parallel_codegen.cpp
@@ -82,9 +82,9 @@
 // CHECK-DEBUG-NEXT:  }
 
 // CHECK-DAG: define linkonce_odr {{.*}}void [[FOO]]({{i32[ ]?[a-z]*}} %argc)
-// CHECK-DAG: declare {{.*}}void @__kmpc_fork_call(%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...)
+// CHECK-DAG: declare !callback ![[cbid:[0-9]+]] {{.*}}void @__kmpc_fork_call(%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...)
 // CHECK-DEBUG-DAG: define linkonce_odr void [[FOO]](i32 %argc)
-// CHECK-DEBUG-DAG: declare void @__kmpc_fork_call(%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...)
+// CHECK-DEBUG-DAG: declare !callback ![[cbid:[0-9]+]] void @__kmpc_fork_call(%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...)
 // CHECK-DEBUG-DAG:       define internal void [[OMP_OUTLINED]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i64 [[VLA_SIZE:%.+]], i32* {{.+}} [[VLA_ADDR:%[^)]+]])
 // CHECK-DEBUG-DAG:       call void [[OMP_OUTLINED_DEBUG]]
 
@@ -131,5 +131,6 @@
 
 // CHECK: attributes #[[FN_ATTRS]] = {{.+}} nounwind
 // CHECK-DEBUG: attributes #[[FN_ATTRS]] = {{.+}} nounwind
-
+// CHECK: ![[cbid]] = !{![[cbidb:[0-9]+]]}
+// CHECK: ![[cbidb]] = !{i64 2, i64 -1, i64 -1, i1 true}
 #endif
Index: test/Misc/pragma-attribute-supported-attributes-list.test
===================================================================
--- test/Misc/pragma-attribute-supported-attributes-list.test
+++ test/Misc/pragma-attribute-supported-attributes-list.test
@@ -32,6 +32,7 @@
 // CHECK-NEXT: CUDAShared (SubjectMatchRule_variable)
 // CHECK-NEXT: CXX11NoReturn (SubjectMatchRule_function)
 // CHECK-NEXT: CallableWhen (SubjectMatchRule_function_is_member)
+// CHECK-NEXT: Callback (SubjectMatchRule_function)
 // CHECK-NEXT: Capability (SubjectMatchRule_record, SubjectMatchRule_type_alias)
 // CHECK-NEXT: CarriesDependency (SubjectMatchRule_variable_is_parameter, SubjectMatchRule_objc_method, SubjectMatchRule_function)
 // CHECK-NEXT: Cold (SubjectMatchRule_function)
Index: test/CodeGenCXX/attr-callback.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/attr-callback.cpp
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
+
+struct Base {
+
+  void no_args_1(void (*callback)(void));
+  __attribute__((callback(1))) void no_args_2(void (*callback1)(void), void (*callback2)(void));
+  __attribute__((callback(callback1))) void no_args_3(void (*callback1)(void), void (*callback2)(void));
+
+  // TODO: There should probably be a warning or even an error for different
+  //       callbacks on the same method.
+  __attribute__((callback(1))) virtual void
+  virtual_1(void (*callback)(void));
+
+  __attribute__((callback(callback, __this, __, __this))) virtual void
+  this_unknown_this(void (*callback)(Base *, Base *, Base *));
+};
+
+// CHECK-DAG:      define void @_ZN4Base9no_args_1EPFvvE({{[^!]*!callback}} ![[cid0:[0-9]+]]
+__attribute__((callback(1))) void
+Base::no_args_1(void (*callback)(void)) {
+}
+
+// CHECK-DAG:      define void @_ZN4Base9no_args_2EPFvvES1_({{[^!]*!callback}} ![[cid1:[0-9]+]]
+__attribute__((callback(2))) void Base::no_args_2(void (*callback1)(void), void (*callback2)(void)) {
+}
+// CHECK-DAG:      define void @_ZN4Base9no_args_3EPFvvES1_({{[^!]*!callback}} ![[cid1]]
+__attribute__((callback(callback2))) void Base::no_args_3(void (*callback1)(void), void (*callback2)(void)) {
+}
+
+// CHECK-DAG:      define void @_ZN4Base17this_unknown_thisEPFvPS_S0_S0_E({{[^!]*!callback}} ![[cid2:[0-9]+]]
+void Base::this_unknown_this(void (*callback)(Base *, Base *, Base *)) {
+}
+
+struct Derived_1 : public Base {
+  __attribute__((callback(1))) virtual void
+  virtual_1(void (*callback)(void)) override;
+};
+
+// CHECK-DAG:      define void @_ZN9Derived_19virtual_1EPFvvE({{[^!]*!callback}} ![[cid0]]
+void Derived_1::virtual_1(void (*callback)(void)) {}
+
+struct Derived_2 : public Base {
+  void virtual_1(void (*callback)(void)) override;
+};
+
+// CHECK-DAG: define void @_ZN9Derived_29virtual_1EPFvvE
+// CHECK-NOT: !callback
+void Derived_2::virtual_1(void (*callback)(void)) {}
+
+// CHECK-DAG: ![[cid0]] = !{![[cid0b:[0-9]+]]}
+// CHECK-DAG: ![[cid0b]] = !{i64 1, i1 false}
+// CHECK-DAG: ![[cid1]] = !{![[cid1b:[0-9]+]]}
+// CHECK-DAG: ![[cid1b]] = !{i64 2, i1 false}
+// CHECK-DAG: ![[cid2]] = !{![[cid2b:[0-9]+]]}
+// CHECK-DAG: ![[cid2b]] = !{i64 1, i64 0, i64 -1, i64 0, i1 false}
Index: test/CodeGen/callback_pthread_create.c
===================================================================
--- /dev/null
+++ test/CodeGen/callback_pthread_create.c
@@ -0,0 +1,32 @@
+// RUN: %clang -O1 %s -S -c -emit-llvm -o - | FileCheck %s
+// RUN: %clang -O1 %s -S -c -emit-llvm -o - | opt -ipconstprop -S | FileCheck --check-prefix=IPCP %s
+
+// CHECK: declare !callback ![[cid:[0-9]+]] dso_local i32 @pthread_create
+// CHECK: ![[cid]] = !{![[cidb:[0-9]+]]}
+// CHECK: ![[cidb]] = !{i64 2, i64 3, i1 false}
+
+#include <pthread.h>
+
+const int GlobalVar = 0;
+
+static void *callee0(void *payload) {
+// IPCP:      define internal i8* @callee0
+// IPCP-NEXT:   entry:
+// IPCP-NEXT:     ret i8* null
+  return payload;
+}
+
+static void *callee1(void *payload) {
+// IPCP:      define internal i8* @callee1
+// IPCP-NEXT:   entry:
+// IPCP-NEXT:     ret i8* bitcast (i32* @GlobalVar to i8*)
+  return payload;
+}
+
+void foo() {
+  pthread_t MyFirstThread;
+  pthread_create(&MyFirstThread, NULL, callee0, NULL);
+
+  pthread_t MySecondThread;
+  pthread_create(&MySecondThread, NULL, callee1, (void *)&GlobalVar);
+}
Index: test/CodeGen/callback_openmp.c
===================================================================
--- /dev/null
+++ test/CodeGen/callback_openmp.c
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 %s -emit-llvm -o - | opt -ipconstprop -S | FileCheck --check-prefix=IPCP %s
+
+// CHECK: declare !callback ![[cid:[0-9]+]] void @__kmpc_fork_call
+// CHECK: declare !callback ![[cid]] void @__kmpc_fork_teams
+// CHECK: ![[cid]] = !{![[cidb:[0-9]+]]}
+// CHECK: ![[cidb]] = !{i64 2, i64 -1, i64 -1, i1 true}
+
+void work1(int, int);
+void work2(int, int);
+void work12(int, int);
+
+void foo(int q) {
+  int p = 2;
+
+  #pragma omp parallel firstprivate(q, p)
+  work1(p, q);
+// IPCP: call void @work1(i32 2, i32 %{{[._a-zA-Z0-9]*}})
+
+  #pragma omp parallel for firstprivate(p, q)
+  for (int i = 0; i < q; i++)
+    work2(i, p);
+// IPCP: call void @work2(i32 %{{[._a-zA-Z0-9]*}}, i32 2)
+
+  #pragma omp target teams firstprivate(p)
+  work12(p, p);
+// IPCP: call void @work12(i32 2, i32 2)
+}
Index: test/CodeGen/callback_annotated.c
===================================================================
--- /dev/null
+++ test/CodeGen/callback_annotated.c
@@ -0,0 +1,76 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 %s -emit-llvm -o - | FileCheck %s --check-prefix=RUN1
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 %s -emit-llvm -o - | FileCheck %s --check-prefix=RUN2
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 %s -emit-llvm -o - | opt -ipconstprop -S | FileCheck --check-prefix=IPCP %s
+
+// RUN1-DAG: @broker0({{[^#]*#[0-9]+}} !callback ![[cid0:[0-9]+]]
+__attribute__((callback (1, 2)))
+void* broker0(void* (*callee)(void *), void *payload) {
+  return callee(payload);
+}
+
+// RUN1-DAG: @broker1({{[^#]*#[0-9]+}} !callback ![[cid1:[0-9]+]]
+__attribute__((callback (callee, payload)))
+void* broker1(void *payload, void* (*callee)(void *)) {
+  return broker0(callee, payload);
+}
+
+// RUN1-DAG: declare !callback ![[cid2:[0-9]+]] i8* @broker2
+__attribute__((callback (callee)))
+void* broker2(void (*callee)(void));
+
+// RUN1-DAG: declare !callback ![[cid3:[0-9]+]] i8* @broker3
+__attribute__((callback (4, 1, 2, c)))
+void* broker3(int, int, int c, int (*callee)(int, int, int), int);
+
+// RUN1-DAG: declare !callback ![[cid4:[0-9]+]] i8* @broker4
+__attribute__((callback (4, -1, a, __)))
+void* broker4(int a, int, int, int (*callee)(int, int, int), int);
+
+// RUN1-DAG: declare !callback ![[cid5:[0-9]+]] i8* @broker5
+__attribute__((callback (4, d, 5, 2)))
+void* broker5(int, int, int, int (*callee)(int, int, int), int d);
+
+
+static void *VoidPtr2VoidPtr(void *payload) {
+// RUN2: ret i8* %payload
+// IPCP:  ret i8* null
+  return payload;
+}
+
+static int ThreeInt2Int(int a, int b, int c) {
+// RUN2:      define internal i32 @ThreeInt2Int(i32 %a, i32 %b, i32 %c)
+// RUN2-NEXT: entry:
+// RUN2-NEXT:     %mul = mul nsw i32 %b, %a
+// RUN2-NEXT:     %add = add nsw i32 %mul, %c
+// RUN2-NEXT:     ret i32 %add
+
+// IPCP:       define internal i32 @ThreeInt2Int(i32 %a, i32 %b, i32 %c)
+// IPCP-NEXT:  entry:
+// IPCP-NEXT:      %mul = mul nsw i32 4, %a
+// IPCP-NEXT:      %add = add nsw i32 %mul, %c
+// IPCP-NEXT:      ret i32 %add
+
+  return a * b + c;
+}
+
+void foo() {
+  broker0(VoidPtr2VoidPtr, 0l);
+  broker1(0l, VoidPtr2VoidPtr);
+  broker2(foo);
+  broker3(1, 4, 5, ThreeInt2Int, 1);
+  broker4(4, 2, 7, ThreeInt2Int, 0);
+  broker5(8, 0, 3, ThreeInt2Int, 4);
+}
+
+// RUN1-DAG: ![[cid0]] = !{![[cid0b:[0-9]+]]}
+// RUN1-DAG: ![[cid0b]] = !{i64 0, i64 1, i1 false}
+// RUN1-DAG: ![[cid1]] = !{![[cid1b:[0-9]+]]}
+// RUN1-DAG: ![[cid1b]] = !{i64 1, i64 0, i1 false}
+// RUN1-DAG: ![[cid2]] = !{![[cid2b:[0-9]+]]}
+// RUN1-DAG: ![[cid2b]] = !{i64 0, i1 false}
+// RUN1-DAG: ![[cid3]] = !{![[cid3b:[0-9]+]]}
+// RUN1-DAG: ![[cid3b]] = !{i64 3, i64 0, i64 1, i64 2, i1 false}
+// RUN1-DAG: ![[cid4]] = !{![[cid4b:[0-9]+]]}
+// RUN1-DAG: ![[cid4b]] = !{i64 3, i64 -1, i64 0, i64 -1, i1 false}
+// RUN1-DAG: ![[cid5]] = !{![[cid5b:[0-9]+]]}
+// RUN1-DAG: ![[cid5b]] = !{i64 3, i64 4, i64 4, i64 1, i1 false}
Index: test/CodeGen/attr-callback.c
===================================================================
--- /dev/null
+++ test/CodeGen/attr-callback.c
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
+
+void cb0(void);
+
+// CHECK-DAG: !callback ![[cid0:[0-9]+]] void @no_args
+__attribute__((callback(1)))         void no_args(void (*callback)(void));
+
+// CHECK-DAG: @args_1({{[^#]*#[0-9]+}} !callback ![[cid1:[0-9]+]]
+__attribute__((callback(1, 2, 3)))   void args_1(void (*callback)(int, double), int a, double b) { no_args(cb0); }
+
+// CHECK-DAG: !callback ![[cid2:[0-9]+]]  void @args_2a
+__attribute__((callback(2, 3, 3)))        void args_2a(int a, void (*callback)(double, double), double b);
+// CHECK-DAG: !callback ![[cid2]]         void @args_2b
+__attribute__((callback(callback, b, b))) void args_2b(int a, void (*callback)(double, double), double b);
+
+// CHECK-DAG:                             void @args_3a({{[^#]*#[0-9]+}} !callback ![[cid3:[0-9]+]]
+__attribute__((callback(2, -1, -1)))      void args_3a(int a, void (*callback)(double, double), double b) { args_2a(a, callback, b); }
+// CHECK-DAG:                             void @args_3b({{[^#]*#[0-9]+}} !callback ![[cid3]]
+__attribute__((callback(callback, __, __))) void args_3b(int a, void (*callback)(double, double), double b) { args_2b(a, callback, b); }
+
+// CHECK-DAG: ![[cid0]] = !{![[cid0b:[0-9]+]]}
+// CHECK-DAG: ![[cid0b]] = !{i64 0, i1 false}
+// CHECK-DAG: ![[cid1]] = !{![[cid1b:[0-9]+]]}
+// CHECK-DAG: ![[cid1b]] = !{i64 0, i64 1, i64 2, i1 false}
+// CHECK-DAG: ![[cid2]] = !{![[cid2b:[0-9]+]]}
+// CHECK-DAG: ![[cid2b]] = !{i64 1, i64 2, i64 2, i1 false}
+// CHECK-DAG: ![[cid3]] = !{![[cid3b:[0-9]+]]}
+// CHECK-DAG: ![[cid3b]] = !{i64 1, i64 -1, i64 -1, i1 false}
Index: test/Analysis/retain-release.m
===================================================================
--- test/Analysis/retain-release.m
+++ test/Analysis/retain-release.m
@@ -2,8 +2,8 @@
 // RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10\
 // RUN:     -analyzer-checker=core,osx.coreFoundation.CFRetainRelease\
 // RUN:     -analyzer-checker=osx.cocoa.ClassRelease,osx.cocoa.RetainCount\
-// RUN:     -analyzer-checker=debug.ExprInspection -fblocks -verify %s\
-// RUN:     -Wno-objc-root-class -analyzer-output=plist -o %t.objcpp.plist
+// RUN:     -analyzer-checker=debug.ExprInspection -fblocks -verify=expected,C\
+// RUN:     -Wno-objc-root-class -analyzer-output=plist -o %t.objcpp.plist %s
 // RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10\
 // RUN:     -analyzer-checker=core,osx.coreFoundation.CFRetainRelease\
 // RUN:     -analyzer-checker=osx.cocoa.ClassRelease,osx.cocoa.RetainCount\
@@ -1202,7 +1202,7 @@
 typedef unsigned long __darwin_pthread_key_t;
 typedef __darwin_pthread_key_t pthread_key_t;
 
-int pthread_create(pthread_t *, const pthread_attr_t *,
+int pthread_create(pthread_t *, const pthread_attr_t *,  // C-warning{{declaration of built-in function 'pthread_create' requires inclusion of the header <pthread.h>}}
                    void *(*)(void *), void *);
 
 int pthread_setspecific(pthread_key_t key, const void *value);
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -3462,6 +3462,145 @@
     D->addAttr(NewAttr);
 }
 
+/// Handle __attribute__((callback(CalleeIdx, PayloadIdx0, ...))) attributes.
+static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+  // The index that identifies the callback callee is mandatory.
+  if (AL.getNumArgs() == 0) {
+    S.Diag(AL.getLoc(), diag::err_callback_attribute_no_callee)
+        << AL.getRange();
+    return;
+  }
+
+  bool HasImplicitThisParam = isInstanceMethod(D);
+  int32_t NumArgs = getFunctionOrMethodNumParams(D);
+
+  FunctionDecl *FD = D->getAsFunction();
+  assert(FD && "Expected a function declaration!");
+
+  llvm::StringMap<int> NameIdxMapping;
+  NameIdxMapping["__"] = -1;
+
+  NameIdxMapping["__this"] = 0;
+
+  int Idx = 1;
+  for (const ParmVarDecl *PVD : FD->parameters())
+    NameIdxMapping[PVD->getName()] = Idx++;
+
+  auto UnknownName = NameIdxMapping.end();
+
+  SmallVector<int, 8> EncodingIndices;
+  for (unsigned u = 0, e = AL.getNumArgs(); u < e; u++) {
+
+    SourceRange SR;
+    int32_t ArgIdx;
+
+    if (AL.isArgIdent(u)) {
+      IdentifierLoc *IdLoc = AL.getArgAsIdent(u);
+      auto It = NameIdxMapping.find(IdLoc->Ident->getName());
+      if (It == UnknownName) {
+        S.Diag(AL.getLoc(), diag::err_callback_attribute_argument_unknown)
+            << IdLoc->Ident->getName() << IdLoc->Loc;
+        return;
+      }
+
+      SR = SourceRange(IdLoc->Loc);
+      ArgIdx = It->second;
+
+    } else if (AL.isArgExpr(u)) {
+      Expr *IdxExpr = AL.getArgAsExpr(u);
+
+      // If the expression is not parseable as an int32_t we have a problem.
+      if (!checkUInt32Argument(S, AL, IdxExpr, (uint32_t &)ArgIdx, u + 1,
+                               false)) {
+        S.Diag(AL.getLoc(), diag::err_callback_attribute_argument_index_oob)
+            << (u + 1) << IdxExpr->getSourceRange();
+        return;
+      }
+
+      // Check oob, excluding the special values, 0 and -1.
+      if (ArgIdx < -1 || ArgIdx > NumArgs) {
+        S.Diag(AL.getLoc(), diag::err_callback_attribute_argument_index_oob)
+            << (u + 1) << IdxExpr->getSourceRange();
+        return;
+      }
+
+      SR = IdxExpr->getSourceRange();
+
+    } else {
+      llvm_unreachable("Unexpected ParsedAttr argument type!");
+    }
+
+    if (ArgIdx == 0 && !HasImplicitThisParam) {
+      S.Diag(AL.getLoc(), diag::err_callback_implicit_this_not_available)
+          << (u + 1) << SR;
+      return;
+    }
+
+    // Adjust for the case we do not have an implicit "this" parameter. In this
+    // case we decrease all positive values by 1 to get LLVM argument indices.
+    if (!HasImplicitThisParam && ArgIdx > 0)
+      ArgIdx -= 1;
+
+    EncodingIndices.push_back(ArgIdx);
+  }
+
+  int CalleeIdx = EncodingIndices.front();
+  // Check if the callee index is proper, thus not "this" and not "unknown".
+  if (CalleeIdx < HasImplicitThisParam) {
+    S.Diag(AL.getLoc(), diag::err_callback_attribute_invalid_callee)
+        << AL.getRange();
+    return;
+  }
+
+  // Get the callee type, note the index adjustment as the AST doesn't contain
+  // the this type (which the callee cannot reference anyway!).
+  const Type *CalleeType =
+      getFunctionOrMethodParamType(D, CalleeIdx - HasImplicitThisParam)
+          .getTypePtr();
+  if (!CalleeType || !CalleeType->isFunctionPointerType()) {
+    S.Diag(AL.getLoc(), diag::err_callback_callee_no_function_type)
+        << AL.getRange();
+    return;
+  }
+
+  const Type *CalleeFnType =
+      CalleeType->getPointeeType()->getUnqualifiedDesugaredType();
+
+  // TODO: Check the type of the callee arguments.
+
+  const auto *CalleeFnProtoType = dyn_cast<FunctionProtoType>(CalleeFnType);
+  if (!CalleeFnProtoType) {
+    S.Diag(AL.getLoc(), diag::err_callback_callee_no_function_type)
+        << AL.getRange();
+    return;
+  }
+
+  if (CalleeFnProtoType->getNumParams() > EncodingIndices.size() - 1) {
+    S.Diag(AL.getLoc(), diag::err_callback_too_few_arguments) << AL.getRange();
+    return;
+  }
+
+  if (CalleeFnProtoType->getNumParams() < EncodingIndices.size() - 1) {
+    S.Diag(AL.getLoc(), diag::err_callback_too_many_arguments) << AL.getRange();
+    return;
+  }
+
+  if (CalleeFnProtoType->isVariadic()) {
+    S.Diag(AL.getLoc(), diag::err_callback_callee_is_variadic) << AL.getRange();
+    return;
+  }
+
+  // Do not allow multiple callback attributes.
+  if (D->hasAttr<CallbackAttr>()) {
+    S.Diag(AL.getLoc(), diag::err_callback_attribute_multiple) << AL.getRange();
+    return;
+  }
+
+  D->addAttr(::new (S.Context) CallbackAttr(
+      AL.getRange(), S.Context, EncodingIndices.data(), EncodingIndices.size(),
+      AL.getAttributeSpellingListIndex()));
+}
+
 static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   // Try to find the underlying union declaration.
   RecordDecl *RD = nullptr;
@@ -6366,6 +6505,9 @@
   case ParsedAttr::AT_FormatArg:
     handleFormatArgAttr(S, D, AL);
     break;
+  case ParsedAttr::AT_Callback:
+    handleCallbackAttr(S, D, AL);
+    break;
   case ParsedAttr::AT_CUDAGlobal:
     handleGlobalAttr(S, D, AL);
     break;
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -1927,10 +1927,13 @@
       Context.setObjCSuperType(Context.getTagDeclType(TD));
 }
 
-static StringRef getHeaderName(ASTContext::GetBuiltinTypeError Error) {
+static StringRef getHeaderName(Builtin::Context &BuiltinInfo, unsigned ID,
+                               ASTContext::GetBuiltinTypeError Error) {
   switch (Error) {
   case ASTContext::GE_None:
     return "";
+  case ASTContext::GE_Missing_type:
+    return BuiltinInfo.getHeaderName(ID);
   case ASTContext::GE_Missing_stdio:
     return "stdio.h";
   case ASTContext::GE_Missing_setjmp:
@@ -1955,7 +1958,8 @@
   if (Error) {
     if (ForRedeclaration)
       Diag(Loc, diag::warn_implicit_decl_requires_sysheader)
-          << getHeaderName(Error) << Context.BuiltinInfo.getName(ID);
+          << getHeaderName(Context.BuiltinInfo, ID, Error)
+          << Context.BuiltinInfo.getName(ID);
     return nullptr;
   }
 
@@ -13578,6 +13582,14 @@
                                               FD->getLocation()));
     }
 
+    // Handle automatically recognized callbacks.
+    SmallVector<int, 4> Encoding;
+    if (Context.BuiltinInfo.performsCallback(BuiltinID, Encoding)) {
+      if (!FD->hasAttr<CallbackAttr>())
+        FD->addAttr(CallbackAttr::CreateImplicit(
+            Context, Encoding.data(), Encoding.size(), FD->getLocation()));
+    }
+
     // Mark const if we don't care about errno and that is the only thing
     // preventing the function from being const. This allows IRgen to use LLVM
     // intrinsics for such functions.
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -1603,6 +1603,23 @@
 
   if (getLangOpts().OpenMP && FD->hasAttr<OMPDeclareSimdDeclAttr>())
     getOpenMPRuntime().emitDeclareSimdFunction(FD, F);
+
+  if (const auto *CB = FD->getAttr<CallbackAttr>()) {
+    // Annotate the callback behavior as metadata:
+    //  - The callback callee (as argument number).
+    //  - The callback payloads (as argument numbers).
+    llvm::LLVMContext &Ctx = F->getContext();
+    llvm::MDBuilder MDB(Ctx);
+
+    // The payload indices are all but the first one in the encoding. The first
+    // identifies the callback callee.
+    int CalleeIdx = *CB->encoding_begin();
+    ArrayRef<int> PayloadIndices(CB->encoding_begin() + 1, CB->encoding_end());
+    F->addMetadata(llvm::LLVMContext::MD_callback,
+                   *llvm::MDNode::get(Ctx, {MDB.createCallbackEncoding(
+                                               CalleeIdx, PayloadIndices,
+                                               /* VarArgsArePassed */ false)}));
+  }
 }
 
 void CodeGenModule::addUsedGlobal(llvm::GlobalValue *GV) {
Index: lib/CodeGen/CGOpenMPRuntime.cpp
===================================================================
--- lib/CodeGen/CGOpenMPRuntime.cpp
+++ lib/CodeGen/CGOpenMPRuntime.cpp
@@ -1677,6 +1677,22 @@
     auto *FnTy =
         llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ true);
     RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_fork_call");
+    if (auto *F = dyn_cast<llvm::Function>(RTLFn)) {
+      if (!F->hasMetadata(llvm::LLVMContext::MD_callback)) {
+        llvm::LLVMContext &Ctx = F->getContext();
+        llvm::MDBuilder MDB(Ctx);
+        // Annotate the callback behavior of the __kmpc_fork_call:
+        //  - The callback callee is argument number 2 (microtask).
+        //  - The first two arguments of the callback callee are unknown (-1).
+        //  - All variadic arguments to the __kmpc_fork_call are passed to the
+        //    callback callee.
+        F->addMetadata(
+            llvm::LLVMContext::MD_callback,
+            *llvm::MDNode::get(Ctx, {MDB.createCallbackEncoding(
+                                        2, {-1, -1},
+                                        /* VarArgsArePassed */ true)}));
+      }
+    }
     break;
   }
   case OMPRTL__kmpc_global_thread_num: {
@@ -2084,6 +2100,22 @@
     auto *FnTy =
         llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ true);
     RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_fork_teams");
+    if (auto *F = dyn_cast<llvm::Function>(RTLFn)) {
+      if (!F->hasMetadata(llvm::LLVMContext::MD_callback)) {
+        llvm::LLVMContext &Ctx = F->getContext();
+        llvm::MDBuilder MDB(Ctx);
+        // Annotate the callback behavior of the __kmpc_fork_teams:
+        //  - The callback callee is argument number 2 (microtask).
+        //  - The first two arguments of the callback callee are unknown (-1).
+        //  - All variadic arguments to the __kmpc_fork_teams are passed to the
+        //    callback callee.
+        F->addMetadata(
+            llvm::LLVMContext::MD_callback,
+            *llvm::MDNode::get(Ctx, {MDB.createCallbackEncoding(
+                                        2, {-1, -1},
+                                        /* VarArgsArePassed */ true)}));
+      }
+    }
     break;
   }
   case OMPRTL__kmpc_taskloop: {
Index: lib/Basic/Builtins.cpp
===================================================================
--- lib/Basic/Builtins.cpp
+++ lib/Basic/Builtins.cpp
@@ -156,6 +156,33 @@
   return isLike(ID, FormatIdx, HasVAListArg, "sS");
 }
 
+bool Builtin::Context::performsCallback(unsigned ID,
+                                        SmallVectorImpl<int> &Encoding) const {
+  const char *CalleePos = ::strchr(getRecord(ID).Attributes, 'C');
+  if (!CalleePos)
+    return false;
+
+  ++CalleePos;
+  assert(*CalleePos == '<' &&
+         "Callback callee specifier must be followed by a '<'");
+  ++CalleePos;
+
+  char *EndPos;
+  int CalleeIdx = ::strtol(CalleePos, &EndPos, 10);
+  assert(CalleeIdx >= 0 && "Callee index is supposed to be positive!");
+  Encoding.push_back(CalleeIdx);
+
+  while (*EndPos == ',') {
+    const char *PayloadPos = EndPos + 1;
+
+    int PayloadIdx = ::strtol(PayloadPos, &EndPos, 10);
+    Encoding.push_back(PayloadIdx);
+  }
+
+  assert(*EndPos == '>' && "Callback callee specifier must end with a '>'");
+  return true;
+}
+
 bool Builtin::Context::canBeRedeclared(unsigned ID) const {
   return ID == Builtin::NotBuiltin ||
          ID == Builtin::BI__va_start ||
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -9518,6 +9518,10 @@
                                     GetBuiltinTypeError &Error,
                                     unsigned *IntegerConstantArgs) const {
   const char *TypeStr = BuiltinInfo.getTypeString(Id);
+  if (TypeStr[0] == '\0') {
+    Error = GE_Missing_type;
+    return {};
+  }
 
   SmallVector<QualType, 8> ArgTypes;
 
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2568,6 +2568,28 @@
 def err_format_attribute_implicit_this_format_string : Error<
   "format attribute cannot specify the implicit this argument as the format "
   "string">;
+def err_callback_attribute_no_callee : Error<
+  "no callback callee specified">;
+def err_callback_attribute_invalid_callee : Error<
+  "invalid callback callee specified">;
+def err_callback_attribute_multiple : Error<
+  "multiple 'callback' attributes specified">;
+def err_callback_attribute_argument_unknown : Error<
+  "'callback' argument '%0' is not a known function parameter">;
+def err_callback_attribute_argument_index_oob : Error<
+  "'callback' argument at position %0 is out-of-bounds">;
+def err_callback_incomplete_function_type : Error<
+  "'callback' function has incomplete function type">;
+def err_callback_callee_no_function_type : Error<
+  "'callback' callee does not have function type">;
+def err_callback_callee_is_variadic : Error<
+  "'callback' callee shall not be variadic">;
+def err_callback_implicit_this_not_available : Error<
+  "'callback' argument at position %0 references unavailable implicit 'this'">;
+def err_callback_too_few_arguments : Error<
+  "'callback' attribute specifies too few arguments">;
+def err_callback_too_many_arguments : Error<
+  "'callback' attribute specifies too many arguments">;
 def err_init_method_bad_return_type : Error<
   "init methods must return an object pointer type, not %0">;
 def err_attribute_invalid_size : Error<
Index: include/clang/Basic/Builtins.h
===================================================================
--- include/clang/Basic/Builtins.h
+++ include/clang/Basic/Builtins.h
@@ -194,6 +194,12 @@
   /// argument and whether this function as a va_list argument.
   bool isScanfLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg);
 
+  /// Determine whether this builtin has callback behavior (see
+  /// llvm::AbstractCallSites for details). If so, add the index to the
+  /// callback callee argument and the callback payload arguments.
+  bool performsCallback(unsigned ID,
+                        llvm::SmallVectorImpl<int> &Encoding) const;
+
   /// Return true if this function has no side effects and doesn't
   /// read memory, except for possibly errno.
   ///
Index: include/clang/Basic/Builtins.def
===================================================================
--- include/clang/Basic/Builtins.def
+++ include/clang/Basic/Builtins.def
@@ -93,6 +93,7 @@
 //  j -> returns_twice (like setjmp)
 //  u -> arguments are not evaluated for their side-effects
 //  V:N: -> requires vectors of at least N bits to be legal
+//  C<N,M_0,...,M_k> -> callback behavior: argument N is called with argument M_0, ..., M_k as payload
 //  FIXME: gcc has nonnull
 
 #if defined(BUILTIN) && !defined(LIBBUILTIN)
@@ -960,6 +961,9 @@
 // POSIX unistd.h
 LIBBUILTIN(_exit, "vi",           "fr",    "unistd.h", ALL_GNU_LANGUAGES)
 LIBBUILTIN(vfork, "p",            "fj",    "unistd.h", ALL_LANGUAGES)
+// POSIX pthread.h
+LIBBUILTIN(pthread_create, "",  "fC<2,3>", "pthread.h", ALL_GNU_LANGUAGES)
+
 // POSIX setjmp.h
 
 LIBBUILTIN(_setjmp, "iJ",         "fj",   "setjmp.h", ALL_LANGUAGES)
Index: include/clang/Basic/AttrDocs.td
===================================================================
--- include/clang/Basic/AttrDocs.td
+++ include/clang/Basic/AttrDocs.td
@@ -3766,6 +3766,51 @@
   }];
 }
 
+def CallbackDocs : Documentation {
+  let Category = DocCatVariable;
+  let Content = [{
+The ``callback`` attribute specifies that the annotated function may invoke the
+specified callback zero or more times. The callback, as well as the passed
+arguments, are identified by their parameter name or position (starting with
+1!) in the annotated function. The first position in the attribute identifies
+the callback callee, the following positions declare describe its arguments.
+The callback callee is required to be callable with the number, and order, of
+the specified arguments. The index '0', or the identifier "this", is used to
+represent an implicit "this" pointer in class methods. If there is no implicit
+"this" pointer it shall not be referenced. The index '-1', or the name "?",
+represents an unknown callback callee argument. This can be a value which is
+not present in the declared parameter list, or one that is but potentially
+inspected, captured, or modified. Parameter names and indices can be mixed in
+the callback attribute.
+
+The ``callback`` attribute, which are directly translated to ``callback``
+metadata <http://llvm.org/docs/LangRef.html#callback-metadata>, make the
+connection between the call to the annotated function and the callback callee.
+This can enable interprocedural optimizations which were otherwise impossible.
+If a function parameter is mentioned in the ``callback`` attribute, through its
+position, it is undefined if that parameter is used for anything other than the
+actual callback. Inspected, captured, or modified parameters shall not be
+listed in the ``callback`` metadata.
+
+Example encodings for the callback performed by `pthread_create` are shown
+below. The explicit attribute annotation indicates that the third parameter
+(`start_routine`) is called zero or more times by the `pthread_create` function,
+and that the fourth parameter (`arg`) is passed along. Note that the callback
+behavior of `pthread_create` is automatically recognized by Clang.
+
+  .. code-block:: c
+
+    __attribute__((callback (start_routine, arg)))
+    int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+                       void *(*start_routine) (void *), void *arg);
+
+    __attribute__((callback (3, 4)))
+    int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+                       void *(*start_routine) (void *), void *arg);
+
+  }];
+}
+
 def GnuInlineDocs : Documentation {
   let Category = DocCatFunction;
   let Content = [{
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td
+++ include/clang/Basic/Attr.td
@@ -190,6 +190,9 @@
 // Like VariadicUnsignedArgument except values are ParamIdx.
 class VariadicParamIdxArgument<string name> : Argument<name, 1>;
 
+// A list of identifiers matching parameters or ParamIdx indices.
+class VariadicParamOrParamIdxArgument<string name> : Argument<name, 1>;
+
 // Like VariadicParamIdxArgument but for a single function parameter index.
 class ParamIdxArgument<string name, bit opt = 0> : Argument<name, opt>;
 
@@ -1198,6 +1201,13 @@
   let Documentation = [Undocumented];
 }
 
+def Callback : InheritableAttr {
+  let Spellings = [Clang<"callback">];
+  let Args = [VariadicParamOrParamIdxArgument<"Encoding">];
+  let Subjects = SubjectList<[Function]>;
+  let Documentation = [CallbackDocs];
+}
+
 def GNUInline : InheritableAttr {
   let Spellings = [GCC<"gnu_inline">];
   let Subjects = SubjectList<[Function]>;
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -2002,6 +2002,9 @@
     /// No error
     GE_None,
 
+    /// Missing a type
+    GE_Missing_type,
+
     /// Missing a type from <stdio.h>
     GE_Missing_stdio,
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to