<div dir="ltr"><div dir="ltr">On Sat, Jan 19, 2019 at 2:18 AM Johannes Doerfert via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Author: jdoerfert<br>
Date: Fri Jan 18 21:36:54 2019<br>
New Revision: 351629<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=351629&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=351629&view=rev</a><br>
Log:<br>
Emit !callback metadata and introduce the callback attribute<br>
<br>
  With commit r351627, LLVM gained the ability to apply (existing) IPO<br>
  optimizations on indirections through callbacks, or transitive calls.<br>
  The general idea is that we use an abstraction to hide the middle man<br>
  and represent the callback call in the context of the initial caller.<br>
  It is described in more detail in the commit message of the LLVM patch<br>
  r351627, the llvm::AbstractCallSite class description, and the<br>
  language reference section on callback-metadata.<br>
<br>
  This commit enables clang to emit !callback metadata that is<br>
  understood by LLVM. It does so in three different cases:<br>
    1) For known broker functions declarations that are directly<br>
       generated, e.g., __kmpc_fork_call for the OpenMP pragma parallel.<br>
    2) For known broker functions that are identified by their name and<br>
       source location through the builtin detection, e.g.,<br>
       pthread_create from the POSIX thread API.<br>
    3) For user annotated functions that carry the "callback(callee, ...)"<br>
       attribute. The attribute has to include the name, or index, of<br>
       the callback callee and how the passed arguments can be<br>
       identified (as many as the callback callee has). See the callback<br>
       attribute documentation for detailed information.<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D55483" rel="noreferrer" target="_blank">https://reviews.llvm.org/D55483</a><br>
<br>
Added:<br>
    cfe/trunk/test/CodeGen/attr-callback.c<br>
    cfe/trunk/test/CodeGen/callback_annotated.c<br>
    cfe/trunk/test/CodeGen/callback_openmp.c<br>
    cfe/trunk/test/CodeGen/callback_pthread_create.c<br>
    cfe/trunk/test/CodeGenCXX/attr-callback.cpp<br>
    cfe/trunk/test/Sema/attr-callback-broken.c<br>
    cfe/trunk/test/Sema/attr-callback.c<br>
    cfe/trunk/test/SemaCXX/attr-callback-broken.cpp<br>
    cfe/trunk/test/SemaCXX/attr-callback.cpp<br>
Modified:<br>
    cfe/trunk/include/clang/AST/ASTContext.h<br>
    cfe/trunk/include/clang/Basic/Attr.td<br>
    cfe/trunk/include/clang/Basic/AttrDocs.td<br>
    cfe/trunk/include/clang/Basic/Builtins.def<br>
    cfe/trunk/include/clang/Basic/Builtins.h<br>
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
    cfe/trunk/lib/AST/ASTContext.cpp<br>
    cfe/trunk/lib/Basic/Builtins.cpp<br>
    cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp<br>
    cfe/trunk/lib/CodeGen/CodeGenModule.cpp<br>
    cfe/trunk/lib/Parse/ParseDecl.cpp<br>
    cfe/trunk/lib/Sema/SemaDecl.cpp<br>
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp<br>
    cfe/trunk/test/Analysis/retain-release.m<br>
    cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test<br>
    cfe/trunk/test/OpenMP/parallel_codegen.cpp<br>
    cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp<br>
<br>
Modified: cfe/trunk/include/clang/AST/ASTContext.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=351629&r1=351628&r2=351629&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=351629&r1=351628&r2=351629&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/AST/ASTContext.h (original)<br>
+++ cfe/trunk/include/clang/AST/ASTContext.h Fri Jan 18 21:36:54 2019<br>
@@ -2003,6 +2003,9 @@ public:<br>
     /// No error<br>
     GE_None,<br>
<br>
+    /// Missing a type<br>
+    GE_Missing_type,<br>
+<br>
     /// Missing a type from <stdio.h><br>
     GE_Missing_stdio,<br>
<br>
<br>
Modified: cfe/trunk/include/clang/Basic/Attr.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=351629&r1=351628&r2=351629&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=351629&r1=351628&r2=351629&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/Attr.td (original)<br>
+++ cfe/trunk/include/clang/Basic/Attr.td Fri Jan 18 21:36:54 2019<br>
@@ -190,6 +190,9 @@ class VariadicIdentifierArgument<string<br>
 // Like VariadicUnsignedArgument except values are ParamIdx.<br>
 class VariadicParamIdxArgument<string name> : Argument<name, 1>;<br>
<br>
+// A list of identifiers matching parameters or ParamIdx indices.<br>
+class VariadicParamOrParamIdxArgument<string name> : Argument<name, 1>;<br>
+<br>
 // Like VariadicParamIdxArgument but for a single function parameter index.<br>
 class ParamIdxArgument<string name, bit opt = 0> : Argument<name, opt>;<br>
<br>
@@ -1210,6 +1213,13 @@ def FormatArg : InheritableAttr {<br>
   let Documentation = [Undocumented];<br>
 }<br>
<br>
+def Callback : InheritableAttr {<br>
+  let Spellings = [Clang<"callback">];<br>
+  let Args = [VariadicParamOrParamIdxArgument<"Encoding">];<br>
+  let Subjects = SubjectList<[Function]>;<br>
+  let Documentation = [CallbackDocs];<br>
+}<br>
+<br>
 def GNUInline : InheritableAttr {<br>
   let Spellings = [GCC<"gnu_inline">];<br>
   let Subjects = SubjectList<[Function]>;<br>
<br>
Modified: cfe/trunk/include/clang/Basic/AttrDocs.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrDocs.td?rev=351629&r1=351628&r2=351629&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrDocs.td?rev=351629&r1=351628&r2=351629&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/AttrDocs.td (original)<br>
+++ cfe/trunk/include/clang/Basic/AttrDocs.td Fri Jan 18 21:36:54 2019<br>
@@ -3781,6 +3781,55 @@ it rather documents the programmer's int<br>
   }];<br>
 }<br>
<br>
+def CallbackDocs : Documentation {<br>
+  let Category = DocCatVariable;<br>
+  let Content = [{<br>
+The ``callback`` attribute specifies that the annotated function may invoke the<br>
+specified callback zero or more times. The callback, as well as the passed<br>
+arguments, are identified by their parameter name or position (starting with<br>
+1!) in the annotated function. The first position in the attribute identifies<br>
+the callback callee, the following positions declare describe its arguments.<br>
+The callback callee is required to be callable with the number, and order, of<br>
+the specified arguments. The index `0`, or the identifier `this`, is used to<br>
+represent an implicit "this" pointer in class methods. If there is no implicit<br>
+"this" pointer it shall not be referenced. The index '-1', or the name "__",<br>
+represents an unknown callback callee argument. This can be a value which is<br>
+not present in the declared parameter list, or one that is, but is potentially<br>
+inspected, captured, or modified. Parameter names and indices can be mixed in<br>
+the callback attribute.<br>
+<br>
+The ``callback`` attribute, which is directly translated to ``callback``<br>
+metadata <<a href="http://llvm.org/docs/LangRef.html#callback-metadata" rel="noreferrer" target="_blank">http://llvm.org/docs/LangRef.html#callback-metadata</a>>, make the<br>
+connection between the call to the annotated function and the callback callee.<br>
+This can enable interprocedural optimizations which were otherwise impossible.<br>
+If a function parameter is mentioned in the ``callback`` attribute, through its<br>
+position, it is undefined if that parameter is used for anything other than the<br>
+actual callback. Inspected, captured, or modified parameters shall not be<br>
+listed in the ``callback`` metadata.<br>
+<br>
+Example encodings for the callback performed by `pthread_create` are shown<br>
+below. The explicit attribute annotation indicates that the third parameter<br>
+(`start_routine`) is called zero or more times by the `pthread_create` function,<br>
+and that the fourth parameter (`arg`) is passed along. Note that the callback<br>
+behavior of `pthread_create` is automatically recognized by Clang. In addition,<br>
+the declarations of `__kmpc_fork_teams` and `__kmpc_fork_call`, generated for <br>
+`#pragma omp target teams` and `#pragma omp parallel`, respectively, are also<br>
+automatically recognized as broker functions. Further functions might be added<br>
+in the future.<br>
+<br>
+  .. code-block:: c<br>
+<br>
+    __attribute__((callback (start_routine, arg)))<br>
+    int pthread_create(pthread_t *thread, const pthread_attr_t *attr,<br>
+                       void *(*start_routine) (void *), void *arg);<br>
+<br>
+    __attribute__((callback (3, 4)))<br>
+    int pthread_create(pthread_t *thread, const pthread_attr_t *attr,<br>
+                       void *(*start_routine) (void *), void *arg);<br>
+<br>
+  }];<br>
+}<br>
+<br>
 def GnuInlineDocs : Documentation {<br>
   let Category = DocCatFunction;<br>
   let Content = [{<br>
<br>
Modified: cfe/trunk/include/clang/Basic/Builtins.def<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Builtins.def?rev=351629&r1=351628&r2=351629&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Builtins.def?rev=351629&r1=351628&r2=351629&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/Builtins.def (original)<br>
+++ cfe/trunk/include/clang/Basic/Builtins.def Fri Jan 18 21:36:54 2019<br>
@@ -93,6 +93,8 @@<br>
 //  j -> returns_twice (like setjmp)<br>
 //  u -> arguments are not evaluated for their side-effects<br>
 //  V:N: -> requires vectors of at least N bits to be legal<br>
+//  C<N,M_0,...,M_k> -> callback behavior: argument N is called with argument<br>
+//                      M_0, ..., M_k as payload<br>
 //  FIXME: gcc has nonnull<br>
<br>
 #if defined(BUILTIN) && !defined(LIBBUILTIN)<br>
@@ -960,6 +962,9 @@ LIBBUILTIN(strncasecmp, "icC*cC*z", "f",<br>
 // POSIX unistd.h<br>
 LIBBUILTIN(_exit, "vi",           "fr",    "unistd.h", ALL_GNU_LANGUAGES)<br>
 LIBBUILTIN(vfork, "p",            "fj",    "unistd.h", ALL_LANGUAGES)<br>
+// POSIX pthread.h<br>
+LIBBUILTIN(pthread_create, "",  "fC<2,3>", "pthread.h", ALL_GNU_LANGUAGES)<br>
+<br>
 // POSIX setjmp.h<br>
<br>
 LIBBUILTIN(_setjmp, "iJ",         "fj",   "setjmp.h", ALL_LANGUAGES)<br>
<br>
Modified: cfe/trunk/include/clang/Basic/Builtins.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Builtins.h?rev=351629&r1=351628&r2=351629&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Builtins.h?rev=351629&r1=351628&r2=351629&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/Builtins.h (original)<br>
+++ cfe/trunk/include/clang/Basic/Builtins.h Fri Jan 18 21:36:54 2019<br>
@@ -194,6 +194,12 @@ public:<br>
   /// argument and whether this function as a va_list argument.<br>
   bool isScanfLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg);<br>
<br>
+  /// Determine whether this builtin has callback behavior (see<br>
+  /// llvm::AbstractCallSites for details). If so, add the index to the<br>
+  /// callback callee argument and the callback payload arguments.<br>
+  bool performsCallback(unsigned ID,<br>
+                        llvm::SmallVectorImpl<int> &Encoding) const;<br>
+<br>
   /// Return true if this function has no side effects and doesn't<br>
   /// read memory, except for possibly errno.<br>
   ///<br>
<br>
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=351629&r1=351628&r2=351629&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=351629&r1=351628&r2=351629&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)<br>
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jan 18 21:36:54 2019<br>
@@ -2578,6 +2578,20 @@ def err_format_attribute_result_not : Er<br>
 def err_format_attribute_implicit_this_format_string : Error<<br>
   "format attribute cannot specify the implicit this argument as the format "<br>
   "string">;<br>
+def err_callback_attribute_no_callee : Error<<br>
+  "'callback' attribute specifies no callback callee">;<br>
+def err_callback_attribute_invalid_callee : Error<<br>
+  "'callback' attribute specifies invalid callback callee">;<br>
+def err_callback_attribute_multiple : Error<<br>
+  "multiple 'callback' attributes specified">;<br>
+def err_callback_attribute_argument_unknown : Error<<br>
+  "'callback' attribute argument %0 is not a known function parameter">;<br>
+def err_callback_callee_no_function_type : Error<<br>
+  "'callback' attribute callee does not have function type">;<br>
+def err_callback_callee_is_variadic : Error<<br>
+  "'callback' attribute callee may not be variadic">;<br>
+def err_callback_implicit_this_not_available : Error<<br>
+  "'callback' argument at position %0 references unavailable implicit 'this'">;<br>
 def err_init_method_bad_return_type : Error<<br>
   "init methods must return an object pointer type, not %0">;<br>
 def err_attribute_invalid_size : Error<<br>
<br>
Modified: cfe/trunk/lib/AST/ASTContext.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=351629&r1=351628&r2=351629&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=351629&r1=351628&r2=351629&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/ASTContext.cpp (original)<br>
+++ cfe/trunk/lib/AST/ASTContext.cpp Fri Jan 18 21:36:54 2019<br>
@@ -9518,6 +9518,10 @@ QualType ASTContext::GetBuiltinType(unsi<br>
                                     GetBuiltinTypeError &Error,<br>
                                     unsigned *IntegerConstantArgs) const {<br>
   const char *TypeStr = BuiltinInfo.getTypeString(Id);<br>
+  if (TypeStr[0] == '\0') {<br>
+    Error = GE_Missing_type;<br>
+    return {};<br>
+  }<br>
<br>
   SmallVector<QualType, 8> ArgTypes;<br>
<br>
<br>
Modified: cfe/trunk/lib/Basic/Builtins.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Builtins.cpp?rev=351629&r1=351628&r2=351629&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Builtins.cpp?rev=351629&r1=351628&r2=351629&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Basic/Builtins.cpp (original)<br>
+++ cfe/trunk/lib/Basic/Builtins.cpp Fri Jan 18 21:36:54 2019<br>
@@ -156,6 +156,33 @@ bool Builtin::Context::isScanfLike(unsig<br>
   return isLike(ID, FormatIdx, HasVAListArg, "sS");<br>
 }<br>
<br>
+bool Builtin::Context::performsCallback(unsigned ID,<br>
+                                        SmallVectorImpl<int> &Encoding) const {<br>
+  const char *CalleePos = ::strchr(getRecord(ID).Attributes, 'C');<br>
+  if (!CalleePos)<br>
+    return false;<br>
+<br>
+  ++CalleePos;<br>
+  assert(*CalleePos == '<' &&<br>
+         "Callback callee specifier must be followed by a '<'");<br>
+  ++CalleePos;<br>
+<br>
+  char *EndPos;<br>
+  int CalleeIdx = ::strtol(CalleePos, &EndPos, 10);<br>
+  assert(CalleeIdx >= 0 && "Callee index is supposed to be positive!");<br>
+  Encoding.push_back(CalleeIdx);<br>
+<br>
+  while (*EndPos == ',') {<br>
+    const char *PayloadPos = EndPos + 1;<br>
+<br>
+    int PayloadIdx = ::strtol(PayloadPos, &EndPos, 10);<br>
+    Encoding.push_back(PayloadIdx);<br>
+  }<br>
+<br>
+  assert(*EndPos == '>' && "Callback callee specifier must end with a '>'");<br>
+  return true;<br>
+}<br>
+<br>
 bool Builtin::Context::canBeRedeclared(unsigned ID) const {<br>
   return ID == Builtin::NotBuiltin ||<br>
          ID == Builtin::BI__va_start ||<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp?rev=351629&r1=351628&r2=351629&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp?rev=351629&r1=351628&r2=351629&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGOpenMPRuntime.cpp Fri Jan 18 21:36:54 2019<br>
@@ -1677,6 +1677,22 @@ CGOpenMPRuntime::createRuntimeFunction(u<br>
     auto *FnTy =<br>
         llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ true);<br>
     RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_fork_call");<br>
+    if (auto *F = dyn_cast<llvm::Function>(RTLFn)) {<br>
+      if (!F->hasMetadata(llvm::LLVMContext::MD_callback)) {<br>
+        llvm::LLVMContext &Ctx = F->getContext();<br>
+        llvm::MDBuilder MDB(Ctx);<br>
+        // Annotate the callback behavior of the __kmpc_fork_call:<br>
+        //  - The callback callee is argument number 2 (microtask).<br>
+        //  - The first two arguments of the callback callee are unknown (-1).<br>
+        //  - All variadic arguments to the __kmpc_fork_call are passed to the<br>
+        //    callback callee.<br>
+        F->addMetadata(<br>
+            llvm::LLVMContext::MD_callback,<br>
+            *llvm::MDNode::get(Ctx, {MDB.createCallbackEncoding(<br>
+                                        2, {-1, -1},<br>
+                                        /* VarArgsArePassed */ true)}));<br>
+      }<br>
+    }<br>
     break;<br>
   }<br>
   case OMPRTL__kmpc_global_thread_num: {<br>
@@ -2084,6 +2100,22 @@ CGOpenMPRuntime::createRuntimeFunction(u<br>
     auto *FnTy =<br>
         llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ true);<br>
     RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_fork_teams");<br>
+    if (auto *F = dyn_cast<llvm::Function>(RTLFn)) {<br>
+      if (!F->hasMetadata(llvm::LLVMContext::MD_callback)) {<br>
+        llvm::LLVMContext &Ctx = F->getContext();<br>
+        llvm::MDBuilder MDB(Ctx);<br>
+        // Annotate the callback behavior of the __kmpc_fork_teams:<br>
+        //  - The callback callee is argument number 2 (microtask).<br>
+        //  - The first two arguments of the callback callee are unknown (-1).<br>
+        //  - All variadic arguments to the __kmpc_fork_teams are passed to the<br>
+        //    callback callee.<br>
+        F->addMetadata(<br>
+            llvm::LLVMContext::MD_callback,<br>
+            *llvm::MDNode::get(Ctx, {MDB.createCallbackEncoding(<br>
+                                        2, {-1, -1},<br>
+                                        /* VarArgsArePassed */ true)}));<br>
+      }<br>
+    }<br>
     break;<br>
   }<br>
   case OMPRTL__kmpc_taskloop: {<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=351629&r1=351628&r2=351629&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=351629&r1=351628&r2=351629&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Fri Jan 18 21:36:54 2019<br>
@@ -1603,6 +1603,23 @@ void CodeGenModule::SetFunctionAttribute<br>
<br>
   if (getLangOpts().OpenMP && FD->hasAttr<OMPDeclareSimdDeclAttr>())<br>
     getOpenMPRuntime().emitDeclareSimdFunction(FD, F);<br>
+<br>
+  if (const auto *CB = FD->getAttr<CallbackAttr>()) {<br>
+    // Annotate the callback behavior as metadata:<br>
+    //  - The callback callee (as argument number).<br>
+    //  - The callback payloads (as argument numbers).<br>
+    llvm::LLVMContext &Ctx = F->getContext();<br>
+    llvm::MDBuilder MDB(Ctx);<br>
+<br>
+    // The payload indices are all but the first one in the encoding. The first<br>
+    // identifies the callback callee.<br>
+    int CalleeIdx = *CB->encoding_begin();<br>
+    ArrayRef<int> PayloadIndices(CB->encoding_begin() + 1, CB->encoding_end());<br>
+    F->addMetadata(llvm::LLVMContext::MD_callback,<br>
+                   *llvm::MDNode::get(Ctx, {MDB.createCallbackEncoding(<br>
+                                               CalleeIdx, PayloadIndices,<br>
+                                               /* VarArgsArePassed */ false)}));<br>
+  }<br>
 }<br>
<br>
 void CodeGenModule::addUsedGlobal(llvm::GlobalValue *GV) {<br>
<br>
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=351629&r1=351628&r2=351629&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=351629&r1=351628&r2=351629&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)<br>
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Fri Jan 18 21:36:54 2019<br>
@@ -223,6 +223,15 @@ static bool attributeHasVariadicIdentifi<br>
 #undef CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST<br>
 }<br>
<br>
+/// Determine whether the given attribute treats kw_this as an identifier.<br>
+static bool attributeTreatsKeywordThisAsIdentifier(const IdentifierInfo &II) {<br>
+#define CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST<br>
+  return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))<br>
+#include "clang/Parse/AttrParserStringSwitches.inc"<br>
+           .Default(false);<br>
+#undef CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST<br>
+}<br>
+<br>
 /// Determine whether the given attribute parses a type argument.<br>
 static bool attributeIsTypeArgAttr(const IdentifierInfo &II) {<br>
 #define CLANG_ATTR_TYPE_ARG_LIST<br>
@@ -287,6 +296,12 @@ unsigned Parser::ParseAttributeArgsCommo<br>
   // Ignore the left paren location for now.<br>
   ConsumeParen();<br>
<br>
+  bool ChangeKWThisToIdent = attributeTreatsKeywordThisAsIdentifier(*AttrName);<br>
+<br>
+  // Interpret "kw_this" as an identifier if the attributed requests it.<br>
+  if (ChangeKWThisToIdent && Tok.is(tok::kw_this))<br>
+    Tok.setKind(tok::identifier);<br>
+<br>
   ArgsVector ArgExprs;<br>
   if (Tok.is(tok::identifier)) {<br>
     // If this attribute wants an 'identifier' argument, make it so.<br>
@@ -314,6 +329,10 @@ unsigned Parser::ParseAttributeArgsCommo<br>
<br>
     // Parse the non-empty comma-separated list of expressions.<br>
     do {<br>
+      // Interpret "kw_this" as an identifier if the attributed requests it.<br>
+      if (ChangeKWThisToIdent && Tok.is(tok::kw_this))<br>
+        Tok.setKind(tok::identifier);<br>
+<br>
       ExprResult ArgExpr;<br>
       if (Tok.is(tok::identifier) &&<br>
           attributeHasVariadicIdentifierArg(*AttrName)) {<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=351629&r1=351628&r2=351629&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=351629&r1=351628&r2=351629&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Jan 18 21:36:54 2019<br>
@@ -1927,10 +1927,13 @@ static void LookupPredefedObjCSuperType(<br>
       Context.setObjCSuperType(Context.getTagDeclType(TD));<br>
 }<br>
<br>
-static StringRef getHeaderName(ASTContext::GetBuiltinTypeError Error) {<br>
+static StringRef getHeaderName(Builtin::Context &BuiltinInfo, unsigned ID,<br>
+                               ASTContext::GetBuiltinTypeError Error) {<br>
   switch (Error) {<br>
   case ASTContext::GE_None:<br>
     return "";<br>
+  case ASTContext::GE_Missing_type:<br>
+    return BuiltinInfo.getHeaderName(ID);<br>
   case ASTContext::GE_Missing_stdio:<br>
     return "stdio.h";<br>
   case ASTContext::GE_Missing_setjmp:<br>
@@ -1955,7 +1958,8 @@ NamedDecl *Sema::LazilyCreateBuiltin(Ide<br>
   if (Error) {<br>
     if (ForRedeclaration)<br>
       Diag(Loc, diag::warn_implicit_decl_requires_sysheader)<br>
-          << getHeaderName(Error) << Context.BuiltinInfo.getName(ID);<br>
+          << getHeaderName(Context.BuiltinInfo, ID, Error)<br>
+          << Context.BuiltinInfo.getName(ID);<br>
     return nullptr;<br>
   }<br>
<br>
@@ -13580,6 +13584,13 @@ void Sema::AddKnownFunctionAttributes(Fu<br>
                                               FD->getLocation()));<br>
     }<br>
<br>
+    // Handle automatically recognized callbacks.<br>
+    SmallVector<int, 4> Encoding;<br>
+    if (!FD->hasAttr<CallbackAttr>() &&<br>
+        Context.BuiltinInfo.performsCallback(BuiltinID, Encoding))<br>
+      FD->addAttr(CallbackAttr::CreateImplicit(<br>
+          Context, Encoding.data(), Encoding.size(), FD->getLocation()));<br>
+<br>
     // Mark const if we don't care about errno and that is the only thing<br>
     // preventing the function from being const. This allows IRgen to use LLVM<br>
     // intrinsics for such functions.<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=351629&r1=351628&r2=351629&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=351629&r1=351628&r2=351629&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Fri Jan 18 21:36:54 2019<br>
@@ -3480,6 +3480,144 @@ static void handleFormatAttr(Sema &S, De<br>
     D->addAttr(NewAttr);<br>
 }<br>
<br>
+/// Handle __attribute__((callback(CalleeIdx, PayloadIdx0, ...))) attributes.<br>
+static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) {<br>
+  // The index that identifies the callback callee is mandatory.<br>
+  if (AL.getNumArgs() == 0) {<br>
+    S.Diag(AL.getLoc(), diag::err_callback_attribute_no_callee)<br>
+        << AL.getRange();<br>
+    return;<br>
+  }<br>
+<br>
+  bool HasImplicitThisParam = isInstanceMethod(D);<br>
+  int32_t NumArgs = getFunctionOrMethodNumParams(D);<br>
+<br>
+  FunctionDecl *FD = D->getAsFunction();<br>
+  assert(FD && "Expected a function declaration!");<br>
+<br>
+  llvm::StringMap<int> NameIdxMapping;<br>
+  NameIdxMapping["__"] = -1;<br>
+<br>
+  NameIdxMapping["this"] = 0;<br>
+<br>
+  int Idx = 1;<br>
+  for (const ParmVarDecl *PVD : FD->parameters())<br>
+    NameIdxMapping[PVD->getName()] = Idx++;<br>
+<br>
+  auto UnknownName = NameIdxMapping.end();<br>
+<br>
+  SmallVector<int, 8> EncodingIndices;<br>
+  for (unsigned I = 0, E = AL.getNumArgs(); I < E; ++I) {<br>
+    SourceRange SR;<br>
+    int32_t ArgIdx;<br>
+<br>
+    if (AL.isArgIdent(I)) {<br>
+      IdentifierLoc *IdLoc = AL.getArgAsIdent(I);<br>
+      auto It = NameIdxMapping.find(IdLoc->Ident->getName());<br>
+      if (It == UnknownName) {<br>
+        S.Diag(AL.getLoc(), diag::err_callback_attribute_argument_unknown)<br>
+            << IdLoc->Ident << IdLoc->Loc;<br>
+        return;<br>
+      }<br>
+<br>
+      SR = SourceRange(IdLoc->Loc);<br>
+      ArgIdx = It->second;<br>
+    } else if (AL.isArgExpr(I)) {<br>
+      Expr *IdxExpr = AL.getArgAsExpr(I);<br>
+<br>
+      // If the expression is not parseable as an int32_t we have a problem.<br>
+      if (!checkUInt32Argument(S, AL, IdxExpr, (uint32_t &)ArgIdx, I + 1,<br>
+                               false)) {<br>
+        S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)<br>
+            << AL << (I + 1) << IdxExpr->getSourceRange();<br>
+        return;<br>
+      }<br>
+<br>
+      // Check oob, excluding the special values, 0 and -1.<br>
+      if (ArgIdx < -1 || ArgIdx > NumArgs) {<br>
+        S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)<br>
+            << AL << (I + 1) << IdxExpr->getSourceRange();<br>
+        return;<br>
+      }<br>
+<br>
+      SR = IdxExpr->getSourceRange();<br>
+    } else {<br>
+      llvm_unreachable("Unexpected ParsedAttr argument type!");<br>
+    }<br>
+<br>
+    if (ArgIdx == 0 && !HasImplicitThisParam) {<br>
+      S.Diag(AL.getLoc(), diag::err_callback_implicit_this_not_available)<br>
+          << (I + 1) << SR;<br>
+      return;<br>
+    }<br>
+<br>
+    // Adjust for the case we do not have an implicit "this" parameter. In this<br>
+    // case we decrease all positive values by 1 to get LLVM argument indices.<br>
+    if (!HasImplicitThisParam && ArgIdx > 0)<br>
+      ArgIdx -= 1;<br>
+<br>
+    EncodingIndices.push_back(ArgIdx);<br>
+  }<br>
+<br>
+  int CalleeIdx = EncodingIndices.front();<br>
+  // Check if the callee index is proper, thus not "this" and not "unknown".<br>
+  if (CalleeIdx < HasImplicitThisParam) {<br>
+    S.Diag(AL.getLoc(), diag::err_callback_attribute_invalid_callee)<br>
+        << AL.getRange();<br>
+    return;<br>
+  }<br>
+<br>
+  // Get the callee type, note the index adjustment as the AST doesn't contain<br>
+  // the this type (which the callee cannot reference anyway!).<br>
+  const Type *CalleeType =<br>
+      getFunctionOrMethodParamType(D, CalleeIdx - HasImplicitThisParam)<br>
+          .getTypePtr();<br>
+  if (!CalleeType || !CalleeType->isFunctionPointerType()) {<br>
+    S.Diag(AL.getLoc(), diag::err_callback_callee_no_function_type)<br>
+        << AL.getRange();<br>
+    return;<br>
+  }<br>
+<br>
+  const Type *CalleeFnType =<br>
+      CalleeType->getPointeeType()->getUnqualifiedDesugaredType();<br>
+<br>
+  // TODO: Check the type of the callee arguments.<br>
+<br>
+  const auto *CalleeFnProtoType = dyn_cast<FunctionProtoType>(CalleeFnType);<br>
+  if (!CalleeFnProtoType) {<br>
+    S.Diag(AL.getLoc(), diag::err_callback_callee_no_function_type)<br>
+        << AL.getRange();<br>
+    return;<br>
+  }<br>
+<br>
+  if (CalleeFnProtoType->getNumParams() > EncodingIndices.size() - 1) {<br>
+    S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments)<br>
+        << AL << (unsigned)(EncodingIndices.size() - 1);<br>
+    return;<br>
+  }<br>
+<br>
+  if (CalleeFnProtoType->getNumParams() < EncodingIndices.size() - 1) {<br>
+    S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments)<br>
+        << AL << (unsigned)(EncodingIndices.size() - 1);<br>
+    return;<br>
+  }<br>
+<br>
+  if (CalleeFnProtoType->isVariadic()) {<br>
+    S.Diag(AL.getLoc(), diag::err_callback_callee_is_variadic) << AL.getRange();<br>
+    return;<br>
+  }<br>
+<br>
+  // Do not allow multiple callback attributes.<br>
+  if (D->hasAttr<CallbackAttr>()) {<br>
+    S.Diag(AL.getLoc(), diag::err_callback_attribute_multiple) << AL.getRange();<br>
+    return;<br>
+  }<br>
+<br>
+  D->addAttr(::new (S.Context) CallbackAttr(<br>
+      AL.getRange(), S.Context, EncodingIndices.data(), EncodingIndices.size(),<br>
+      AL.getAttributeSpellingListIndex()));<br>
+}<br>
+<br>
 static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {<br>
   // Try to find the underlying union declaration.<br>
   RecordDecl *RD = nullptr;<br>
@@ -6451,6 +6589,9 @@ static void ProcessDeclAttribute(Sema &S<br>
   case ParsedAttr::AT_FormatArg:<br>
     handleFormatArgAttr(S, D, AL);<br>
     break;<br>
+  case ParsedAttr::AT_Callback:<br>
+    handleCallbackAttr(S, D, AL);<br>
+    break;<br>
   case ParsedAttr::AT_CUDAGlobal:<br>
     handleGlobalAttr(S, D, AL);<br>
     break;<br>
<br>
Modified: cfe/trunk/test/Analysis/retain-release.m<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release.m?rev=351629&r1=351628&r2=351629&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/retain-release.m?rev=351629&r1=351628&r2=351629&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/Analysis/retain-release.m (original)<br>
+++ cfe/trunk/test/Analysis/retain-release.m Fri Jan 18 21:36:54 2019<br>
@@ -2,7 +2,7 @@<br>
 // RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10\<br>
 // RUN:     -analyzer-checker=core,osx.coreFoundation.CFRetainRelease\<br>
 // RUN:     -analyzer-checker=osx.cocoa.ClassRelease,osx.cocoa.RetainCount\<br>
-// RUN:     -analyzer-checker=debug.ExprInspection -fblocks -verify %s\<br>
+// RUN:     -analyzer-checker=debug.ExprInspection -fblocks -verify=expected,C %s\<br>
 // RUN:     -Wno-objc-root-class -analyzer-output=plist -o %t.objc.plist<br>
 // RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10\<br>
 // RUN:     -analyzer-checker=core,osx.coreFoundation.CFRetainRelease\<br>
@@ -1202,7 +1202,7 @@ typedef __darwin_pthread_attr_t pthread_<br>
 typedef unsigned long __darwin_pthread_key_t;<br>
 typedef __darwin_pthread_key_t pthread_key_t;<br>
<br>
-int pthread_create(pthread_t *, const pthread_attr_t *,<br>
+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>}}<br>
                    void *(*)(void *), void *);<br>
<br>
 int pthread_setspecific(pthread_key_t key, const void *value);<br>
<br>
Added: cfe/trunk/test/CodeGen/attr-callback.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/attr-callback.c?rev=351629&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/attr-callback.c?rev=351629&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGen/attr-callback.c (added)<br>
+++ cfe/trunk/test/CodeGen/attr-callback.c Fri Jan 18 21:36:54 2019<br>
@@ -0,0 +1,28 @@<br>
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s<br>
+<br>
+void cb0(void);<br>
+<br>
+// CHECK-DAG: !callback ![[cid0:[0-9]+]] void @no_args<br>
+__attribute__((callback(1))) void no_args(void (*callback)(void));<br>
+<br>
+// CHECK-DAG: @args_1({{[^#]*#[0-9]+}} !callback ![[cid1:[0-9]+]]<br>
+__attribute__((callback(1, 2, 3))) void args_1(void (*callback)(int, double), int a, double b) { no_args(cb0); }<br>
+<br>
+// CHECK-DAG: !callback ![[cid2:[0-9]+]]  void @args_2a<br>
+__attribute__((callback(2, 3, 3))) void args_2a(int a, void (*callback)(double, double), double b);<br>
+// CHECK-DAG: !callback ![[cid2]]         void @args_2b<br>
+__attribute__((callback(callback, b, b))) void args_2b(int a, void (*callback)(double, double), double b);<br>
+<br>
+// CHECK-DAG: void @args_3a({{[^#]*#[0-9]+}} !callback ![[cid3:[0-9]+]]<br>
+__attribute__((callback(2, -1, -1))) void args_3a(int a, void (*callback)(double, double), double b) { args_2a(a, callback, b); }<br>
+// CHECK-DAG: void @args_3b({{[^#]*#[0-9]+}} !callback ![[cid3]]<br>
+__attribute__((callback(callback, __, __))) void args_3b(int a, void (*callback)(double, double), double b) { args_2b(a, callback, b); }<br>
+<br>
+// CHECK-DAG: ![[cid0]] = !{![[cid0b:[0-9]+]]}<br>
+// CHECK-DAG: ![[cid0b]] = !{i64 0, i1 false}<br>
+// CHECK-DAG: ![[cid1]] = !{![[cid1b:[0-9]+]]}<br>
+// CHECK-DAG: ![[cid1b]] = !{i64 0, i64 1, i64 2, i1 false}<br>
+// CHECK-DAG: ![[cid2]] = !{![[cid2b:[0-9]+]]}<br>
+// CHECK-DAG: ![[cid2b]] = !{i64 1, i64 2, i64 2, i1 false}<br>
+// CHECK-DAG: ![[cid3]] = !{![[cid3b:[0-9]+]]}<br>
+// CHECK-DAG: ![[cid3b]] = !{i64 1, i64 -1, i64 -1, i1 false}<br>
<br>
Added: cfe/trunk/test/CodeGen/callback_annotated.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/callback_annotated.c?rev=351629&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/callback_annotated.c?rev=351629&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGen/callback_annotated.c (added)<br>
+++ cfe/trunk/test/CodeGen/callback_annotated.c Fri Jan 18 21:36:54 2019<br>
@@ -0,0 +1,73 @@<br>
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 %s -emit-llvm -o - | FileCheck %s --check-prefix=RUN1<br>
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 %s -emit-llvm -o - | FileCheck %s --check-prefix=RUN2<br>
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 %s -emit-llvm -o - | opt -ipconstprop -S | FileCheck --check-prefix=IPCP %s<br>
+<br>
+// RUN1-DAG: @broker0({{[^#]*#[0-9]+}} !callback ![[cid0:[0-9]+]]<br>
+__attribute__((callback(1, 2))) void *broker0(void *(*callee)(void *), void *payload) {<br>
+  return callee(payload);<br>
+}<br>
+<br>
+// RUN1-DAG: @broker1({{[^#]*#[0-9]+}} !callback ![[cid1:[0-9]+]]<br>
+__attribute__((callback(callee, payload))) void *broker1(void *payload, void *(*callee)(void *)) {<br>
+  return broker0(callee, payload);<br>
+}<br>
+<br>
+void *broker2(void (*callee)(void));<br>
+<br>
+// RUN1-DAG: declare !callback ![[cid2:[0-9]+]] i8* @broker2<br>
+__attribute__((callback(callee))) void *broker2(void (*callee)(void));<br>
+<br>
+void *broker2(void (*callee)(void));<br>
+<br>
+// RUN1-DAG: declare !callback ![[cid3:[0-9]+]] i8* @broker3<br>
+__attribute__((callback(4, 1, 2, c))) void *broker3(int, int, int c, int (*callee)(int, int, int), int);<br>
+<br>
+// RUN1-DAG: declare !callback ![[cid4:[0-9]+]] i8* @broker4<br>
+__attribute__((callback(4, -1, a, __))) void *broker4(int a, int, int, int (*callee)(int, int, int), int);<br>
+<br>
+// RUN1-DAG: declare !callback ![[cid5:[0-9]+]] i8* @broker5<br>
+__attribute__((callback(4, d, 5, 2))) void *broker5(int, int, int, int (*callee)(int, int, int), int d);<br>
+<br>
+static void *VoidPtr2VoidPtr(void *payload) {<br>
+  // RUN2: ret i8* %payload<br>
+  // IPCP:  ret i8* null<br>
+  return payload;<br>
+}<br>
+<br>
+static int ThreeInt2Int(int a, int b, int c) {<br>
+  // RUN2:      define internal i32 @ThreeInt2Int(i32 %a, i32 %b, i32 %c)<br>
+  // RUN2-NEXT: entry:<br>
+  // RUN2-NEXT:     %mul = mul nsw i32 %b, %a<br>
+  // RUN2-NEXT:     %add = add nsw i32 %mul, %c<br>
+  // RUN2-NEXT:     ret i32 %add<br>
+<br>
+  // IPCP:       define internal i32 @ThreeInt2Int(i32 %a, i32 %b, i32 %c)<br>
+  // IPCP-NEXT:  entry:<br>
+  // IPCP-NEXT:      %mul = mul nsw i32 4, %a<br>
+  // IPCP-NEXT:      %add = add nsw i32 %mul, %c<br>
+  // IPCP-NEXT:      ret i32 %add<br>
+<br>
+  return a * b + c;<br>
+}<br>
+<br>
+void foo() {<br>
+  broker0(VoidPtr2VoidPtr, 0l);<br>
+  broker1(0l, VoidPtr2VoidPtr);<br>
+  broker2(foo);<br>
+  broker3(1, 4, 5, ThreeInt2Int, 1);<br>
+  broker4(4, 2, 7, ThreeInt2Int, 0);<br>
+  broker5(8, 0, 3, ThreeInt2Int, 4);<br>
+}<br>
+<br>
+// RUN1-DAG: ![[cid0]] = !{![[cid0b:[0-9]+]]}<br>
+// RUN1-DAG: ![[cid0b]] = !{i64 0, i64 1, i1 false}<br>
+// RUN1-DAG: ![[cid1]] = !{![[cid1b:[0-9]+]]}<br>
+// RUN1-DAG: ![[cid1b]] = !{i64 1, i64 0, i1 false}<br>
+// RUN1-DAG: ![[cid2]] = !{![[cid2b:[0-9]+]]}<br>
+// RUN1-DAG: ![[cid2b]] = !{i64 0, i1 false}<br>
+// RUN1-DAG: ![[cid3]] = !{![[cid3b:[0-9]+]]}<br>
+// RUN1-DAG: ![[cid3b]] = !{i64 3, i64 0, i64 1, i64 2, i1 false}<br>
+// RUN1-DAG: ![[cid4]] = !{![[cid4b:[0-9]+]]}<br>
+// RUN1-DAG: ![[cid4b]] = !{i64 3, i64 -1, i64 0, i64 -1, i1 false}<br>
+// RUN1-DAG: ![[cid5]] = !{![[cid5b:[0-9]+]]}<br>
+// RUN1-DAG: ![[cid5b]] = !{i64 3, i64 4, i64 4, i64 1, i1 false}<br>
<br>
Added: cfe/trunk/test/CodeGen/callback_openmp.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/callback_openmp.c?rev=351629&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/callback_openmp.c?rev=351629&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGen/callback_openmp.c (added)<br>
+++ cfe/trunk/test/CodeGen/callback_openmp.c Fri Jan 18 21:36:54 2019<br>
@@ -0,0 +1,28 @@<br>
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 %s -emit-llvm -o - | FileCheck %s<br>
+// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 %s -emit-llvm -o - | opt -ipconstprop -S | FileCheck --check-prefix=IPCP %s<br>
+<br>
+// CHECK: declare !callback ![[cid:[0-9]+]] void @__kmpc_fork_call<br>
+// CHECK: declare !callback ![[cid]] void @__kmpc_fork_teams<br>
+// CHECK: ![[cid]] = !{![[cidb:[0-9]+]]}<br>
+// CHECK: ![[cidb]] = !{i64 2, i64 -1, i64 -1, i1 true}<br>
+<br>
+void work1(int, int);<br>
+void work2(int, int);<br>
+void work12(int, int);<br>
+<br>
+void foo(int q) {<br>
+  int p = 2;<br>
+<br>
+  #pragma omp parallel firstprivate(q, p)<br>
+  work1(p, q);<br>
+// IPCP: call void @work1(i32 2, i32 %{{[._a-zA-Z0-9]*}})<br>
+<br>
+  #pragma omp parallel for firstprivate(p, q)<br>
+  for (int i = 0; i < q; i++)<br>
+    work2(i, p);<br>
+// IPCP: call void @work2(i32 %{{[._a-zA-Z0-9]*}}, i32 2)<br>
+<br>
+  #pragma omp target teams firstprivate(p)<br>
+  work12(p, p);<br>
+// IPCP: call void @work12(i32 2, i32 2)<br>
+}<br>
<br>
Added: cfe/trunk/test/CodeGen/callback_pthread_create.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/callback_pthread_create.c?rev=351629&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/callback_pthread_create.c?rev=351629&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGen/callback_pthread_create.c (added)<br>
+++ cfe/trunk/test/CodeGen/callback_pthread_create.c Fri Jan 18 21:36:54 2019<br>
@@ -0,0 +1,32 @@<br>
+// RUN: %clang -O1 %s -S -c -emit-llvm -o - | FileCheck %s<br>
+// RUN: %clang -O1 %s -S -c -emit-llvm -o - | opt -ipconstprop -S | FileCheck --check-prefix=IPCP %s<br>
+<br>
+// CHECK: declare !callback ![[cid:[0-9]+]] dso_local i32 @pthread_create<br>
+// CHECK: ![[cid]] = !{![[cidb:[0-9]+]]}<br>
+// CHECK: ![[cidb]] = !{i64 2, i64 3, i1 false}<br>
+<br>
+#include <pthread.h></blockquote><div><br></div><div>Another thing I notecide is that this code assumes the system has `pthread.h` -- what about systems without it? I mean, you can disable the test, but it seems bad to lose test coverage just because of that.</div><div><br></div><div>I would much prefer that you provide your own stub `pthread.h` in the Inputs/... tree of the test suite and use that to test this in a portable way.</div><div><br></div><div>-Chandler </div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+const int GlobalVar = 0;<br>
+<br>
+static void *callee0(void *payload) {<br>
+// IPCP:      define internal i8* @callee0<br>
+// IPCP-NEXT:   entry:<br>
+// IPCP-NEXT:     ret i8* null<br>
+  return payload;<br>
+}<br>
+<br>
+static void *callee1(void *payload) {<br>
+// IPCP:      define internal i8* @callee1<br>
+// IPCP-NEXT:   entry:<br>
+// IPCP-NEXT:     ret i8* bitcast (i32* @GlobalVar to i8*)<br>
+  return payload;<br>
+}<br>
+<br>
+void foo() {<br>
+  pthread_t MyFirstThread;<br>
+  pthread_create(&MyFirstThread, NULL, callee0, NULL);<br>
+<br>
+  pthread_t MySecondThread;<br>
+  pthread_create(&MySecondThread, NULL, callee1, (void *)&GlobalVar);<br>
+}<br>
<br>
Added: cfe/trunk/test/CodeGenCXX/attr-callback.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/attr-callback.cpp?rev=351629&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/attr-callback.cpp?rev=351629&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/attr-callback.cpp (added)<br>
+++ cfe/trunk/test/CodeGenCXX/attr-callback.cpp Fri Jan 18 21:36:54 2019<br>
@@ -0,0 +1,55 @@<br>
+// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s<br>
+<br>
+struct Base {<br>
+<br>
+  void no_args_1(void (*callback)(void));<br>
+  __attribute__((callback(1))) void no_args_2(void (*callback1)(void), void (*callback2)(void));<br>
+  __attribute__((callback(callback1))) void no_args_3(void (*callback1)(void), void (*callback2)(void));<br>
+<br>
+  // TODO: There should probably be a warning or even an error for different<br>
+  //       callbacks on the same method.<br>
+  __attribute__((callback(1))) virtual void<br>
+  virtual_1(void (*callback)(void));<br>
+<br>
+  __attribute__((callback(callback, this, __, this))) virtual void<br>
+  this_unknown_this(void (*callback)(Base *, Base *, Base *));<br>
+};<br>
+<br>
+// CHECK-DAG:      define void @_ZN4Base9no_args_1EPFvvE({{[^!]*!callback}} ![[cid0:[0-9]+]]<br>
+__attribute__((callback(1))) void<br>
+Base::no_args_1(void (*callback)(void)) {<br>
+}<br>
+<br>
+// CHECK-DAG:      define void @_ZN4Base9no_args_2EPFvvES1_({{[^!]*!callback}} ![[cid1:[0-9]+]]<br>
+__attribute__((callback(2))) void Base::no_args_2(void (*callback1)(void), void (*callback2)(void)) {<br>
+}<br>
+// CHECK-DAG:      define void @_ZN4Base9no_args_3EPFvvES1_({{[^!]*!callback}} ![[cid1]]<br>
+__attribute__((callback(callback2))) void Base::no_args_3(void (*callback1)(void), void (*callback2)(void)) {<br>
+}<br>
+<br>
+// CHECK-DAG:      define void @_ZN4Base17this_unknown_thisEPFvPS_S0_S0_E({{[^!]*!callback}} ![[cid2:[0-9]+]]<br>
+void Base::this_unknown_this(void (*callback)(Base *, Base *, Base *)) {<br>
+}<br>
+<br>
+struct Derived_1 : public Base {<br>
+  __attribute__((callback(1))) virtual void<br>
+  virtual_1(void (*callback)(void)) override;<br>
+};<br>
+<br>
+// CHECK-DAG:      define void @_ZN9Derived_19virtual_1EPFvvE({{[^!]*!callback}} ![[cid0]]<br>
+void Derived_1::virtual_1(void (*callback)(void)) {}<br>
+<br>
+struct Derived_2 : public Base {<br>
+  void virtual_1(void (*callback)(void)) override;<br>
+};<br>
+<br>
+// CHECK-DAG: define void @_ZN9Derived_29virtual_1EPFvvE<br>
+// CHECK-NOT: !callback<br>
+void Derived_2::virtual_1(void (*callback)(void)) {}<br>
+<br>
+// CHECK-DAG: ![[cid0]] = !{![[cid0b:[0-9]+]]}<br>
+// CHECK-DAG: ![[cid0b]] = !{i64 1, i1 false}<br>
+// CHECK-DAG: ![[cid1]] = !{![[cid1b:[0-9]+]]}<br>
+// CHECK-DAG: ![[cid1b]] = !{i64 2, i1 false}<br>
+// CHECK-DAG: ![[cid2]] = !{![[cid2b:[0-9]+]]}<br>
+// CHECK-DAG: ![[cid2b]] = !{i64 1, i64 0, i64 -1, i64 0, i1 false}<br>
<br>
Modified: cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test?rev=351629&r1=351628&r2=351629&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test?rev=351629&r1=351628&r2=351629&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test (original)<br>
+++ cfe/trunk/test/Misc/pragma-attribute-supported-attributes-list.test Fri Jan 18 21:36:54 2019<br>
@@ -32,6 +32,7 @@<br>
 // CHECK-NEXT: CUDAShared (SubjectMatchRule_variable)<br>
 // CHECK-NEXT: CXX11NoReturn (SubjectMatchRule_function)<br>
 // CHECK-NEXT: CallableWhen (SubjectMatchRule_function_is_member)<br>
+// CHECK-NEXT: Callback (SubjectMatchRule_function)<br>
 // CHECK-NEXT: Capability (SubjectMatchRule_record, SubjectMatchRule_type_alias)<br>
 // CHECK-NEXT: CarriesDependency (SubjectMatchRule_variable_is_parameter, SubjectMatchRule_objc_method, SubjectMatchRule_function)<br>
 // CHECK-NEXT: Cold (SubjectMatchRule_function)<br>
<br>
Modified: cfe/trunk/test/OpenMP/parallel_codegen.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/parallel_codegen.cpp?rev=351629&r1=351628&r2=351629&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/OpenMP/parallel_codegen.cpp?rev=351629&r1=351628&r2=351629&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/OpenMP/parallel_codegen.cpp (original)<br>
+++ cfe/trunk/test/OpenMP/parallel_codegen.cpp Fri Jan 18 21:36:54 2019<br>
@@ -82,9 +82,9 @@ int main (int argc, char **argv) {<br>
 // CHECK-DEBUG-NEXT:  }<br>
<br>
 // CHECK-DAG: define linkonce_odr {{.*}}void [[FOO]]({{i32[ ]?[a-z]*}} %argc)<br>
-// CHECK-DAG: declare {{.*}}void @__kmpc_fork_call(%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...)<br>
+// CHECK-DAG: declare !callback ![[cbid:[0-9]+]] {{.*}}void @__kmpc_fork_call(%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...)<br>
 // CHECK-DEBUG-DAG: define linkonce_odr void [[FOO]](i32 %argc)<br>
-// CHECK-DEBUG-DAG: declare void @__kmpc_fork_call(%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...)<br>
+// CHECK-DEBUG-DAG: declare !callback ![[cbid:[0-9]+]] void @__kmpc_fork_call(%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...)<br>
 // CHECK-DEBUG-DAG:       define internal void [[OMP_OUTLINED]](i32* noalias %.global_tid., i32* noalias %.bound_tid., i64 [[VLA_SIZE:%.+]], i32* {{.+}} [[VLA_ADDR:%[^)]+]])<br>
 // CHECK-DEBUG-DAG:       call void [[OMP_OUTLINED_DEBUG]]<br>
<br>
@@ -131,5 +131,6 @@ int main (int argc, char **argv) {<br>
<br>
 // CHECK: attributes #[[FN_ATTRS]] = {{.+}} nounwind<br>
 // CHECK-DEBUG: attributes #[[FN_ATTRS]] = {{.+}} nounwind<br>
-<br>
+// CHECK: ![[cbid]] = !{![[cbidb:[0-9]+]]}<br>
+// CHECK: ![[cbidb]] = !{i64 2, i64 -1, i64 -1, i1 true}<br>
 #endif<br>
<br>
Added: cfe/trunk/test/Sema/attr-callback-broken.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-callback-broken.c?rev=351629&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-callback-broken.c?rev=351629&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/Sema/attr-callback-broken.c (added)<br>
+++ cfe/trunk/test/Sema/attr-callback-broken.c Fri Jan 18 21:36:54 2019<br>
@@ -0,0 +1,75 @@<br>
+// RUN: %clang_cc1 %s -verify -fsyntax-only<br>
+<br>
+__attribute__((callback())) void no_callee(void (*callback)(void)); // expected-error {{'callback' attribute specifies no callback callee}}<br>
+<br>
+__attribute__((callback(1, 1))) void too_many_args_1(void (*callback)(void)) {}      // expected-error {{'callback' attribute takes one argument}}<br>
+__attribute__((callback(1, -1))) void too_many_args_2(double (*callback)(void));     // expected-error {{'callback' attribute takes one argument}}<br>
+__attribute__((callback(1, 2, 2))) void too_many_args_3(void (*callback)(int), int); // expected-error {{'callback' attribute requires exactly 2 arguments}}<br>
+<br>
+__attribute__((callback(1, 2))) void too_few_args_1(void (*callback)(int, int), int); // expected-error {{'callback' attribute takes one argument}}<br>
+__attribute__((callback(1))) void too_few_args_2(int (*callback)(int));               // expected-error {{'callback' attribute takes no arguments}}<br>
+__attribute__((callback(1, -1))) void too_few_args_3(void (*callback)(int, int)) {}   // expected-error {{'callback' attribute takes one argument}}<br>
+<br>
+__attribute__((callback(-1))) void oob_args_1(void (*callback)(void));         // expected-error {{'callback' attribute specifies invalid callback callee}}<br>
+__attribute__((callback(2))) void oob_args_2(int *(*callback)(void)) {}        // expected-error {{'callback' attribute parameter 1 is out of bounds}}<br>
+__attribute__((callback(1, 3))) void oob_args_3(short (*callback)(int), int);  // expected-error {{'callback' attribute parameter 2 is out of bounds}}<br>
+__attribute__((callback(-2, 2))) void oob_args_4(void *(*callback)(int), int); // expected-error {{'callback' attribute parameter 1 is out of bounds}}<br>
+__attribute__((callback(1, -2))) void oob_args_5(void *(*callback)(int), int); // expected-error {{'callback' attribute parameter 2 is out of bounds}}<br>
+__attribute__((callback(1, 2))) void oob_args_6(void *(*callback)(int), ...);  // expected-error {{'callback' attribute parameter 2 is out of bounds}}<br>
+<br>
+__attribute__((callback(1))) __attribute__((callback(1))) void multiple_cb_1(void (*callback)(void));                           // expected-error {{multiple 'callback' attributes specified}}<br>
+__attribute__((callback(1))) __attribute__((callback(2))) void multiple_cb_2(void (*callback1)(void), void (*callback2)(void)); // expected-error {{multiple 'callback' attributes specified}}<br>
+<br>
+#ifdef HAS_THIS<br>
+__attribute__((callback(0))) void oob_args_0(void (*callback)(void)); // expected-error {{'callback' attribute specifies invalid callback callee}}<br>
+#else<br>
+__attribute__((callback(0))) void oob_args_0(void (*callback)(void));                 // expected-error {{'callback' argument at position 1 references unavailable implicit 'this'}}<br>
+__attribute__((callback(1, 0))) void no_this_1(void *(*callback)(void *));            // expected-error {{'callback' argument at position 2 references unavailable implicit 'this'}}<br>
+__attribute__((callback(1, 0))) void no_this_2(void *(*callback)(int, void *));       // expected-error {{'callback' argument at position 2 references unavailable implicit 'this'}}<br>
+#endif<br>
+<br>
+// We could allow the following declarations if we at some point need to:<br>
+<br>
+__attribute__((callback(1, -1))) void vararg_cb_1(void (*callback)(int, ...)) {}     // expected-error {{'callback' attribute callee may not be variadic}}<br>
+__attribute__((callback(1, 1))) void vararg_cb_2(void (*callback)(int, ...), int a); // expected-error {{'callback' attribute callee may not be variadic}}<br>
+<br>
+__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 requires exactly 6 arguments}}<br>
+__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 requires exactly 6 arguments}}<br>
+<br>
+__attribute__((callback(1, -1, 1))) void self_arg_1(void (*callback)(int, ...)) {}          // expected-error {{'callback' attribute requires exactly 2 arguments}}<br>
+__attribute__((callback(1, -1, 1, -1, -1, 1))) void self_arg_2(void (*callback)(int, ...)); // expected-error {{'callback' attribute requires exactly 5 arguments}}<br>
+<br>
+__attribute__((callback(cb))) void unknown_name1(void (*callback)(void)) {}     // expected-error {{'callback' attribute argument 'cb' is not a known function parameter}}<br>
+__attribute__((callback(cb, ab))) void unknown_name2(void (*cb)(int), int a) {} // expected-error {{'callback' attribute argument 'ab' is not a known function parameter}}<br>
+<br>
+__attribute__((callback(callback, 1))) void too_many_args_1b(void (*callback)(void)) {}      // expected-error {{'callback' attribute takes one argument}}<br>
+__attribute__((callback(callback, __))) void too_many_args_2b(double (*callback)(void));     // expected-error {{'callback' attribute takes one argument}}<br>
+__attribute__((callback(callback, 2, 2))) void too_many_args_3b(void (*callback)(int), int); // expected-error {{'callback' attribute requires exactly 2 arguments}}<br>
+<br>
+__attribute__((callback(callback, a))) void too_few_args_1b(void (*callback)(int, int), int a); // expected-error {{'callback' attribute takes one argument}}<br>
+__attribute__((callback(callback))) void too_few_args_2b(int (*callback)(int));                 // expected-error {{'callback' attribute takes no arguments}}<br>
+__attribute__((callback(callback, __))) void too_few_args_3b(void (*callback)(int, int)) {}     // expected-error {{'callback' attribute takes one argument}}<br>
+<br>
+__attribute__((callback(__))) void oob_args_1b(void (*callback)(void)); // expected-error {{'callback' attribute specifies invalid callback callee}}<br>
+<br>
+__attribute__((callback(callback))) __attribute__((callback(callback))) void multiple_cb_1b(void (*callback)(void));                     // expected-error {{multiple 'callback' attributes specified}}<br>
+__attribute__((callback(1))) __attribute__((callback(callback2))) void multiple_cb_2b(void (*callback1)(void), void (*callback2)(void)); // expected-error {{multiple 'callback' attributes specified}}<br>
+<br>
+#ifdef HAS_THIS<br>
+__attribute__((callback(this))) void oob_args_0b(void (*callback)(void)); // expected-error {{'callback' attribute specifies invalid callback callee}}<br>
+#else<br>
+__attribute__((callback(this))) void oob_args_0b(void (*callback)(void));           // expected-error {{'callback' argument at position 1 references unavailable implicit 'this'}}<br>
+__attribute__((callback(1, this))) void no_this_1b(void *(*callback)(void *));      // expected-error {{'callback' argument at position 2 references unavailable implicit 'this'}}<br>
+__attribute__((callback(1, this))) void no_this_2b(void *(*callback)(int, void *)); // expected-error {{'callback' argument at position 2 references unavailable implicit 'this'}}<br>
+#endif<br>
+<br>
+// We could allow the following declarations if we at some point need to:<br>
+<br>
+__attribute__((callback(callback, __))) void vararg_cb_1b(void (*callback)(int, ...)) {} // expected-error {{'callback' attribute callee may not be variadic}}<br>
+__attribute__((callback(1, a))) void vararg_cb_2b(void (*callback)(int, ...), int a);    // expected-error {{'callback' attribute callee may not be variadic}}<br>
+<br>
+__attribute__((callback(callback, __, callback, a, b, c, __))) void varargs_1b(void (*callback)(int, ...), int a, float b, double c) {} // expected-error {{'callback' attribute requires exactly 6 arguments}}<br>
+__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 requires exactly 6 arguments}}<br>
+<br>
+__attribute__((callback(1, __, callback))) void self_arg_1b(void (*callback)(int, ...)) {}                        // expected-error {{'callback' attribute requires exactly 2 arguments}}<br>
+__attribute__((callback(callback, __, callback, __, __, callback))) void self_arg_2b(void (*callback)(int, ...)); // expected-error {{'callback' attribute requires exactly 5 arguments}}<br>
<br>
Added: cfe/trunk/test/Sema/attr-callback.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-callback.c?rev=351629&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-callback.c?rev=351629&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/Sema/attr-callback.c (added)<br>
+++ cfe/trunk/test/Sema/attr-callback.c Fri Jan 18 21:36:54 2019<br>
@@ -0,0 +1,14 @@<br>
+// RUN: %clang_cc1 %s -verify -fsyntax-only<br>
+<br>
+// expected-no-diagnostics<br>
+<br>
+__attribute__((callback(1))) void no_args(void (*callback)(void));<br>
+__attribute__((callback(1, 2, 3))) void args_1(void (*callback)(int, double), int a, double b);<br>
+__attribute__((callback(2, 3, 3))) void args_2(int a, void (*callback)(double, double), double b);<br>
+__attribute__((callback(2, -1, -1))) void args_3(int a, void (*callback)(double, double), double b);<br>
+<br>
+__attribute__((callback(callback))) void no_argsb(void (*callback)(void));<br>
+__attribute__((callback(callback, a, 3))) void args_1b(void (*callback)(int, double), int a, double b);<br>
+__attribute__((callback(callback, b, b))) void args_2b(int a, void (*callback)(double, double), double b);<br>
+__attribute__((callback(2, __, __))) void args_3b(int a, void (*callback)(double, double), double b);<br>
+__attribute__((callback(callback, -1, __))) void args_3c(int a, void (*callback)(double, double), double b);<br>
<br>
Added: cfe/trunk/test/SemaCXX/attr-callback-broken.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-callback-broken.cpp?rev=351629&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-callback-broken.cpp?rev=351629&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/SemaCXX/attr-callback-broken.cpp (added)<br>
+++ cfe/trunk/test/SemaCXX/attr-callback-broken.cpp Fri Jan 18 21:36:54 2019<br>
@@ -0,0 +1,7 @@<br>
+// RUN: %clang_cc1 %s -verify -fsyntax-only<br>
+<br>
+class C_in_class {<br>
+#define HAS_THIS<br>
+#include "../Sema/attr-callback-broken.c"<br>
+#undef HAS_THIS<br>
+};<br>
<br>
Added: cfe/trunk/test/SemaCXX/attr-callback.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-callback.cpp?rev=351629&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-callback.cpp?rev=351629&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/SemaCXX/attr-callback.cpp (added)<br>
+++ cfe/trunk/test/SemaCXX/attr-callback.cpp Fri Jan 18 21:36:54 2019<br>
@@ -0,0 +1,67 @@<br>
+// RUN: %clang_cc1 %s -verify -fsyntax-only<br>
+<br>
+// expected-no-diagnostics<br>
+<br>
+class C_in_class {<br>
+#include "../Sema/attr-callback.c"<br>
+};<br>
+<br>
+struct Base {<br>
+<br>
+  void no_args_1(void (*callback)(void));<br>
+  __attribute__((callback(1))) void no_args_2(void (*callback)(void));<br>
+  __attribute__((callback(callback))) void no_args_3(void (*callback)(void)) {}<br>
+<br>
+  __attribute__((callback(1, 0))) virtual void<br>
+  this_tr(void (*callback)(Base *));<br>
+<br>
+  __attribute__((callback(1, this, __, this))) virtual void<br>
+  this_unknown_this(void (*callback)(Base *, Base *, Base *));<br>
+<br>
+  __attribute__((callback(1))) virtual void<br>
+  virtual_1(void (*callback)(void));<br>
+<br>
+  __attribute__((callback(callback))) virtual void<br>
+  virtual_2(void (*callback)(void));<br>
+<br>
+  __attribute__((callback(1))) virtual void<br>
+  virtual_3(void (*callback)(void));<br>
+};<br>
+<br>
+__attribute__((callback(1))) void<br>
+Base::no_args_1(void (*callback)(void)) {<br>
+}<br>
+<br>
+void Base::no_args_2(void (*callback)(void)) {<br>
+}<br>
+<br>
+struct Derived_1 : public Base {<br>
+<br>
+  __attribute__((callback(1, 0))) virtual void<br>
+  this_tr(void (*callback)(Base *)) override;<br>
+<br>
+  __attribute__((callback(1))) virtual void<br>
+  virtual_1(void (*callback)(void)) override {}<br>
+<br>
+  virtual void<br>
+  virtual_3(void (*callback)(void)) override {}<br>
+};<br>
+<br>
+struct Derived_2 : public Base {<br>
+<br>
+  __attribute__((callback(callback))) virtual void<br>
+  virtual_1(void (*callback)(void)) override;<br>
+<br>
+  virtual void<br>
+  virtual_2(void (*callback)(void)) override;<br>
+<br>
+  virtual void<br>
+  virtual_3(void (*callback)(void)) override;<br>
+};<br>
+<br>
+void Derived_2::virtual_1(void (*callback)(void)) {}<br>
+<br>
+__attribute__((callback(1))) void<br>
+Derived_2::virtual_2(void (*callback)(void)) {}<br>
+<br>
+void Derived_2::virtual_3(void (*callback)(void)) {}<br>
<br>
Modified: cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=351629&r1=351628&r2=351629&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp?rev=351629&r1=351628&r2=351629&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp (original)<br>
+++ cfe/trunk/utils/TableGen/ClangAttrEmitter.cpp Fri Jan 18 21:36:54 2019<br>
@@ -776,6 +776,11 @@ namespace {<br>
     }<br>
   };<br>
<br>
+  struct VariadicParamOrParamIdxArgument : public VariadicArgument {<br>
+    VariadicParamOrParamIdxArgument(const Record &Arg, StringRef Attr)<br>
+        : VariadicArgument(Arg, Attr, "int") {}<br>
+  };<br>
+<br>
   // Unique the enums, but maintain the original declaration ordering.<br>
   std::vector<StringRef><br>
   uniqueEnumsInOrder(const std::vector<StringRef> &enums) {<br>
@@ -1284,6 +1289,8 @@ createArgument(const Record &Arg, String<br>
     Ptr = llvm::make_unique<VariadicExprArgument>(Arg, Attr);<br>
   else if (ArgName == "VariadicParamIdxArgument")<br>
     Ptr = llvm::make_unique<VariadicParamIdxArgument>(Arg, Attr);<br>
+  else if (ArgName == "VariadicParamOrParamIdxArgument")<br>
+    Ptr = llvm::make_unique<VariadicParamOrParamIdxArgument>(Arg, Attr);<br>
   else if (ArgName == "ParamIdxArgument")<br>
     Ptr = llvm::make_unique<SimpleArgument>(Arg, Attr, "ParamIdx");<br>
   else if (ArgName == "VariadicIdentifierArgument")<br>
@@ -2117,6 +2124,7 @@ static bool isVariadicIdentifierArgument<br>
          llvm::StringSwitch<bool>(<br>
              Arg->getSuperClasses().back().first->getName())<br>
              .Case("VariadicIdentifierArgument", true)<br>
+             .Case("VariadicParamOrParamIdxArgument", true)<br>
              .Default(false);<br>
 }<br>
<br>
@@ -2159,6 +2167,34 @@ static void emitClangAttrIdentifierArgLi<br>
   OS << "#endif // CLANG_ATTR_IDENTIFIER_ARG_LIST\n\n";<br>
 }<br>
<br>
+static bool keywordThisIsaIdentifierInArgument(const Record *Arg) {<br>
+  return !Arg->getSuperClasses().empty() &&<br>
+         llvm::StringSwitch<bool>(<br>
+             Arg->getSuperClasses().back().first->getName())<br>
+             .Case("VariadicParamOrParamIdxArgument", true)<br>
+             .Default(false);<br>
+}<br>
+<br>
+static void emitClangAttrThisIsaIdentifierArgList(RecordKeeper &Records,<br>
+                                                  raw_ostream &OS) {<br>
+  OS << "#if defined(CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST)\n";<br>
+  std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");<br>
+  for (const auto *A : Attrs) {<br>
+    // Determine whether the first argument is a variadic identifier.<br>
+    std::vector<Record *> Args = A->getValueAsListOfDefs("Args");<br>
+    if (Args.empty() || !keywordThisIsaIdentifierInArgument(Args[0]))<br>
+      continue;<br>
+<br>
+    // All these spellings take an identifier argument.<br>
+    forEachUniqueSpelling(*A, [&](const FlattenedSpelling &S) {<br>
+      OS << ".Case(\"" << S.name() << "\", "<br>
+         << "true"<br>
+         << ")\n";<br>
+    });<br>
+  }<br>
+  OS << "#endif // CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST\n\n";<br>
+}<br>
+<br>
 namespace clang {<br>
<br>
 // Emits the class definitions for attributes.<br>
@@ -3767,6 +3803,7 @@ void EmitClangAttrParserStringSwitches(R<br>
   emitClangAttrArgContextList(Records, OS);<br>
   emitClangAttrIdentifierArgList(Records, OS);<br>
   emitClangAttrVariadicIdentifierArgList(Records, OS);<br>
+  emitClangAttrThisIsaIdentifierArgList(Records, OS);<br>
   emitClangAttrTypeArgList(Records, OS);<br>
   emitClangAttrLateParsedList(Records, OS);<br>
 }<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div></div>